/** * 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.dscalarm1.internal; import java.util.Collections; import java.util.Dictionary; import java.util.EventObject; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.StringUtils; import org.openhab.binding.dscalarm1.DSCAlarmActionProvider; import org.openhab.binding.dscalarm1.DSCAlarmBindingConfig; import org.openhab.binding.dscalarm1.DSCAlarmBindingProvider; import org.openhab.binding.dscalarm1.internal.connector.DSCAlarmConnectorType; import org.openhab.binding.dscalarm1.internal.connector.DSCAlarmInterfaceType; import org.openhab.binding.dscalarm1.internal.model.DSCAlarmDeviceType; import org.openhab.binding.dscalarm1.internal.protocol.API; import org.openhab.binding.dscalarm1.internal.protocol.APICode; import org.openhab.binding.dscalarm1.internal.protocol.APIMessage; import org.openhab.core.binding.AbstractActiveBinding; import org.openhab.core.binding.BindingProvider; import org.openhab.core.items.Item; import org.openhab.core.library.types.OnOffType; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ManagedService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * DSCAlarmActiveBinding Class. Polls the DSC Alarm panel, * responds to item commands, and also handles events coming * from the DSC Alarm panel. * * @author Russell Stephens * @since 1.6.0 */ public class DSCAlarmActiveBinding extends AbstractActiveBinding<DSCAlarmBindingProvider> implements ManagedService, DSCAlarmEventListener, DSCAlarmActionProvider { private static final Logger logger = LoggerFactory.getLogger(DSCAlarmActiveBinding.class); private long refreshInterval = 5000; private DSCAlarmConnectorType connectorType = null; /** Default Poll Period. **/ public static final long DEFAULT_POLL_PERIOD = 1; /** Interface Type **/ private DSCAlarmInterfaceType interfaceType = null; /** * The serial port name of the DSC-IT100 Serial Interface * Valid values are e.g. COM1 for Windows and /dev/ttyS0 or /dev/ttyUSB0 for Linux */ private String serialPort = null; /** The IP address of the EyezOn Envisalink 3/2DS DSC Alarm Interface */ private String ipAddress = null; /** The TCP port of the EyezOn Envisalink 3/2DS DSC Alarm Interface */ private int tcpPort = 4025; /** Baud rate for a serial connection */ private int baudRate = 0; /** User name for EyezOn Envisalink 3/2DS authentication */ /** * private String username = null; * * /** Password for EyezOn Envisalink 3/2DS authentication */ private String password = null; /** User Code for some DSC Alarm commands */ private String userCode = null; /** Suppress Acknowledge Messages when received */ private boolean suppressAcknowledgementMsgs = false; /** API Session for EyezOn Envisalink 3/2DS */ private API api = null; private boolean connected = false; private long pollTime = 0; private long pollTimeStart = 0; private long pollPeriod = DEFAULT_POLL_PERIOD; /** * New items or items needing to be refreshed get added to refreshmao * the worker thread will refresh and remove them */ private Map<String, DSCAlarmBindingConfig> dscAlarmUpdateMap = Collections.synchronizedMap(new HashMap<String, DSCAlarmBindingConfig>()); private DSCAlarmItemUpdate dscAlarmItemUpdate = new DSCAlarmItemUpdate(); private int itemCount = 0; private boolean itemHasChanged = false; private boolean processUpdates = 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("DSC Alarm Binding Activated!"); } /** * Deactivates the binding */ @Override public void deactivate() { logger.debug("DSC Alarm Binding Deactivated!"); closeConnection(); } /** * @{inheritDoc */ @Override protected void execute() { logger.debug("DSC Alarm Execute"); if (api != null) { connected = api.isConnected(); } if (connected) { if (pollTimeStart == 0) { pollTimeStart = System.currentTimeMillis(); } pollTime = ((System.currentTimeMillis() - pollTimeStart) / 1000) / 60; // Send Poll command to the DSC Alarm if idle for 'pollPeriod' minutes if (pollTime >= pollPeriod) { api.sendCommand(APICode.Poll); pollTimeStart = 0; logger.debug("execute(): Poll Command Sent to DSC Alarm."); } } else { closeConnection(); logger.error("execute(): Not Connected to the DSC Alarm!"); reconnect(); } // Need to allow one cycle to pass before processing item updates after binding changes. if (itemHasChanged) { if (processUpdates) { processUpdateMap(); itemHasChanged = false; processUpdates = false; if (connected) { // Get a status report from API. api.sendCommand(APICode.StatusReport); } } else { processUpdates = true; } } } /** * {@inheritDoc} */ @Override public void bindingChanged(BindingProvider provider, String itemName) { logger.debug("bindingChanged(): Item Name: {}", itemName); boolean itemRemoved = false; int icount = provider.getItemNames().size(); if (icount < itemCount) { itemRemoved = true; } if (itemRemoved) { dscAlarmUpdateMap.clear(); } else { DSCAlarmBindingProvider dscAlarmBindingProvider = (DSCAlarmBindingProvider) provider; if (dscAlarmBindingProvider != null) { DSCAlarmBindingConfig dscAlarmBindingConfig = dscAlarmBindingProvider.getDSCAlarmBindingConfig(itemName); if (dscAlarmBindingConfig != null) { dscAlarmUpdateMap.put(itemName, dscAlarmBindingConfig); } } } itemCount = provider.getItemNames().size(); itemHasChanged = true; } /** * @{inheritDoc */ @Override protected void internalReceiveCommand(String itemName, Command command) { DSCAlarmBindingConfig dscAlarmBindingConfig = null; for (DSCAlarmBindingProvider prov : providers) { dscAlarmBindingConfig = prov.getDSCAlarmBindingConfig(itemName); if (dscAlarmBindingConfig != null) { DSCAlarmDeviceType dscAlarmDeviceType = dscAlarmBindingConfig.getDeviceType(); int partitionId; int zoneId; int cmd; logger.debug("internalReceiveCommand(): Item Name: {} Command: {} Item Device Type: {}", itemName, command, dscAlarmDeviceType); if (connected) { switch (dscAlarmDeviceType) { case PANEL: switch (dscAlarmBindingConfig.getDSCAlarmItemType()) { case PANEL_CONNECTION: if (command.toString().equals("0")) { closeConnection(); if (!connected) { dscAlarmItemUpdate.setConnected(false); } } break; case PANEL_COMMAND: cmd = Integer.parseInt(command.toString()); switch (cmd) { case 0: api.sendCommand(APICode.Poll); break; case 1: api.sendCommand(APICode.StatusReport); break; case 2: api.sendCommand(APICode.LabelsRequest); break; case 8: api.sendCommand(APICode.DumpZoneTimers); break; case 10: api.sendCommand(APICode.SetTimeDate); break; case 200: api.sendCommand(APICode.CodeSend); break; default: break; } itemName = getItemName(DSCAlarmItemType.PANEL_COMMAND, 0, 0); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, -1, ""); } break; case PANEL_TIME_STAMP: if (command instanceof OnOffType) { cmd = command == OnOffType.ON ? 1 : 0; api.sendCommand(APICode.TimeStampControl, String.valueOf(cmd)); updateItem(itemName, cmd, ""); } break; case PANEL_TIME_BROADCAST: if (command instanceof OnOffType) { cmd = command == OnOffType.ON ? 1 : 0; api.sendCommand(APICode.TimeDateBroadcastControl, String.valueOf(cmd)); updateItem(itemName, cmd, ""); } break; default: break; } break; case PARTITION: partitionId = dscAlarmBindingConfig.getPartitionId(); switch (dscAlarmBindingConfig.getDSCAlarmItemType()) { case PARTITION_ARM_MODE: if (command.toString().equals("0")) { api.sendCommand(APICode.PartitionDisarmControl, String.valueOf(partitionId)); } else if (command.toString().equals("1")) { api.sendCommand(APICode.PartitionArmControlAway, String.valueOf(partitionId)); } else if (command.toString().equals("2")) { api.sendCommand(APICode.PartitionArmControlStay, String.valueOf(partitionId)); } else if (command.toString().equals("3")) { api.sendCommand(APICode.PartitionArmControlZeroEntryDelay, String.valueOf(partitionId)); } else if (command.toString().equals("4")) { api.sendCommand(APICode.PartitionArmControlWithUserCode, String.valueOf(partitionId)); } break; default: break; } break; case ZONE: partitionId = dscAlarmBindingConfig.getPartitionId(); zoneId = dscAlarmBindingConfig.getZoneId(); switch (dscAlarmBindingConfig.getDSCAlarmItemType()) { case ZONE_BYPASS_MODE: if (command.toString().equals("0")) { String data = String.valueOf(partitionId) + "*1" + String.format("%02d", zoneId) + "#"; api.sendCommand(APICode.KeySequence, data); } else if (command.toString().equals("1")) { String data = String.valueOf(partitionId) + "*1" + String.format("%02d", zoneId) + "#"; api.sendCommand(APICode.KeySequence, data); } break; default: break; } break; default: logger.debug("internalReceiveCommand(): No Command Sent."); break; } } else { if (dscAlarmDeviceType == DSCAlarmDeviceType.PANEL) { if (dscAlarmBindingConfig.getDSCAlarmItemType() == DSCAlarmItemType.PANEL_CONNECTION) { if (command.toString().equals("1")) { if (api != null) { openConnection(); if (connected) { dscAlarmItemUpdate.setConnected(true); } } } } } } } } } /** * @{inheritDoc */ @Override protected long getRefreshInterval() { return refreshInterval; } /** * @{inheritDoc */ @Override protected String getName() { return "DSC Alarm Monitor Service"; } /** * @{inheritDoc */ @Override public void updated(Dictionary<String, ?> config) throws ConfigurationException { logger.debug("updated(): Configuration? - {}", config != null ? true : false); if (config != null) { if (StringUtils.isNotBlank((String) config.get("deviceType"))) { String intType = (String) config.get("deviceType"); if (intType.equals("it100")) { interfaceType = DSCAlarmInterfaceType.IT100; } else if (intType.equals("envisalink")) { interfaceType = DSCAlarmInterfaceType.ENVISALINK; } else { interfaceType = null; logger.error("updated(): Device type not configured!"); } } if (StringUtils.isNotBlank((String) config.get("serialPort"))) { serialPort = (String) config.get("serialPort"); } if (StringUtils.isNotBlank((String) config.get("ip"))) { ipAddress = (String) config.get("ip"); } try { if (StringUtils.isNotBlank((String) config.get("tcpPort"))) { tcpPort = Integer.parseInt((String) config.get("tcpPort")); } } catch (NumberFormatException numberFormatException) { tcpPort = 4025; logger.error("updated(): TCP Port not configured correctly!"); return; } if (serialPort != null && ipAddress != null) { logger.error("updated(): Can only configure one connection type at a time: Serial Port or Ip Address!"); return; } if (serialPort != null) { if (interfaceType == null) { interfaceType = DSCAlarmInterfaceType.IT100; } if (connectorType == null) { connectorType = DSCAlarmConnectorType.SERIAL; } try { if (StringUtils.isNotBlank((String) config.get("baud"))) { baudRate = Integer.parseInt((String) config.get("baud")); } } catch (NumberFormatException numberFormatException) { baudRate = 0; logger.error("updated(): Baud Rate not configured correctly!"); return; } } if (ipAddress != null) { if (interfaceType == null) { interfaceType = DSCAlarmInterfaceType.ENVISALINK; } connectorType = DSCAlarmConnectorType.TCP; } logger.debug("updated(): Connector Type: {}, Interface Type: {}", connectorType, interfaceType); if (StringUtils.isNotBlank((String) config.get("password"))) { password = (String) config.get("password"); } if (StringUtils.isNotBlank((String) config.get("usercode"))) { userCode = (String) config.get("usercode"); } if (StringUtils.isNotBlank((String) config.get("pollPeriod"))) { try { pollPeriod = Integer.parseInt((String) config.get("pollperiod")); } catch (NumberFormatException numberFormatException) { logger.error("updated(): Poll Period not configured correctly!"); return; } if (pollPeriod > 15) { pollPeriod = 15; } else if (pollPeriod < 1) { pollPeriod = 1; } } else { pollPeriod = DEFAULT_POLL_PERIOD; } if (StringUtils.isNotBlank((String) config.get("suppressAcknowledgementMsgs"))) { try { suppressAcknowledgementMsgs = Boolean.parseBoolean((String) config.get("suppressAcknowledgementMsgs")); } catch (NumberFormatException numberFormatException) { suppressAcknowledgementMsgs = false; logger.error("updated(): Error parsing 'suppressAcknowledgementMsgs'. This must be boolean!"); } } } else { logger.debug("updated(): No Configuration!"); return; } initialize(); } /** * Initializes the binding */ private void initialize() { // Check to see if openHAB read in our items while the binding was configuring, and add them to // dscAlarmUpdateMap. if (dscAlarmUpdateMap.isEmpty() && itemHasChanged == false) { buildUpdateMap(); itemHasChanged = true; } // Open a connection to the DSC Alarm Panel openConnection(); if (!connected) { dscAlarmItemUpdate.setConnected(false); } else { dscAlarmItemUpdate.setConnected(true); } this.setProperlyConfigured(true); logger.debug("initialize(): Binding initialized!"); } /** * Build the Update Items Map */ private void buildUpdateMap() { DSCAlarmBindingConfig config; for (DSCAlarmBindingProvider prov : providers) { if (!prov.getItemNames().isEmpty()) { itemCount = prov.getItemNames().size(); dscAlarmUpdateMap.clear(); for (String iName : prov.getItemNames()) { config = prov.getDSCAlarmBindingConfig(iName); if (config != null) { dscAlarmUpdateMap.put(iName, config); } } } } } /** * Processes the Update Items Map */ private void processUpdateMap() { if (dscAlarmUpdateMap.size() == 0) { logger.debug("processUpdateMap(): Nothing to update."); return; } Map<String, DSCAlarmBindingConfig> itemsMap = new HashMap<String, DSCAlarmBindingConfig>(dscAlarmUpdateMap); for (String itemName : itemsMap.keySet()) { DSCAlarmBindingConfig dscAlarmBindingConfig = itemsMap.get(itemName); dscAlarmUpdateMap.remove(itemName); Item item = null; for (DSCAlarmBindingProvider provider : providers) { item = provider.getItem(itemName); } if (dscAlarmBindingConfig.getDSCAlarmItemType().equals(DSCAlarmItemType.PANEL_COMMAND)) { dscAlarmItemUpdate.updateDeviceItem(item, dscAlarmBindingConfig, eventPublisher, null, -1, ""); } else { dscAlarmItemUpdate.updateDeviceItem(item, dscAlarmBindingConfig, eventPublisher, null, 0, ""); } logger.debug("processUpdateMap(): Updated item: {}", itemName); } } /** * Open a TCP or Serial connection to the DSC Alarm Panel */ private void openConnection() { switch (connectorType) { case SERIAL: if (api == null) { api = new API(serialPort, baudRate, userCode, interfaceType); } break; case TCP: if (api == null) { api = new API(ipAddress, tcpPort, password, userCode, interfaceType); } break; default: connected = false; logger.debug("openConnection(): Unable to make a connection!"); return; } connected = api.open(); if (connected) { api.addEventListener(this); } } /** * Attempt to reconnect to TCP or Serial connection */ private void reconnect() { String itemName; logger.debug("reconnect(): API Reconnection!"); openConnection(); if (connected) { dscAlarmItemUpdate.setConnected(true); itemName = getItemName(DSCAlarmItemType.PANEL_CONNECTION, 0, 0); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, 1, "Panel Connected"); } buildUpdateMap(); itemHasChanged = true; } else { setPanelMessage("PANEL DISCONNECTED!!!"); logger.error("reconnect(): API reconnection failed!"); } } /** * Close TCP or Serial connection to the DSC Alarm Panel and remove the Event Listener */ private void closeConnection() { String itemName; if (api != null) { connected = api.close(); api.removeEventListener(this); } dscAlarmItemUpdate.setConnected(false); itemName = getItemName(DSCAlarmItemType.PANEL_CONNECTION, 0, 0); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, 0, "Panel Disconnected"); } logger.debug("closeConnection(): {} Connection Closed!", connectorType); } /** * Find Item by Item Name * * @param itemName * @return item */ private Item getItem(String itemName) { Item item = null; for (DSCAlarmBindingProvider prov : providers) { for (String iName : prov.getItemNames()) { if (itemName == iName) { item = prov.getItem(itemName); break; } } } return item; } /** * Searches for an items name and returns it * * @param dscAlarmItemType * @param partitionId * @param zoneId * @return itemName */ private String getItemName(DSCAlarmItemType dscAlarmItemType, int partitionId, int zoneId) { String itemName = ""; DSCAlarmBindingConfig config = null; for (DSCAlarmBindingProvider prov : providers) { for (String iName : prov.getItemNames()) { config = prov.getDSCAlarmBindingConfig(iName); if (config.getDSCAlarmItemType() == dscAlarmItemType) { if (partitionId == -1) { if (config.getZoneId() == zoneId) { itemName = iName; break; } } else if (zoneId == -1) { if (config.getPartitionId() == partitionId) { itemName = iName; break; } } else if ((config.getPartitionId() == partitionId) && (config.getZoneId() == zoneId)) { itemName = iName; break; } } } } return itemName; } /** * Find Item Configuration by Item Name * * @param itemName * @return item */ private DSCAlarmBindingConfig getItemConfig(String itemName) { DSCAlarmBindingConfig config = null; for (DSCAlarmBindingProvider prov : providers) { for (String iName : prov.getItemNames()) { if (itemName == iName) { config = prov.getDSCAlarmBindingConfig(iName); break; } } } return config; } /** * Update an item by item name * * @param itemName */ private void updateItem(String itemName, int state, String description) { DSCAlarmBindingConfig config = null; Item item = null; for (DSCAlarmBindingProvider prov : providers) { for (String iName : prov.getItemNames()) { if (itemName == iName) { config = prov.getDSCAlarmBindingConfig(iName); if (config != null) { item = prov.getItem(itemName); dscAlarmItemUpdate.updateDeviceItem(item, config, eventPublisher, null, state, description); break; } } } } } /** * Update an item by DSC Alarm Item Type * * @param dscAlarmItemType * @param trigger */ private void updateItemByItemType(DSCAlarmItemType dscAlarmItemType, int partitionId, int zoneId, int propertyState) { String itemName = ""; itemName = getItemName(dscAlarmItemType, partitionId, zoneId); logger.debug("updateItemByItemType(): Item Name: {} Partition: {} Zone: {}", itemName, partitionId, zoneId); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, propertyState, ""); } } /** * Method to set the panel message item * * @param message */ private void setPanelMessage(String message) { String itemName; dscAlarmItemUpdate.setSysMessage(message); itemName = getItemName(DSCAlarmItemType.PANEL_MESSAGE, 0, 0); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, 0, message); } } /** * Method to set a partition status item * * @param partitionID * @param state * @param description */ private void setPartitionStatus(int partitionID, int state, String description) { String itemName; itemName = getItemName(DSCAlarmItemType.PARTITION_STATUS, partitionID, 0); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, state, description); } } /** * Method to set the System Error Code * * @param partitionID * @param state * @param description */ private void setSystemErrorCode(int state, String description) { String itemName; itemName = getItemName(DSCAlarmItemType.PANEL_SYSTEM_ERROR, 0, 0); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, state, description); } } /** * Method to send a sequence of key presses one at a time using the '070' command. * * @param keySequence */ private boolean sendKeySequence(String keySequence) { logger.debug("sendKeySequence(): Sending key sequence '{}'.", keySequence); boolean sent = false; for (char key : keySequence.toCharArray()) { sent = api.sendCommand(APICode.KeyStroke, String.valueOf(key)); if (!sent) { return sent; } } return sent; } /** * Method to set the time stamp state * * @param timeStamp */ private void setTimeStampState(String timeStamp) { logger.debug("setTimeStampState(): Time Stamp: {}", timeStamp); int state = 0; String itemName = ""; itemName = getItemName(DSCAlarmItemType.PANEL_TIME_STAMP, 0, 0); if (StringUtils.isNotEmpty(itemName)) { DSCAlarmBindingConfig config = getItemConfig(itemName); if (config != null) { Item item = getItem(itemName); if (item != null) { State onOffState = item.getState(); if (onOffState instanceof OnOffType) { OnOffType value = (OnOffType) onOffState; if ((StringUtils.isEmpty(timeStamp) && value.equals(OnOffType.OFF)) || (StringUtils.isNotEmpty(timeStamp) && value.equals(OnOffType.ON))) { logger.debug("setTimeStampState(): Already Set!", timeStamp); return; } else if (StringUtils.isNotEmpty(timeStamp)) { state = 1; } } } } } updateItemByItemType(DSCAlarmItemType.PANEL_TIME_STAMP, 0, 0, state); logger.debug("setTimeStampState(): Changed state to '{}'.", state == 1 ? OnOffType.ON : OnOffType.OFF); } /** * Handle Keypad LED events for the EyezOn Envisalink 3/2DS DSC Alarm Interface * * @param event */ private void keypadLEDStateEventHandler(EventObject event) { DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event; APIMessage apiMessage = dscAlarmEvent.getAPIMessage(); DSCAlarmItemType[] dscAlarmItemTypes = { DSCAlarmItemType.KEYPAD_READY_LED, DSCAlarmItemType.KEYPAD_ARMED_LED, DSCAlarmItemType.KEYPAD_MEMORY_LED, DSCAlarmItemType.KEYPAD_BYPASS_LED, DSCAlarmItemType.KEYPAD_TROUBLE_LED, DSCAlarmItemType.KEYPAD_PROGRAM_LED, DSCAlarmItemType.KEYPAD_FIRE_LED, DSCAlarmItemType.KEYPAD_BACKLIGHT_LED }; String itemName; APICode apiCode = APICode.getAPICodeValue(apiMessage.getAPICode()); int bitField = Integer.decode("0x" + apiMessage.getAPIData()); int[] masks = { 1, 2, 4, 8, 16, 32, 64, 128 }; int[] bits = new int[8]; for (int i = 0; i < 8; i++) { bits[i] = bitField & masks[i]; itemName = getItemName(dscAlarmItemTypes[i], 0, 0); if (StringUtils.isNotEmpty(itemName)) { switch (apiCode) { case KeypadLEDState: /* 510 */ updateItem(itemName, bits[i] != 0 ? 1 : 0, ""); break; case KeypadLEDFlashState: /* 511 */ if (bits[i] != 0) { updateItem(itemName, 2, ""); } break; default: break; } } } } /** * Handle Verbose Trouble Status events for the EyezOn Envisalink 3/2DS DSC Alarm Interface * * @param event */ private void verboseTroubleStatusHandler(EventObject event) { DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event; APIMessage apiMessage = dscAlarmEvent.getAPIMessage(); DSCAlarmItemType[] dscAlarmItemTypes = { DSCAlarmItemType.PANEL_SERVICE_REQUIRED, DSCAlarmItemType.PANEL_AC_TROUBLE, DSCAlarmItemType.PANEL_TELEPHONE_TROUBLE, DSCAlarmItemType.PANEL_FTC_TROUBLE, DSCAlarmItemType.PANEL_ZONE_FAULT, DSCAlarmItemType.PANEL_ZONE_TAMPER, DSCAlarmItemType.PANEL_ZONE_LOW_BATTERY, DSCAlarmItemType.PANEL_TIME_LOSS }; String itemName; int bitField = Integer.decode("0x" + apiMessage.getAPIData()); int[] masks = { 1, 2, 4, 8, 16, 32, 64, 128 }; int[] bits = new int[8]; for (int i = 0; i < 8; i++) { bits[i] = bitField & masks[i]; itemName = getItemName(dscAlarmItemTypes[i], 0, 0); if (StringUtils.isNotEmpty(itemName)) { updateItem(itemName, bits[i] != 0 ? 1 : 0, ""); } } } /** * Receives incoming DSC Alarm events * * @param event */ @Override public void dscAlarmEventRecieved(EventObject event) { DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event; APIMessage apiMessage = dscAlarmEvent.getAPIMessage(); APICode apiCode = APICode.getAPICodeValue(apiMessage.getAPICode()); String apiData = apiMessage.getAPIData(); boolean suppressPanelMsg = false; int state = 0; setTimeStampState(apiMessage.getTimeStamp()); switch (apiCode) { case CommandAcknowledge: /* 500 */ dscAlarmItemUpdate.setConnected(true); if (apiData.equals("000")) { handleDSCAlarmEvent(DSCAlarmItemType.PANEL_CONNECTION, dscAlarmEvent, apiMessage); } if (suppressAcknowledgementMsgs) { suppressPanelMsg = true; } break; case SystemError: /* 502 */ int errorCode = Integer.parseInt(apiData); if (errorCode == 23 || errorCode == 24) { for (int i = 1; i < 9; i++) { updateItemByItemType(DSCAlarmItemType.PARTITION_ARM_MODE, i, 0, 0); } } handleDSCAlarmEvent(DSCAlarmItemType.PANEL_SYSTEM_ERROR, dscAlarmEvent, apiMessage); break; case KeypadLEDState: /* 510 */ case KeypadLEDFlashState: /* 511 */ keypadLEDStateEventHandler(event); break; case TimeDateBroadcast: /* 550 */ updateItemByItemType(DSCAlarmItemType.PANEL_TIME_BROADCAST, 0, 0, 1); if (suppressAcknowledgementMsgs) { suppressPanelMsg = true; } handleDSCAlarmEvent(DSCAlarmItemType.PANEL_TIME, dscAlarmEvent, apiMessage); break; case PartitionReady: /* 650 */ case PartitionNotReady: /* 651 */ case PartitionReadyForceArming: /* 653 */ case SystemArmingInProgress: /* 674 */ handleDSCAlarmEvent(DSCAlarmItemType.PARTITION_STATUS, dscAlarmEvent, apiMessage); break; case PartitionArmed: /* 652 */ updateItemByItemType(DSCAlarmItemType.PARTITION_ARMED, apiMessage.getPartition(), -1, 1); updateItemByItemType(DSCAlarmItemType.PARTITION_ENTRY_DELAY, apiMessage.getPartition(), -1, 0); updateItemByItemType(DSCAlarmItemType.PARTITION_EXIT_DELAY, apiMessage.getPartition(), -1, 0); setPartitionStatus(apiMessage.getPartition(), 0, apiMessage.getAPIName()); setSystemErrorCode(0, "No Error"); handleDSCAlarmEvent(DSCAlarmItemType.PARTITION_ARM_MODE, dscAlarmEvent, apiMessage); break; case PartitionDisarmed: /* 655 */ updateItemByItemType(DSCAlarmItemType.PARTITION_ARMED, apiMessage.getPartition(), -1, 0); updateItemByItemType(DSCAlarmItemType.PARTITION_ENTRY_DELAY, apiMessage.getPartition(), -1, 0); updateItemByItemType(DSCAlarmItemType.PARTITION_EXIT_DELAY, apiMessage.getPartition(), -1, 0); updateItemByItemType(DSCAlarmItemType.PARTITION_IN_ALARM, apiMessage.getPartition(), -1, 0); setPartitionStatus(apiMessage.getPartition(), 0, apiMessage.getAPIName()); setSystemErrorCode(0, "No Error"); handleDSCAlarmEvent(DSCAlarmItemType.PARTITION_ARM_MODE, dscAlarmEvent, apiMessage); break; case PartitionInAlarm: /* 654 */ updateItemByItemType(DSCAlarmItemType.PARTITION_IN_ALARM, apiMessage.getPartition(), -1, 1); handleDSCAlarmEvent(DSCAlarmItemType.PARTITION_STATUS, dscAlarmEvent, apiMessage); break; case ZoneAlarm: /* 601 */ state = 1; case ZoneAlarmRestore: /* 602 */ updateItemByItemType(DSCAlarmItemType.ZONE_IN_ALARM, apiMessage.getPartition(), apiMessage.getZone(), state); handleDSCAlarmEvent(DSCAlarmItemType.ZONE_ALARM_STATUS, dscAlarmEvent, apiMessage); break; case ZoneTamper: /* 603 */ state = 1; case ZoneTamperRestore: /* 604 */ updateItemByItemType(DSCAlarmItemType.ZONE_TAMPER, apiMessage.getPartition(), apiMessage.getZone(), state); handleDSCAlarmEvent(DSCAlarmItemType.ZONE_TAMPER_STATUS, dscAlarmEvent, apiMessage); break; case ZoneFault: /* 605 */ state = 1; case ZoneFaultRestore: /* 606 */ updateItemByItemType(DSCAlarmItemType.ZONE_FAULT, apiMessage.getPartition(), apiMessage.getZone(), state); handleDSCAlarmEvent(DSCAlarmItemType.ZONE_FAULT_STATUS, dscAlarmEvent, apiMessage); break; case ZoneOpen: /* 609 */ state = 1; case ZoneRestored: /* 610 */ updateItemByItemType(DSCAlarmItemType.ZONE_TRIPPED, apiMessage.getPartition(), apiMessage.getZone(), state); handleDSCAlarmEvent(DSCAlarmItemType.ZONE_GENERAL_STATUS, dscAlarmEvent, apiMessage); break; case FireKeyAlarm: /* 621 */ state = 1; case FireKeyRestored: /* 622 */ updateItemByItemType(DSCAlarmItemType.PANEL_FIRE_KEY_ALARM, apiMessage.getPartition(), apiMessage.getZone(), state); break; case PanicKeyAlarm: /* 625 */ state = 1; case PanicKeyRestored: /* 626 */ updateItemByItemType(DSCAlarmItemType.PANEL_PANIC_KEY_ALARM, apiMessage.getPartition(), apiMessage.getZone(), state); break; case AuxiliaryKeyAlarm: /* 625 */ state = 1; case AuxiliaryKeyRestored: /* 626 */ updateItemByItemType(DSCAlarmItemType.PANEL_AUX_KEY_ALARM, apiMessage.getPartition(), apiMessage.getZone(), state); break; case AuxiliaryInputAlarm: /* 625 */ state = 1; case AuxiliaryInputAlarmRestored: /* 631 */ updateItemByItemType(DSCAlarmItemType.PANEL_AUX_INPUT_ALARM, apiMessage.getPartition(), apiMessage.getZone(), state); break; case EntryDelayInProgress: /* 656 */ updateItemByItemType(DSCAlarmItemType.PARTITION_ENTRY_DELAY, apiMessage.getPartition(), -1, 1); break; case ExitDelayInProgress: /* 656 */ updateItemByItemType(DSCAlarmItemType.PARTITION_EXIT_DELAY, apiMessage.getPartition(), -1, 1); break; case FailureToArm: /* 672 */ updateItemByItemType(DSCAlarmItemType.PARTITION_ARM_MODE, apiMessage.getPartition(), 0, 0); handleDSCAlarmEvent(DSCAlarmItemType.PARTITION_STATUS, dscAlarmEvent, apiMessage); break; case UserClosing: /* 700 */ case SpecialClosing: /* 701 */ case PartialClosing: /* 702 */ case UserOpening: /* 750 */ case SpecialOpening: /* 751 */ handleDSCAlarmEvent(DSCAlarmItemType.PARTITION_OPENING_CLOSING_MODE, dscAlarmEvent, apiMessage); break; case TroubleLEDOn: /* 840 */ handleDSCAlarmEvent(DSCAlarmItemType.PANEL_TROUBLE_LED, dscAlarmEvent, apiMessage); break; case TroubleLEDOff: /* 841 */ updateItemByItemType(DSCAlarmItemType.PANEL_SERVICE_REQUIRED, 0, 0, 0); updateItemByItemType(DSCAlarmItemType.PANEL_AC_TROUBLE, 0, 0, 0); updateItemByItemType(DSCAlarmItemType.PANEL_TELEPHONE_TROUBLE, 0, 0, 0); updateItemByItemType(DSCAlarmItemType.PANEL_FTC_TROUBLE, 0, 0, 0); updateItemByItemType(DSCAlarmItemType.PANEL_ZONE_FAULT, 0, 0, 0); updateItemByItemType(DSCAlarmItemType.PANEL_ZONE_TAMPER, 0, 0, 0); updateItemByItemType(DSCAlarmItemType.PANEL_ZONE_LOW_BATTERY, 0, 0, 0); updateItemByItemType(DSCAlarmItemType.PANEL_TIME_LOSS, 0, 0, 0); handleDSCAlarmEvent(DSCAlarmItemType.PANEL_TROUBLE_LED, dscAlarmEvent, apiMessage); break; case PanelBatteryTrouble: /* 800 */ case PanelACTrouble: /* 802 */ case SystemBellTrouble: /* 806 */ case TLMLine1Trouble: /* 810 */ case TLMLine2Trouble: /* 812 */ case FTCTrouble: /* 814 */ case GeneralDeviceLowBattery: /* 821 */ case WirelessKeyLowBatteryTrouble: /* 825 */ case HandheldKeypadLowBatteryTrouble: /* 827 */ case GeneralSystemTamper: /* 829 */ case HomeAutomationTrouble: /* 831 */ case KeybusFault: /* 896 */ handleDSCAlarmEvent(DSCAlarmItemType.PANEL_TROUBLE_MESSAGE, dscAlarmEvent, apiMessage); break; case PanelBatteryTroubleRestore: /* 801 */ case PanelACRestore: /* 803 */ case SystemBellTroubleRestore: /* 807 */ case TLMLine1TroubleRestore: /* 811 */ case TLMLine2TroubleRestore: /* 813 */ case GeneralDeviceLowBatteryRestore: /* 822 */ case WirelessKeyLowBatteryTroubleRestore: /* 826 */ case HandheldKeypadLowBatteryTroubleRestore: /* 828 */ case GeneralSystemTamperRestore: /* 830 */ case HomeAutomationTroubleRestore: /* 832 */ case KeybusFaultRestore: /* 897 */ updateItemByItemType(DSCAlarmItemType.PANEL_TROUBLE_MESSAGE, 0, 0, 0); break; case VerboseTroubleStatus: /* 849 */ verboseTroubleStatusHandler(event); break; case CodeRequired: /* 900 */ api.sendCommand(APICode.CodeSend); break; case LCDUpdate: /* 901 */ handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_LCD_UPDATE, dscAlarmEvent, apiMessage); break; case LCDCursor: /* 902 */ handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_LCD_CURSOR, dscAlarmEvent, apiMessage); break; case LEDStatus: /* 903 */ int aData = Integer.parseInt(apiData.substring(0, 1)); switch (aData) { case 1: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_READY_LED, dscAlarmEvent, apiMessage); break; case 2: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_ARMED_LED, dscAlarmEvent, apiMessage); break; case 3: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_MEMORY_LED, dscAlarmEvent, apiMessage); break; case 4: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_BYPASS_LED, dscAlarmEvent, apiMessage); break; case 5: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_TROUBLE_LED, dscAlarmEvent, apiMessage); break; case 6: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_PROGRAM_LED, dscAlarmEvent, apiMessage); break; case 7: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_FIRE_LED, dscAlarmEvent, apiMessage); break; case 8: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_BACKLIGHT_LED, dscAlarmEvent, apiMessage); break; case 9: handleDSCAlarmEvent(DSCAlarmItemType.KEYPAD_AC_LED, dscAlarmEvent, apiMessage); break; } default: break; } if (!suppressPanelMsg) { setPanelMessage(apiMessage.getAPIDescription()); } } /** * Handle incoming DSC Alarm events * * @param dscAlarmItemType * @param dscAlarmEvent * @param apiMessage */ private void handleDSCAlarmEvent(DSCAlarmItemType dscAlarmItemType, DSCAlarmEvent dscAlarmEvent, APIMessage apiMessage) { logger.debug("handleDSCAlarmEvent(): Event received! Looking for item: {}", dscAlarmItemType); DSCAlarmBindingConfig config = null; APIMessage.APIMessageType apiMessageType = apiMessage.getAPIMessageType(); Item item = null; String itemName = ""; int partitionId = apiMessage.getPartition(); int zoneId = apiMessage.getZone(); if (dscAlarmItemType != null) { for (DSCAlarmBindingProvider prov : providers) { for (String iName : prov.getItemNames()) { config = prov.getDSCAlarmBindingConfig(iName); if (config != null) { switch (apiMessageType) { case PANEL_EVENT: if (dscAlarmItemType == config.getDSCAlarmItemType()) { itemName = iName; } break; case PARTITION_EVENT: if (partitionId == config.getPartitionId() && dscAlarmItemType == config.getDSCAlarmItemType()) { itemName = iName; } break; case ZONE_EVENT: if (zoneId == config.getZoneId() && dscAlarmItemType == config.getDSCAlarmItemType()) { itemName = iName; } break; case KEYPAD_EVENT: if (dscAlarmItemType == config.getDSCAlarmItemType()) { itemName = iName; } break; default: break; } } if (StringUtils.isNotEmpty(itemName)) { item = prov.getItem(itemName); dscAlarmItemUpdate.updateDeviceItem(item, config, eventPublisher, dscAlarmEvent, 0, ""); pollTimeStart = 0; return; } } } } } @Override public boolean sendDSCAlarmCommand(String command, String data) { logger.debug("sendDSCAlarmCommand(): Attempting to send DSC Alarm Command: command - {} - data: {}", command, data); try { APICode apiCode = APICode.getAPICodeValue(command); if (interfaceType.equals(DSCAlarmInterfaceType.IT100) && apiCode.equals(APICode.KeySequence)) { return sendKeySequence(data); } else { return api.sendCommand(apiCode, data); } } catch (Exception e) { logger.error("sendDSCAlarmCommand(): Failed to Send DSC Alarm Command! - {}", e); return false; } } }