/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.powermax.internal; import java.util.Calendar; import java.util.Dictionary; import java.util.EventObject; import java.util.HashMap; import java.util.Objects; import org.apache.commons.lang.StringUtils; import org.openhab.binding.powermax.PowerMaxBindingConfig; import org.openhab.binding.powermax.PowerMaxBindingProvider; import org.openhab.binding.powermax.internal.connector.PowerMaxEvent; import org.openhab.binding.powermax.internal.connector.PowerMaxEventListener; import org.openhab.binding.powermax.internal.message.PowerMaxBaseMessage; import org.openhab.binding.powermax.internal.message.PowerMaxCommDriver; import org.openhab.binding.powermax.internal.message.PowerMaxInfoMessage; import org.openhab.binding.powermax.internal.message.PowerMaxPowerlinkMessage; import org.openhab.binding.powermax.internal.message.PowerMaxReceiveType; import org.openhab.binding.powermax.internal.message.PowerMaxSendType; import org.openhab.binding.powermax.internal.state.PowerMaxPanelSettings; import org.openhab.binding.powermax.internal.state.PowerMaxPanelType; import org.openhab.binding.powermax.internal.state.PowerMaxState; import org.openhab.core.binding.AbstractActiveBinding; import org.openhab.core.binding.BindingProvider; 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.library.types.StringType; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.openhab.core.types.TypeParser; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Binding that get information from the Visonic alarm system. * The binding is listening to openHAB event bus and is able to send few commands to the alarm system * * @author Laurent Garnier * @since 1.9.0 */ public class PowerMaxBinding extends AbstractActiveBinding<PowerMaxBindingProvider> implements ManagedService, PowerMaxEventListener { private static final Logger logger = LoggerFactory.getLogger(PowerMaxBinding.class); private static final int ONE_MINUTE = 60000; /** Default delay in milliseconds to reset a motion detection */ private static final int DEFAULT_MOTION_OFF_DELAY = 3 * ONE_MINUTE; /** The serial port to use for connecting to the PowerMax alarm system */ private String serialPort; /** The IP address and TCP port to use for connecting to the PowerMax alarm system */ private String ipAddress; private int tcpPort; /** The delay in milliseconds to reset a motion detection */ private int motionOffDelay; /** The PIN code to use for arming/disarming the PowerMax alarm system from openHAB */ private String pinCode; /** Enable or disable arming the PowerMax alarm system from openHAB */ private boolean allowArming; /** Enable or disable disarming the PowerMax alarm system from openHAB */ private boolean allowDisarming; /** Force the standard mode rather than trying using the Powerlink mode */ private boolean forceStandardMode; /** Panel type used when in standard mode */ private PowerMaxPanelType panelType; /** Automatic sync time */ private boolean autoSyncTime; /** The object to store the current state of the PowerMax alarm system */ private PowerMaxState currentState; /** Number of items managed by the binding */ private int itemCount; /** Boolean indicating whether or not the update of items is temporarily disabled by the binding */ private boolean itemUpdateDisabled; /** * Boolean indicating whether or not an update of all items will be required * during the next refresh cycle */ private boolean triggerItemsUpdate; /** Boolean indicating whether or not connection is established with the alarm system */ private boolean connected; public PowerMaxBinding() { serialPort = null; ipAddress = null; tcpPort = 0; motionOffDelay = DEFAULT_MOTION_OFF_DELAY; pinCode = null; allowArming = false; allowDisarming = false; forceStandardMode = false; panelType = PowerMaxPanelType.POWERMAX_PRO; autoSyncTime = false; currentState = null; itemCount = 0; itemUpdateDisabled = true; triggerItemsUpdate = false; connected = false; } /** * Activates the binding. Actually does nothing, because on activation * OpenHAB always calls updated to indicate that the config is updated * Activation is done there */ @Override public void activate() { logger.debug("Activate PowerMax alarm binding"); } /** * Deactivates the binding */ @Override public void deactivate() { logger.debug("Deactivate PowerMax alarm binding"); closeConnection(); } /** * {@inheritDoc} */ @Override protected long getRefreshInterval() { return 20000; // 20 seconds } /** * {@inheritDoc} */ @Override protected String getName() { return "PowerMax Refresh Service"; } /** * {@inheritDoc} */ @Override protected void execute() { logger.debug("PowerMax alarm Execute"); if (!isProperlyConfigured()) { logger.debug("execute(): not yet properly configured"); return; } // // Off items linked to motion sensors after the delay defined by // the variable motionOffDelay // long now = System.currentTimeMillis(); PowerMaxPanelSettings settings = PowerMaxPanelSettings.getThePanelSettings(); PowerMaxState updateState = null; if ((currentState != null) && (settings != null)) { for (int i = 1; i <= settings.getNbZones(); i++) { if ((settings.getZoneSettings(i) != null) && settings.getZoneSettings(i).getSensorType().equalsIgnoreCase("Motion") && (currentState.isSensorTripped(i) == Boolean.TRUE) && (currentState.getSensorLastTripped(i) != null) && ((now - currentState.getSensorLastTripped(i)) > motionOffDelay)) { if (updateState == null) { updateState = new PowerMaxState(); } updateState.setSensorTripped(i, false); } } } if (updateState != null) { updateItemsFromAlarmState(PowerMaxSelectorType.ZONE_STATUS, updateState); currentState.merge(updateState); } if (PowerMaxCommDriver.getTheCommDriver() != null) { connected = PowerMaxCommDriver.getTheCommDriver().isConnected(); } // Check that we receive a keep alive message during the last minute if (connected && (currentState.isPowerlinkMode() != null) && currentState.isPowerlinkMode().equals(Boolean.TRUE) && (currentState.getLastKeepAlive() != null) && ((now - currentState.getLastKeepAlive()) > ONE_MINUTE)) { // Let Powermax know we are alive PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.RESTORE); currentState.setLastKeepAlive(now); } // // Try to reconnect if disconnected // if (!connected) { logger.debug("execute(): trying to reconnect..."); closeConnection(); if (triggerItemsUpdate) { logger.debug("execute(): items update enabled"); itemUpdateDisabled = false; triggerItemsUpdate = false; } currentState = new PowerMaxState(); openConnection(); if (connected) { // TODO is INIT message required or not ? if (forceStandardMode) { currentState.setPowerlinkMode(false); updateItemsFromAlarmState(PowerMaxSelectorType.PANEL_MODE, currentState); settings = PowerMaxPanelSettings.getThePanelSettings(); settings.process(false, panelType, null); updateItemsFromPanelSettings(); logger.info("PowerMax alarm binding: running in Standard mode"); PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESNAME); PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESTYPE); PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.STATUS); } else { PowerMaxCommDriver.getTheCommDriver().startDownload(); } } else { logger.debug("execute(): reconnection failed"); } } else if (triggerItemsUpdate) { logger.debug("execute(): update all items"); itemUpdateDisabled = false; triggerItemsUpdate = false; // Adjust all the items to the current alarm state updateItemsFromAlarmState(currentState); // Adjust all the items to the current alarm settings updateItemsFromPanelSettings(); } } /** * {@inheritDoc} */ @Override public void bindingChanged(BindingProvider provider, String itemName) { logger.debug("bindingChanged(): Item Name: {} Provider items count: {}", itemName, provider.getItemNames().size()); itemUpdateDisabled = true; if (provider.getItemNames().size() >= itemCount) { triggerItemsUpdate = true; } itemCount = provider.getItemNames().size(); super.bindingChanged(provider, itemName); } /** * {@inheritDoc} */ @Override public void allBindingsChanged(BindingProvider provider) { logger.debug("allBindingsChanged(): Provider items count: {}", provider.getItemNames().size()); itemUpdateDisabled = true; if (provider.getItemNames().size() > 0) { triggerItemsUpdate = true; } itemCount = provider.getItemNames().size(); super.allBindingsChanged(provider); } /** * {@inheritDoc} */ @Override protected void internalReceiveCommand(String itemName, Command command) { // the code being executed when a command was sent on the openHAB // event bus goes here. This method is only called if one of the // BindingProviders provide a binding for the given 'itemName'. logger.debug("internalReceiveCommand({},{}) is called", itemName, command); if (!isProperlyConfigured() || !connected) { logger.warn("PowerMax alarm binding is not properly configured. Command is ignored."); return; } String armMode = null; String actionPGMX10 = null; Byte devicePGMX10 = null; Boolean bypass = null; byte zoneNr = 0; String commandStr = null; PowerMaxPanelSettings settings = PowerMaxPanelSettings.getThePanelSettings(); PowerMaxCommDriver comm = PowerMaxCommDriver.getTheCommDriver(); for (PowerMaxBindingProvider provider : providers) { PowerMaxBindingConfig config = provider.getConfig(itemName); if (config == null) { continue; } switch (config.getSelectorType()) { case PARTITION_ARM_MODE: if (command instanceof StringType) { armMode = command.toString(); } break; case PARTITION_ARMED: if (command instanceof OnOffType) { armMode = command.equals(OnOffType.ON) ? "Armed" : "Disarmed"; } break; case PGM_STATUS: if (command instanceof OnOffType) { actionPGMX10 = command.toString(); } break; case X10_STATUS: if (command instanceof OnOffType || command instanceof StringType) { actionPGMX10 = command.toString(); } try { devicePGMX10 = Byte.parseByte(config.getSelectorParam()); } catch (NumberFormatException e) { logger.warn("PowerMax alarm binding: invalid X10 device id: {}", config.getSelectorParam()); actionPGMX10 = null; } break; case ZONE_BYPASSED: if (command instanceof OnOffType) { bypass = command.equals(OnOffType.ON) ? Boolean.TRUE : Boolean.FALSE; } try { zoneNr = Byte.parseByte(config.getSelectorParam()); } catch (NumberFormatException e) { logger.warn("PowerMax alarm binding: invalid zone number: {}", config.getSelectorParam()); bypass = null; } break; case COMMAND: if (command instanceof StringType) { commandStr = command.toString(); eventPublisher.postUpdate(itemName, new StringType(commandStr)); } break; default: break; } if (armMode != null) { HashMap<String, Boolean> allowedModes = new HashMap<String, Boolean>(); allowedModes.put("Disarmed", allowDisarming); allowedModes.put("Stay", allowArming); allowedModes.put("Armed", allowArming); allowedModes.put("StayInstant", allowArming); allowedModes.put("ArmedInstant", allowArming); allowedModes.put("Night", allowArming); allowedModes.put("NightInstant", allowArming); Boolean allowed = allowedModes.get(armMode); if ((allowed == null) || !allowed) { logger.warn("PowerMax alarm binding: rejected command {}", armMode); } else { comm.requestArmMode(armMode, currentState.isPowerlinkMode() ? PowerMaxPanelSettings.getThePanelSettings().getFirstPinCode() : pinCode); } break; } else if (actionPGMX10 != null) { comm.sendPGMX10(actionPGMX10, devicePGMX10); break; } else if (bypass != null) { if ((currentState.isPowerlinkMode() == null) || currentState.isPowerlinkMode().equals(Boolean.FALSE)) { logger.warn("PowerMax alarm binding: Bypass option only supported in Powerlink mode"); } else if (!PowerMaxPanelSettings.getThePanelSettings().isBypassEnabled()) { logger.warn("PowerMax alarm binding: Bypass option not enabled in panel settings"); } else { comm.sendZoneBypass(bypass.booleanValue(), zoneNr, PowerMaxPanelSettings.getThePanelSettings().getFirstPinCode()); } break; } else if (commandStr != null) { if (commandStr.equalsIgnoreCase("get_event_log")) { comm.requestEventLog(currentState.isPowerlinkMode() ? PowerMaxPanelSettings.getThePanelSettings().getFirstPinCode() : pinCode); } else if (commandStr.equalsIgnoreCase("download_setup")) { if ((currentState.isPowerlinkMode() == null) || currentState.isPowerlinkMode().equals(Boolean.FALSE)) { logger.warn("PowerMax alarm binding: download setup only supported in Powerlink mode"); } else { comm.startDownload(); if (currentState.getLastKeepAlive() != null) { currentState.setLastKeepAlive(System.currentTimeMillis()); } } } else if (commandStr.equalsIgnoreCase("log_setup")) { settings.log(); } else if (commandStr.equalsIgnoreCase("help_items")) { settings.helpItems(); } else { logger.warn("PowerMax alarm binding: rejected command {}", commandStr); } break; } } } /** * {@inheritDoc} */ @Override public void updated(Dictionary<String, ?> config) throws ConfigurationException { logger.debug("updated(): updating configuration"); closeConnection(); serialPort = null; ipAddress = null; tcpPort = 0; motionOffDelay = DEFAULT_MOTION_OFF_DELAY; allowArming = false; allowDisarming = false; forceStandardMode = false; panelType = PowerMaxPanelType.POWERMAX_PRO; autoSyncTime = false; pinCode = null; PowerMaxReceiveType.POWERLINK.setHandlerClass(PowerMaxPowerlinkMessage.class); if (config != null) { String serialPortString = Objects.toString(config.get("serialPort"), null); if (StringUtils.isNotBlank(serialPortString)) { serialPort = serialPortString; } String ipString = Objects.toString(config.get("ip"), null); if (StringUtils.isNotBlank(ipString)) { ipAddress = ipString; } if (serialPort == null && ipAddress == null) { logger.warn("PowerMax alarm binding: one connection type (Serial Port or IP Address) must be defined"); this.setProperlyConfigured(false); throw new ConfigurationException(null, "one connection type (Serial Port or IP Address) must be defined"); } if (serialPort != null && ipAddress != null) { logger.warn( "PowerMax alarm binding: can only configure one connection type at a time: Serial Port or IP Address"); this.setProperlyConfigured(false); throw new ConfigurationException(null, "can only configure one connection type at a time: Serial Port or IP Address"); } if (ipAddress != null) { String tcpPortString = Objects.toString(config.get("tcpPort"), null); if (StringUtils.isNotBlank(tcpPortString)) { try { tcpPort = Integer.parseInt(tcpPortString); } catch (NumberFormatException numberFormatException) { tcpPort = 0; logger.warn( "PowerMax alarm binding: TCP port not configured correctly (number expected, received '{}')", tcpPortString); this.setProperlyConfigured(false); throw new ConfigurationException("tcpPort", "TCP port not configured correctly (number expected, received '" + tcpPortString + "')"); } } } String motionOffDelayString = Objects.toString(config.get("motionOffDelay"), null); if (StringUtils.isNotBlank(motionOffDelayString)) { try { motionOffDelay = Integer.parseInt(motionOffDelayString) * 60000; } catch (NumberFormatException numberFormatException) { motionOffDelay = DEFAULT_MOTION_OFF_DELAY; logger.warn( "PowerMax alarm binding: motion off delay not configured correctly (number expected, received '{}')", motionOffDelayString); } } String allowArmingString = Objects.toString(config.get("allowArming"), null); if (StringUtils.isNotBlank(allowArmingString)) { allowArming = Boolean.valueOf(allowArmingString); } String allowDisarmingString = Objects.toString(config.get("allowDisarming"), null); if (StringUtils.isNotBlank(allowDisarmingString)) { allowDisarming = Boolean.valueOf(allowDisarmingString); } String forceStandardModeString = Objects.toString(config.get("forceStandardMode"), null); if (StringUtils.isNotBlank(forceStandardModeString)) { forceStandardMode = Boolean.valueOf(forceStandardModeString); PowerMaxReceiveType.POWERLINK.setHandlerClass( forceStandardMode ? PowerMaxBaseMessage.class : PowerMaxPowerlinkMessage.class); } String panelTypeString = Objects.toString(config.get("panelType"), null); if (StringUtils.isNotBlank(panelTypeString)) { try { panelType = PowerMaxPanelType.fromLabel(panelTypeString); } catch (IllegalArgumentException exception) { panelType = PowerMaxPanelType.POWERMAX_PRO; logger.warn("PowerMax alarm binding: panel type not configured correctly"); } } PowerMaxPanelSettings.initPanelSettings(panelType); String autoSyncTimeString = Objects.toString(config.get("autoSyncTime"), null); if (StringUtils.isNotBlank(autoSyncTimeString)) { autoSyncTime = Boolean.valueOf(autoSyncTimeString); } String pinCodeString = Objects.toString(config.get("pinCode"), null); if (StringUtils.isNotBlank(pinCodeString)) { pinCode = pinCodeString; } this.setProperlyConfigured(true); } } /** * Open a TCP or Serial connection to the PowerMax Alarm Panel */ private void openConnection() { PowerMaxCommDriver.initTheCommDriver(serialPort, ipAddress, tcpPort); PowerMaxCommDriver comm = PowerMaxCommDriver.getTheCommDriver(); if (comm != null) { comm.addEventListener(this); connected = comm.open(); if (serialPort != null) { logger.info("PowerMax alarm binding: serial connection ({}): {}", serialPort, connected ? "connected" : "disconnected"); } else if (ipAddress != null) { logger.info("PowerMax alarm binding: TCP connection (IP {} port {}): {}", ipAddress, tcpPort, connected ? "connected" : "disconnected"); } } else { connected = false; } logger.debug("openConnection(): {}", connected ? "connected" : "disconnected"); } /** * Close TCP or Serial connection to the PowerMax Alarm Panel and remove the Event Listener */ private void closeConnection() { PowerMaxCommDriver comm = PowerMaxCommDriver.getTheCommDriver(); if (comm != null) { comm.close(); comm.removeEventListener(this); } connected = false; logger.debug("closeConnection(): disconnected"); } /** * PowerMax Alarm incoming message event handler * * @param event */ @Override public void powerMaxEventReceived(EventObject event) { PowerMaxEvent powerMaxEvent = (PowerMaxEvent) event; PowerMaxBaseMessage message = powerMaxEvent.getPowerMaxMessage(); if (logger.isDebugEnabled()) { logger.debug("powerMaxEventReceived(): received message {}", (message.getReceiveType() != null) ? message.getReceiveType().toString() : String.format("%02X", message.getCode())); } if (message instanceof PowerMaxInfoMessage) { ((PowerMaxInfoMessage) message).setAutoSyncTime(autoSyncTime); } PowerMaxState updateState = message.handleMessage(); if (updateState != null) { if ((currentState.isPowerlinkMode() != null) && currentState.isPowerlinkMode().equals(Boolean.TRUE) && (updateState.isDownloadSetupRequired() != null) && updateState.isDownloadSetupRequired().equals(Boolean.TRUE)) { // After Enrolling Powerlink or if a reset is required logger.info("PowerMax alarm binding: Reset"); PowerMaxCommDriver.getTheCommDriver().startDownload(); if (currentState.getLastKeepAlive() != null) { currentState.setLastKeepAlive(System.currentTimeMillis()); } } else if ((currentState.isPowerlinkMode() != null) && currentState.isPowerlinkMode().equals(Boolean.FALSE) && (updateState.getLastKeepAlive() != null)) { // Were are in standard mode but received a keep alive message // so we switch in PowerLink mode logger.info("PowerMax alarm binding: Switching to Powerlink mode"); PowerMaxCommDriver.getTheCommDriver().startDownload(); } boolean doProcessSettings = (updateState.isPowerlinkMode() != null); for (int i = 1; i <= PowerMaxPanelSettings.getThePanelSettings().getNbZones(); i++) { if ((updateState.isSensorArmed(i) != null) && updateState.isSensorArmed(i).equals(Boolean.TRUE) && (currentState.isSensorBypassed(i) != null) && currentState.isSensorBypassed(i).equals(Boolean.TRUE)) { updateState.setSensorArmed(i, false); } } updateState.keepOnlyDifferencesWith(currentState); updateItemsFromAlarmState(updateState); currentState.merge(updateState); if (updateState.getUpdateSettings() != null) { PowerMaxPanelSettings.getThePanelSettings().updateRawSettings(updateState.getUpdateSettings()); } if (doProcessSettings) { // There is a change of mode (standard or Powerlink) PowerMaxPanelSettings.getThePanelSettings().process(currentState.isPowerlinkMode(), panelType, PowerMaxCommDriver.getTheCommDriver().getSyncTimeCheck()); updateItemsFromPanelSettings(); if (currentState.isPowerlinkMode()) { logger.info("PowerMax alarm binding: running in Powerlink mode"); PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.RESTORE); } else { logger.info("PowerMax alarm binding: running in Standard mode"); PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESNAME); PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.ZONESTYPE); PowerMaxCommDriver.getTheCommDriver().sendMessage(PowerMaxSendType.STATUS); } PowerMaxCommDriver.getTheCommDriver().exitDownload(); } } } /** * Post item updates on the bus to match a new alarm system state * * @param selector * filter on selector type; if null, no filter on selector type * @param state * the alarm system state */ private void updateItemsFromAlarmState(PowerMaxSelectorType selector, PowerMaxState state) { updateItemsFromAlarmState(null, null, selector, state); } /** * Post item updates on the bus to match a new alarm system state * * @param state * the alarm system state */ private void updateItemsFromAlarmState(PowerMaxState state) { updateItemsFromAlarmState(null, null, null, state); } /** * Post item updates on the bus to match a new alarm system state * * @param provider * filter on provider; if null, no filter on provider * @param name * filter on item name; if null, no filter on item name * @param selector * filter on selector type; if null, no filter on selector type * @param state * the alarm system state */ private synchronized void updateItemsFromAlarmState(PowerMaxBindingProvider provider, String name, PowerMaxSelectorType selector, PowerMaxState state) { if (state == null) { return; } if (itemUpdateDisabled) { logger.debug("updateItemsFromAlarmState(): items update disabled"); return; } if (provider == null) { for (PowerMaxBindingProvider prov : providers) { if (prov != null) { updateItemsFromAlarmState(prov, name, selector, state); } } } else { for (String itemName : provider.getItemNames()) { if ((name == null) || itemName.equals(name)) { String value = null; String value2 = null; PowerMaxBindingConfig config = provider.getConfig(itemName); Integer num = config.getSelectorIntParam(); if ((selector == null) || (selector == config.getSelectorType())) { switch (config.getSelectorType()) { case PANEL_MODE: value = state.getPanelMode(); break; case PARTITION_STATUS: value = state.getStatusStr(); break; case PARTITION_READY: if (state.isReady() != null) { value = state.isReady() ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case PARTITION_BYPASS: if (state.isBypass() != null) { value = state.isBypass() ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case PARTITION_ALARM: if (state.isAlarmActive() != null) { value = state.isAlarmActive() ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case PANEL_TROUBLE: if (state.isTrouble() != null) { value = state.isTrouble() ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case PANEL_ALERT_IN_MEMORY: if (state.isAlertInMemory() != null) { value = state.isAlertInMemory() ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case EVENT_LOG: if ((num != null) && (state.getEventLog(num) != null)) { value = state.getEventLog(num); } break; case PARTITION_ARMED: if (state.isArmed() != null) { value = state.isArmed() ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case PARTITION_ARM_MODE: value = state.getShortArmMode(); break; case ZONE_STATUS: if ((num != null) && (state.isSensorTripped(num) != null)) { value = state.isSensorTripped(num) ? OpenClosedType.OPEN.toString() : OpenClosedType.CLOSED.toString(); value2 = state.isSensorTripped(num) ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case ZONE_LAST_TRIP: if ((num != null) && (state.getSensorLastTripped(num) != null)) { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(state.getSensorLastTripped(num)); value = new DateTimeType(cal).toString(); } break; case ZONE_BYPASSED: if ((num != null) && (state.isSensorBypassed(num) != null)) { value = state.isSensorBypassed(num) ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case ZONE_ARMED: if ((num != null) && (state.isSensorArmed(num) != null)) { value = state.isSensorArmed(num) ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case ZONE_LOW_BATTERY: if ((num != null) && (state.isSensorLowBattery(num) != null)) { value = state.isSensorLowBattery(num) ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case PGM_STATUS: if (state.getPGMX10DeviceStatus(0) != null) { value = state.getPGMX10DeviceStatus(0) ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; case X10_STATUS: if ((num != null) && (state.getPGMX10DeviceStatus(num) != null)) { value = state.getPGMX10DeviceStatus(num) ? OnOffType.ON.toString() : OnOffType.OFF.toString(); } break; default: break; } } State itemState = null; if (value != null) { itemState = TypeParser.parseState(config.getAcceptedDataTypes(), value); } if ((itemState == null) && (value2 != null)) { itemState = TypeParser.parseState(config.getAcceptedDataTypes(), value2); } if (itemState != null) { eventPublisher.postUpdate(itemName, itemState); } } } } } /** * Post item updates on the bus to match the alarm panel settings */ private void updateItemsFromPanelSettings() { updateItemsFromPanelSettings(null, null, null); } /** * Post item updates on the bus to match the alarm panel settings * * @param provider * filter on provider; if null, no filter on provider * @param name * filter on item name; if null, no filter on item name * @param selector * filter on selector type; if null, no filter on selector type */ private synchronized void updateItemsFromPanelSettings(PowerMaxBindingProvider provider, String name, PowerMaxSelectorType selector) { if (itemUpdateDisabled) { logger.debug("updateItemsFromPanelSettings(): items update disabled"); return; } if (provider == null) { for (PowerMaxBindingProvider prov : providers) { if (prov != null) { updateItemsFromPanelSettings(prov, name, selector); } } } else { PowerMaxPanelSettings settings = PowerMaxPanelSettings.getThePanelSettings(); for (String itemName : provider.getItemNames()) { if ((name == null) || itemName.equals(name)) { String value = null; PowerMaxBindingConfig config = provider.getConfig(itemName); if ((selector == null) || (selector == config.getSelectorType())) { switch (config.getSelectorType()) { case PANEL_TYPE: value = (settings.getPanelType() != null) ? settings.getPanelType().getLabel() : null; break; case PANEL_SERIAL: value = settings.getPanelSerial(); break; case PANEL_EPROM: value = settings.getPanelEprom(); break; case PANEL_SOFTWARE: value = settings.getPanelSoftware(); break; default: break; } } if (value != null) { State itemState = TypeParser.parseState(config.getAcceptedDataTypes(), value); if (itemState != null) { eventPublisher.postUpdate(itemName, itemState); } } } } } } }