]> git.basschouten.com Git - openhab-addons.git/commitdiff
[powermax] Refactor state objects (#9684)
authorRon Isaacson <isaacson.ron@gmail.com>
Wed, 13 Jan 2021 20:29:22 +0000 (15:29 -0500)
committerGitHub <noreply@github.com>
Wed, 13 Jan 2021 20:29:22 +0000 (12:29 -0800)
* Improve debugging in message classes

Each PowermaxBaseMessage subclass had its own toString() which added
useful debug info but duplicated a lot of the logic in the message
handler. I've moved the debug info inline and removed the duplication,
and also added decoding for more values to the debug output.

* Fix for 0xFF byte values, which convert to int -1

Signed-off-by: Ron Isaacson <isaacson.ron@gmail.com>
15 files changed:
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/PowermaxHandlerFactory.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/connector/PowermaxSerialConnector.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/console/PowermaxCommandExtension.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxBridgeHandler.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxThingHandler.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxAckMessage.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxCommManager.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxDeniedMessage.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxInfoMessage.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPanelMessage.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPowerlinkMessage.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxStatusMessage.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxState.java
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxStateContainer.java [new file with mode: 0644]
bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxZoneState.java

index 1b62b5803c2cfe40ae86a5df9d0c17ae144bbefc..94135961a2eff73a32fe9395a940e3d62975c9b6 100644 (file)
@@ -80,9 +80,9 @@ public class PowermaxHandlerFactory extends BaseThingHandlerFactory {
         ThingTypeUID thingTypeUID = thing.getThingTypeUID();
 
         if (SUPPORTED_BRIDGE_TYPES_UIDS.contains(thingTypeUID)) {
-            return new PowermaxBridgeHandler((Bridge) thing, serialPortManager);
+            return new PowermaxBridgeHandler((Bridge) thing, serialPortManager, timeZoneProvider);
         } else if (SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID)) {
-            return new PowermaxThingHandler(thing, timeZoneProvider);
+            return new PowermaxThingHandler(thing);
         }
 
         return null;
index c9286cf2c09ff334182f3dcea2e09083c1148606..28aec1acf1ed2402c471ce75e57849a03a85b83b 100644 (file)
@@ -37,8 +37,8 @@ public class PowermaxSerialConnector extends PowermaxConnector implements Serial
 
     private final String serialPortName;
     private final int baudRate;
+    private final SerialPortManager serialPortManager;
     private SerialPort serialPort;
-    private SerialPortManager serialPortManager;
 
     /**
      * Constructor
index e8e3449ab00e20fb5eae70ea331bb954c0fb6d4e..3d58f5250eed9e531c7b6e4beb3ba067f3ec6e4b 100644 (file)
@@ -36,6 +36,7 @@ public class PowermaxCommandExtension extends AbstractConsoleCommandExtension {
 
     private static final String INFO_SETUP = "info_setup";
     private static final String DOWNLOAD_SETUP = "download_setup";
+    private static final String BRIDGE_STATE = "bridge_state";
 
     private ThingRegistry thingRegistry;
 
@@ -81,6 +82,11 @@ public class PowermaxCommandExtension extends AbstractConsoleCommandExtension {
                         handler.downloadSetup();
                         console.println("Command '" + args[1] + "' handled.");
                         break;
+                    case BRIDGE_STATE:
+                        for (String line : handler.getCurrentState().toString().split("\n")) {
+                            console.println(line);
+                        }
+                        break;
                     default:
                         console.println("Unknown Powermax sub command '" + args[1] + "'");
                         printUsage(console);
@@ -95,7 +101,8 @@ public class PowermaxCommandExtension extends AbstractConsoleCommandExtension {
     @Override
     public List<String> getUsages() {
         return Arrays.asList(new String[] { buildCommandUsage("<bridgeUID> " + INFO_SETUP, "information on setup"),
-                buildCommandUsage("<bridgeUID> " + DOWNLOAD_SETUP, "download setup") });
+                buildCommandUsage("<bridgeUID> " + DOWNLOAD_SETUP, "download setup"),
+                buildCommandUsage("<bridgeUID> " + BRIDGE_STATE, "show current state") });
     }
 
     @Reference
index ae6fc184ce4d362e88f77c1540374997edce5bae..f5033c8065c92ea8d071ded4ce45e27a1be83d46 100644 (file)
@@ -32,8 +32,10 @@ import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettingsListener;
 import org.openhab.binding.powermax.internal.state.PowermaxPanelType;
 import org.openhab.binding.powermax.internal.state.PowermaxState;
+import org.openhab.binding.powermax.internal.state.PowermaxStateContainer.Value;
 import org.openhab.binding.powermax.internal.state.PowermaxStateEvent;
 import org.openhab.binding.powermax.internal.state.PowermaxStateEventListener;
+import org.openhab.core.i18n.TimeZoneProvider;
 import org.openhab.core.io.transport.serial.SerialPortManager;
 import org.openhab.core.library.types.OnOffType;
 import org.openhab.core.library.types.StringType;
@@ -58,6 +60,8 @@ import org.slf4j.LoggerFactory;
 public class PowermaxBridgeHandler extends BaseBridgeHandler implements PowermaxStateEventListener {
 
     private final Logger logger = LoggerFactory.getLogger(PowermaxBridgeHandler.class);
+    private final SerialPortManager serialPortManager;
+    private final TimeZoneProvider timeZoneProvider;
 
     private static final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
 
@@ -92,11 +96,11 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
     private PowermaxCommManager commManager;
 
     private int remainingDownloadAttempts;
-    private SerialPortManager serialPortManager;
 
-    public PowermaxBridgeHandler(Bridge thing, SerialPortManager serialPortManager) {
+    public PowermaxBridgeHandler(Bridge thing, SerialPortManager serialPortManager, TimeZoneProvider timeZoneProvider) {
         super(thing);
         this.serialPortManager = serialPortManager;
+        this.timeZoneProvider = timeZoneProvider;
     }
 
     @Override
@@ -173,7 +177,7 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
             PowermaxArmMode.ARMED_NIGHT_INSTANT.setAllowedCommand(allowArming);
 
             commManager = new PowermaxCommManager(config.serialPort, panelType, forceStandardMode, autoSyncTime,
-                    serialPortManager, threadName);
+                    serialPortManager, threadName, timeZoneProvider);
         } else {
             if (config.serialPort != null && config.serialPort.trim().startsWith("rfc2217")) {
                 errorMsg = "Please use the IP Connection thing type for a serial over IP connection.";
@@ -204,7 +208,7 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
             PowermaxArmMode.ARMED_NIGHT_INSTANT.setAllowedCommand(allowArming);
 
             commManager = new PowermaxCommManager(config.ip, config.tcpPort, panelType, forceStandardMode, autoSyncTime,
-                    threadName);
+                    threadName, timeZoneProvider);
         } else {
             errorMsg = "ip and port settings must be defined in thing configuration";
         }
@@ -235,9 +239,9 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
             PowermaxPanelSettings panelSettings = getPanelSettings();
             for (int i = 1; i <= panelSettings.getNbZones(); i++) {
                 if (panelSettings.getZoneSettings(i) != null && panelSettings.getZoneSettings(i).isMotionSensor()
-                        && currentState.isLastTripBeforeTime(i, now - motionOffDelay)) {
+                        && currentState.getZone(i).isLastTripBeforeTime(now - motionOffDelay)) {
                     update = true;
-                    updateState.setSensorTripped(i, false);
+                    updateState.getZone(i).tripped.setValue(false);
                 }
             }
             if (update) {
@@ -252,11 +256,12 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
      */
     private void checkKeepAlive() {
         long now = System.currentTimeMillis();
-        if (Boolean.TRUE.equals(currentState.isPowerlinkMode()) && (currentState.getLastKeepAlive() != null)
-                && ((now - currentState.getLastKeepAlive()) > ONE_MINUTE)) {
+        if (Boolean.TRUE.equals(currentState.powerlinkMode.getValue())
+                && (currentState.lastKeepAlive.getValue() != null)
+                && ((now - currentState.lastKeepAlive.getValue()) > ONE_MINUTE)) {
             // Let Powermax know we are alive
             commManager.sendRestoreMessage();
-            currentState.setLastKeepAlive(now);
+            currentState.lastKeepAlive.setValue(now);
         }
     }
 
@@ -267,7 +272,7 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
         if (openConnection()) {
             updateStatus(ThingStatus.ONLINE);
             if (forceStandardMode) {
-                currentState.setPowerlinkMode(false);
+                currentState.powerlinkMode.setValue(false);
                 updateChannelsFromAlarmState(MODE, currentState);
                 processPanelSettings();
             } else {
@@ -354,7 +359,8 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
             logger.debug("Powermax alarm binding not connected. Arm command is ignored.");
         } else {
             commManager.requestArmMode(armMode,
-                    currentState.isPowerlinkMode() ? getPanelSettings().getFirstPinCode() : pinCode);
+                    Boolean.TRUE.equals(currentState.powerlinkMode.getValue()) ? getPanelSettings().getFirstPinCode()
+                            : pinCode);
         }
     }
 
@@ -377,7 +383,7 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
     public void zoneBypassed(byte zoneNr, boolean bypassed) {
         if (!isConnected()) {
             logger.debug("Powermax alarm binding not connected. Zone bypass command is ignored.");
-        } else if (!Boolean.TRUE.equals(currentState.isPowerlinkMode())) {
+        } else if (!Boolean.TRUE.equals(currentState.powerlinkMode.getValue())) {
             logger.debug("Powermax alarm binding: Bypass option only supported in Powerlink mode");
         } else if (!getPanelSettings().isBypassEnabled()) {
             logger.debug("Powermax alarm binding: Bypass option not enabled in panel settings");
@@ -390,22 +396,23 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
         if (!isConnected()) {
             logger.debug("Powermax alarm binding not connected. Event logs command is ignored.");
         } else {
-            commManager
-                    .requestEventLog(currentState.isPowerlinkMode() ? getPanelSettings().getFirstPinCode() : pinCode);
+            commManager.requestEventLog(
+                    Boolean.TRUE.equals(currentState.powerlinkMode.getValue()) ? getPanelSettings().getFirstPinCode()
+                            : pinCode);
         }
     }
 
     public void downloadSetup() {
         if (!isConnected()) {
             logger.debug("Powermax alarm binding not connected. Download setup command is ignored.");
-        } else if (!Boolean.TRUE.equals(currentState.isPowerlinkMode())) {
+        } else if (!Boolean.TRUE.equals(currentState.powerlinkMode.getValue())) {
             logger.debug("Powermax alarm binding: download setup only supported in Powerlink mode");
         } else if (commManager.isDownloadRunning()) {
             logger.debug("Powermax alarm binding: download setup not started as one is in progress");
         } else {
             commManager.startDownload();
-            if (currentState.getLastKeepAlive() != null) {
-                currentState.setLastKeepAlive(System.currentTimeMillis());
+            if (currentState.lastKeepAlive.getValue() != null) {
+                currentState.lastKeepAlive.setValue(System.currentTimeMillis());
             }
         }
     }
@@ -419,27 +426,29 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
         PowermaxStateEvent stateEvent = (PowermaxStateEvent) event;
         PowermaxState updateState = stateEvent.getState();
 
-        if (Boolean.TRUE.equals(currentState.isPowerlinkMode())
-                && Boolean.TRUE.equals(updateState.isDownloadSetupRequired())) {
+        if (Boolean.TRUE.equals(currentState.powerlinkMode.getValue())
+                && Boolean.TRUE.equals(updateState.downloadSetupRequired.getValue())) {
             // After Enrolling Powerlink or if a reset is required
             logger.debug("Powermax alarm binding: Reset");
             commManager.startDownload();
-            if (currentState.getLastKeepAlive() != null) {
-                currentState.setLastKeepAlive(System.currentTimeMillis());
+            updateState.downloadSetupRequired.setValue(false);
+            if (currentState.lastKeepAlive.getValue() != null) {
+                currentState.lastKeepAlive.setValue(System.currentTimeMillis());
             }
-        } else if (Boolean.FALSE.equals(currentState.isPowerlinkMode()) && updateState.getLastKeepAlive() != null) {
+        } else if (Boolean.FALSE.equals(currentState.powerlinkMode.getValue())
+                && updateState.lastKeepAlive.getValue() != null) {
             // Were are in standard mode but received a keep alive message
             // so we switch in PowerLink mode
             logger.debug("Powermax alarm binding: Switching to Powerlink mode");
             commManager.startDownload();
         }
 
-        boolean doProcessSettings = (updateState.isPowerlinkMode() != null);
+        boolean doProcessSettings = (updateState.powerlinkMode.getValue() != null);
 
         for (int i = 1; i <= getPanelSettings().getNbZones(); i++) {
-            if (Boolean.TRUE.equals(updateState.isSensorArmed(i))
-                    && Boolean.TRUE.equals(currentState.isSensorBypassed(i))) {
-                updateState.setSensorArmed(i, false);
+            if (Boolean.TRUE.equals(updateState.getZone(i).armed.getValue())
+                    && Boolean.TRUE.equals(currentState.getZone(i).bypassed.getValue())) {
+                updateState.getZone(i).armed.setValue(false);
             }
         }
 
@@ -466,7 +475,7 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
     }
 
     private void processPanelSettings() {
-        if (commManager.processPanelSettings(currentState.isPowerlinkMode())) {
+        if (commManager.processPanelSettings(Boolean.TRUE.equals(currentState.powerlinkMode.getValue()))) {
             for (PowermaxPanelSettingsListener listener : listeners) {
                 listener.onPanelSettingsUpdated(getPanelSettings());
             }
@@ -479,7 +488,7 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
             remainingDownloadAttempts--;
         }
         updatePropertiesFromPanelSettings();
-        if (currentState.isPowerlinkMode()) {
+        if (Boolean.TRUE.equals(currentState.powerlinkMode.getValue())) {
             logger.debug("Powermax alarm binding: running in Powerlink mode");
             commManager.sendRestoreMessage();
         } else {
@@ -508,43 +517,15 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
             return;
         }
 
-        if (((channel == null) || channel.equals(MODE)) && isLinked(MODE) && (state.getPanelMode() != null)) {
-            updateState(MODE, new StringType(state.getPanelMode()));
-        }
-        if (((channel == null) || channel.equals(SYSTEM_STATUS)) && isLinked(SYSTEM_STATUS)
-                && (state.getStatusStr() != null)) {
-            updateState(SYSTEM_STATUS, new StringType(state.getStatusStr()));
-        }
-        if (((channel == null) || channel.equals(READY)) && isLinked(READY) && (state.isReady() != null)) {
-            updateState(READY, state.isReady() ? OnOffType.ON : OnOffType.OFF);
-        }
-        if (((channel == null) || channel.equals(WITH_ZONES_BYPASSED)) && isLinked(WITH_ZONES_BYPASSED)
-                && (state.isBypass() != null)) {
-            updateState(WITH_ZONES_BYPASSED, state.isBypass() ? OnOffType.ON : OnOffType.OFF);
-        }
-        if (((channel == null) || channel.equals(ALARM_ACTIVE)) && isLinked(ALARM_ACTIVE)
-                && (state.isAlarmActive() != null)) {
-            updateState(ALARM_ACTIVE, state.isAlarmActive() ? OnOffType.ON : OnOffType.OFF);
-        }
-        if (((channel == null) || channel.equals(TROUBLE)) && isLinked(TROUBLE) && (state.isTrouble() != null)) {
-            updateState(TROUBLE, state.isTrouble() ? OnOffType.ON : OnOffType.OFF);
-        }
-        if (((channel == null) || channel.equals(ALERT_IN_MEMORY)) && isLinked(ALERT_IN_MEMORY)
-                && (state.isAlertInMemory() != null)) {
-            updateState(ALERT_IN_MEMORY, state.isAlertInMemory() ? OnOffType.ON : OnOffType.OFF);
-        }
-        if (((channel == null) || channel.equals(SYSTEM_ARMED)) && isLinked(SYSTEM_ARMED)
-                && (state.isArmed() != null)) {
-            updateState(SYSTEM_ARMED, state.isArmed() ? OnOffType.ON : OnOffType.OFF);
-        }
-        if (((channel == null) || channel.equals(ARM_MODE)) && isLinked(ARM_MODE)
-                && (state.getShortArmMode() != null)) {
-            updateState(ARM_MODE, new StringType(state.getShortArmMode()));
-        }
-        if (((channel == null) || channel.equals(PGM_STATUS)) && isLinked(PGM_STATUS)
-                && (state.getPGMX10DeviceStatus(0) != null)) {
-            updateState(PGM_STATUS, state.getPGMX10DeviceStatus(0) ? OnOffType.ON : OnOffType.OFF);
+        for (Value<?> value : state.getValues()) {
+            String vChannel = value.getChannel();
+
+            if (((channel == null) || channel.equals(vChannel)) && (vChannel != null) && isLinked(vChannel)
+                    && (value.getValue() != null)) {
+                updateState(vChannel, value.getState());
+            }
         }
+
         for (int i = 1; i <= NB_EVENT_LOG; i++) {
             String channel2 = String.format(EVENT_LOG, i);
             if (((channel == null) || channel.equals(channel2)) && isLinked(channel2)
@@ -558,8 +539,14 @@ public class PowermaxBridgeHandler extends BaseBridgeHandler implements Powermax
                 PowermaxThingHandler handler = (PowermaxThingHandler) thing.getHandler();
                 if (handler != null) {
                     if (thing.getThingTypeUID().equals(THING_TYPE_ZONE)) {
-                        for (String channelId : List.of(TRIPPED, LAST_TRIP, BYPASSED, ARMED, LOCKED, LOW_BATTERY)) {
-                            if ((channel == null) || channel.equals(channelId)) {
+
+                        // All of the zone state objects will have the same list of values.
+                        // The use of getZone(1) here is just to get any PowermaxZoneState
+                        // and use it to get the list of zone channels.
+
+                        for (Value<?> value : state.getZone(1).getValues()) {
+                            String channelId = value.getChannel();
+                            if ((channelId != null) && ((channel == null) || channel.equals(channelId))) {
                                 handler.updateChannelFromAlarmState(channelId, state);
                             }
                         }
index f6b55f38b0b29ca8c70e01a6797405a3085c991b..c31c1b777e38c691d9394438c3bf8e4b4e282d4a 100644 (file)
@@ -14,21 +14,16 @@ package org.openhab.binding.powermax.internal.handler;
 
 import static org.openhab.binding.powermax.internal.PowermaxBindingConstants.*;
 
-import java.time.Instant;
-import java.time.ZonedDateTime;
-
 import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.powermax.internal.config.PowermaxX10Configuration;
 import org.openhab.binding.powermax.internal.config.PowermaxZoneConfiguration;
 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettings;
 import org.openhab.binding.powermax.internal.state.PowermaxPanelSettingsListener;
 import org.openhab.binding.powermax.internal.state.PowermaxState;
+import org.openhab.binding.powermax.internal.state.PowermaxStateContainer.Value;
 import org.openhab.binding.powermax.internal.state.PowermaxX10Settings;
 import org.openhab.binding.powermax.internal.state.PowermaxZoneSettings;
-import org.openhab.core.i18n.TimeZoneProvider;
-import org.openhab.core.library.types.DateTimeType;
 import org.openhab.core.library.types.OnOffType;
-import org.openhab.core.library.types.OpenClosedType;
 import org.openhab.core.thing.Bridge;
 import org.openhab.core.thing.ChannelUID;
 import org.openhab.core.thing.Thing;
@@ -57,13 +52,10 @@ public class PowermaxThingHandler extends BaseThingHandler implements PowermaxPa
     private static final int X10_NR_MIN = 1;
     private static final int X10_NR_MAX = 16;
 
-    private final TimeZoneProvider timeZoneProvider;
-
     private PowermaxBridgeHandler bridgeHandler;
 
-    public PowermaxThingHandler(Thing thing, TimeZoneProvider timeZoneProvider) {
+    public PowermaxThingHandler(Thing thing) {
         super(thing);
-        this.timeZoneProvider = timeZoneProvider;
     }
 
     @Override
@@ -181,20 +173,13 @@ public class PowermaxThingHandler extends BaseThingHandler implements PowermaxPa
 
         if (getThing().getThingTypeUID().equals(THING_TYPE_ZONE)) {
             int num = getConfigAs(PowermaxZoneConfiguration.class).zoneNumber.intValue();
-            if (channel.equals(TRIPPED) && (state.isSensorTripped(num) != null)) {
-                updateState(TRIPPED, state.isSensorTripped(num) ? OpenClosedType.OPEN : OpenClosedType.CLOSED);
-            } else if (channel.equals(LAST_TRIP) && (state.getSensorLastTripped(num) != null)) {
-                ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(state.getSensorLastTripped(num)),
-                        timeZoneProvider.getTimeZone());
-                updateState(LAST_TRIP, new DateTimeType(zoned));
-            } else if (channel.equals(BYPASSED) && (state.isSensorBypassed(num) != null)) {
-                updateState(BYPASSED, state.isSensorBypassed(num) ? OnOffType.ON : OnOffType.OFF);
-            } else if (channel.equals(ARMED) && (state.isSensorArmed(num) != null)) {
-                updateState(ARMED, state.isSensorArmed(num) ? OnOffType.ON : OnOffType.OFF);
-            } else if (channel.equals(LOCKED) && (state.isSensorArmed(num) != null)) {
-                updateState(LOCKED, state.isSensorArmed(num) ? OpenClosedType.CLOSED : OpenClosedType.OPEN);
-            } else if (channel.equals(LOW_BATTERY) && (state.isSensorLowBattery(num) != null)) {
-                updateState(LOW_BATTERY, state.isSensorLowBattery(num) ? OnOffType.ON : OnOffType.OFF);
+
+            for (Value<?> value : state.getZone(num).getValues()) {
+                String v_channel = value.getChannel();
+
+                if (channel.equals(v_channel) && (value.getValue() != null)) {
+                    updateState(v_channel, value.getState());
+                }
             }
         } else if (getThing().getThingTypeUID().equals(THING_TYPE_X10)) {
             int num = getConfigAs(PowermaxX10Configuration.class).deviceNumber.intValue();
index 994f44d35c54b798c16825607943c721cdfeafdd..c17598bd1ccadf1182678b423b4c16352e821922 100644 (file)
@@ -41,8 +41,8 @@ public class PowermaxAckMessage extends PowermaxBaseMessage {
 
         if (commManager.getLastSendMsg().getSendType() == PowermaxSendType.EXIT) {
             updatedState = commManager.createNewState();
-            updatedState.setPowerlinkMode(true);
-            updatedState.setDownloadMode(false);
+            updatedState.powerlinkMode.setValue(true);
+            updatedState.downloadMode.setValue(false);
         }
 
         return updatedState;
index 99e07e2efd486a9d5b0d85ff25a2575d38d8055d..e902002000d0bf7b78347e9b1ea8fa3bffac2753 100644 (file)
@@ -33,6 +33,7 @@ import org.openhab.binding.powermax.internal.state.PowermaxState;
 import org.openhab.binding.powermax.internal.state.PowermaxStateEvent;
 import org.openhab.binding.powermax.internal.state.PowermaxStateEventListener;
 import org.openhab.core.common.ThreadPoolManager;
+import org.openhab.core.i18n.TimeZoneProvider;
 import org.openhab.core.io.transport.serial.SerialPortManager;
 import org.openhab.core.types.Command;
 import org.openhab.core.util.HexUtils;
@@ -68,6 +69,7 @@ public class PowermaxCommManager implements PowermaxMessageEventListener {
 
     private boolean forceStandardMode;
     private boolean autoSyncTime;
+    private final TimeZoneProvider timeZoneProvider;
 
     private List<PowermaxStateEventListener> listeners = new ArrayList<>();
 
@@ -100,10 +102,12 @@ public class PowermaxCommManager implements PowermaxMessageEventListener {
      * @param threadName the prefix name of threads to be created
      */
     public PowermaxCommManager(String sPort, PowermaxPanelType panelType, boolean forceStandardMode,
-            boolean autoSyncTime, SerialPortManager serialPortManager, String threadName) {
+            boolean autoSyncTime, SerialPortManager serialPortManager, String threadName,
+            TimeZoneProvider timeZoneProvider) {
         this.panelType = panelType;
         this.forceStandardMode = forceStandardMode;
         this.autoSyncTime = autoSyncTime;
+        this.timeZoneProvider = timeZoneProvider;
         this.panelSettings = new PowermaxPanelSettings(panelType);
         this.scheduler = ThreadPoolManager.getScheduledPool(threadName + "-sender");
         String serialPort = (sPort != null && !sPort.trim().isEmpty()) ? sPort.trim() : null;
@@ -127,10 +131,11 @@ public class PowermaxCommManager implements PowermaxMessageEventListener {
      * @param threadName the prefix name of threads to be created
      */
     public PowermaxCommManager(String ip, int port, PowermaxPanelType panelType, boolean forceStandardMode,
-            boolean autoSyncTime, String threadName) {
+            boolean autoSyncTime, String threadName, TimeZoneProvider timeZoneProvider) {
         this.panelType = panelType;
         this.forceStandardMode = forceStandardMode;
         this.autoSyncTime = autoSyncTime;
+        this.timeZoneProvider = timeZoneProvider;
         this.panelSettings = new PowermaxPanelSettings(panelType);
         this.scheduler = ThreadPoolManager.getScheduledPool(threadName + "-sender");
         String ipAddress = (ip != null && !ip.trim().isEmpty()) ? ip.trim() : null;
@@ -223,7 +228,7 @@ public class PowermaxCommManager implements PowermaxMessageEventListener {
      * @return a new instance of PowermaxState
      */
     public PowermaxState createNewState() {
-        return new PowermaxState(panelSettings);
+        return new PowermaxState(panelSettings, timeZoneProvider);
     }
 
     /**
index 87e5229f4d6a4c65ffd912e3f8be15bfd98ba261..52593acc572b453af4b545184d3d7668a13f2e0f 100644 (file)
@@ -50,7 +50,7 @@ public class PowermaxDeniedMessage extends PowermaxBaseMessage {
         } else if (lastSendType == PowermaxSendType.DOWNLOAD) {
             logger.debug("Powermax alarm binding: openHAB Powerlink not enrolled");
             updatedState = commManager.createNewState();
-            updatedState.setPowerlinkMode(false);
+            updatedState.powerlinkMode.setValue(false);
         }
 
         return updatedState;
index 96cd471e24c5414eb75647837fb3883d3b123a63..7d6bb8c8196400bd501c81b18ce5599261df9275 100644 (file)
@@ -60,7 +60,7 @@ public class PowermaxInfoMessage extends PowermaxBaseMessage {
         debug("Panel type", panelTypeNr, panelTypeStr);
 
         logger.debug("Reading panel settings");
-        updatedState.setDownloadMode(true);
+        updatedState.downloadMode.setValue(true);
         commManager.sendMessage(PowermaxSendType.DL_PANELFW);
         commManager.sendMessage(PowermaxSendType.DL_SERIAL);
         commManager.sendMessage(PowermaxSendType.DL_ZONESTR);
index 3894717222c8c1317433ed1833fbe8a05453b4fe..a08313472e23f2713d89faeb78e23306050408c5 100644 (file)
@@ -50,7 +50,7 @@ public class PowermaxPanelMessage extends PowermaxBaseMessage {
             int eventType = logEvent & 0x0000007F;
             String logEventStr = PowermaxMessageConstants.getSystemEventString(eventType);
             String logUserStr = PowermaxMessageConstants.getZoneOrUserString(eventZone & 0x000000FF);
-            updatedState.setPanelStatus(logEventStr + " (" + logUserStr + ")");
+            updatedState.panelStatus.setValue(logEventStr + " (" + logUserStr + ")");
 
             debug("Event " + i + " zone code", eventZone, logUserStr);
             debug("Event " + i + " event code", eventType, logEventStr);
@@ -62,7 +62,7 @@ public class PowermaxPanelMessage extends PowermaxBaseMessage {
             } catch (IllegalArgumentException e) {
                 alarmStatus = "None";
             }
-            updatedState.setAlarmType(alarmStatus);
+            updatedState.alarmType.setValue(alarmStatus);
 
             String troubleStatus;
             try {
@@ -71,11 +71,11 @@ public class PowermaxPanelMessage extends PowermaxBaseMessage {
             } catch (IllegalArgumentException e) {
                 troubleStatus = "None";
             }
-            updatedState.setTroubleType(troubleStatus);
+            updatedState.troubleType.setValue(troubleStatus);
 
             if (eventType == 0x60) {
                 // System reset
-                updatedState.setDownloadSetupRequired(true);
+                updatedState.downloadSetupRequired.setValue(true);
             }
         }
 
index 613830c14902908022d320f5ac155e7d074c0eee..795b22ae8b9d4742624babc07a4d957746b4003f 100644 (file)
@@ -53,7 +53,7 @@ public class PowermaxPowerlinkMessage extends PowermaxBaseMessage {
 
             commManager.sendAck(this, (byte) 0x02);
             updatedState = commManager.createNewState();
-            updatedState.setLastKeepAlive(System.currentTimeMillis());
+            updatedState.lastKeepAlive.setValue(System.currentTimeMillis());
         } else if (subType == 0x0A) {
             byte enroll = message[4];
 
@@ -64,7 +64,7 @@ public class PowermaxPowerlinkMessage extends PowermaxBaseMessage {
                 logger.debug("Powermax alarm binding: Enrolling Powerlink");
                 commManager.enrollPowerlink();
                 updatedState = commManager.createNewState();
-                updatedState.setDownloadSetupRequired(true);
+                updatedState.downloadSetupRequired.setValue(true);
             } else {
                 commManager.sendAck(this, (byte) 0x02);
             }
index 2bcba321ede26570f4af7ba617907a36a7626fe4..d30bf0951e309abb462375e19c5e64410cac5edd 100644 (file)
@@ -93,8 +93,8 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
             String batteryStatusStr = zoneList(batteryStatusBytes);
 
             for (int i = 1; i <= panelSettings.getNbZones(); i++) {
-                updatedState.setSensorTripped(i, zoneStatus[i]);
-                updatedState.setSensorLowBattery(i, batteryStatus[i]);
+                updatedState.getZone(i).tripped.setValue(zoneStatus[i]);
+                updatedState.getZone(i).lowBattery.setValue(batteryStatus[i]);
             }
 
             debug("Zone status", zoneStatusBytes, zoneStatusStr);
@@ -110,17 +110,17 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
             String zoneETypeStr = PowermaxMessageConstants.getZoneEventString(zoneEType & 0x000000FF);
 
             if (zoneEType == 0x03) {
-                updatedState.setSensorTripped(eventZone, Boolean.TRUE);
-                updatedState.setSensorLastTripped(eventZone, System.currentTimeMillis());
+                updatedState.getZone(eventZone).tripped.setValue(true);
+                updatedState.getZone(eventZone).lastTripped.setValue(System.currentTimeMillis());
             } else if (zoneEType == 0x04) {
-                updatedState.setSensorTripped(eventZone, Boolean.FALSE);
+                updatedState.getZone(eventZone).tripped.setValue(false);
             } else if (zoneEType == 0x05) {
                 PowermaxZoneSettings zone = panelSettings.getZoneSettings(eventZone);
                 if ((zone != null) && zone.getSensorType().equalsIgnoreCase("unknown")) {
                     zone.setSensorType("Motion");
                 }
-                updatedState.setSensorTripped(eventZone, Boolean.TRUE);
-                updatedState.setSensorLastTripped(eventZone, System.currentTimeMillis());
+                updatedState.getZone(eventZone).tripped.setValue(true);
+                updatedState.getZone(eventZone).lastTripped.setValue(System.currentTimeMillis());
             }
 
             // PGM & X10 devices
@@ -131,30 +131,30 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
             String sysStatusStr = "";
             if ((sysFlags & 0x1) == 1) {
                 sysStatusStr = sysStatusStr + "Ready, ";
-                updatedState.setReady(true);
+                updatedState.ready.setValue(true);
             } else {
                 sysStatusStr = sysStatusStr + "Not ready, ";
-                updatedState.setReady(false);
+                updatedState.ready.setValue(false);
             }
             if (((sysFlags >> 1) & 0x1) == 1) {
                 sysStatusStr = sysStatusStr + "Alert in memory, ";
-                updatedState.setAlertInMemory(true);
+                updatedState.alertInMemory.setValue(true);
             } else {
-                updatedState.setAlertInMemory(false);
+                updatedState.alertInMemory.setValue(false);
             }
             if (((sysFlags >> 2) & 0x1) == 1) {
                 sysStatusStr = sysStatusStr + "Trouble, ";
-                updatedState.setTrouble(true);
+                updatedState.trouble.setValue(true);
             } else {
-                updatedState.setTrouble(false);
+                updatedState.trouble.setValue(false);
             }
             if (((sysFlags >> 3) & 0x1) == 1) {
                 sysStatusStr = sysStatusStr + "Bypass on, ";
-                updatedState.setBypass(true);
+                updatedState.bypass.setValue(true);
             } else {
-                updatedState.setBypass(false);
+                updatedState.bypass.setValue(false);
                 for (int i = 1; i <= panelSettings.getNbZones(); i++) {
-                    updatedState.setSensorBypassed(i, false);
+                    updatedState.getZone(i).bypassed.setValue(false);
                 }
             }
             if (((sysFlags >> 4) & 0x1) == 1) {
@@ -175,9 +175,9 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
             }
             if (((sysFlags >> 7) & 0x1) == 1) {
                 sysStatusStr = sysStatusStr + "Alarm event, ";
-                updatedState.setAlarmActive(true);
+                updatedState.alarmActive.setValue(true);
             } else {
-                updatedState.setAlarmActive(false);
+                updatedState.alarmActive.setValue(false);
             }
             sysStatusStr = sysStatusStr.substring(0, sysStatusStr.length() - 2);
             String statusStr;
@@ -187,8 +187,8 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
             } catch (IllegalArgumentException e) {
                 statusStr = "UNKNOWN";
             }
-            updatedState.setArmMode(statusStr);
-            updatedState.setStatusStr(statusStr + ", " + sysStatusStr);
+            updatedState.armMode.setValue(statusStr);
+            updatedState.statusStr.setValue(statusStr + ", " + sysStatusStr);
 
             debug("System status", sysStatus, statusStr);
             debug("System flags", sysFlags, sysStatusStr);
@@ -208,7 +208,7 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
                     boolean armed = (!zone.getType().equalsIgnoreCase("Non-Alarm") && (zone.isAlwaysInAlarm()
                             || (mode == 0x5) || ((mode == 0x4) && !zone.getType().equalsIgnoreCase("Interior-Follow")
                                     && !zone.getType().equalsIgnoreCase("Interior"))));
-                    updatedState.setSensorArmed(i, armed);
+                    updatedState.getZone(i).armed.setValue(armed);
                 }
             }
         } else if (eventType == 0x06) {
@@ -217,7 +217,7 @@ public class PowermaxStatusMessage extends PowermaxBaseMessage {
             String zoneBypassStr = zoneList(zoneBypassBytes);
 
             for (int i = 1; i <= panelSettings.getNbZones(); i++) {
-                updatedState.setSensorBypassed(i, zoneBypass[i]);
+                updatedState.getZone(i).bypassed.setValue(zoneBypass[i]);
             }
 
             debug("Zone bypass", zoneBypassBytes, zoneBypassStr);
index 97baedfbdfda4da0628c6378db9bf5e243b36025..a6722222a38ace0a626508f29eda53048bd11cbd 100644 (file)
  */
 package org.openhab.binding.powermax.internal.state;
 
+import static org.openhab.binding.powermax.internal.PowermaxBindingConstants.*;
+
 import java.util.HashMap;
 import java.util.Map;
 
+import org.openhab.core.i18n.TimeZoneProvider;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.StringType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * A class to store the state of the alarm system
  *
  * @author Laurent Garnier - Initial contribution
  */
-public class PowermaxState {
+public class PowermaxState extends PowermaxStateContainer {
+
+    private final Logger logger = LoggerFactory.getLogger(PowermaxState.class);
+
+    // For values that are mapped to channels, use a channel name constant from
+    // PowermaxBindingConstants. For values used internally but not mapped to
+    // channels, use a unique name starting with "_".
+
+    public BooleanValue powerlinkMode = new BooleanValue(this, "_powerlink_mode");
+    public BooleanValue downloadMode = new BooleanValue(this, "_download_mode");
+    public BooleanValue ready = new BooleanValue(this, READY);
+    public BooleanValue bypass = new BooleanValue(this, WITH_ZONES_BYPASSED);
+    public BooleanValue alarmActive = new BooleanValue(this, ALARM_ACTIVE);
+    public BooleanValue trouble = new BooleanValue(this, TROUBLE);
+    public BooleanValue alertInMemory = new BooleanValue(this, ALERT_IN_MEMORY);
+    public StringValue statusStr = new StringValue(this, SYSTEM_STATUS);
+    public StringValue armMode = new StringValue(this, "_arm_mode");
+    public BooleanValue downloadSetupRequired = new BooleanValue(this, "_download_setup_required");
+    public DateTimeValue lastKeepAlive = new DateTimeValue(this, "_last_keepalive");
+    public StringValue panelStatus = new StringValue(this, "_panel_status");
+    public StringValue alarmType = new StringValue(this, "_alarm_type");
+    public StringValue troubleType = new StringValue(this, "_trouble_type");
+
+    public DynamicValue<Boolean> isArmed = new DynamicValue<>(this, SYSTEM_ARMED, () -> {
+        return isArmed();
+    }, () -> {
+        return isArmed() ? OnOffType.ON : OnOffType.OFF;
+    });
+
+    public DynamicValue<String> panelMode = new DynamicValue<>(this, MODE, () -> {
+        return getPanelMode();
+    }, () -> {
+        return new StringType(getPanelMode());
+    });
+
+    public DynamicValue<String> shortArmMode = new DynamicValue<>(this, ARM_MODE, () -> {
+        return getShortArmMode();
+    }, () -> {
+        return new StringType(getShortArmMode());
+    });
+
+    public DynamicValue<Boolean> pgmStatus = new DynamicValue<>(this, PGM_STATUS, () -> {
+        return getPGMX10DeviceStatus(0);
+    }, () -> {
+        return getPGMX10DeviceStatus(0) ? OnOffType.ON : OnOffType.OFF;
+    });
 
-    private Boolean powerlinkMode;
-    private Boolean downloadMode;
     private PowermaxZoneState[] zones;
     private Boolean[] pgmX10DevicesStatus;
-    private Boolean ready;
-    private Boolean bypass;
-    private Boolean alarmActive;
-    private Boolean trouble;
-    private Boolean alertInMemory;
-    private String statusStr;
-    private String armMode;
-    private Boolean downloadSetupRequired;
-    private Long lastKeepAlive;
     private byte[] updateSettings;
-    private String panelStatus;
-    private String alarmType;
-    private String troubleType;
     private String[] eventLog;
     private Map<Integer, Byte> updatedZoneNames;
     private Map<Integer, Integer> updatedZoneInfos;
@@ -46,10 +85,12 @@ public class PowermaxState {
     /**
      * Constructor (default values)
      */
-    public PowermaxState(PowermaxPanelSettings panelSettings) {
+    public PowermaxState(PowermaxPanelSettings panelSettings, TimeZoneProvider timeZoneProvider) {
+        super(timeZoneProvider);
+
         zones = new PowermaxZoneState[panelSettings.getNbZones()];
         for (int i = 0; i < panelSettings.getNbZones(); i++) {
-            zones[i] = new PowermaxZoneState();
+            zones[i] = new PowermaxZoneState(timeZoneProvider);
         }
         pgmX10DevicesStatus = new Boolean[panelSettings.getNbPGMX10Devices()];
         updatedZoneNames = new HashMap<>();
@@ -57,165 +98,20 @@ public class PowermaxState {
     }
 
     /**
-     * Get the current mode (standard or Powerlink)
-     *
-     * @return true when the current mode is Powerlink; false when standard
-     */
-    public Boolean isPowerlinkMode() {
-        return powerlinkMode;
-    }
-
-    /**
-     * Set the current mode (standard or Powerlink)
-     *
-     * @param powerlinkMode true for Powerlink or false for standard
-     */
-    public void setPowerlinkMode(Boolean powerlinkMode) {
-        this.powerlinkMode = powerlinkMode;
-    }
-
-    /**
-     * Get whether or not the setup is being downloaded
-     *
-     * @return true when downloading the setup
-     */
-    public Boolean isDownloadMode() {
-        return downloadMode;
-    }
-
-    /**
-     * Set whether or not the setup is being downloaded
-     *
-     * @param downloadMode true when downloading the setup
-     */
-    public void setDownloadMode(Boolean downloadMode) {
-        this.downloadMode = downloadMode;
-    }
-
-    /**
-     * Get whether or not the zone sensor is tripped
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     *
-     * @return true when the zone sensor is tripped
-     */
-    public Boolean isSensorTripped(int zone) {
-        return ((zone < 1) || (zone > zones.length)) ? null : zones[zone - 1].isTripped();
-    }
-
-    /**
-     * Set whether or not the zone sensor is tripped
+     * Return the PowermaxZoneState object for a given zone. If the zone number is
+     * out of range, returns a dummy PowermaxZoneState object that won't be
+     * persisted. The return value is never null, so it's safe to chain method
+     * calls.
      *
      * @param zone the index of the zone (first zone is index 1)
-     * @param tripped true if tripped
+     * @return the zone state object (or a dummy zone state)
      */
-    public void setSensorTripped(int zone, Boolean tripped) {
-        if ((zone >= 1) && (zone <= zones.length)) {
-            this.zones[zone - 1].setTripped(tripped);
-        }
-    }
-
-    /**
-     * Get the timestamp when the zone sensor was last tripped
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     *
-     * @return the timestamp
-     */
-    public Long getSensorLastTripped(int zone) {
-        return ((zone < 1) || (zone > zones.length)) ? null : zones[zone - 1].getLastTripped();
-    }
-
-    /**
-     * Set the timestamp when the zone sensor was last tripped
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     * @param lastTripped the timestamp
-     */
-    public void setSensorLastTripped(int zone, Long lastTripped) {
-        if ((zone >= 1) && (zone <= zones.length)) {
-            this.zones[zone - 1].setLastTripped(lastTripped);
-        }
-    }
-
-    /**
-     * Compare the sensor last trip with a given time
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     * @param refTime the time in ms to compare with
-     *
-     * @return true if the sensor is tripped and last trip is older than the given time
-     */
-    public boolean isLastTripBeforeTime(int zone, long refTime) {
-        return ((zone < 1) || (zone > zones.length)) ? false : zones[zone - 1].isLastTripBeforeTime(refTime);
-    }
-
-    /**
-     * Get whether or not the battery of the zone sensor is low
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     *
-     * @return true when the battery is low
-     */
-    public Boolean isSensorLowBattery(int zone) {
-        return ((zone < 1) || (zone > zones.length)) ? null : zones[zone - 1].isLowBattery();
-    }
-
-    /**
-     * Set whether or not the battery of the zone sensor is low
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     * @param lowBattery true if battery is low
-     */
-    public void setSensorLowBattery(int zone, Boolean lowBattery) {
-        if ((zone >= 1) && (zone <= zones.length)) {
-            this.zones[zone - 1].setLowBattery(lowBattery);
-        }
-    }
-
-    /**
-     * Get whether or not the zone sensor is bypassed
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     *
-     * @return true if bypassed
-     */
-    public Boolean isSensorBypassed(int zone) {
-        return ((zone < 1) || (zone > zones.length)) ? null : zones[zone - 1].isBypassed();
-    }
-
-    /**
-     * Set whether or not the zone sensor is bypassed
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     * @param bypassed true if bypassed
-     */
-    public void setSensorBypassed(int zone, Boolean bypassed) {
-        if ((zone >= 1) && (zone <= zones.length)) {
-            this.zones[zone - 1].setBypassed(bypassed);
-        }
-    }
-
-    /**
-     * Get whether or not the zone sensor is armed
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     *
-     * @return true if armed
-     */
-    public Boolean isSensorArmed(int zone) {
-        return ((zone < 1) || (zone > zones.length)) ? null : zones[zone - 1].isArmed();
-    }
-
-    /**
-     * Set whether or not the zone sensor is armed
-     *
-     * @param zone the index of the zone (first zone is index 1)
-     * @param armed true if armed
-     */
-    public void setSensorArmed(int zone, Boolean armed) {
-        if ((zone >= 1) && (zone <= zones.length)) {
-            this.zones[zone - 1].setArmed(armed);
+    public PowermaxZoneState getZone(int zone) {
+        if ((zone < 1) || (zone > zones.length)) {
+            logger.warn("Received update for invalid zone {}", zone);
+            return new PowermaxZoneState(timeZoneProvider);
+        } else {
+            return zones[zone - 1];
         }
     }
 
@@ -242,168 +138,6 @@ public class PowermaxState {
         }
     }
 
-    /**
-     * Get whether or not the panel is ready
-     *
-     * @return true if ready
-     */
-    public Boolean isReady() {
-        return ready;
-    }
-
-    /**
-     * Set whether or not the panel is ready
-     *
-     * @param ready true if ready
-     */
-    public void setReady(Boolean ready) {
-        this.ready = ready;
-    }
-
-    /**
-     * Get whether or not at least one zone is bypassed
-     *
-     * @return true if at least one zone is bypassed
-     */
-    public Boolean isBypass() {
-        return bypass;
-    }
-
-    /**
-     * Set whether or not at least one zone is bypassed
-     *
-     * @param bypass true if at least one zone is bypassed
-     */
-    public void setBypass(Boolean bypass) {
-        this.bypass = bypass;
-    }
-
-    /**
-     * Get whether or not the alarm is active
-     *
-     * @return true if active
-     */
-    public Boolean isAlarmActive() {
-        return alarmActive;
-    }
-
-    /**
-     * Set whether or not the alarm is active
-     *
-     * @param alarmActive true if the alarm is active
-     */
-    public void setAlarmActive(Boolean alarmActive) {
-        this.alarmActive = alarmActive;
-    }
-
-    /**
-     * Get whether or not the panel is identifying a trouble
-     *
-     * @return true if the panel is identifying a trouble
-     */
-    public Boolean isTrouble() {
-        return trouble;
-    }
-
-    /**
-     * Set whether or not the panel is identifying a trouble
-     *
-     * @param trouble true if trouble is identified
-     */
-    public void setTrouble(Boolean trouble) {
-        this.trouble = trouble;
-    }
-
-    /**
-     * Get whether or not the panel has saved an alert in memory
-     *
-     * @return true if the panel has saved an alert in memory
-     */
-    public Boolean isAlertInMemory() {
-        return alertInMemory;
-    }
-
-    /**
-     * Set whether or not the panel has saved an alert in memory
-     *
-     * @param alertInMemory true if an alert is saved in memory
-     */
-    public void setAlertInMemory(Boolean alertInMemory) {
-        this.alertInMemory = alertInMemory;
-    }
-
-    /**
-     * Get the partition status
-     *
-     * @return the status as a short string
-     */
-    public String getStatusStr() {
-        return statusStr;
-    }
-
-    /**
-     * Set the partition status
-     *
-     * @param statusStr the status as a short string
-     */
-    public void setStatusStr(String statusStr) {
-        this.statusStr = statusStr;
-    }
-
-    /**
-     * Get the arming name
-     *
-     * @return the arming mode
-     */
-    public String getArmMode() {
-        return armMode;
-    }
-
-    /**
-     * Set the arming name
-     *
-     * @param armMode the arming name
-     */
-    public void setArmMode(String armMode) {
-        this.armMode = armMode;
-    }
-
-    /**
-     * Get whether or not the setup downloading is required
-     *
-     * @return true when downloading the setup is required
-     */
-    public Boolean isDownloadSetupRequired() {
-        return downloadSetupRequired;
-    }
-
-    /**
-     * Set whether or not the setup downloading is required
-     *
-     * @param downloadSetupRequired true when downloading setup is required
-     */
-    public void setDownloadSetupRequired(Boolean downloadSetupRequired) {
-        this.downloadSetupRequired = downloadSetupRequired;
-    }
-
-    /**
-     * Get the timestamp of the last received "keep alive" message
-     *
-     * @return the timestamp
-     */
-    public Long getLastKeepAlive() {
-        return lastKeepAlive;
-    }
-
-    /**
-     * Set the timestamp of the last received "keep alive" message
-     *
-     * @param lastKeepAlive the timestamp
-     */
-    public void setLastKeepAlive(Long lastKeepAlive) {
-        this.lastKeepAlive = lastKeepAlive;
-    }
-
     /**
      * Get the raw buffer containing all the settings
      *
@@ -422,60 +156,6 @@ public class PowermaxState {
         this.updateSettings = updateSettings;
     }
 
-    /**
-     * Get the panel status
-     *
-     * @return the panel status
-     */
-    public String getPanelStatus() {
-        return panelStatus;
-    }
-
-    /**
-     * Set the panel status
-     *
-     * @param panelStatus the status as a short string
-     */
-    public void setPanelStatus(String panelStatus) {
-        this.panelStatus = panelStatus;
-    }
-
-    /**
-     * Get the kind of the current alarm identified by the panel
-     *
-     * @return the kind of the current alarm; null if no alarm
-     */
-    public String getAlarmType() {
-        return alarmType;
-    }
-
-    /**
-     * Set the kind of the current alarm identified by the panel
-     *
-     * @param alarmType the kind of alarm (set it to null if no alarm)
-     */
-    public void setAlarmType(String alarmType) {
-        this.alarmType = alarmType;
-    }
-
-    /**
-     * Get the kind of the current trouble identified by the panel
-     *
-     * @return the kind of the current trouble; null if no trouble
-     */
-    public String getTroubleType() {
-        return troubleType;
-    }
-
-    /**
-     * Set the kind of the current trouble identified by the panel
-     *
-     * @param troubleType the kind of trouble (set it to null if no trouble)
-     */
-    public void setTroubleType(String troubleType) {
-        this.troubleType = troubleType;
-    }
-
     /**
      * Get the number of entries in the event log
      *
@@ -540,11 +220,11 @@ public class PowermaxState {
      */
     public String getPanelMode() {
         String mode = null;
-        if (Boolean.TRUE.equals(downloadMode)) {
+        if (Boolean.TRUE.equals(downloadMode.getValue())) {
             mode = "Download";
-        } else if (Boolean.TRUE.equals(powerlinkMode)) {
+        } else if (Boolean.TRUE.equals(powerlinkMode.getValue())) {
             mode = "Powerlink";
-        } else if (Boolean.FALSE.equals(powerlinkMode)) {
+        } else if (Boolean.FALSE.equals(powerlinkMode.getValue())) {
             mode = "Standard";
         }
         return mode;
@@ -556,7 +236,7 @@ public class PowermaxState {
      * @return true or false
      */
     public Boolean isArmed() {
-        return isArmed(getArmMode());
+        return isArmed(armMode.getValue());
     }
 
     /**
@@ -585,7 +265,7 @@ public class PowermaxState {
      * @return the short description
      */
     public String getShortArmMode() {
-        return getShortArmMode(getArmMode());
+        return getShortArmMode(armMode.getValue());
     }
 
     /**
@@ -614,62 +294,34 @@ public class PowermaxState {
      * @param otherState the other state
      */
     public void keepOnlyDifferencesWith(PowermaxState otherState) {
-        for (int i = 1; i <= zones.length; i++) {
-            if ((isSensorTripped(i) != null) && isSensorTripped(i).equals(otherState.isSensorTripped(i))) {
-                setSensorTripped(i, null);
-            }
-            if ((getSensorLastTripped(i) != null)
-                    && getSensorLastTripped(i).equals(otherState.getSensorLastTripped(i))) {
-                setSensorLastTripped(i, null);
-            }
-            if ((isSensorLowBattery(i) != null) && isSensorLowBattery(i).equals(otherState.isSensorLowBattery(i))) {
-                setSensorLowBattery(i, null);
-            }
-            if ((isSensorBypassed(i) != null) && isSensorBypassed(i).equals(otherState.isSensorBypassed(i))) {
-                setSensorBypassed(i, null);
-            }
-            if ((isSensorArmed(i) != null) && isSensorArmed(i).equals(otherState.isSensorArmed(i))) {
-                setSensorArmed(i, null);
+        for (int zone = 1; zone <= zones.length; zone++) {
+            PowermaxZoneState thisZone = getZone(zone);
+            PowermaxZoneState otherZone = otherState.getZone(zone);
+
+            for (int i = 0; i < thisZone.getValues().size(); i++) {
+                Value<?> thisValue = thisZone.getValues().get(i);
+                Value<?> otherValue = otherZone.getValues().get(i);
+
+                if ((thisValue.getValue() != null) && thisValue.getValue().equals(otherValue.getValue())) {
+                    thisValue.setValue(null);
+                }
             }
         }
+
         for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
             if ((getPGMX10DeviceStatus(i) != null)
                     && getPGMX10DeviceStatus(i).equals(otherState.getPGMX10DeviceStatus(i))) {
                 setPGMX10DeviceStatus(i, null);
             }
         }
-        if ((ready != null) && ready.equals(otherState.isReady())) {
-            ready = null;
-        }
-        if ((bypass != null) && bypass.equals(otherState.isBypass())) {
-            bypass = null;
-        }
-        if ((alarmActive != null) && alarmActive.equals(otherState.isAlarmActive())) {
-            alarmActive = null;
-        }
-        if ((trouble != null) && trouble.equals(otherState.isTrouble())) {
-            trouble = null;
-        }
-        if ((alertInMemory != null) && alertInMemory.equals(otherState.isAlertInMemory())) {
-            alertInMemory = null;
-        }
-        if ((statusStr != null) && statusStr.equals(otherState.getStatusStr())) {
-            statusStr = null;
-        }
-        if ((armMode != null) && armMode.equals(otherState.getArmMode())) {
-            armMode = null;
-        }
-        if ((lastKeepAlive != null) && lastKeepAlive.equals(otherState.getLastKeepAlive())) {
-            lastKeepAlive = null;
-        }
-        if ((panelStatus != null) && panelStatus.equals(otherState.getPanelStatus())) {
-            panelStatus = null;
-        }
-        if ((alarmType != null) && alarmType.equals(otherState.getAlarmType())) {
-            alarmType = null;
-        }
-        if ((troubleType != null) && troubleType.equals(otherState.getTroubleType())) {
-            troubleType = null;
+
+        for (int i = 0; i < getValues().size(); i++) {
+            Value<?> thisValue = getValues().get(i);
+            Value<?> otherValue = otherState.getValues().get(i);
+
+            if ((thisValue.getValue() != null) && thisValue.getValue().equals(otherValue.getValue())) {
+                thisValue.setValue(null);
+            }
         }
     }
 
@@ -680,67 +332,35 @@ public class PowermaxState {
      * @param update the other state to consider for the update
      */
     public void merge(PowermaxState update) {
-        if (update.isPowerlinkMode() != null) {
-            powerlinkMode = update.isPowerlinkMode();
-        }
-        if (update.isDownloadMode() != null) {
-            downloadMode = update.isDownloadMode();
-        }
-        for (int i = 1; i <= zones.length; i++) {
-            if (update.isSensorTripped(i) != null) {
-                setSensorTripped(i, update.isSensorTripped(i));
-            }
-            if (update.getSensorLastTripped(i) != null) {
-                setSensorLastTripped(i, update.getSensorLastTripped(i));
-            }
-            if (update.isSensorLowBattery(i) != null) {
-                setSensorLowBattery(i, update.isSensorLowBattery(i));
-            }
-            if (update.isSensorBypassed(i) != null) {
-                setSensorBypassed(i, update.isSensorBypassed(i));
-            }
-            if (update.isSensorArmed(i) != null) {
-                setSensorArmed(i, update.isSensorArmed(i));
+        for (int zone = 1; zone <= zones.length; zone++) {
+            PowermaxZoneState thisZone = getZone(zone);
+            PowermaxZoneState otherZone = update.getZone(zone);
+
+            for (int i = 0; i < thisZone.getValues().size(); i++) {
+                Value<?> thisValue = thisZone.getValues().get(i);
+                Value<?> otherValue = otherZone.getValues().get(i);
+
+                if (otherValue.getValue() != null) {
+                    thisValue.setValueUnsafe(otherValue.getValue());
+                }
             }
         }
+
         for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
             if (update.getPGMX10DeviceStatus(i) != null) {
                 setPGMX10DeviceStatus(i, update.getPGMX10DeviceStatus(i));
             }
         }
-        if (update.isReady() != null) {
-            ready = update.isReady();
-        }
-        if (update.isBypass() != null) {
-            bypass = update.isBypass();
-        }
-        if (update.isAlarmActive() != null) {
-            alarmActive = update.isAlarmActive();
-        }
-        if (update.isTrouble() != null) {
-            trouble = update.isTrouble();
-        }
-        if (update.isAlertInMemory() != null) {
-            alertInMemory = update.isAlertInMemory();
-        }
-        if (update.getStatusStr() != null) {
-            statusStr = update.getStatusStr();
-        }
-        if (update.getArmMode() != null) {
-            armMode = update.getArmMode();
-        }
-        if (update.getLastKeepAlive() != null) {
-            lastKeepAlive = update.getLastKeepAlive();
-        }
-        if (update.getPanelStatus() != null) {
-            panelStatus = update.getPanelStatus();
-        }
-        if (update.getAlarmType() != null) {
-            alarmType = update.getAlarmType();
-        }
-        if (update.getTroubleType() != null) {
-            troubleType = update.getTroubleType();
+
+        for (int i = 0; i < getValues().size(); i++) {
+            Value<?> thisValue = getValues().get(i);
+            Value<?> otherValue = update.getValues().get(i);
+
+            if (otherValue.getValue() != null) {
+                thisValue.setValueUnsafe(otherValue.getValue());
+            }
         }
+
         if (update.getEventLogSize() > getEventLogSize()) {
             setEventLogSize(update.getEventLogSize());
         }
@@ -753,70 +373,43 @@ public class PowermaxState {
 
     @Override
     public String toString() {
-        String str = "";
-
-        if (powerlinkMode != null) {
-            str += "\n - powerlink mode = " + (powerlinkMode ? "yes" : "no");
-        }
-        if (downloadMode != null) {
-            str += "\n - download mode = " + (downloadMode ? "yes" : "no");
-        }
-        for (int i = 1; i <= zones.length; i++) {
-            if (isSensorTripped(i) != null) {
-                str += String.format("\n - sensor zone %d %s", i, isSensorTripped(i) ? "tripped" : "untripped");
-            }
-            if (getSensorLastTripped(i) != null) {
-                str += String.format("\n - sensor zone %d last trip %d", i, getSensorLastTripped(i));
-            }
-            if (isSensorLowBattery(i) != null) {
-                str += String.format("\n - sensor zone %d %s", i, isSensorLowBattery(i) ? "low battery" : "battery ok");
-            }
-            if (isSensorBypassed(i) != null) {
-                str += String.format("\n - sensor zone %d %sbypassed", i, isSensorBypassed(i) ? "" : "not ");
-            }
-            if (isSensorArmed(i) != null) {
-                str += String.format("\n - sensor zone %d %s", i, isSensorArmed(i) ? "armed" : "disarmed");
+        String str = "Bridge state:";
+
+        for (Value<?> value : getValues()) {
+            if ((value.getChannel() != null) && (value.getValue() != null)) {
+                String channel = value.getChannel();
+                String v_str = value.getValue().toString();
+                String state = value.getState().toString();
+
+                str += "\n - " + channel + " = " + v_str;
+                if (!v_str.equals(state)) {
+                    str += " (" + state + ")";
+                }
             }
         }
+
         for (int i = 0; i < pgmX10DevicesStatus.length; i++) {
             if (getPGMX10DeviceStatus(i) != null) {
                 str += String.format("\n - %s status = %s", (i == 0) ? "PGM device" : String.format("X10 device %d", i),
                         getPGMX10DeviceStatus(i) ? "ON" : "OFF");
             }
         }
-        if (ready != null) {
-            str += "\n - ready = " + (ready ? "yes" : "no");
-        }
-        if (bypass != null) {
-            str += "\n - bypass = " + (bypass ? "yes" : "no");
-        }
-        if (alarmActive != null) {
-            str += "\n - alarm active = " + (alarmActive ? "yes" : "no");
-        }
-        if (trouble != null) {
-            str += "\n - trouble = " + (trouble ? "yes" : "no");
-        }
-        if (alertInMemory != null) {
-            str += "\n - alert in memory = " + (alertInMemory ? "yes" : "no");
-        }
-        if (statusStr != null) {
-            str += "\n - status = " + statusStr;
-        }
-        if (armMode != null) {
-            str += "\n - arm mode = " + armMode;
-        }
-        if (lastKeepAlive != null) {
-            str += "\n - last keep alive = " + lastKeepAlive;
-        }
-        if (panelStatus != null) {
-            str += "\n - panel status = " + panelStatus;
-        }
-        if (alarmType != null) {
-            str += "\n - alarm type = " + alarmType;
-        }
-        if (troubleType != null) {
-            str += "\n - trouble type = " + troubleType;
+
+        for (int i = 1; i <= zones.length; i++) {
+            for (Value<?> value : zones[i - 1].getValues()) {
+                if ((value.getChannel() != null) && (value.getValue() != null)) {
+                    String channel = value.getChannel();
+                    String v_str = value.getValue().toString();
+                    String state = value.getState().toString();
+
+                    str += String.format("\n - sensor zone %d %s = %s", i, channel, v_str);
+                    if (!v_str.equals(state)) {
+                        str += " (" + state + ")";
+                    }
+                }
+            }
         }
+
         for (int i = 1; i <= getEventLogSize(); i++) {
             if (getEventLog(i) != null) {
                 str += "\n - event log " + i + " = " + getEventLog(i);
diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxStateContainer.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxStateContainer.java
new file mode 100644 (file)
index 0000000..21015ce
--- /dev/null
@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2010-2021 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.binding.powermax.internal.state;
+
+import java.time.Instant;
+import java.time.ZonedDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.i18n.TimeZoneProvider;
+import org.openhab.core.library.types.DateTimeType;
+import org.openhab.core.library.types.OnOffType;
+import org.openhab.core.library.types.StringType;
+import org.openhab.core.types.State;
+
+/**
+ * Base class for extensible state objects
+ *
+ * @author Ron Isaacson - Initial contribution
+ */
+public abstract class PowermaxStateContainer {
+
+    protected final TimeZoneProvider timeZoneProvider;
+    protected List<Value<?>> values;
+
+    public abstract class Value<T> {
+        protected T value;
+        protected final String channel;
+
+        public Value(PowermaxStateContainer parent, String channel) {
+            this.channel = channel;
+            this.value = null;
+
+            parent.getValues().add(this);
+        }
+
+        public T getValue() {
+            return value;
+        }
+
+        public void setValue(@Nullable T value) {
+            this.value = value;
+        }
+
+        @SuppressWarnings("unchecked")
+        public void setValueUnsafe(@Nullable Object value) {
+            this.value = (T) value;
+        }
+
+        public String getChannel() {
+            return channel;
+        }
+
+        public abstract State getState();
+    }
+
+    public class DynamicValue<T> extends Value<T> {
+        Supplier<T> valueFunction;
+        Supplier<State> stateFunction;
+
+        public DynamicValue(PowermaxStateContainer parent, String channel, Supplier<T> valueFunction,
+                Supplier<State> stateFunction) {
+            super(parent, channel);
+            this.valueFunction = valueFunction;
+            this.stateFunction = stateFunction;
+        }
+
+        // Note: setValue() is still valid, but the saved value will be ignored
+
+        @Override
+        public T getValue() {
+            return valueFunction.get();
+        }
+
+        @Override
+        public State getState() {
+            return stateFunction.get();
+        }
+    }
+
+    public class BooleanValue extends Value<Boolean> {
+        State trueState;
+        State falseState;
+
+        public BooleanValue(PowermaxStateContainer parent, String channel, State trueState, State falseState) {
+            super(parent, channel);
+            this.trueState = trueState;
+            this.falseState = falseState;
+        }
+
+        public BooleanValue(PowermaxStateContainer parent, String channel) {
+            this(parent, channel, OnOffType.ON, OnOffType.OFF);
+        }
+
+        @Override
+        public State getState() {
+            return value ? trueState : falseState;
+        }
+    }
+
+    public class StringValue extends Value<String> {
+        public StringValue(PowermaxStateContainer parent, String channel) {
+            super(parent, channel);
+        }
+
+        @Override
+        public State getState() {
+            return new StringType(value);
+        }
+    }
+
+    public class DateTimeValue extends Value<Long> {
+        public DateTimeValue(PowermaxStateContainer parent, String channel) {
+            super(parent, channel);
+        }
+
+        @Override
+        public State getState() {
+            ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(value), timeZoneProvider.getTimeZone());
+            return new DateTimeType(zoned);
+        }
+    }
+
+    protected PowermaxStateContainer(TimeZoneProvider timeZoneProvider) {
+        this.timeZoneProvider = timeZoneProvider;
+        this.values = new ArrayList<>();
+    }
+
+    public List<Value<?>> getValues() {
+        return values;
+    }
+}
index 902efaa6c310f383c0f9dd612da36c7be8121380..b6a1bebf11b964f20f118aabf0936c0514666067 100644 (file)
  */
 package org.openhab.binding.powermax.internal.state;
 
+import static org.openhab.binding.powermax.internal.PowermaxBindingConstants.*;
+
+import org.openhab.core.i18n.TimeZoneProvider;
+import org.openhab.core.library.types.OpenClosedType;
+
 /**
  * A class to store the state of a zone
  *
  * @author Laurent Garnier - Initial contribution
  */
-public class PowermaxZoneState {
-
-    private Boolean tripped;
-    private Long lastTripped;
-    private Boolean lowBattery;
-    private Boolean bypassed;
-    private Boolean armed;
+public class PowermaxZoneState extends PowermaxStateContainer {
 
-    public PowermaxZoneState() {
-        tripped = null;
-        lastTripped = null;
-        lowBattery = null;
-        bypassed = null;
-        armed = null;
-    }
+    public BooleanValue tripped = new BooleanValue(this, TRIPPED, OpenClosedType.OPEN, OpenClosedType.CLOSED);
+    public DateTimeValue lastTripped = new DateTimeValue(this, LAST_TRIP);
+    public BooleanValue lowBattery = new BooleanValue(this, LOW_BATTERY);
+    public BooleanValue bypassed = new BooleanValue(this, BYPASSED);
+    public BooleanValue armed = new BooleanValue(this, ARMED);
 
-    public Boolean isTripped() {
-        return tripped;
-    }
+    public DynamicValue<Boolean> locked = new DynamicValue<>(this, LOCKED, () -> {
+        return armed.getValue();
+    }, () -> {
+        Boolean isArmed = armed.getValue();
+        if (isArmed == null) {
+            return null;
+        }
+        return isArmed ? OpenClosedType.CLOSED : OpenClosedType.OPEN;
+    });
 
-    public void setTripped(Boolean tripped) {
-        this.tripped = tripped;
-    }
-
-    public Long getLastTripped() {
-        return lastTripped;
-    }
-
-    public void setLastTripped(Long lastTripped) {
-        this.lastTripped = lastTripped;
+    public PowermaxZoneState(TimeZoneProvider timeZoneProvider) {
+        super(timeZoneProvider);
     }
 
     public boolean isLastTripBeforeTime(long refTime) {
-        return isTripped() == Boolean.TRUE && getLastTripped() != null && getLastTripped() < refTime;
-    }
-
-    public Boolean isLowBattery() {
-        return lowBattery;
-    }
-
-    public void setLowBattery(Boolean lowBattery) {
-        this.lowBattery = lowBattery;
-    }
-
-    public Boolean isBypassed() {
-        return bypassed;
-    }
-
-    public void setBypassed(Boolean bypassed) {
-        this.bypassed = bypassed;
-    }
-
-    public Boolean isArmed() {
-        return armed;
-    }
-
-    public void setArmed(Boolean armed) {
-        this.armed = armed;
+        return Boolean.TRUE.equals(tripped.getValue()) && (lastTripped.getValue() != null)
+                && (lastTripped.getValue() < refTime);
     }
 }