{"action":"created","comment":{"url":"https://api.github.com/repos/openhab/openhab/pulls/comments/53605440","id":53605440,"diff_hunk":"@@ -0,0 +1,907 @@\n+/**\n+ * Copyright (c) 2010-2016, openHAB.org and others.\n+ *\n+ * All rights reserved. This program and the accompanying materials\n+ * are made available under the terms of the Eclipse Public License v1.0\n+ * which accompanies this distribution, and is available at\n+ * http://www.eclipse.org/legal/epl-v10.html\n+ */\n+package org.openhab.binding.powermax.internal;\n+\n+import java.util.Calendar;\n+import java.util.Dictionary;\n+import java.util.EventObject;\n+import java.util.HashMap;\n+\n+import org.apache.commons.lang.StringUtils;\n+import org.openhab.binding.powermax.PowerMaxBindingConfig;\n+import org.openhab.binding.powermax.PowerMaxBindingProvider;\n+import org.openhab.binding.powermax.internal.connector.PowerMaxEvent;\n+import org.openhab.binding.powermax.internal.connector.PowerMaxEventListener;\n+import org.openhab.binding.powermax.internal.message.PowerMaxBaseMessage;\n+import org.openhab.binding.powermax.internal.message.PowerMaxCommDriver;\n+import org.openhab.binding.powermax.internal.message.PowerMaxInfoMessage;\n+import org.openhab.binding.powermax.internal.message.PowerMaxPowerlinkMessage;\n+import org.openhab.binding.powermax.internal.message.PowerMaxReceiveType;\n+import org.openhab.binding.powermax.internal.message.PowerMaxSendType;\n+import org.openhab.binding.powermax.internal.state.PowerMaxPanelSettings;\n+import org.openhab.binding.powermax.internal.state.PowerMaxPanelType;\n+import org.openhab.binding.powermax.internal.state.PowerMaxState;\n+import org.openhab.core.binding.AbstractActiveBinding;\n+import org.openhab.core.binding.BindingProvider;\n+import org.openhab.core.items.Item;\n+import org.openhab.core.library.items.ContactItem;\n+import org.openhab.core.library.items.StringItem;\n+import org.openhab.core.library.items.SwitchItem;\n+import org.openhab.core.library.types.DateTimeType;\n+import org.openhab.core.library.types.OnOffType;\n+import org.openhab.core.library.types.OpenClosedType;\n+import org.openhab.core.library.types.StringType;\n+import org.openhab.core.types.Command;\n+import org.openhab.core.types.State;\n+import org.osgi.service.cm.ConfigurationException;\n+import org.osgi.service.cm.ManagedService;\n+import org.slf4j.Logger;\n+import org.slf4j.LoggerFactory;\n+\n+/**\n+ * Binding that get information from the Visonic alarm system.\n+ * The binding is listening to openHAB event bus and is able to send few commands to the alarm system\n+ *\n+ * @author lolodomo\n+ * @since 1.9.0\n+ */\n+public class PowerMaxBinding extends AbstractActiveBinding<PowerMaxBindingProvider>\n+        implements ManagedService, PowerMaxEventListener {\n+\n+    private static final Logger logger = LoggerFactory.getLogger(PowerMaxBinding.class);\n+\n+    private static final int ONE_MINUTE = 60000;\n+\n+    /** Default delay in milliseconds to reset a motion detection */\n+    private static final int DEFAULT_MOTION_OFF_DELAY = 3 * ONE_MINUTE;\n+\n+    /** The serial port to use for connecting to the PowerMax alarm system */\n+    private String serialPort;\n+\n+    /** The IP address and TCP port to use for connecting to the PowerMax alarm system */\n+    private String ipAddress;\n+    private int tcpPort;\n+\n+    /** The delay in milliseconds to reset a motion detection */\n+    private int motionOffDelay;\n+\n+    /** The PIN code to use for arming/disarming the PowerMax alarm system from openHAB */\n+    private String pinCode;\n+\n+    /** Enable or disable arming the PowerMax alarm system from openHAB */\n+    private boolean allowArming;\n+\n+    /** Enable or disable disarming the PowerMax alarm system from openHAB */\n+    private boolean allowDisarming;\n+\n+    /** Force the standard mode rather than trying using the Powerlink mode */\n+    private boolean forceStandardMode;\n+\n+    /** Panel type used when in standard mode */\n+    private PowerMaxPanelType panelType;\n+\n+    /** Automatic sync time */\n+    private boolean autoSyncTime;\n+\n+    /** The object to store the current state of the PowerMax alarm system */\n+    private PowerMaxState currentState;\n+\n+    /** Number of items managed by the binding */\n+    private int itemCount;\n+\n+    /** Boolean indicating whether or not the update of items is temporarily disabled by the binding */\n+    private boolean itemUpdateDisabled;\n+\n+    /**\n+     * Boolean indicating whether or not an update of all items will be required\n+     * during the next refresh cycle\n+     */\n+    private boolean triggerItemsUpdate;\n+\n+    /** Boolean indicating whether or not connection is established with the alarm system */\n+    private boolean connected;\n+\n+    public PowerMaxBinding() {\n+        serialPort = null;\n+        ipAddress = null;\n+        tcpPort = 0;\n+        motionOffDelay = DEFAULT_MOTION_OFF_DELAY;\n+        pinCode = null;\n+        allowArming = false;\n+        allowDisarming = false;\n+        forceStandardMode = false;\n+        panelType = PowerMaxPanelType.POWERMAX_PRO;\n+        autoSyncTime = false;\n+        currentState = null;\n+        itemCount = 0;\n+        itemUpdateDisabled = true;\n+        triggerItemsUpdate = false;\n+        connected = false;\n+    }\n+\n+    /**\n+     * Activates the binding. Actually does nothing, because on activation\n+     * OpenHAB always calls updated to indicate that the config is updated\n+     * Activation is done there\n+     */\n+    @Override\n+    public void activate() {\n+        logger.debug(\"Activate PowerMax alarm binding\");\n+    }\n+\n+    /**\n+     * Deactivates the binding\n+     */\n+    @Override\n+    public void deactivate() {\n+        logger.debug(\"Deactivate PowerMax alarm binding\");\n+        closeConnection();\n+    }\n+\n+    /**\n+     * @{inheritDoc\n+     */\n+    @Override\n+    protected long getRefreshInterval() {\n+        return 20000; // 20 seconds\n+    }\n+\n+    /**\n+     * @{inheritDoc\n+     */\n+    @Override\n+    protected String getName() {\n+        return \"PowerMax Refresh Service\";\n+    }\n+\n+    /**\n+     * @{inheritDoc\n+     */\n+    @Override\n+    protected void execute() {\n+        logger.debug(\"PowerMax alarm Execute\");\n+\n+        if (!isProperlyConfigured()) {\n+            logger.debug(\"execute(): not yet properly configured\");\n+            return;\n+        }\n+\n+        //\n+        // Off items linked to motion sensors after the delay defined by\n+        // the variable motionOffDelay\n+        //\n+\n+        long now = System.currentTimeMillis();\n+        PowerMaxPanelSettings settings = PowerMaxPanelSettings.getThePanelSettings();\n+        PowerMaxState updateState = null;\n+        if ((currentState != null) && (settings != null)) {\n+            for (int i = 1; i <= settings.getNbZones(); i++) {\n+                if ((settings.getZoneSettings(i) != null)\n+                        && settings.getZoneSettings(i).getSensorType().equalsIgnoreCase(\"Motion\")\n+                        && (currentState.isSensorTripped(i) == Boolean.TRUE)\n+                        && (currentState.getSensorLastTripped(i) != null)\n+                        && ((now - currentState.getSensorLastTripped(i)) > motionOffDelay)) {\n+                    if (updateState == null) {\n+                        updateState = new PowerMaxState();\n+                    }\n+                    updateState.setSensorTripped(i, false);\n+                }\n+            }\n+        }\n+        if (updateState != null) {\n+            updateItemsFromAlarmState(PowerMaxSelectorType.ZONE_STATUS, updateState);\n+            currentState.merge(updateState);\n+        }\n+\n+        if (PowerMaxCommDriver.getTheCommDriver() != null) {\n+            connected = PowerMaxCommDriver.getTheCommDriver().isConnected();\n+        }\n+\n+        // Check that we receive a keep alive message during the last minute\n+        if (connected && (currentState.isPowerlinkMode() != null) && currentState.isPowerlinkMode().equals(Boolean.TRUE)\n+                && (currentState.getLastKeepAlive() != null)\n+                && ((now - currentState.getLastKeepAlive()) > ONE_MINUTE)) {\n+            // Let Powermax know we are alive\n+            PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.RESTORE);\n+            currentState.setLastKeepAlive(now);\n+        }\n+\n+        //\n+        // Try to reconnect if disconnected\n+        //\n+\n+        if (!connected) {\n+            logger.debug(\"execute(): trying to reconnect...\");\n+            closeConnection();\n+            if (triggerItemsUpdate) {\n+                logger.debug(\"execute(): items update enabled\");\n+                itemUpdateDisabled = false;\n+                triggerItemsUpdate = false;\n+            }\n+            currentState = new PowerMaxState();\n+            openConnection();\n+            if (connected) {\n+                // TODO is INIT message required or not ?\n+\n+                if (forceStandardMode) {\n+                    currentState.setPowerlinkMode(false);\n+                    updateItemsFromAlarmState(PowerMaxSelectorType.PANEL_MODE, currentState);\n+                    settings = PowerMaxPanelSettings.getThePanelSettings();\n+                    settings.process(false, panelType, null);\n+                    updateItemsFromPanelSettings();\n+                    logger.info(\"PowerMax alarm binding: running in Standard mode\");\n+                    PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESNAME);\n+                    PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESTYPE);\n+                    PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.STATUS);\n+                } else {\n+                    PowerMaxCommDriver.getTheCommDriver().startDownload();\n+                }\n+            } else {\n+                logger.debug(\"execute(): reconnection failed\");\n+            }\n+        } else if (triggerItemsUpdate) {\n+            logger.debug(\"execute(): update all items\");\n+            itemUpdateDisabled = false;\n+            triggerItemsUpdate = false;\n+            // Adjust all the items to the current alarm state\n+            updateItemsFromAlarmState(currentState);\n+            // Adjust all the items to the current alarm settings\n+            updateItemsFromPanelSettings();\n+        }\n+    }\n+\n+    /**\n+     * {@inheritDoc}\n+     */\n+    @Override\n+    public void bindingChanged(BindingProvider provider, String itemName) {\n+        logger.debug(\"bindingChanged(): Item Name: {} Provider items count: {}\", itemName,\n+                provider.getItemNames().size());\n+\n+        itemUpdateDisabled = true;\n+        if (provider.getItemNames().size() >= itemCount) {\n+            triggerItemsUpdate = true;\n+        }\n+        itemCount = provider.getItemNames().size();\n+\n+        super.bindingChanged(provider, itemName);\n+    }\n+\n+    /**\n+     * {@inheritDoc}\n+     */\n+    @Override\n+    public void allBindingsChanged(BindingProvider provider) {\n+        logger.debug(\"allBindingsChanged(): Provider items count: {}\", provider.getItemNames().size());\n+\n+        itemUpdateDisabled = true;\n+        if (provider.getItemNames().size() > 0) {\n+            triggerItemsUpdate = true;\n+        }\n+        itemCount = provider.getItemNames().size();\n+\n+        super.allBindingsChanged(provider);\n+    }\n+\n+    /**\n+     * @{inheritDoc\n+     */\n+    @Override\n+    protected void internalReceiveCommand(String itemName, Command command) {\n+        // the code being executed when a command was sent on the openHAB\n+        // event bus goes here. This method is only called if one of the\n+        // BindingProviders provide a binding for the given 'itemName'.\n+        logger.debug(\"internalReceiveCommand({},{}) is called\", itemName, command);\n+        if (!isProperlyConfigured() || !connected) {\n+            logger.warn(\"PowerMax alarm binding is not properly configured. Command is ignored.\");\n+            return;\n+        }\n+\n+        String armMode = null;\n+        String actionPGMX10 = null;\n+        Byte devicePGMX10 = null;\n+        Boolean bypass = null;\n+        byte zoneNr = 0;\n+        String commandStr = null;\n+\n+        PowerMaxPanelSettings settings = PowerMaxPanelSettings.getThePanelSettings();\n+        PowerMaxCommDriver comm = PowerMaxCommDriver.getTheCommDriver();\n+\n+        for (PowerMaxBindingProvider provider : providers) {\n+            PowerMaxBindingConfig config = provider.getConfig(itemName);\n+            if (config == null) {\n+                continue;\n+            }\n+            switch (config.getSelectorType()) {\n+                case PARTITION_ARM_MODE:\n+                    if (command instanceof StringType) {\n+                        armMode = command.toString();\n+                    }\n+                    break;\n+                case PARTITION_ARMED:\n+                    if (command instanceof OnOffType) {\n+                        armMode = command.equals(OnOffType.ON) ? \"Armed\" : \"Disarmed\";\n+                    }\n+                    break;\n+                case PGM_STATUS:\n+                    if (command instanceof OnOffType) {\n+                        actionPGMX10 = command.toString();\n+                    }\n+                    break;\n+                case X10_STATUS:\n+                    if (command instanceof OnOffType || command instanceof StringType) {\n+                        actionPGMX10 = command.toString();\n+                    }\n+                    try {\n+                        devicePGMX10 = Byte.parseByte(config.getSelectorParam());\n+                    } catch (NumberFormatException e) {\n+                        logger.warn(\"PowerMax alarm binding: invalid X10 device id: {}\", config.getSelectorParam());\n+                        actionPGMX10 = null;\n+                    }\n+                    break;\n+                case ZONE_BYPASSED:\n+                    if (command instanceof OnOffType) {\n+                        bypass = command.equals(OnOffType.ON) ? Boolean.TRUE : Boolean.FALSE;\n+                    }\n+                    try {\n+                        zoneNr = Byte.parseByte(config.getSelectorParam());\n+                    } catch (NumberFormatException e) {\n+                        logger.warn(\"PowerMax alarm binding: invalid zone number: {}\", config.getSelectorParam());\n+                        bypass = null;\n+                    }\n+                    break;\n+                case COMMAND:\n+                    if (command instanceof StringType) {\n+                        commandStr = command.toString();\n+                        eventPublisher.postUpdate(itemName, new StringType(commandStr));\n+                    }\n+                    break;\n+                default:\n+                    break;\n+            }\n+            if (armMode != null) {\n+\n+                HashMap<String, Boolean> allowedModes = new HashMap<String, Boolean>();\n+                allowedModes.put(\"Disarmed\", allowDisarming);\n+                allowedModes.put(\"Stay\", allowArming);\n+                allowedModes.put(\"Armed\", allowArming);\n+                allowedModes.put(\"StayInstant\", allowArming);\n+                allowedModes.put(\"ArmedInstant\", allowArming);\n+                allowedModes.put(\"Night\", allowArming);\n+                allowedModes.put(\"NightInstant\", allowArming);\n+\n+                Boolean allowed = allowedModes.get(armMode);\n+                if ((allowed == null) || !allowed) {\n+                    logger.warn(\"PowerMax alarm binding: rejected command {}\", armMode);\n+                } else {\n+                    comm.requestArmMode(armMode, currentState.isPowerlinkMode()\n+                            ? PowerMaxPanelSettings.getThePanelSettings().getFirstPinCode() : pinCode);\n+                }\n+                break;\n+            } else if (actionPGMX10 != null) {\n+                comm.sendPGMX10(actionPGMX10, devicePGMX10);\n+                break;\n+            } else if (bypass != null) {\n+                if ((currentState.isPowerlinkMode() == null) || currentState.isPowerlinkMode().equals(Boolean.FALSE)) {\n+                    logger.warn(\"PowerMax alarm binding: Bypass option only supported in Powerlink mode\");\n+                } else if (!PowerMaxPanelSettings.getThePanelSettings().isBypassEnabled()) {\n+                    logger.warn(\"PowerMax alarm binding: Bypass option not enabled in panel settings\");\n+                } else {\n+                    comm.sendZoneBypass(bypass.booleanValue(), zoneNr,\n+                            PowerMaxPanelSettings.getThePanelSettings().getFirstPinCode());\n+                }\n+                break;\n+            } else if (commandStr != null) {\n+                if (commandStr.equalsIgnoreCase(\"get_event_log\")) {\n+                    comm.requestEventLog(currentState.isPowerlinkMode()\n+                            ? PowerMaxPanelSettings.getThePanelSettings().getFirstPinCode() : pinCode);\n+                } else if (commandStr.equalsIgnoreCase(\"download_setup\")) {\n+                    if ((currentState.isPowerlinkMode() == null)\n+                            || currentState.isPowerlinkMode().equals(Boolean.FALSE)) {\n+                        logger.warn(\"PowerMax alarm binding: download setup only supported in Powerlink mode\");\n+                    } else {\n+                        comm.startDownload();\n+                        if (currentState.getLastKeepAlive() != null) {\n+                            currentState.setLastKeepAlive(System.currentTimeMillis());\n+                        }\n+                    }\n+                } else if (commandStr.equalsIgnoreCase(\"log_setup\")) {\n+                    settings.log();\n+                } else if (commandStr.equalsIgnoreCase(\"help_items\")) {\n+                    settings.helpItems();\n+                } else {\n+                    logger.warn(\"PowerMax alarm binding: rejected command {}\", commandStr);\n+                }\n+                break;\n+            }\n+        }\n+    }\n+\n+    /**\n+     * @{inheritDoc\n+     */\n+    @Override\n+    protected void internalReceiveUpdate(String itemName, State newState) {\n+        // the code being executed when a state was sent on the openHAB\n+        // event bus goes here. This method is only called if one of the\n+        // BindingProviders provide a binding for the given 'itemName'.\n+        logger.debug(\"internalReceiveUpdate({},{}) is called\", itemName, newState);\n+        logger.warn(\"Item {}: state can be updated only by the PowerMax alarm binding.\", itemName);\n+    }\n+\n+    /**\n+     * @{inheritDoc\n+     */\n+    @Override\n+    public void updated(Dictionary<String, ?> config) throws ConfigurationException {\n+        logger.debug(\"updated(): updating configuration\");\n+\n+        closeConnection();\n+\n+        serialPort = null;\n+        ipAddress = null;\n+        tcpPort = 0;\n+        motionOffDelay = DEFAULT_MOTION_OFF_DELAY;\n+        allowArming = false;\n+        allowDisarming = false;\n+        forceStandardMode = false;\n+        panelType = PowerMaxPanelType.POWERMAX_PRO;\n+        autoSyncTime = false;\n+        pinCode = null;\n+\n+        PowerMaxReceiveType.POWERLINK.setHandlerClass(PowerMaxPowerlinkMessage.class);\n+\n+        boolean properlyConfigured = false;\n+        try {\n+\n+            if (config == null) {\n+                throw new ConfigurationException(null, \"missing configuration\");\n+            }\n+\n+            if (StringUtils.isNotBlank((String) config.get(\"serialPort\"))) {\n+                serialPort = (String) config.get(\"serialPort\");\n+            }\n+\n+            if (StringUtils.isNotBlank((String) config.get(\"ip\"))) {\n+                ipAddress = (String) config.get(\"ip\");\n+            }\n+\n+            if (serialPort == null && ipAddress == null) {\n+                throw new ConfigurationException(null,\n+                        \"one connection type (Serial Port or IP Address) must be defined\");\n+            }\n+\n+            if (serialPort != null && ipAddress != null) {\n+                throw new ConfigurationException(null,\n+                        \"can only configure one connection type at a time: Serial Port or IP Address\");\n+            }\n+\n+            if (ipAddress != null) {\n+                if (StringUtils.isNotBlank((String) config.get(\"tcpPort\"))) {\n+                    try {\n+                        tcpPort = Integer.parseInt((String) config.get(\"tcpPort\"));\n+                    } catch (NumberFormatException numberFormatException) {\n+                        tcpPort = 0;\n+                        throw new ConfigurationException(\"tcpPort\",\n+                                \"TCP port not configured correctly (number expected)\");\n+                    }\n+                }\n+            }\n+\n+            if (StringUtils.isNotBlank((String) config.get(\"motionOffDelay\"))) {\n+                try {\n+                    motionOffDelay = Integer.parseInt((String) config.get(\"motionOffDelay\")) * 60000;\n+                } catch (NumberFormatException numberFormatException) {\n+                    motionOffDelay = DEFAULT_MOTION_OFF_DELAY;\n+                    logger.warn(\"PowerMax alarm binding: motion off delay not configured correctly (number expected)\");\n+                }\n+            }\n+\n+            if (StringUtils.isNotBlank((String) config.get(\"allowArming\"))) {\n+                allowArming = Boolean.valueOf((String) config.get(\"allowArming\"));\n+            }\n+            if (StringUtils.isNotBlank((String) config.get(\"allowDisarming\"))) {\n+                allowDisarming = Boolean.valueOf((String) config.get(\"allowDisarming\"));\n+            }\n+            if (StringUtils.isNotBlank((String) config.get(\"forceStandardMode\"))) {\n+                forceStandardMode = Boolean.valueOf((String) config.get(\"forceStandardMode\"));\n+                PowerMaxReceiveType.POWERLINK.setHandlerClass(\n+                        forceStandardMode ? PowerMaxBaseMessage.class : PowerMaxPowerlinkMessage.class);\n+            }\n+\n+            if (StringUtils.isNotBlank((String) config.get(\"panelType\"))) {\n+                try {\n+                    panelType = PowerMaxPanelType.fromLabel((String) config.get(\"panelType\"));\n+                } catch (IllegalArgumentException exception) {\n+                    panelType = PowerMaxPanelType.POWERMAX_PRO;\n+                    logger.warn(\"PowerMax alarm binding: panel type not configured correctly\");\n+                }\n+            }\n+            PowerMaxPanelSettings.initPanelSettings(panelType);\n+\n+            if (StringUtils.isNotBlank((String) config.get(\"autoSyncTime\"))) {\n+                autoSyncTime = Boolean.valueOf((String) config.get(\"autoSyncTime\"));\n+            }\n+\n+            if (StringUtils.isNotBlank((String) config.get(\"pinCode\"))) {\n+                pinCode = (String) config.get(\"pinCode\");\n+            }\n+\n+            properlyConfigured = true;\n+\n+        } catch (ConfigurationException e) {\n+\n+            logger.warn(\"PowerMax alarm binding: {}\", e.getReason());\n+\n+        } finally {\n+\n+            this.setProperlyConfigured(properlyConfigured);\n+\n+        }\n+    }\n+\n+    /**\n+     * Open a TCP or Serial connection to the PowerMax Alarm Panel\n+     */\n+    private void openConnection() {\n+        PowerMaxCommDriver.initTheCommDriver(serialPort, ipAddress, tcpPort);\n+        PowerMaxCommDriver comm = PowerMaxCommDriver.getTheCommDriver();\n+        if (comm != null) {\n+            comm.addEventListener(this);\n+            connected = comm.open();\n+            if (serialPort != null) {\n+                logger.info(\"PowerMax alarm binding: serial connection ({}): {}\", serialPort,\n+                        connected ? \"connected\" : \"disconnected\");\n+            } else if (ipAddress != null) {\n+                logger.info(\"PowerMax alarm binding: TCP connection (IP {} port {}): {}\", ipAddress, tcpPort,\n+                        connected ? \"connected\" : \"disconnected\");\n+            }\n+        } else {\n+            connected = false;\n+        }\n+        logger.debug(\"openConnection(): {}\", connected ? \"connected\" : \"disconnected\");\n+    }\n+\n+    /**\n+     * Close TCP or Serial connection to the PowerMax Alarm Panel and remove the Event Listener\n+     */\n+    private void closeConnection() {\n+        PowerMaxCommDriver comm = PowerMaxCommDriver.getTheCommDriver();\n+        if (comm != null) {\n+            comm.close();\n+            comm.removeEventListener(this);\n+        }\n+        connected = false;\n+        logger.debug(\"closeConnection(): disconnected\");\n+    }\n+\n+    /**\n+     * PowerMax Alarm incoming message event handler\n+     *\n+     * @param event\n+     */\n+    @Override\n+    public void powerMaxEventReceived(EventObject event) {\n+        PowerMaxEvent powerMaxEvent = (PowerMaxEvent) event;\n+        PowerMaxBaseMessage message = powerMaxEvent.getPowerMaxMessage();\n+\n+        logger.debug(\"powerMaxEventReceived(): received message {}\", (message.getReceiveType() != null)\n+                ? message.getReceiveType().getDescription() : String.format(\"%02X\", message.getCode()));\n+\n+        if (message instanceof PowerMaxInfoMessage) {\n+            ((PowerMaxInfoMessage) message).setAutoSyncTime(autoSyncTime);\n+        }\n+\n+        PowerMaxState updateState = message.handleMessage();\n+        if (updateState != null) {\n+\n+            if ((currentState.isPowerlinkMode() != null) && currentState.isPowerlinkMode().equals(Boolean.TRUE)\n+                    && (updateState.isDownloadSetupRequired() != null)\n+                    && updateState.isDownloadSetupRequired().equals(Boolean.TRUE)) {\n+                // After Enrolling Powerlink or if a reset is required\n+                logger.info(\"PowerMax alarm binding: Reset\");\n+                PowerMaxCommDriver.getTheCommDriver().startDownload();\n+                if (currentState.getLastKeepAlive() != null) {\n+                    currentState.setLastKeepAlive(System.currentTimeMillis());\n+                }\n+            } else if ((currentState.isPowerlinkMode() != null) && currentState.isPowerlinkMode().equals(Boolean.FALSE)\n+                    && (updateState.getLastKeepAlive() != null)) {\n+                // Were are in standard mode but received a keep alive message\n+                // so we switch in PowerLink mode\n+                logger.info(\"PowerMax alarm binding: Switching to Powerlink mode\");\n+                PowerMaxCommDriver.getTheCommDriver().startDownload();\n+            }\n+\n+            boolean doProcessSettings = (updateState.isPowerlinkMode() != null);\n+\n+            for (int i = 1; i <= PowerMaxPanelSettings.getThePanelSettings().getNbZones(); i++) {\n+                if ((updateState.isSensorArmed(i) != null) && updateState.isSensorArmed(i).equals(Boolean.TRUE)\n+                        && (currentState.isSensorBypassed(i) != null)\n+                        && currentState.isSensorBypassed(i).equals(Boolean.TRUE)) {\n+                    updateState.setSensorArmed(i, false);\n+                }\n+            }\n+\n+            updateState.keepOnlyDiifWith(currentState);\n+            updateItemsFromAlarmState(updateState);\n+            currentState.merge(updateState);\n+\n+            if (updateState.getUpdateSettings() != null) {\n+                PowerMaxPanelSettings.getThePanelSettings().updateRawSettings(updateState.getUpdateSettings());\n+            }\n+\n+            if (doProcessSettings) {\n+                // There is a change of mode (standard or Powerlink)\n+                PowerMaxPanelSettings.getThePanelSettings().process(currentState.isPowerlinkMode(), panelType,\n+                        PowerMaxCommDriver.getTheCommDriver().getSyncTimeCheck());\n+                updateItemsFromPanelSettings();\n+                if (currentState.isPowerlinkMode()) {\n+                    logger.info(\"PowerMax alarm binding: running in Powerlink mode\");\n+                    PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.RESTORE);\n+                } else {\n+                    logger.info(\"PowerMax alarm binding: running in Standard mode\");\n+                    PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESNAME);\n+                    PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESTYPE);\n+                    PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.STATUS);\n+                }\n+                PowerMaxCommDriver.getTheCommDriver().exitDownload();\n+            }\n+        }\n+    }\n+\n+    /**\n+     * Post item updates on the bus to match a new alarm system state\n+     *\n+     * @param selector\n+     *            filter on selector type; if null, no filter on selector type\n+     * @param state\n+     *            the alarm system state\n+     */\n+    private void updateItemsFromAlarmState(PowerMaxSelectorType selector, PowerMaxState state) {\n+        updateItemsFromAlarmState(null, null, selector, state);\n+    }\n+\n+    /**\n+     * Post item updates on the bus to match a new alarm system state\n+     *\n+     * @param state\n+     *            the alarm system state\n+     */\n+    private void updateItemsFromAlarmState(PowerMaxState state) {\n+        updateItemsFromAlarmState(null, null, null, state);\n+    }\n+\n+    /**\n+     * Post item updates on the bus to match a new alarm system state\n+     *\n+     * @param provider\n+     *            filter on provider; if null, no filter on provider\n+     * @param name\n+     *            filter on item name; if null, no filter on item name\n+     * @param selector\n+     *            filter on selector type; if null, no filter on selector type\n+     * @param state\n+     *            the alarm system state\n+     */\n+    private synchronized void updateItemsFromAlarmState(PowerMaxBindingProvider provider, String name,\n+            PowerMaxSelectorType selector, PowerMaxState state) {\n+\n+        if (state == null) {\n+            return;\n+        }\n+        if (itemUpdateDisabled) {\n+            logger.debug(\"updateItemsFromAlarmState(): items update disabled\");\n+            return;\n+        }\n+\n+        if (provider == null) {\n+            for (PowerMaxBindingProvider prov : providers) {\n+                updateItemsFromAlarmState(prov, name, selector, state);\n+            }\n+        } else {\n+            for (String itemName : provider.getItemNames()) {\n+                if ((name == null) || itemName.equals(name)) {\n+                    State itemState = null;\n+\n+                    PowerMaxBindingConfig config = provider.getConfig(itemName);\n+                    Integer num = config.getSelectorIntParam();\n+                    Item item = config.getItem();","path":"bundles/binding/org.openhab.binding.powermax/src/main/java/org/openhab/binding/powermax/internal/PowerMaxBinding.java","position":714,"original_position":714,"commit_id":"43a3d4e65a9022acdcc8271b260a2a1000043f36","original_commit_id":"43a3d4e65a9022acdcc8271b260a2a1000043f36","user":{"login":"lolodomo","id":10186704,"avatar_url":"https://avatars.githubusercontent.com/u/10186704?v=3","gravatar_id":"","url":"https://api.github.com/users/lolodomo","html_url":"https://github.com/lolodomo","followers_url":"https://api.github.com/users/lolodomo/followers","following_url":"https://api.github.com/users/lolodomo/following{/other_user}","gists_url":"https://api.github.com/users/lolodomo/gists{/gist_id}","starred_url":"https://api.github.com/users/lolodomo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lolodomo/subscriptions","organizations_url":"https://api.github.com/users/lolodomo/orgs","repos_url":"https://api.github.com/users/lolodomo/repos","events_url":"https://api.github.com/users/lolodomo/events{/privacy}","received_events_url":"https://api.github.com/users/lolodomo/received_events","type":"User","site_admin":false},"body":"Ok thank you, I understand now perfectly how to implement that and will update my code.","created_at":"2016-02-22T10:09:15Z","updated_at":"2016-02-22T10:09:15Z","html_url":"https://github.com/openhab/openhab/pull/4079#discussion_r53605440","pull_request_url":"https://api.github.com/repos/openhab/openhab/pulls/4079","_links":{"self":{"href":"https://api.github.com/repos/openhab/openhab/pulls/comments/53605440"},"html":{"href":"https://github.com/openhab/openhab/pull/4079#discussion_r53605440"},"pull_request":{"href":"https://api.github.com/repos/openhab/openhab/pulls/4079"}}},"pull_request":{"url":"https://api.github.com/repos/openhab/openhab/pulls/4079","id":60050420,"html_url":"https://github.com/openhab/openhab/pull/4079","diff_url":"https://github.com/openhab/openhab/pull/4079.diff","patch_url":"https://github.com/openhab/openhab/pull/4079.patch","issue_url":"https://api.github.com/repos/openhab/openhab/issues/4079","number":4079,"state":"open","locked":false,"title":"Initial commit for new Powermax alarm binding","user":{"login":"lolodomo","id":10186704,"avatar_url":"https://avatars.githubusercontent.com/u/10186704?v=3","gravatar_id":"","url":"https://api.github.com/users/lolodomo","html_url":"https://github.com/lolodomo","followers_url":"https://api.github.com/users/lolodomo/followers","following_url":"https://api.github.com/users/lolodomo/following{/other_user}","gists_url":"https://api.github.com/users/lolodomo/gists{/gist_id}","starred_url":"https://api.github.com/users/lolodomo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lolodomo/subscriptions","organizations_url":"https://api.github.com/users/lolodomo/orgs","repos_url":"https://api.github.com/users/lolodomo/repos","events_url":"https://api.github.com/users/lolodomo/events{/privacy}","received_events_url":"https://api.github.com/users/lolodomo/received_events","type":"User","site_admin":false},"body":"Here is the finished 1.x version of my Powermax/Powermaster binding.\r\n\r\nFeedback from beta testers can be found [here](https://community.openhab.org/t/powermax-binding/2824)","created_at":"2016-02-20T15:04:30Z","updated_at":"2016-02-22T10:09:15Z","closed_at":null,"merged_at":null,"merge_commit_sha":null,"assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/openhab/openhab/pulls/4079/commits","review_comments_url":"https://api.github.com/repos/openhab/openhab/pulls/4079/comments","review_comment_url":"https://api.github.com/repos/openhab/openhab/pulls/comments{/number}","comments_url":"https://api.github.com/repos/openhab/openhab/issues/4079/comments","statuses_url":"https://api.github.com/repos/openhab/openhab/statuses/43a3d4e65a9022acdcc8271b260a2a1000043f36","head":{"label":"lolodomo:powermax","ref":"powermax","sha":"43a3d4e65a9022acdcc8271b260a2a1000043f36","user":{"login":"lolodomo","id":10186704,"avatar_url":"https://avatars.githubusercontent.com/u/10186704?v=3","gravatar_id":"","url":"https://api.github.com/users/lolodomo","html_url":"https://github.com/lolodomo","followers_url":"https://api.github.com/users/lolodomo/followers","following_url":"https://api.github.com/users/lolodomo/following{/other_user}","gists_url":"https://api.github.com/users/lolodomo/gists{/gist_id}","starred_url":"https://api.github.com/users/lolodomo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lolodomo/subscriptions","organizations_url":"https://api.github.com/users/lolodomo/orgs","repos_url":"https://api.github.com/users/lolodomo/repos","events_url":"https://api.github.com/users/lolodomo/events{/privacy}","received_events_url":"https://api.github.com/users/lolodomo/received_events","type":"User","site_admin":false},"repo":{"id":51026939,"name":"openhab","full_name":"lolodomo/openhab","owner":{"login":"lolodomo","id":10186704,"avatar_url":"https://avatars.githubusercontent.com/u/10186704?v=3","gravatar_id":"","url":"https://api.github.com/users/lolodomo","html_url":"https://github.com/lolodomo","followers_url":"https://api.github.com/users/lolodomo/followers","following_url":"https://api.github.com/users/lolodomo/following{/other_user}","gists_url":"https://api.github.com/users/lolodomo/gists{/gist_id}","starred_url":"https://api.github.com/users/lolodomo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lolodomo/subscriptions","organizations_url":"https://api.github.com/users/lolodomo/orgs","repos_url":"https://api.github.com/users/lolodomo/repos","events_url":"https://api.github.com/users/lolodomo/events{/privacy}","received_events_url":"https://api.github.com/users/lolodomo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/lolodomo/openhab","description":"Source code of the open Home Automation Bus (openHAB)","fork":true,"url":"https://api.github.com/repos/lolodomo/openhab","forks_url":"https://api.github.com/repos/lolodomo/openhab/forks","keys_url":"https://api.github.com/repos/lolodomo/openhab/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lolodomo/openhab/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lolodomo/openhab/teams","hooks_url":"https://api.github.com/repos/lolodomo/openhab/hooks","issue_events_url":"https://api.github.com/repos/lolodomo/openhab/issues/events{/number}","events_url":"https://api.github.com/repos/lolodomo/openhab/events","assignees_url":"https://api.github.com/repos/lolodomo/openhab/assignees{/user}","branches_url":"https://api.github.com/repos/lolodomo/openhab/branches{/branch}","tags_url":"https://api.github.com/repos/lolodomo/openhab/tags","blobs_url":"https://api.github.com/repos/lolodomo/openhab/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lolodomo/openhab/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lolodomo/openhab/git/refs{/sha}","trees_url":"https://api.github.com/repos/lolodomo/openhab/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lolodomo/openhab/statuses/{sha}","languages_url":"https://api.github.com/repos/lolodomo/openhab/languages","stargazers_url":"https://api.github.com/repos/lolodomo/openhab/stargazers","contributors_url":"https://api.github.com/repos/lolodomo/openhab/contributors","subscribers_url":"https://api.github.com/repos/lolodomo/openhab/subscribers","subscription_url":"https://api.github.com/repos/lolodomo/openhab/subscription","commits_url":"https://api.github.com/repos/lolodomo/openhab/commits{/sha}","git_commits_url":"https://api.github.com/repos/lolodomo/openhab/git/commits{/sha}","comments_url":"https://api.github.com/repos/lolodomo/openhab/comments{/number}","issue_comment_url":"https://api.github.com/repos/lolodomo/openhab/issues/comments{/number}","contents_url":"https://api.github.com/repos/lolodomo/openhab/contents/{+path}","compare_url":"https://api.github.com/repos/lolodomo/openhab/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lolodomo/openhab/merges","archive_url":"https://api.github.com/repos/lolodomo/openhab/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lolodomo/openhab/downloads","issues_url":"https://api.github.com/repos/lolodomo/openhab/issues{/number}","pulls_url":"https://api.github.com/repos/lolodomo/openhab/pulls{/number}","milestones_url":"https://api.github.com/repos/lolodomo/openhab/milestones{/number}","notifications_url":"https://api.github.com/repos/lolodomo/openhab/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lolodomo/openhab/labels{/name}","releases_url":"https://api.github.com/repos/lolodomo/openhab/releases{/id}","deployments_url":"https://api.github.com/repos/lolodomo/openhab/deployments","created_at":"2016-02-03T20:05:57Z","updated_at":"2016-02-03T20:06:10Z","pushed_at":"2016-02-20T19:18:58Z","git_url":"git://github.com/lolodomo/openhab.git","ssh_url":"git@github.com:lolodomo/openhab.git","clone_url":"https://github.com/lolodomo/openhab.git","svn_url":"https://github.com/lolodomo/openhab","homepage":null,"size":189038,"stargazers_count":0,"watchers_count":0,"language":"Java","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"openhab:master","ref":"master","sha":"a3d8675bb6939370b5672813bb53ccaf7918dd9a","user":{"login":"openhab","id":1007353,"avatar_url":"https://avatars.githubusercontent.com/u/1007353?v=3","gravatar_id":"","url":"https://api.github.com/users/openhab","html_url":"https://github.com/openhab","followers_url":"https://api.github.com/users/openhab/followers","following_url":"https://api.github.com/users/openhab/following{/other_user}","gists_url":"https://api.github.com/users/openhab/gists{/gist_id}","starred_url":"https://api.github.com/users/openhab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openhab/subscriptions","organizations_url":"https://api.github.com/users/openhab/orgs","repos_url":"https://api.github.com/users/openhab/repos","events_url":"https://api.github.com/users/openhab/events{/privacy}","received_events_url":"https://api.github.com/users/openhab/received_events","type":"Organization","site_admin":false},"repo":{"id":12983151,"name":"openhab","full_name":"openhab/openhab","owner":{"login":"openhab","id":1007353,"avatar_url":"https://avatars.githubusercontent.com/u/1007353?v=3","gravatar_id":"","url":"https://api.github.com/users/openhab","html_url":"https://github.com/openhab","followers_url":"https://api.github.com/users/openhab/followers","following_url":"https://api.github.com/users/openhab/following{/other_user}","gists_url":"https://api.github.com/users/openhab/gists{/gist_id}","starred_url":"https://api.github.com/users/openhab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/openhab/subscriptions","organizations_url":"https://api.github.com/users/openhab/orgs","repos_url":"https://api.github.com/users/openhab/repos","events_url":"https://api.github.com/users/openhab/events{/privacy}","received_events_url":"https://api.github.com/users/openhab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/openhab/openhab","description":"Source code of the open Home Automation Bus (openHAB)","fork":false,"url":"https://api.github.com/repos/openhab/openhab","forks_url":"https://api.github.com/repos/openhab/openhab/forks","keys_url":"https://api.github.com/repos/openhab/openhab/keys{/key_id}","collaborators_url":"https://api.github.com/repos/openhab/openhab/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/openhab/openhab/teams","hooks_url":"https://api.github.com/repos/openhab/openhab/hooks","issue_events_url":"https://api.github.com/repos/openhab/openhab/issues/events{/number}","events_url":"https://api.github.com/repos/openhab/openhab/events","assignees_url":"https://api.github.com/repos/openhab/openhab/assignees{/user}","branches_url":"https://api.github.com/repos/openhab/openhab/branches{/branch}","tags_url":"https://api.github.com/repos/openhab/openhab/tags","blobs_url":"https://api.github.com/repos/openhab/openhab/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/openhab/openhab/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/openhab/openhab/git/refs{/sha}","trees_url":"https://api.github.com/repos/openhab/openhab/git/trees{/sha}","statuses_url":"https://api.github.com/repos/openhab/openhab/statuses/{sha}","languages_url":"https://api.github.com/repos/openhab/openhab/languages","stargazers_url":"https://api.github.com/repos/openhab/openhab/stargazers","contributors_url":"https://api.github.com/repos/openhab/openhab/contributors","subscribers_url":"https://api.github.com/repos/openhab/openhab/subscribers","subscription_url":"https://api.github.com/repos/openhab/openhab/subscription","commits_url":"https://api.github.com/repos/openhab/openhab/commits{/sha}","git_commits_url":"https://api.github.com/repos/openhab/openhab/git/commits{/sha}","comments_url":"https://api.github.com/repos/openhab/openhab/comments{/number}","issue_comment_url":"https://api.github.com/repos/openhab/openhab/issues/comments{/number}","contents_url":"https://api.github.com/repos/openhab/openhab/contents/{+path}","compare_url":"https://api.github.com/repos/openhab/openhab/compare/{base}...{head}","merges_url":"https://api.github.com/repos/openhab/openhab/merges","archive_url":"https://api.github.com/repos/openhab/openhab/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/openhab/openhab/downloads","issues_url":"https://api.github.com/repos/openhab/openhab/issues{/number}","pulls_url":"https://api.github.com/repos/openhab/openhab/pulls{/number}","milestones_url":"https://api.github.com/repos/openhab/openhab/milestones{/number}","notifications_url":"https://api.github.com/repos/openhab/openhab/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/openhab/openhab/labels{/name}","releases_url":"https://api.github.com/repos/openhab/openhab/releases{/id}","deployments_url":"https://api.github.com/repos/openhab/openhab/deployments","created_at":"2013-09-20T20:28:43Z","updated_at":"2016-02-22T04:59:59Z","pushed_at":"2016-02-22T03:08:05Z","git_url":"git://github.com/openhab/openhab.git","ssh_url":"git@github.com:openhab/openhab.git","clone_url":"https://github.com/openhab/openhab.git","svn_url":"https://github.com/openhab/openhab","homepage":null,"size":270945,"stargazers_count":2288,"watchers_count":2288,"language":"Java","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1207,"mirror_url":null,"open_issues_count":509,"forks":1207,"open_issues":509,"watchers":2288,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/openhab/openhab/pulls/4079"},"html":{"href":"https://github.com/openhab/openhab/pull/4079"},"issue":{"href":"https://api.github.com/repos/openhab/openhab/issues/4079"},"comments":{"href":"https://api.github.com/repos/openhab/openhab/issues/4079/comments"},"review_comments":{"href":"https://api.github.com/repos/openhab/openhab/pulls/4079/comments"},"review_comment":{"href":"https://api.github.com/repos/openhab/openhab/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/openhab/openhab/pulls/4079/commits"},"statuses":{"href":"https://api.github.com/repos/openhab/openhab/statuses/43a3d4e65a9022acdcc8271b260a2a1000043f36"}}}}