From 0a9c5a0b2c4798cb5e1da44064d07c9e788f3ddc Mon Sep 17 00:00:00 2001 From: Ron Isaacson Date: Wed, 13 Jan 2021 15:29:22 -0500 Subject: [PATCH] [powermax] Refactor state objects (#9684) * 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 --- .../internal/PowermaxHandlerFactory.java | 4 +- .../connector/PowermaxSerialConnector.java | 2 +- .../console/PowermaxCommandExtension.java | 9 +- .../handler/PowermaxBridgeHandler.java | 119 ++- .../handler/PowermaxThingHandler.java | 33 +- .../internal/message/PowermaxAckMessage.java | 4 +- .../internal/message/PowermaxCommManager.java | 11 +- .../message/PowermaxDeniedMessage.java | 2 +- .../internal/message/PowermaxInfoMessage.java | 2 +- .../message/PowermaxPanelMessage.java | 8 +- .../message/PowermaxPowerlinkMessage.java | 4 +- .../message/PowermaxStatusMessage.java | 44 +- .../internal/state/PowermaxState.java | 691 ++++-------------- .../state/PowermaxStateContainer.java | 144 ++++ .../internal/state/PowermaxZoneState.java | 76 +- 15 files changed, 423 insertions(+), 730 deletions(-) create mode 100644 bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxStateContainer.java diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/PowermaxHandlerFactory.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/PowermaxHandlerFactory.java index 1b62b5803..94135961a 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/PowermaxHandlerFactory.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/PowermaxHandlerFactory.java @@ -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; diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/connector/PowermaxSerialConnector.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/connector/PowermaxSerialConnector.java index c9286cf2c..28aec1acf 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/connector/PowermaxSerialConnector.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/connector/PowermaxSerialConnector.java @@ -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 diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/console/PowermaxCommandExtension.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/console/PowermaxCommandExtension.java index e8e3449ab..3d58f5250 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/console/PowermaxCommandExtension.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/console/PowermaxCommandExtension.java @@ -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 getUsages() { return Arrays.asList(new String[] { buildCommandUsage(" " + INFO_SETUP, "information on setup"), - buildCommandUsage(" " + DOWNLOAD_SETUP, "download setup") }); + buildCommandUsage(" " + DOWNLOAD_SETUP, "download setup"), + buildCommandUsage(" " + BRIDGE_STATE, "show current state") }); } @Reference diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxBridgeHandler.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxBridgeHandler.java index ae6fc184c..f5033c806 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxBridgeHandler.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxBridgeHandler.java @@ -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); } } diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxThingHandler.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxThingHandler.java index f6b55f38b..c31c1b777 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxThingHandler.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/handler/PowermaxThingHandler.java @@ -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(); diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxAckMessage.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxAckMessage.java index 994f44d35..c17598bd1 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxAckMessage.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxAckMessage.java @@ -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; diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxCommManager.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxCommManager.java index 99e07e2ef..e90200200 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxCommManager.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxCommManager.java @@ -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 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); } /** diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxDeniedMessage.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxDeniedMessage.java index 87e5229f4..52593acc5 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxDeniedMessage.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxDeniedMessage.java @@ -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; diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxInfoMessage.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxInfoMessage.java index 96cd471e2..7d6bb8c81 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxInfoMessage.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxInfoMessage.java @@ -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); diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPanelMessage.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPanelMessage.java index 389471722..a08313472 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPanelMessage.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPanelMessage.java @@ -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); } } diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPowerlinkMessage.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPowerlinkMessage.java index 613830c14..795b22ae8 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPowerlinkMessage.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxPowerlinkMessage.java @@ -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); } diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxStatusMessage.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxStatusMessage.java index 2bcba321e..d30bf0951 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxStatusMessage.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/message/PowermaxStatusMessage.java @@ -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); diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxState.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxState.java index 97baedfbd..a6722222a 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxState.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxState.java @@ -12,33 +12,72 @@ */ 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 isArmed = new DynamicValue<>(this, SYSTEM_ARMED, () -> { + return isArmed(); + }, () -> { + return isArmed() ? OnOffType.ON : OnOffType.OFF; + }); + + public DynamicValue panelMode = new DynamicValue<>(this, MODE, () -> { + return getPanelMode(); + }, () -> { + return new StringType(getPanelMode()); + }); + + public DynamicValue shortArmMode = new DynamicValue<>(this, ARM_MODE, () -> { + return getShortArmMode(); + }, () -> { + return new StringType(getShortArmMode()); + }); + + public DynamicValue 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 updatedZoneNames; private Map 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 + * 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) - * - * @return true when the zone sensor is tripped + * @return the zone state object (or a dummy zone state) */ - 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 - * - * @param zone the index of the zone (first zone is index 1) - * @param tripped true if tripped - */ - 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 = ""; + String str = "Bridge state:"; - 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"); + 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 index 000000000..21015ce6c --- /dev/null +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxStateContainer.java @@ -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> values; + + public abstract class Value { + 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 extends Value { + Supplier valueFunction; + Supplier stateFunction; + + public DynamicValue(PowermaxStateContainer parent, String channel, Supplier valueFunction, + Supplier 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 { + 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 { + public StringValue(PowermaxStateContainer parent, String channel) { + super(parent, channel); + } + + @Override + public State getState() { + return new StringType(value); + } + } + + public class DateTimeValue extends Value { + 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> getValues() { + return values; + } +} diff --git a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxZoneState.java b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxZoneState.java index 902efaa6c..b6a1bebf1 100644 --- a/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxZoneState.java +++ b/bundles/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/state/PowermaxZoneState.java @@ -12,68 +12,40 @@ */ 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 { +public class PowermaxZoneState extends PowermaxStateContainer { - private Boolean tripped; - private Long lastTripped; - private Boolean lowBattery; - private Boolean bypassed; - private Boolean armed; + 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 PowermaxZoneState() { - tripped = null; - lastTripped = null; - lowBattery = null; - bypassed = null; - armed = null; - } + public DynamicValue locked = new DynamicValue<>(this, LOCKED, () -> { + return armed.getValue(); + }, () -> { + Boolean isArmed = armed.getValue(); + if (isArmed == null) { + return null; + } + return isArmed ? OpenClosedType.CLOSED : OpenClosedType.OPEN; + }); - public Boolean isTripped() { - return tripped; - } - - 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); } }