2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.powermax.internal.handler;
15 import static org.openhab.binding.powermax.internal.PowermaxBindingConstants.*;
17 import java.util.Collection;
18 import java.util.EventObject;
19 import java.util.List;
22 import java.util.concurrent.CopyOnWriteArrayList;
23 import java.util.concurrent.ScheduledFuture;
24 import java.util.concurrent.TimeUnit;
26 import org.eclipse.jdt.annotation.NonNullByDefault;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.openhab.binding.powermax.internal.config.PowermaxIpConfiguration;
29 import org.openhab.binding.powermax.internal.config.PowermaxSerialConfiguration;
30 import org.openhab.binding.powermax.internal.discovery.PowermaxDiscoveryService;
31 import org.openhab.binding.powermax.internal.message.PowermaxCommManager;
32 import org.openhab.binding.powermax.internal.message.PowermaxSendType;
33 import org.openhab.binding.powermax.internal.state.PowermaxArmMode;
34 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
35 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettingsListener;
36 import org.openhab.binding.powermax.internal.state.PowermaxPanelType;
37 import org.openhab.binding.powermax.internal.state.PowermaxState;
38 import org.openhab.binding.powermax.internal.state.PowermaxStateContainer.Value;
39 import org.openhab.binding.powermax.internal.state.PowermaxStateEvent;
40 import org.openhab.binding.powermax.internal.state.PowermaxStateEventListener;
41 import org.openhab.binding.powermax.internal.state.PowermaxZoneSettings;
42 import org.openhab.core.i18n.TimeZoneProvider;
43 import org.openhab.core.io.transport.serial.SerialPortManager;
44 import org.openhab.core.library.types.OnOffType;
45 import org.openhab.core.library.types.StringType;
46 import org.openhab.core.thing.Bridge;
47 import org.openhab.core.thing.ChannelUID;
48 import org.openhab.core.thing.Thing;
49 import org.openhab.core.thing.ThingStatus;
50 import org.openhab.core.thing.ThingStatusDetail;
51 import org.openhab.core.thing.binding.BaseBridgeHandler;
52 import org.openhab.core.thing.binding.ThingHandler;
53 import org.openhab.core.thing.binding.ThingHandlerService;
54 import org.openhab.core.types.Command;
55 import org.openhab.core.types.RefreshType;
56 import org.openhab.core.types.UnDefType;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
61 * The {@link PowermaxBridgeHandler} is responsible for handling commands, which are
62 * sent to one of the channels.
64 * @author Laurent Garnier - Initial contribution
67 public class PowermaxBridgeHandler extends BaseBridgeHandler implements PowermaxStateEventListener {
69 private static final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
70 private static final long FIVE_MINUTES = TimeUnit.MINUTES.toMillis(5);
72 private static final int NB_EVENT_LOG = 10;
74 private static final PowermaxPanelType DEFAULT_PANEL_TYPE = PowermaxPanelType.POWERMAX_PRO;
76 private static final int JOB_REPEAT = 20;
78 private static final int MAX_DOWNLOAD_ATTEMPTS = 3;
80 private final Logger logger = LoggerFactory.getLogger(PowermaxBridgeHandler.class);
82 private final SerialPortManager serialPortManager;
83 private final TimeZoneProvider timeZoneProvider;
85 private final List<PowermaxPanelSettingsListener> listeners = new CopyOnWriteArrayList<>();
87 private @Nullable ScheduledFuture<?> globalJob;
89 /** The delay in milliseconds to reset a motion detection */
90 private long motionOffDelay;
92 /** The PIN code to use for arming/disarming the Powermax alarm system from openHAB */
93 private String pinCode;
95 /** Force the standard mode rather than trying using the Powerlink mode */
96 private boolean forceStandardMode;
98 /** The object to store the current state of the Powermax alarm system */
99 private PowermaxState currentState;
101 /** The object in charge of the communication with the Powermax alarm system */
102 private @Nullable PowermaxCommManager commManager;
104 private int remainingDownloadAttempts;
106 public PowermaxBridgeHandler(Bridge thing, SerialPortManager serialPortManager, TimeZoneProvider timeZoneProvider) {
108 this.serialPortManager = serialPortManager;
109 this.timeZoneProvider = timeZoneProvider;
111 this.currentState = new PowermaxState(new PowermaxPanelSettings(DEFAULT_PANEL_TYPE), timeZoneProvider);
115 public Collection<Class<? extends ThingHandlerService>> getServices() {
116 return Set.of(PowermaxDiscoveryService.class);
119 public @Nullable PowermaxState getCurrentState() {
120 PowermaxCommManager localCommManager = commManager;
121 return (localCommManager == null) ? null : currentState;
124 public @Nullable PowermaxPanelSettings getPanelSettings() {
125 PowermaxCommManager localCommManager = commManager;
126 return (localCommManager == null) ? null : localCommManager.getPanelSettings();
130 public void initialize() {
131 logger.debug("initializing handler for thing {}", getThing().getUID());
135 String threadName = "OH-binding-" + getThing().getUID().getAsString();
137 String errorMsg = String.format("@text/offline.config-error-unexpected-thing-type [ \"%s\" ]",
138 getThing().getThingTypeUID().getAsString());
139 if (getThing().getThingTypeUID().equals(BRIDGE_TYPE_SERIAL)) {
140 errorMsg = initializeBridgeSerial(getConfigAs(PowermaxSerialConfiguration.class), threadName);
141 } else if (getThing().getThingTypeUID().equals(BRIDGE_TYPE_IP)) {
142 errorMsg = initializeBridgeIp(getConfigAs(PowermaxIpConfiguration.class), threadName);
145 if (errorMsg == null) {
146 ScheduledFuture<?> job = globalJob;
147 if (job == null || job.isCancelled()) {
148 // Delay the startup in case the handler is restarted immediately
149 globalJob = scheduler.scheduleWithFixedDelay(() -> {
151 logger.trace("Powermax job...");
152 updateMotionSensorState();
153 updateRingingState();
156 retryDownloadSetup();
160 } catch (Exception e) {
161 logger.warn("Exception in scheduled job: {}", e.getMessage(), e);
163 }, 10, JOB_REPEAT, TimeUnit.SECONDS);
166 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
170 private @Nullable String initializeBridgeSerial(PowermaxSerialConfiguration config, String threadName) {
171 String errorMsg = null;
172 String serialPort = config.serialPort.trim();
173 if (!serialPort.isEmpty() && !serialPort.startsWith("rfc2217")) {
174 motionOffDelay = config.motionOffDelay * ONE_MINUTE;
175 pinCode = config.pinCode;
176 forceStandardMode = config.forceStandardMode;
177 PowermaxPanelType panelType = getPanelTypeSetting(config.panelType, DEFAULT_PANEL_TYPE);
179 PowermaxArmMode.DISARMED.setAllowedCommand(config.allowDisarming);
180 PowermaxArmMode.ARMED_HOME.setAllowedCommand(config.allowArming);
181 PowermaxArmMode.ARMED_AWAY.setAllowedCommand(config.allowArming);
182 PowermaxArmMode.ARMED_HOME_INSTANT.setAllowedCommand(config.allowArming);
183 PowermaxArmMode.ARMED_AWAY_INSTANT.setAllowedCommand(config.allowArming);
184 PowermaxArmMode.ARMED_NIGHT.setAllowedCommand(config.allowArming);
185 PowermaxArmMode.ARMED_NIGHT_INSTANT.setAllowedCommand(config.allowArming);
187 commManager = new PowermaxCommManager(serialPort, panelType, forceStandardMode, config.autoSyncTime,
188 serialPortManager, threadName, timeZoneProvider);
190 if (serialPort.startsWith("rfc2217")) {
191 errorMsg = "@text/offline.config-error-invalid-thing-type";
193 errorMsg = "@text/offline.config-error-mandatory-serial-port";
199 private @Nullable String initializeBridgeIp(PowermaxIpConfiguration config, String threadName) {
200 String errorMsg = null;
201 String ip = config.ip.trim();
202 if (!ip.isEmpty() && config.tcpPort > 0) {
203 motionOffDelay = config.motionOffDelay * ONE_MINUTE;
204 pinCode = config.pinCode;
205 forceStandardMode = config.forceStandardMode;
206 PowermaxPanelType panelType = getPanelTypeSetting(config.panelType, DEFAULT_PANEL_TYPE);
208 PowermaxArmMode.DISARMED.setAllowedCommand(config.allowDisarming);
209 PowermaxArmMode.ARMED_HOME.setAllowedCommand(config.allowArming);
210 PowermaxArmMode.ARMED_AWAY.setAllowedCommand(config.allowArming);
211 PowermaxArmMode.ARMED_HOME_INSTANT.setAllowedCommand(config.allowArming);
212 PowermaxArmMode.ARMED_AWAY_INSTANT.setAllowedCommand(config.allowArming);
213 PowermaxArmMode.ARMED_NIGHT.setAllowedCommand(config.allowArming);
214 PowermaxArmMode.ARMED_NIGHT_INSTANT.setAllowedCommand(config.allowArming);
216 commManager = new PowermaxCommManager(ip, config.tcpPort, panelType, forceStandardMode, config.autoSyncTime,
217 threadName, timeZoneProvider);
219 errorMsg = "@text/offline.config-error-mandatory-ip-port";
225 public void dispose() {
226 logger.debug("Handler disposed for thing {}", getThing().getUID());
227 ScheduledFuture<?> job = globalJob;
228 if (job != null && !job.isCancelled()) {
238 * Set the state of items linked to motion sensors to OFF when the last trip is older
239 * than the value defined by the variable motionOffDelay
241 private void updateMotionSensorState() {
242 PowermaxCommManager localCommManager = commManager;
243 if (localCommManager != null) {
244 long now = System.currentTimeMillis();
245 boolean update = false;
246 PowermaxState updateState = localCommManager.createNewState();
247 PowermaxPanelSettings panelSettings = localCommManager.getPanelSettings();
248 for (int i = 1; i <= panelSettings.getNbZones(); i++) {
249 PowermaxZoneSettings zoneSettings = panelSettings.getZoneSettings(i);
250 if (zoneSettings != null && zoneSettings.isMotionSensor()
251 && currentState.getZone(i).isLastTripBeforeTime(now - motionOffDelay)) {
253 updateState.getZone(i).tripped.setValue(false);
257 updateChannelsFromAlarmState(TRIPPED, updateState);
258 currentState.merge(updateState);
264 * Turn off the Ringing flag when the bell time expires
266 private void updateRingingState() {
267 PowermaxCommManager localCommManager = commManager;
268 if (localCommManager != null && Boolean.TRUE.equals(currentState.ringing.getValue())) {
269 long now = System.currentTimeMillis();
270 long bellTime = localCommManager.getPanelSettings().getBellTime() * ONE_MINUTE;
272 Long ringingSince = currentState.ringingSince.getValue();
273 if (ringingSince != null && (ringingSince + bellTime) < now) {
274 PowermaxState updateState = localCommManager.createNewState();
275 updateState.ringing.setValue(false);
276 updateChannelsFromAlarmState(RINGING, updateState);
277 currentState.merge(updateState);
283 * Check that we're actively communicating with the panel
285 private void checkKeepAlive() {
286 PowermaxCommManager localCommManager = commManager;
287 if (localCommManager == null) {
290 long now = System.currentTimeMillis();
291 Long lastKeepAlive = currentState.lastKeepAlive.getValue();
292 Long lastMessageTime = currentState.lastMessageTime.getValue();
293 if (Boolean.TRUE.equals(currentState.powerlinkMode.getValue()) && (lastKeepAlive != null)
294 && ((now - lastKeepAlive) > ONE_MINUTE)) {
295 // In Powerlink mode: let Powermax know we are alive
296 localCommManager.sendRestoreMessage();
297 currentState.lastKeepAlive.setValue(now);
298 } else if (!Boolean.TRUE.equals(currentState.downloadMode.getValue()) && (lastMessageTime != null)
299 && ((now - lastMessageTime) > FIVE_MINUTES)) {
300 // In Standard mode: ping the panel every so often to detect disconnects
301 localCommManager.sendMessage(PowermaxSendType.STATUS);
305 private void tryReconnect() {
306 PowermaxCommManager localCommManager = commManager;
307 if (localCommManager == null) {
310 logger.info("Trying to connect or reconnect...");
312 currentState = localCommManager.createNewState();
315 logger.debug("openConnection(): connected");
316 updateStatus(ThingStatus.ONLINE);
317 updateChannelsFromAlarmState(currentState);
318 if (forceStandardMode) {
319 currentState.powerlinkMode.setValue(false);
320 updateChannelsFromAlarmState(MODE, currentState);
321 processPanelSettings();
323 localCommManager.startDownload();
325 } catch (Exception e) {
326 logger.debug("openConnection(): {}", e.getMessage(), e);
327 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
328 setAllChannelsOffline();
333 * Open a TCP or Serial connection to the Powermax Alarm Panel
335 * @return true if the connection has been opened
337 private synchronized void openConnection() throws Exception {
338 PowermaxCommManager localCommManager = commManager;
339 if (localCommManager != null) {
340 localCommManager.addEventListener(this);
341 localCommManager.open();
343 remainingDownloadAttempts = MAX_DOWNLOAD_ATTEMPTS;
347 * Close TCP or Serial connection to the Powermax Alarm Panel and remove the Event Listener
349 private synchronized void closeConnection() {
350 PowermaxCommManager localCommManager = commManager;
351 if (localCommManager != null) {
352 localCommManager.close();
353 localCommManager.removeEventListener(this);
355 logger.debug("closeConnection(): disconnected");
358 private boolean isConnected() {
359 PowermaxCommManager localCommManager = commManager;
360 return localCommManager == null ? false : localCommManager.isConnected();
363 private void retryDownloadSetup() {
364 PowermaxCommManager localCommManager = commManager;
365 if (localCommManager != null) {
366 localCommManager.retryDownloadSetup(remainingDownloadAttempts);
371 public void handleCommand(ChannelUID channelUID, Command command) {
372 logger.debug("Received command {} from channel {}", command, channelUID.getId());
374 if (command instanceof RefreshType) {
375 updateChannelsFromAlarmState(channelUID.getId(), getCurrentState());
377 switch (channelUID.getId()) {
380 PowermaxArmMode armMode = PowermaxArmMode.fromShortName(command.toString());
382 } catch (IllegalArgumentException e) {
383 logger.debug("Powermax alarm binding: invalid command {}", command);
387 if (command instanceof OnOffType) {
389 command.equals(OnOffType.ON) ? PowermaxArmMode.ARMED_AWAY : PowermaxArmMode.DISARMED);
391 logger.debug("Command of type {} while OnOffType is expected. Command is ignored.",
392 command.getClass().getSimpleName());
398 case UPDATE_EVENT_LOGS:
405 logger.debug("No available command for channel {}. Command is ignored.", channelUID.getId());
411 private void armCommand(PowermaxArmMode armMode) {
412 PowermaxCommManager localCommManager = commManager;
413 if (localCommManager == null) {
414 logger.debug("Powermax alarm binding not correctly initialized. Arm command is ignored.");
415 } else if (!isConnected()) {
416 logger.debug("Powermax alarm binding not connected. Arm command is ignored.");
418 localCommManager.requestArmMode(armMode,
419 Boolean.TRUE.equals(currentState.powerlinkMode.getValue())
420 ? localCommManager.getPanelSettings().getFirstPinCode()
425 private void pgmCommand(Command command) {
426 PowermaxCommManager localCommManager = commManager;
427 if (localCommManager == null) {
428 logger.debug("Powermax alarm binding not correctly initialized. PGM command is ignored.");
429 } else if (!isConnected()) {
430 logger.debug("Powermax alarm binding not connected. PGM command is ignored.");
432 localCommManager.sendPGMX10(command, null);
436 public void x10Command(Byte deviceNr, Command command) {
437 PowermaxCommManager localCommManager = commManager;
438 if (localCommManager == null) {
439 logger.debug("Powermax alarm binding not correctly initialized. X10 command is ignored.");
440 } else if (!isConnected()) {
441 logger.debug("Powermax alarm binding not connected. X10 command is ignored.");
443 localCommManager.sendPGMX10(command, deviceNr);
447 public void zoneBypassed(byte zoneNr, boolean bypassed) {
448 PowermaxCommManager localCommManager = commManager;
449 if (localCommManager == null) {
450 logger.debug("Powermax alarm binding not correctly initialized. Zone bypass command is ignored.");
451 } else if (!isConnected()) {
452 logger.debug("Powermax alarm binding not connected. Zone bypass command is ignored.");
453 } else if (!Boolean.TRUE.equals(currentState.powerlinkMode.getValue())) {
454 logger.debug("Powermax alarm binding: Bypass option only supported in Powerlink mode");
455 } else if (!localCommManager.getPanelSettings().isBypassEnabled()) {
456 logger.debug("Powermax alarm binding: Bypass option not enabled in panel settings");
458 localCommManager.sendZoneBypass(bypassed, zoneNr, localCommManager.getPanelSettings().getFirstPinCode());
462 private void downloadEventLog() {
463 PowermaxCommManager localCommManager = commManager;
464 if (localCommManager == null) {
465 logger.debug("Powermax alarm binding not correctly initialized. Event logs command is ignored.");
466 } else if (!isConnected()) {
467 logger.debug("Powermax alarm binding not connected. Event logs command is ignored.");
469 localCommManager.requestEventLog(Boolean.TRUE.equals(currentState.powerlinkMode.getValue())
470 ? localCommManager.getPanelSettings().getFirstPinCode()
475 public void downloadSetup() {
476 PowermaxCommManager localCommManager = commManager;
477 if (localCommManager == null) {
478 logger.debug("Powermax alarm binding not correctly initialized. Download setup command is ignored.");
479 } else if (!isConnected()) {
480 logger.debug("Powermax alarm binding not connected. Download setup command is ignored.");
481 } else if (!Boolean.TRUE.equals(currentState.powerlinkMode.getValue())) {
482 logger.debug("Powermax alarm binding: download setup only supported in Powerlink mode");
483 } else if (localCommManager.isDownloadRunning()) {
484 logger.debug("Powermax alarm binding: download setup not started as one is in progress");
486 localCommManager.startDownload();
487 if (currentState.lastKeepAlive.getValue() != null) {
488 currentState.lastKeepAlive.setValue(System.currentTimeMillis());
493 public String getInfoSetup() {
494 PowermaxPanelSettings panelSettings = getPanelSettings();
495 return (panelSettings == null) ? "" : panelSettings.getInfo();
499 public void onNewStateEvent(EventObject event) {
500 PowermaxCommManager localCommManager = commManager;
501 if (localCommManager == null) {
505 PowermaxStateEvent stateEvent = (PowermaxStateEvent) event;
506 PowermaxState updateState = stateEvent.getState();
508 if (Boolean.TRUE.equals(currentState.powerlinkMode.getValue())
509 && Boolean.TRUE.equals(updateState.downloadSetupRequired.getValue())) {
510 // After Enrolling Powerlink or if a reset is required
511 logger.debug("Powermax alarm binding: Reset");
512 localCommManager.startDownload();
513 updateState.downloadSetupRequired.setValue(false);
514 if (currentState.lastKeepAlive.getValue() != null) {
515 currentState.lastKeepAlive.setValue(System.currentTimeMillis());
517 } else if (Boolean.FALSE.equals(currentState.powerlinkMode.getValue())
518 && updateState.lastKeepAlive.getValue() != null) {
519 // Were are in standard mode but received a keep alive message
520 // so we switch in PowerLink mode
521 logger.debug("Powermax alarm binding: Switching to Powerlink mode");
522 localCommManager.startDownload();
525 boolean doProcessSettings = (updateState.powerlinkMode.getValue() != null);
527 PowermaxPanelSettings panelSettings = localCommManager.getPanelSettings();
528 panelSettings.getZoneRange().forEach(i -> {
529 if (Boolean.TRUE.equals(updateState.getZone(i).armed.getValue())
530 && Boolean.TRUE.equals(currentState.getZone(i).bypassed.getValue())) {
531 updateState.getZone(i).armed.setValue(false);
535 updateState.keepOnlyDifferencesWith(currentState);
536 updateChannelsFromAlarmState(updateState);
537 currentState.merge(updateState);
539 if (!updateState.getUpdatedZoneNames().isEmpty()) {
540 for (Integer zoneIdx : updateState.getUpdatedZoneNames().keySet()) {
541 if (panelSettings.getZoneSettings(zoneIdx) != null) {
542 for (PowermaxPanelSettingsListener listener : listeners) {
543 listener.onZoneSettingsUpdated(zoneIdx, panelSettings);
549 if (doProcessSettings) {
550 // There is a change of mode (standard or Powerlink)
551 processPanelSettings();
552 localCommManager.exitDownload();
557 public void onCommunicationFailure(String message) {
558 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
559 setAllChannelsOffline();
562 private void processPanelSettings() {
563 PowermaxCommManager localCommManager = commManager;
564 if (localCommManager == null) {
568 if (localCommManager.processPanelSettings(Boolean.TRUE.equals(currentState.powerlinkMode.getValue()))) {
569 for (PowermaxPanelSettingsListener listener : listeners) {
570 listener.onPanelSettingsUpdated(localCommManager.getPanelSettings());
572 remainingDownloadAttempts = 0;
574 logger.info("Powermax alarm binding: setup download failed!");
575 for (PowermaxPanelSettingsListener listener : listeners) {
576 listener.onPanelSettingsUpdated(null);
578 remainingDownloadAttempts--;
580 updatePropertiesFromPanelSettings();
581 if (Boolean.TRUE.equals(currentState.powerlinkMode.getValue())) {
582 logger.info("Powermax alarm binding: running in Powerlink mode");
583 localCommManager.sendRestoreMessage();
585 logger.info("Powermax alarm binding: running in Standard mode");
586 localCommManager.getInfosWhenInStandardMode();
591 * Update channels to match a new alarm system state
593 * @param state: the alarm system state
595 private void updateChannelsFromAlarmState(@Nullable PowermaxState state) {
596 updateChannelsFromAlarmState(null, state);
600 * Update channels to match a new alarm system state
602 * @param channel: filter on a particular channel; if null, consider all channels
603 * @param state: the alarm system state
605 private synchronized void updateChannelsFromAlarmState(@Nullable String channel, @Nullable PowermaxState state) {
606 if (state == null || !isConnected()) {
610 for (Value<?> value : state.getValues()) {
611 String vChannel = value.getChannel();
613 if (((channel == null) || channel.equals(vChannel)) && isLinked(vChannel) && (value.getValue() != null)) {
614 updateState(vChannel, value.getState());
618 for (int i = 1; i <= NB_EVENT_LOG; i++) {
619 String channel2 = String.format(EVENT_LOG, i);
620 String log = state.getEventLog(i);
621 if (((channel == null) || channel.equals(channel2)) && isLinked(channel2) && (log != null)) {
622 updateState(channel2, new StringType(log));
626 for (Thing thing : getThing().getThings()) {
627 if (!thing.isEnabled()) {
630 ThingHandler thingHandler = thing.getHandler();
631 if (thingHandler instanceof PowermaxThingHandler powermaxThingHandler) {
632 if (thing.getThingTypeUID().equals(THING_TYPE_ZONE)) {
633 // All of the zone state objects will have the same list of values.
634 // The use of getZone(1) here is just to get any PowermaxZoneState
635 // and use it to get the list of zone channels.
637 for (Value<?> value : state.getZone(1).getValues()) {
638 String channelId = value.getChannel();
639 if ((channel == null) || channel.equals(channelId)) {
640 powermaxThingHandler.updateChannelFromAlarmState(channelId, state);
643 } else if (thing.getThingTypeUID().equals(THING_TYPE_X10)) {
644 if ((channel == null) || channel.equals(X10_STATUS)) {
645 powermaxThingHandler.updateChannelFromAlarmState(X10_STATUS, state);
653 * Update all channels to an UNDEF state to indicate that communication with the panel is offline
655 private synchronized void setAllChannelsOffline() {
656 getThing().getChannels().forEach(c -> updateState(c.getUID(), UnDefType.UNDEF));
660 * Update properties to match the alarm panel settings
662 private void updatePropertiesFromPanelSettings() {
663 PowermaxPanelSettings panelSettings = getPanelSettings();
664 if (panelSettings == null) {
668 Map<String, String> properties = editProperties();
669 value = panelSettings.getPanelType().getLabel();
670 if (!value.isEmpty()) {
671 properties.put(Thing.PROPERTY_MODEL_ID, value);
673 value = panelSettings.getPanelSerial();
674 if (value != null && !value.isEmpty()) {
675 properties.put(Thing.PROPERTY_SERIAL_NUMBER, value);
677 value = panelSettings.getPanelEprom();
678 if (value != null && !value.isEmpty()) {
679 properties.put(Thing.PROPERTY_HARDWARE_VERSION, value);
681 value = panelSettings.getPanelSoftware();
682 if (value != null && !value.isEmpty()) {
683 properties.put(Thing.PROPERTY_FIRMWARE_VERSION, value);
685 updateProperties(properties);
688 public boolean registerPanelSettingsListener(PowermaxPanelSettingsListener listener) {
689 boolean inList = true;
690 if (!listeners.contains(listener)) {
691 inList = listeners.add(listener);
696 public boolean unregisterPanelSettingsListener(PowermaxPanelSettingsListener listener) {
697 return listeners.remove(listener);
700 private PowermaxPanelType getPanelTypeSetting(String value, PowermaxPanelType defaultValue) {
701 PowermaxPanelType result;
703 result = PowermaxPanelType.fromLabel(value);
704 } catch (IllegalArgumentException e) {
705 result = defaultValue;
706 logger.debug("Powermax alarm binding: panel type not configured correctly");