added migrated 2.x add-ons

Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
Kai Kreuzer
2020-09-21 01:58:32 +02:00
parent bbf1a7fd29
commit 6df6783b60
11662 changed files with 1302875 additions and 11 deletions

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<features name="org.openhab.binding.dscalarm-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
<feature name="openhab-binding-dscalarm" description="DSCAlarm Binding" version="${project.version}">
<feature>openhab-runtime-base</feature>
<feature>openhab-transport-serial</feature>
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.dscalarm/${project.version}</bundle>
</feature>
</features>

View File

@@ -0,0 +1,122 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.thing.ThingTypeUID;
/**
* The DSCAlarmBinding class defines common constants, which are used across the whole binding.
*
* @author Russell Stephens - Initial contribution
*/
@NonNullByDefault
public class DSCAlarmBindingConstants {
// Binding ID
public static final String BINDING_ID = "dscalarm";
// List of bridge device types
public static final String ENVISALINK_BRIDGE = "envisalink";
public static final String IT100_BRIDGE = "it100";
public static final String TCPSERVER_BRIDGE = "tcpserver";
// List of DSC Alarm device types
public static final String PANEL = "panel";
public static final String PARTITION = "partition";
public static final String ZONE = "zone";
public static final String KEYPAD = "keypad";
// List of all Bridge Thing Type UIDs
public static final ThingTypeUID ENVISALINKBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, ENVISALINK_BRIDGE);
public static final ThingTypeUID IT100BRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, IT100_BRIDGE);
public static final ThingTypeUID TCPSERVERBRIDGE_THING_TYPE = new ThingTypeUID(BINDING_ID, TCPSERVER_BRIDGE);
// List of all DSC Alarm Thing Type UIDs
public static final ThingTypeUID PANEL_THING_TYPE = new ThingTypeUID(BINDING_ID, PANEL);
public static final ThingTypeUID PARTITION_THING_TYPE = new ThingTypeUID(BINDING_ID, PARTITION);
public static final ThingTypeUID ZONE_THING_TYPE = new ThingTypeUID(BINDING_ID, ZONE);
public static final ThingTypeUID KEYPAD_THING_TYPE = new ThingTypeUID(BINDING_ID, KEYPAD);
// List of all Channel IDs
public static final String BRIDGE_RESET = "bridge_reset";
public static final String SEND_COMMAND = "send_command";
public static final String PANEL_MESSAGE = "panel_message";
public static final String PANEL_COMMAND = "panel_command";
public static final String PANEL_SYSTEM_ERROR = "panel_system_error";
public static final String PANEL_TROUBLE_MESSAGE = "panel_trouble_message";
public static final String PANEL_TROUBLE_LED = "panel_trouble_led";
public static final String PANEL_SERVICE_REQUIRED = "panel_service_required";
public static final String PANEL_AC_TROUBLE = "panel_ac_trouble";
public static final String PANEL_TELEPHONE_TROUBLE = "panel_telephone_trouble";
public static final String PANEL_FTC_TROUBLE = "panel_ftc_trouble";
public static final String PANEL_ZONE_FAULT = "panel_zone_fault";
public static final String PANEL_ZONE_TAMPER = "panel_zone_tamper";
public static final String PANEL_ZONE_LOW_BATTERY = "panel_zone_low_battery";
public static final String PANEL_TIME_LOSS = "panel_time_loss";
public static final String PANEL_TIME = "panel_time";
public static final String PANEL_TIME_STAMP = "panel_time_stamp";
public static final String PANEL_TIME_BROADCAST = "panel_time_broadcast";
public static final String PANEL_FIRE_KEY_ALARM = "panel_fire_key_alarm";
public static final String PANEL_PANIC_KEY_ALARM = "panel_panic_key_alarm";
public static final String PANEL_AUX_KEY_ALARM = "panel_aux_key_alarm";
public static final String PANEL_AUX_INPUT_ALARM = "panel_aux_input_alarm";
public static final String PARTITION_STATUS = "partition_status";
public static final String PARTITION_ARM_MODE = "partition_arm_mode";
public static final String PARTITION_ARMED = "partition_armed";
public static final String PARTITION_ENTRY_DELAY = "partition_entry_delay";
public static final String PARTITION_EXIT_DELAY = "partition_exit_delay";
public static final String PARTITION_IN_ALARM = "partition_in_alarm";
public static final String PARTITION_OPENING_CLOSING_MODE = "partition_opening_closing_mode";
public static final String ZONE_STATUS = "zone_status";
public static final String ZONE_MESSAGE = "zone_message";
public static final String ZONE_BYPASS_MODE = "zone_bypass_mode";
public static final String ZONE_IN_ALARM = "zone_in_alarm";
public static final String ZONE_TAMPER = "zone_tamper";
public static final String ZONE_FAULT = "zone_fault";
public static final String ZONE_TRIPPED = "zone_tripped";
public static final String KEYPAD_READY_LED = "keypad_ready_led";
public static final String KEYPAD_ARMED_LED = "keypad_armed_led";
public static final String KEYPAD_MEMORY_LED = "keypad_memory_led";
public static final String KEYPAD_BYPASS_LED = "keypad_bypass_led";
public static final String KEYPAD_TROUBLE_LED = "keypad_trouble_led";
public static final String KEYPAD_PROGRAM_LED = "keypad_program_led";
public static final String KEYPAD_FIRE_LED = "keypad_fire_led";
public static final String KEYPAD_BACKLIGHT_LED = "keypad_backlight_led";
public static final String KEYPAD_AC_LED = "keypad_ac_led";
public static final String KEYPAD_LCD_UPDATE = "keypad_lcd_update";
public static final String KEYPAD_LCD_CURSOR = "keypad_lcd_cursor";
// Set of all supported Thing Type UIDs
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream
.of(ENVISALINKBRIDGE_THING_TYPE, IT100BRIDGE_THING_TYPE, TCPSERVERBRIDGE_THING_TYPE,
PANEL_THING_TYPE, PARTITION_THING_TYPE, ZONE_THING_TYPE, KEYPAD_THING_TYPE)
.collect(Collectors.toSet()));
// Set of all supported Bridge Type UIDs
public static final Set<ThingTypeUID> SUPPORTED_BRIDGE_THING_TYPES_UIDS = Collections
.unmodifiableSet(Stream.of(ENVISALINKBRIDGE_THING_TYPE, IT100BRIDGE_THING_TYPE, TCPSERVERBRIDGE_THING_TYPE)
.collect(Collectors.toSet()));
}

View File

@@ -0,0 +1,263 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal;
import java.util.HashMap;
import java.util.Map;
/**
* Enumerator for DSCAlarm Command and Message Codes.
*
* @author Russell Stephens - Initial Contribution
*/
public enum DSCAlarmCode {
// Command Codes
Poll("000", "Poll", "000: The poll command."),
StatusReport("001", "Status Report", "001: Request a status report command."),
LabelsRequest("002", "Labels Request", "002: IT-100 labels request command."),
NetworkLogin("005", "Network Login", "005: Envisalink login command."),
DumpZoneTimers("008", "Dump Zone Timers", "008: Dump the internal Envisalink Zone Timers command."),
SetTimeDate("010", "Set Time and Date", "010: Set the time and date command."),
CommandOutputControl("020", "Command Output Control", "020: Activate the selected Command Output command."),
PartitionArmControlAway("030", "Partition Arm Control - Away", "030: Arm the partition in AWAY mode."),
PartitionArmControlStay("031", "Partition Arm Control - Stay", "031: Arm the partition in STAY mode."),
PartitionArmControlZeroEntryDelay("032", "Partition Arm Control - Zero Entry Delay",
"032: Arm the partition with zero entry delay."),
PartitionArmControlWithUserCode("033", "Partition Arm Control - With User Code",
"033: Arm the partition with user code."),
PartitionDisarmControl("040", "Partition Disarm Control", "040: Disarm the partition with user code."),
TimeStampControl("055", "Time Stamp Control", "055: Prepend all messages with a timestamp."),
TimeDateBroadcastControl("056", "Time/Date Broadcast Control",
"056: Periodically transmit system time broadcasts."),
TemperatureBroadcastControl("057", "Temperature Broadcast Control",
"057: Periodically transmit the interior and exterior temperatures."),
VirtualKeypadControl("058", "Virtual Keypad Control", "058: Enable/Disable the virtual keypad command."),
TriggerPanicAlarm("060", "Trigger Panic Alarm",
"060: Emulates the FAP (Fire, Ambulance, Police) panic keys on a DSC keypad."),
KeyStroke("070", "Key Stroke", "070: Send a single keystroke on Partition 1 only."),
KeySequence("071", "Key Stroke Sequence", "071: Send a keystroke string."),
EnterUserCodeProgramming("072", "Enter User Code Programming",
"072: Cause the partition to enter user code (*5) programming."),
EnterUserProgramming("073", "Enter User Programming",
"073: Cause the partition to enter user code (*6) programming."),
KeepAlive("074", "Keep Alive", "074: Reset the time-out timer on the panel."),
BaudRateChange("080", "Baud Rate Change", "080: Change the baud rate on the IT-100."),
GetTemperatureSetPoint("095", "Get Temperature Set Points", "095: Request the thermostat temperature set points."),
TemperatureChange("096", "Temperature Change", "096: Change the thermostat temperature."),
SaveTemperatureSetting("097", "Save Temperature Setting", "097: Save the thermostat temperature."),
CodeSend("200", "Code Send", "200: Send a user code."),
// Message Codes
CommandAcknowledge("500", "Command Acknowledge", "500: A command has been received successfully."),
CommandError("501", "Command Error", "501: A command has been received with a bad checksum."),
SystemError("502", "System Error", "502: An error has been detected."),
LoginResponse("505", "Login Interaction",
"505: Login response (failed=0, success=1, time out=2, password request=3)."),
KeypadLEDState("510", "Keypad LED State - Partition 1 Only",
"510: A change of state in the Partition 1 keypad LEDs."),
KeypadLEDFlashState("511", "Keypad LED Flash State - Partition 1 Only",
"511: A change of state in the Partition 1 keypad LEDs as to whether to flash or not."),
TimeDateBroadcast("550", "Time-Date Broadcast", "550: The current security system time."),
RingDetected("560", "Ring Detected", "560: A ring on the telephone line."),
IndoorTemperatureBroadcast("561", "Indoor Temperature Broadcast",
"561: The interior temperature and the thermostat number."),
OutdoorTemperatureBroadcast("562", "Outdoor Temperature Broadcast",
"562: The exterior temperature and the thermostat number."),
ThermostatSetPoints("563", "Thermostat Set Points",
"563: Cooling and heating set points and the thermostat number."),
BroadcastLabels("570", "Broadcast Labels", "570: Labels stored in the DSC Alarm."),
BaudRateSet("580", "Baud Rate Set", "580: Baud Rate of the serial interface."),
ZoneAlarm("601", "Zone Alarm", "601: A zone has gone into alarm."),
ZoneAlarmRestore("602", "Zone Alarm Restore", "602: A zone alarm has been restored."),
ZoneTamper("603", "Zone Tamper", "603: A zone has a tamper condition."),
ZoneTamperRestore("604", "Zone Tamper Restored", "604: A zone tamper condition has been restored."),
ZoneFault("605", "Zone Fault", "605: A zone has a fault condition."),
ZoneFaultRestore("606", "Zone Fault Restored", "606: A zone fault condition has been restored."),
ZoneOpen("609", "Zone Open", "609: General status of the zone - open."),
ZoneRestored("610", "Zone Restored", "610: General status of the zone - restored."),
EnvisalinkZoneTimerDump("615", "Envisalink Zone Timer Dump",
"615: The raw zone timers used inside the Envisalink."),
DuressAlarm("620", "Duress Alarm", "620: A duress code has been entered on a system keypad."),
FireKeyAlarm("621", "Fire Key Alarm", "621: A Fire key alarm has been activated."),
FireKeyRestored("622", "Fire Key Alarm Restore", "622: A Fire key alarm has been restored."),
AuxiliaryKeyAlarm("623", "Auxiliary Key Alarm", "623: An Auxiliary key alarm has been activated."),
AuxiliaryKeyRestored("624", "Auxiliary Key Alarm Restore", "624: An Auxiliary key alarm has been restored."),
PanicKeyAlarm("625", "Panic Key Alarm", "625: A Panic key alarm has been activated."),
PanicKeyRestored("626", "Panic Key Alarm Restore", "626: A Panic key alarm has been restored."),
AuxiliaryInputAlarm("631", "2-Wire Smoke/Aux Alarm", "631: A 2-wire smoke/Auxiliary alarm has been activated."),
AuxiliaryInputAlarmRestored("632", "2-Wire Smoke/Aux Alarm Restore",
"632: A 2-wire smoke/Auxiliary alarm has been restored."),
PartitionReady("650", "Partition Ready", "650: Partition can now be armed."),
PartitionNotReady("651", "Partition Not Ready", "651: Partition can not be armed."),
PartitionArmed("652", "Partition Armed", "652: Partition has been armed."),
PartitionReadyForceArming("653", "Partition Ready - Force Arming Enabled",
"653: Partition can now be armed (Force Arming Enabled)."),
PartitionInAlarm("654", "Partition In Alarm", "654: A partition is in alarm."),
PartitionDisarmed("655", "Partition Disarmed", "655: A partition has been disarmed."),
ExitDelayInProgress("656", "Exit Delay in Progress", "656: A partition is in Exit Delay."),
EntryDelayInProgress("657", "Entry Delay in Progress", "657: A partition is in Entry Delay."),
KeypadLockout("658", "Keypad Lock-out", "658: A partition is in Keypad Lockout."),
PartitionFailedToArm("659", "Partition Failed to Arm", "659: An attempt to arm the partition has failed."),
PGMOutputInProgress("660", "PGM Output is in Progress", "660: *71, *72, *73, or *74 has been pressed."),
ChimeEnabled("663", "Chime Enabled", "663: The door chime feature has been enabled."),
ChimeDisabled("664", "Chime Disabled", "664: The door chime feature has been disabled."),
InvalidAccessCode("670", "Invalid Access Code", "670: An access code that was entered was invalid."),
FunctionNotAvailable("671", "Function Not Available", "671: A function that was selected is not available."),
FailureToArm("672", "Failure to Arm", "672: An attempt was made to arm the partition and it failed."),
PartitionBusy("673", "Partition is Busy", "673: The partition is busy."),
SystemArmingInProgress("674", "System Arming in Progress",
"674: This system is auto-arming and is in arm warning delay."),
SystemInInstallerMode("680", "System in Installers Mode", "680: The whole system is in installers mode."),
UserClosing("700", "User Closing", "700: A partition has been armed by a user."),
SpecialClosing("701", "Special Closing",
"701: A partition has been armed by one of the following methods: Quick Arm, Auto Arm, Keyswitch, DLS software, Wireless Key."),
PartialClosing("702", "Partial Closing",
"702: A partition has been armed but one or more zones have been bypassed."),
UserOpening("750", "User Opening", "750: A partition has been disarmed by a user."),
SpecialOpening("751", "Special Opening",
"751: A partition has been disarmed by one of the following methods: Quick Arm, Auto Arm, Keyswitch, DLS software, Wireless Key."),
PanelBatteryTrouble("800", "Panel Battery Trouble", "800: The panel has a low battery."),
PanelBatteryTroubleRestore("801", "Panel Battery Trouble Restore",
"801: The panel low battery trouble has been restored."),
PanelACTrouble("802", "Panel AC Trouble", "802: AC power to the panel has been removed."),
PanelACRestore("803", "Panel AC Restore", "803: AC power to the panel has been restored."),
SystemBellTrouble("806", "System Bell Trouble",
"806: An open circuit has been detected across the bell terminals."),
SystemBellTroubleRestore("807", "System Bell Trouble Restore", "807: The bell trouble has been restored."),
TLMLine1Trouble("810", "TML Line 1 Trouble", "810: The phone line is a open or shorted condition."),
TLMLine1TroubleRestore("811", "TML Line 1 Trouble Restore",
"811: The phone line trouble condition has been restored."),
TLMLine2Trouble("812", "TML Line 2 Trouble", "812: The phone line is a open or shorted condition."),
TLMLine2TroubleRestore("813", "TML Line 2 Trouble Restore",
"813: The phone line trouble condition has been restored."),
FTCTrouble("814", "FTC Trouble",
"814: The panel has failed to communicate successfully to the monitoring station."),
BufferNearFull("816", "Buffer Near Full",
"816: The panel event buffer is 75% full from when it was last uploaded to DLS."),
GeneralDeviceLowBattery("821", "General Device Low Battery", "821: A wireless zone has a low battery."),
GeneralDeviceLowBatteryRestore("822", "General Device Low Battery Restore",
"822: A wireless zone has a low battery."),
WirelessKeyLowBatteryTrouble("825", "Wireless Key Low Battery Trouble", "825: A wireless key has a low battery."),
WirelessKeyLowBatteryTroubleRestore("826", "Wireless Key Low Battery Trouble Restore",
"826: A wireless key low battery condition has been restored."),
HandheldKeypadLowBatteryTrouble("827", "Handheld Keypad Low Battery Trouble",
"827: A handhekd keypad has a low battery."),
HandheldKeypadLowBatteryTroubleRestore("828", "Handheld Keypad Low Battery Trouble Restore",
"828: A handhekd keypad low battery condition has been restored."),
GeneralSystemTamper("829", "General System Tamper", "829: A tamper has occurred with a system module."),
GeneralSystemTamperRestore("830", "General System Tamper Restore",
"830: A general system Tamper has been restored."),
HomeAutomationTrouble("831", "Home Automation Trouble", "831: Escort 5580 module trouble."),
HomeAutomationTroubleRestore("832", "Home Automation Trouble Restore",
"832: Escort 5580 module trouble has been restored."),
TroubleLEDOn("840", "Trouble LED ON", "840: The trouble LED on a keypad is ON."),
TroubleLEDOff("841", "Trouble LED OFF", "841: The trouble LED on a keypad is OFF."),
FireTroubleAlarm("842", "Fire Trouble Alarm", "842: Fire trouble alarm."),
FireTroubleAlarmRestore("843", "Fire Trouble Alarm Restore", "843: Fire trouble alarm restored."),
VerboseTroubleStatus("849", "Verbose Trouble Status",
"849: a trouble appears on the system and roughly every 5 minutes until the trouble is cleared."),
KeybusFault("896", "Keybus Fault", "896: Keybus fault condition."),
KeybusFaultRestore("897", "Keybus Fault Restore", "897: Keybus fault has been restored."),
CodeRequired("900", "Code Required", "900: Tells the API to enter an access code."),
LCDUpdate("901", "LCD Update", "901: Text of the IT-100 menu has changed."),
LCDCursor("902", "LCD Cursor", "902: Cursor position has changed."),
LEDStatus("903", "LED Status", "903: LED Status has changed."),
BeepStatus("904", "Beep Status", "904: Beep status sent."),
ToneStatus("905", "Tone Status", "905: Tone status sent."),
BuzzerStatus("906", "Buzzer Status", "906: Buzzer status sent."),
DoorChimeStatus("907", "Door Chime Status", "907: Door Chime status sent."),
SoftwareVersion("908", "Software Version", "908: Current software version."),
CommandOutputPressed("912", "Command Output Pressed", "912: Tells the API to enter an access code."),
MasterCodeRequired("921", "Master Code Required", "921: Tells the API to enter a master access code."),
InstallersCodeRequired("922", "Installers Code Required", "922: Tells the API to enter an installers access code."),
UnknownCode("-1", "Unknown Code", "Unknown code received.");
private String code;
private String name;
private String description;
/**
* Lookup map to get a DSCAlarmCode value from its string code.
*/
private static Map<String, DSCAlarmCode> codeToDSCAlarmCodeValue;
/**
* Constructor
*
* @param code
*/
private DSCAlarmCode(String code, String name, String description) {
this.code = code;
this.name = name;
this.description = description;
}
/**
* Initialize the lookup map that gets a DSCAlarmCode value from a string code.
*/
private static void initMapping() {
codeToDSCAlarmCodeValue = new HashMap<>();
for (DSCAlarmCode s : values()) {
codeToDSCAlarmCodeValue.put(s.code, s);
}
}
/**
* The DSC Alarm command/message code string (example '005').
*/
public String getCode() {
return code;
}
/**
* The DSC Alarm command/message name string (example 'Poll Command').
*/
public String getName() {
return name;
}
/**
* The DSC Alarm command/message description string.
*/
public String getDescription() {
return description;
}
/**
* Lookup function to return the DSCAlarmCode value based on the string code. Returns 'UnknownCode' if the string
* code is not found.
*
* @param code
* @return enum value
*/
public static DSCAlarmCode getDSCAlarmCodeValue(String code) {
DSCAlarmCode dscAlarmCode;
if (codeToDSCAlarmCodeValue == null) {
initMapping();
}
dscAlarmCode = codeToDSCAlarmCodeValue.get(code);
if (dscAlarmCode == null) {
dscAlarmCode = UnknownCode;
}
return dscAlarmCode;
}
}

View File

@@ -0,0 +1,53 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal;
import java.util.EventObject;
/**
* Event for Receiving API Messages.
*
* @author Russell Stephens - Initial Contribution
*/
public class DSCAlarmEvent extends EventObject {
private static final long serialVersionUID = 1L;
private DSCAlarmMessage dscAlarmMessage;
/**
* Constructor.
*
* @param source
*/
public DSCAlarmEvent(Object source) {
super(source);
}
/**
* Adds the the received API Message to the event.
*
* @param dscAlarmMessage
*/
public void dscAlarmEventMessage(DSCAlarmMessage dscAlarmMessage) {
this.dscAlarmMessage = dscAlarmMessage;
}
/**
* Returns the API Message event from the DSC Alarm System.
*
* @return apiMessage
*/
public DSCAlarmMessage getDSCAlarmMessage() {
return dscAlarmMessage;
}
}

View File

@@ -0,0 +1,606 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal;
import java.util.EnumMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A class that processes DSC Alarm Messages.
*
* @author Russell Stephens - Initial Contribution
*/
public class DSCAlarmMessage {
private final Logger logger = LoggerFactory.getLogger(DSCAlarmMessage.class);
private static final EnumMap<DSCAlarmCode, MessageParameters> DSCALARM_MESSAGE_PARAMETERS = new EnumMap<>(
DSCAlarmCode.class);
public enum DSCAlarmMessageType {
PANEL_EVENT,
PARTITION_EVENT,
ZONE_EVENT,
KEYPAD_EVENT
}
public enum DSCAlarmMessageInfoType {
MESSAGE,
NAME,
DESCRIPTION,
CODE,
TIME_STAMP,
PARTITION,
ZONE,
DATA,
MODE,
USER,
ERROR
}
private DSCAlarmMessageType messageType = DSCAlarmMessageType.PANEL_EVENT;
private String message = "";
private String name = "";
private String description = "";
private String codeReceived = "";
private String timeStamp = "";
private String partition = "0";
private String zone = "0";
private String data = "";
private String mode = "";
private String user = "";
private String error = "";
/**
* Constructor.
*
* @param message
* - the message received
*/
public DSCAlarmMessage(String message) {
this.message = message;
processDSCAlarmMessage();
}
/**
* Processes the incoming DSC Alarm message and extracts the information.
*/
private void processDSCAlarmMessage() {
DSCAlarmCode dscAlarmCode;
if (message.length() > 3) {
try {
if (message.length() >= 8 && message.charAt(2) == ':' && message.charAt(5) == ':') {
timeStamp = message.substring(0, 8);
message = message.substring(9, message.length() - 2);
} else {
message = message.substring(0, message.length() - 2);
}
codeReceived = message.substring(0, 3);
if (message.length() >= 4) {
data = message.substring(3);
}
} catch (Exception e) {
logger.error("processDSCAlarmMessage(): Error processing message: ({}) ", message, e);
return;
}
dscAlarmCode = DSCAlarmCode.getDSCAlarmCodeValue(codeReceived);
if (dscAlarmCode != null) {
name = dscAlarmCode.getName();
description = dscAlarmCode.getDescription();
MessageParameters messageParms = DSCALARM_MESSAGE_PARAMETERS.get(dscAlarmCode);
if (messageParms != null) {
boolean hasPartition = messageParms.hasPartition();
boolean hasZone = messageParms.hasZone();
if (hasPartition) {
partition = message.substring(3, 4);
}
if (hasZone) {
if (hasPartition) {
zone = message.substring(4);
} else {
zone = message.substring(3);
}
}
messageType = messageParms.getType();
}
switch (dscAlarmCode) {
case SystemError: /* 502 */
int systemErrorCode = 0;
systemErrorCode = Integer.parseInt(data);
switch (systemErrorCode) {
case 1:
error = "Receive Buffer Overrun";
break;
case 2:
error = "Receive Buffer Overflow";
break;
case 3:
error = "Transmit Buffer Overflow";
break;
case 10:
error = "Keybus Transmit Buffer Overrun";
break;
case 11:
error = "Keybus Transmit Time Timeout";
break;
case 12:
error = "Keybus Transmit Mode Timeout";
break;
case 13:
error = "Keybus Transmit Keystring Timeout";
break;
case 14:
error = "Keybus Interface Not Functioning";
break;
case 15:
error = "Keybus Busy - Attempting to Disarm or Arm with user code";
break;
case 16:
error = "Keybus Busy Lockout";
break;
case 17:
error = "Keybus Busy Installers Mode";
break;
case 18:
error = "Keybus Busy - General Busy";
break;
case 20:
error = "API Command Syntax Error";
break;
case 21:
error = "API Command Partition Error - Requested Partition is out of bounds";
break;
case 22:
error = "API Command Not Supported";
break;
case 23:
error = "API System Not Armed - Sent in response to a disarm command";
break;
case 24:
error = "API System Not Ready to Arm - System is either not-secure, in exit-delay, or already armed";
break;
case 25:
error = "API Command Invalid Length";
break;
case 26:
error = "API User Code not Required";
break;
case 27:
error = "API Invalid Characters in Command - No alpha characters are allowed except for checksum";
break;
case 28:
error = "API Virtual Keypad is Disabled";
break;
case 29:
error = "API Not Valid Parameter";
break;
case 30:
error = "API Keypad Does Not Come Out of Blank Mode";
break;
case 31:
error = "API IT-100 is Already in Thermostat Menu";
break;
case 32:
error = "API IT-100 is NOT in Thermostat Menu";
break;
case 33:
error = "API No Response From Thermostat or Escort Module";
break;
case 0:
default:
error = "No Error";
break;
}
break;
case PartitionArmed: /* 652 */
mode = message.substring(4);
if (mode.equals("0")) {
name += " (Away)";
} else if (mode.equals("1")) {
name += " (Stay)";
} else if (mode.equals("2")) {
name += " (ZEA)";
} else if (mode.equals("3")) {
name += " (ZES)";
}
messageType = DSCAlarmMessageType.PARTITION_EVENT;
break;
case UserClosing: /* 700 */
user = message.substring(4);
name = name.concat(": " + user);
description = codeReceived + ": Partition " + String.valueOf(partition)
+ " has been armed by user " + user + ".";
messageType = DSCAlarmMessageType.PARTITION_EVENT;
break;
case UserOpening: /* 750 */
user = message.substring(4);
name = name.concat(": " + user);
description = codeReceived + ": Partition " + String.valueOf(partition)
+ " has been disarmed by user " + user + ".";
messageType = DSCAlarmMessageType.PARTITION_EVENT;
break;
default:
break;
}
logger.debug(
"parseAPIMessage(): Message Received ({}) - Code: {}, Name: {}, Description: {}, Data: {}\r\n",
message, codeReceived, name, description, data);
}
} else {
codeReceived = "-1";
data = "";
dscAlarmCode = DSCAlarmCode.getDSCAlarmCodeValue(codeReceived);
name = dscAlarmCode.getName();
description = dscAlarmCode.getDescription();
logger.debug("parseAPIMessage(): Invalid Message Received");
}
}
/**
* Returns the DSCAlarm Message Type.
*
* @return messageType
*/
public DSCAlarmMessageType getDSCAlarmMessageType() {
return messageType;
}
/**
* Returns Information from A DSC Alarm Message
*
* @param dscAlarmMessageInfoType
* @return String
*/
public String getMessageInfo(DSCAlarmMessageInfoType dscAlarmMessageInfoType) {
String info = "";
switch (dscAlarmMessageInfoType) {
case MESSAGE:
info = message;
break;
case NAME:
info = name;
break;
case DESCRIPTION:
info = description;
break;
case CODE:
info = codeReceived;
break;
case TIME_STAMP:
info = timeStamp;
break;
case PARTITION:
info = partition;
break;
case ZONE:
info = zone;
break;
case DATA:
info = data;
break;
case MODE:
info = mode;
break;
case USER:
info = timeStamp;
break;
case ERROR:
info = error;
break;
default:
break;
}
return info;
}
/**
* Returns a string representation of a APIMessage.
*
* @return APIMessage string
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Code: \"");
sb.append(codeReceived);
sb.append("\"");
sb.append(", Name: \"");
sb.append(name);
sb.append("\"");
sb.append(", Description: \"");
sb.append(description);
sb.append("\"");
if (!timeStamp.equals("")) {
sb.append(", Time Stamp: ");
sb.append(timeStamp);
}
if (!partition.equals("0")) {
sb.append(", Partition: ");
sb.append(partition);
}
if (!zone.equals("0")) {
sb.append(", Zone: ");
sb.append(zone);
}
if (!data.equals("")) {
sb.append(", Data: ");
sb.append(data);
}
if (!mode.equals("")) {
sb.append(", Mode: ");
sb.append(mode);
}
if (!user.equals("")) {
sb.append(", user: ");
sb.append(user);
}
if (!error.equals("")) {
sb.append(", error: ");
sb.append(error);
}
return sb.toString();
}
public static class MessageParameters {
private boolean partition;
private boolean zone;
private DSCAlarmMessageType type;
MessageParameters(DSCAlarmMessageType type, boolean partition, boolean zone) {
this.type = type;
this.partition = partition;
this.zone = zone;
}
public DSCAlarmMessageType getType() {
return type;
}
public boolean hasPartition() {
return partition;
}
public boolean hasZone() {
return zone;
}
}
static {
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.CommandAcknowledge,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.CommandError,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SystemError,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.LoginResponse,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.KeypadLEDState,
new MessageParameters(DSCAlarmMessageType.KEYPAD_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.KeypadLEDFlashState,
new MessageParameters(DSCAlarmMessageType.KEYPAD_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.TimeDateBroadcast,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.RingDetected,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.IndoorTemperatureBroadcast,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.OutdoorTemperatureBroadcast,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ThermostatSetPoints,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.BroadcastLabels,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.BaudRateSet,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneAlarm,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, true, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneAlarmRestore,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, true, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneTamper,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, true, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneTamperRestore,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, true, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneFault,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneFaultRestore,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneOpen,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ZoneRestored,
new MessageParameters(DSCAlarmMessageType.ZONE_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.EnvisalinkZoneTimerDump,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.DuressAlarm,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.FireKeyAlarm,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.FireKeyRestored,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.AuxiliaryKeyAlarm,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.AuxiliaryKeyRestored,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PanicKeyAlarm,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PanicKeyRestored,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.AuxiliaryInputAlarm,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.AuxiliaryInputAlarmRestored,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionReady,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionNotReady,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionArmed,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionReadyForceArming,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionInAlarm,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionDisarmed,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ExitDelayInProgress,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.EntryDelayInProgress,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.KeypadLockout,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionFailedToArm,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PGMOutputInProgress,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ChimeEnabled,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ChimeDisabled,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.InvalidAccessCode,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.FunctionNotAvailable,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.FailureToArm,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartitionBusy,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SystemArmingInProgress,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SystemInInstallerMode,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.UserClosing,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SpecialClosing,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PartialClosing,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.UserOpening,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SpecialOpening,
new MessageParameters(DSCAlarmMessageType.PARTITION_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PanelBatteryTrouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PanelBatteryTroubleRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PanelACTrouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.PanelACRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SystemBellTrouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SystemBellTroubleRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.TLMLine1Trouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.TLMLine1TroubleRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.TLMLine2Trouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.TLMLine2TroubleRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.FTCTrouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.BufferNearFull,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.GeneralDeviceLowBattery,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.GeneralDeviceLowBatteryRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.WirelessKeyLowBatteryTrouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.WirelessKeyLowBatteryTroubleRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.HandheldKeypadLowBatteryTrouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.HandheldKeypadLowBatteryTroubleRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, true));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.GeneralSystemTamper,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.GeneralSystemTamperRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.HomeAutomationTrouble,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.HomeAutomationTroubleRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.TroubleLEDOn,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.TroubleLEDOff,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, true, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.FireTroubleAlarm,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.FireTroubleAlarmRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.VerboseTroubleStatus,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.KeybusFault,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.KeybusFaultRestore,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.CodeRequired,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.LCDUpdate,
new MessageParameters(DSCAlarmMessageType.KEYPAD_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.LCDCursor,
new MessageParameters(DSCAlarmMessageType.KEYPAD_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.LEDStatus,
new MessageParameters(DSCAlarmMessageType.KEYPAD_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.BeepStatus,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.ToneStatus,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.BuzzerStatus,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.DoorChimeStatus,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.SoftwareVersion,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.CommandOutputPressed,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.MasterCodeRequired,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
DSCALARM_MESSAGE_PARAMETERS.put(DSCAlarmCode.InstallersCodeRequired,
new MessageParameters(DSCAlarmMessageType.PANEL_EVENT, false, false));
}
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.config;
/**
* Configuration class for the DSC Alarm Panel Thing.
*
* @author Russell Stephens - Initial contribution
*/
public class DSCAlarmPanelConfiguration {
// Panel Thing constants
public static final String USER_CODE = "userCode";
public static final String SUPPRESS_ACK_MSGS = "suppressAcknowledgementMsgs";
/**
* The Panel User Code. Default is 1234;
*/
public String userCode;
/**
* Suppress Acknowledgement messages when received
*/
public boolean suppressAcknowledgementMsgs;
}

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.config;
/**
* Configuration class for the DSC Alarm Partition Thing.
*
* @author Russell Stephens - Initial contribution
*/
public class DSCAlarmPartitionConfiguration {
// Partition Thing constants
public static final String PARTITION_NUMBER = "partitionNumber";
/**
* The Partition Number. Can be in the range of 1-8. This is a required parameter for a partition.
*/
public Integer partitionNumber;
}

View File

@@ -0,0 +1,36 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.config;
/**
* Configuration class for the DSC Alarm Zone Thing.
*
* @author Russell Stephens - Initial contribution
*/
public class DSCAlarmZoneConfiguration {
// Zone Thing constants
public static final String PARTITION_NUMBER = "partitionNumber";
public static final String ZONE_NUMBER = "zoneNumber";
/**
* The Partition Number. Can be in the range of 1-8. This is not required. Defaults to 1.
*/
public Integer partitionNumber;
/**
* The Zone Number. Can be in the range of 1-64. This is a required parameter for a zone.
*/
public Integer zoneNumber;
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.config;
/**
* Configuration class for the EyezOn Envisalink 3/2DS Ethernet TCP interface bridge, used to connect to the DSC Alarm
* system.
*
* @author Russell Stephens - Initial contribution
*/
public class EnvisalinkBridgeConfiguration {
// Envisalink Bridge Thing constants
public static final String IP_ADDRESS = "ipAddress";
public static final String PORT = "port";
public static final String PASSWORD = "password";
public static final String CONNECTION_TIMEOUT = "connectionTimeout";
public static final String POLL_PERIOD = "pollPeriod";
/**
* The IP address of the Envisalink Ethernet 3/2DS TCP interface
*/
public String ipAddress;
/**
* The port number of the Envisalink Ethernet 3/2DS TCP interface
*/
public Integer port;
/**
* The password of the Envisalink Ethernet 3/2DS TCP interface
*/
public String password;
/**
* The Socket connection timeout for the Envisalink Ethernet 3/2DS TCP interface
*/
public Integer connectionTimeout;
/**
* The Panel Poll Period. Can be set in range 1-15 minutes. Default is 1 minute;
*/
public Integer pollPeriod;
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.config;
/**
* Configuration class for the DSC IT100 RS232 Serial interface bridge, used to connect to the DSC Alarm system.
*
* @author Russell Stephens - Initial contribution
*/
public class IT100BridgeConfiguration {
// IT-100 Bridge Thing constants
public static final String SERIAL_PORT = "serialPort";
public static final String BAUD = "baud";
public static final String POLL_PERIOD = "pollPeriod";
/**
* DSC IT100 port name for a serial connection. Valid values are e.g. COM1 for Windows and /dev/ttyS0 or
* /dev/ttyUSB0 for Linux.
*/
public String serialPort;
/**
* DSC IT100 baud rate for serial connections. Valid values are 9600 (default), 19200, 38400, 57600, and 115200.
*/
public Integer baud;
/**
* The Panel Poll Period. Can be set in range 1-15 minutes. Default is 1 minute;
*/
public Integer pollPeriod;
}

View File

@@ -0,0 +1,55 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.config;
/**
* Configuration class for the TCP Server bridge, used to connect to the DSC Alarm system.
*
* @author Russell Stephens - Initial contribution
*/
public class TCPServerBridgeConfiguration {
// TCP Server Bridge Thing constants
public static final String IP_ADDRESS = "ipAddress";
public static final String PORT = "port";
public static final String PASSWORD = "password";
public static final String CONNECTION_TIMEOUT = "connectionTimeout";
public static final String POLL_PERIOD = "pollPeriod";
public static final String PROTOCOL = "protocol";
/**
* The IP address of the TCP Server
*/
public String ipAddress;
/**
* The port number of the TCP Server
*/
public Integer port;
/**
* The Socket connection timeout for the TCP Server
*/
public Integer connectionTimeout;
/**
* The Panel Poll Period. Can be set in range 1-15 minutes. Default is 1 minute;
*/
public Integer pollPeriod;
/**
* The Protocol Type - 1 for IT-100 API or 2 for Envisalink TPI.
*/
public Integer protocol;
}

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.discovery;
import java.util.HashMap;
import java.util.Map;
import org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants;
import org.openhab.binding.dscalarm.internal.config.EnvisalinkBridgeConfiguration;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.thing.ThingUID;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is responsible for discovering the EyezOn Envisalink 3/2DS Ethernet interface.
*
* @author Russell Stephens - Initial Contribution
*
*/
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.dscalarm")
public class DSCAlarmBridgeDiscovery extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(DSCAlarmBridgeDiscovery.class);
private EnvisalinkBridgeDiscovery envisalinkBridgeDiscovery = new EnvisalinkBridgeDiscovery(this);
public DSCAlarmBridgeDiscovery() {
super(DSCAlarmBindingConstants.SUPPORTED_BRIDGE_THING_TYPES_UIDS, 15, true);
}
@Override
protected void startScan() {
logger.trace("Start DSC Alarm Bridge discovery.");
scheduler.execute(envisalinkBridgeDiscoveryRunnable);
}
private Runnable envisalinkBridgeDiscoveryRunnable = () -> {
envisalinkBridgeDiscovery.discoverBridge();
};
/**
* Method to add an Envisalink Bridge to the Smarthome Inbox.
*
* @param ipAddress
*/
public void addEnvisalinkBridge(String ipAddress) {
logger.trace("addBridge(): Adding new Envisalink Bridge on {} to Smarthome inbox", ipAddress);
String bridgeID = ipAddress.replace('.', '_');
Map<String, Object> properties = new HashMap<>(0);
properties.put(EnvisalinkBridgeConfiguration.IP_ADDRESS, ipAddress);
try {
ThingUID thingUID = new ThingUID(DSCAlarmBindingConstants.ENVISALINKBRIDGE_THING_TYPE, bridgeID);
thingDiscovered(DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withLabel("EyezOn Envisalink Bridge - " + ipAddress).build());
logger.trace("addBridge(): '{}' was added to Smarthome inbox.", thingUID);
} catch (Exception e) {
logger.error("addBridge(): Error", e);
}
}
}

View File

@@ -0,0 +1,145 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.discovery;
import java.util.HashMap;
import java.util.Map;
import org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants;
import org.openhab.binding.dscalarm.internal.DSCAlarmEvent;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageInfoType;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmPartitionConfiguration;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmZoneConfiguration;
import org.openhab.binding.dscalarm.internal.handler.DSCAlarmBaseBridgeHandler;
import org.openhab.binding.dscalarm.internal.handler.DSCAlarmThingType;
import org.openhab.core.config.discovery.AbstractDiscoveryService;
import org.openhab.core.config.discovery.DiscoveryResult;
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is responsible for discovering DSC Alarm Things via the bridge.
*
* @author Russell Stephens - Initial Contribution
*
*/
public class DSCAlarmDiscoveryService extends AbstractDiscoveryService {
private final Logger logger = LoggerFactory.getLogger(DSCAlarmDiscoveryService.class);
/**
* DSC Alarm Bridge handler.
*/
DSCAlarmBaseBridgeHandler dscAlarmBridgeHandler;
/**
* Constructor.
*
* @param dscAlarmBridgeHandler
*/
public DSCAlarmDiscoveryService(DSCAlarmBaseBridgeHandler dscAlarmBridgeHandler) {
super(DSCAlarmBindingConstants.SUPPORTED_THING_TYPES_UIDS, 15, true);
this.dscAlarmBridgeHandler = dscAlarmBridgeHandler;
}
/**
* Activates the Discovery Service.
*/
public void activate() {
dscAlarmBridgeHandler.registerDiscoveryService(this);
}
/**
* Deactivates the Discovery Service.
*/
@Override
public void deactivate() {
dscAlarmBridgeHandler.unregisterDiscoveryService();
}
/**
* Method to add a Thing to the Smarthome Inbox.
*
* @param bridge
* @param dscAlarmThingType
* @param event
*/
public void addThing(Bridge bridge, DSCAlarmThingType dscAlarmThingType, DSCAlarmEvent event) {
logger.trace("addThing(): Adding new DSC Alarm {} to the smarthome inbox", dscAlarmThingType.getLabel());
ThingUID thingUID = null;
String thingID = "";
String thingLabel = "";
Map<String, Object> properties = null;
int partitionNumber = Integer
.parseInt(event.getDSCAlarmMessage().getMessageInfo(DSCAlarmMessageInfoType.PARTITION));
int zoneNumber = Integer.parseInt(event.getDSCAlarmMessage().getMessageInfo(DSCAlarmMessageInfoType.ZONE));
switch (dscAlarmThingType) {
case PANEL:
thingID = "panel";
thingLabel = "Panel";
thingUID = new ThingUID(DSCAlarmBindingConstants.PANEL_THING_TYPE, bridge.getUID(), thingID);
break;
case PARTITION:
if (partitionNumber >= 1 && partitionNumber <= 8) {
thingID = "partition" + String.valueOf(partitionNumber);
thingLabel = "Partition " + String.valueOf(partitionNumber);
properties = new HashMap<>(0);
thingUID = new ThingUID(DSCAlarmBindingConstants.PARTITION_THING_TYPE, bridge.getUID(), thingID);
properties.put(DSCAlarmPartitionConfiguration.PARTITION_NUMBER, partitionNumber);
}
break;
case ZONE:
if (zoneNumber >= 1 && zoneNumber <= 64) {
thingID = "zone" + String.valueOf(zoneNumber);
thingLabel = "Zone " + String.valueOf(zoneNumber);
properties = new HashMap<>(0);
thingUID = new ThingUID(DSCAlarmBindingConstants.ZONE_THING_TYPE, bridge.getUID(), thingID);
properties.put(DSCAlarmZoneConfiguration.ZONE_NUMBER, zoneNumber);
}
break;
case KEYPAD:
thingID = "keypad";
thingLabel = "Keypad";
thingUID = new ThingUID(DSCAlarmBindingConstants.KEYPAD_THING_TYPE, bridge.getUID(), thingID);
break;
}
if (thingUID != null) {
DiscoveryResult discoveryResult;
if (properties != null) {
discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
.withBridge(bridge.getUID()).withLabel(thingLabel).build();
} else {
discoveryResult = DiscoveryResultBuilder.create(thingUID).withBridge(bridge.getUID())
.withLabel(thingLabel).build();
}
thingDiscovered(discoveryResult);
} else {
logger.debug("addThing(): Unable to Add DSC Alarm Thing to Inbox!");
}
}
@Override
protected void startScan() {
// Can be ignored here as discovery is via the bridge
}
}

View File

@@ -0,0 +1,182 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.discovery;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import org.apache.commons.net.util.SubnetUtils;
import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This class is responsible for discovering the EyezOn Envisalink 3/2DS Ethernet interface.
*
* @author Russell Stephens - Initial Contribution
*
*/
public class EnvisalinkBridgeDiscovery {
private final Logger logger = LoggerFactory.getLogger(EnvisalinkBridgeDiscovery.class);
static final int ENVISALINK_BRIDGE_PORT = 4025;
static final int CONNECTION_TIMEOUT = 10;
static final int SO_TIMEOUT = 15000;
static final String ENVISALINK_DISCOVERY_RESPONSE = "505";
private DSCAlarmBridgeDiscovery dscAlarmBridgeDiscovery = null;
private String ipAddress;
/**
* Constructor.
*/
public EnvisalinkBridgeDiscovery(DSCAlarmBridgeDiscovery dscAlarmBridgeDiscovery) {
this.dscAlarmBridgeDiscovery = dscAlarmBridgeDiscovery;
}
/**
* Method for Bridge Discovery.
*/
public synchronized void discoverBridge() {
logger.debug("Starting Envisalink Bridge Discovery.");
SubnetUtils subnetUtils = null;
SubnetInfo subnetInfo = null;
long lowIP = 0;
long highIP = 0;
try {
InetAddress localHost = InetAddress.getLocalHost();
NetworkInterface networkInterface = NetworkInterface.getByInetAddress(localHost);
subnetUtils = new SubnetUtils(localHost.getHostAddress() + "/"
+ networkInterface.getInterfaceAddresses().get(0).getNetworkPrefixLength());
subnetInfo = subnetUtils.getInfo();
lowIP = convertIPToNumber(subnetInfo.getLowAddress());
highIP = convertIPToNumber(subnetInfo.getHighAddress());
} catch (IllegalArgumentException e) {
logger.error("discoverBridge(): Illegal Argument Exception - {}", e.toString());
return;
} catch (Exception e) {
logger.error("discoverBridge(): Error - Unable to get Subnet Information! {}", e.toString());
return;
}
logger.debug(" Local IP Address: {} - {}", subnetInfo.getAddress(),
convertIPToNumber(subnetInfo.getAddress()));
logger.debug(" Subnet: {} - {}", subnetInfo.getNetworkAddress(),
convertIPToNumber(subnetInfo.getNetworkAddress()));
logger.debug(" Network Prefix: {}", subnetInfo.getCidrSignature().split("/")[1]);
logger.debug(" Network Mask: {}", subnetInfo.getNetmask());
logger.debug(" Low IP: {}", convertNumberToIP(lowIP));
logger.debug(" High IP: {}", convertNumberToIP(highIP));
for (long ip = lowIP; ip <= highIP; ip++) {
try (Socket socket = new Socket()) {
ipAddress = convertNumberToIP(ip);
socket.setReuseAddress(true);
socket.setReceiveBufferSize(32);
socket.connect(new InetSocketAddress(ipAddress, ENVISALINK_BRIDGE_PORT), CONNECTION_TIMEOUT);
if (socket.isConnected()) {
String message = "";
socket.setSoTimeout(SO_TIMEOUT);
try (BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
message = input.readLine();
} catch (SocketTimeoutException e) {
logger.debug("discoverBridge(): No Message Read from Socket at [{}] - {}", ipAddress,
e.getMessage());
continue;
} catch (Exception e) {
logger.debug("discoverBridge(): Exception Reading from Socket at [{}]! {}", ipAddress,
e.toString());
continue;
}
if (message.substring(0, 3).equals(ENVISALINK_DISCOVERY_RESPONSE)) {
logger.debug("discoverBridge(): Bridge Found - [{}]! Message - '{}'", ipAddress, message);
dscAlarmBridgeDiscovery.addEnvisalinkBridge(ipAddress);
} else {
logger.debug("discoverBridge(): No Response from Connection - [{}]! Message - '{}'",
ipAddress, message);
}
}
} catch (IllegalArgumentException e) {
logger.debug("discoverBridge(): Illegal Argument Exception - {}", e.toString());
} catch (SocketTimeoutException e) {
logger.trace("discoverBridge(): No Connection on Port 4025! [{}]", ipAddress);
} catch (SocketException e) {
logger.debug("discoverBridge(): Socket Exception! [{}] - {}", ipAddress, e.toString());
} catch (IOException e) {
logger.debug("discoverBridge(): IO Exception! [{}] - {}", ipAddress, e.toString());
}
}
}
/**
* Convert an IP address to a number.
*
* @param ipAddress
* @return
*/
private long convertIPToNumber(String ipAddress) {
String octets[] = ipAddress.split("\\.");
if (octets.length != 4) {
throw new IllegalArgumentException("Invalid IP address: " + ipAddress);
}
long ip = 0;
for (int i = 3; i >= 0; i--) {
long octet = Long.parseLong(octets[3 - i]);
if (octet != (octet & 0xff)) {
throw new IllegalArgumentException("Invalid IP address: " + ipAddress);
}
ip |= octet << (i * 8);
}
return ip;
}
/**
* Convert a number to an IP address.
*
* @param ip
* @return
*/
private String convertNumberToIP(long ip) {
StringBuilder ipAddress = new StringBuilder(15);
for (int i = 0; i < 4; i++) {
ipAddress.insert(0, Long.toString(ip & 0xff));
if (i < 3) {
ipAddress.insert(0, '.');
}
ip = ip >> 8;
}
return ipAddress.toString();
}
}

View File

@@ -0,0 +1,317 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.factory;
import static org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants.SUPPORTED_THING_TYPES_UIDS;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmPartitionConfiguration;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmZoneConfiguration;
import org.openhab.binding.dscalarm.internal.config.EnvisalinkBridgeConfiguration;
import org.openhab.binding.dscalarm.internal.config.IT100BridgeConfiguration;
import org.openhab.binding.dscalarm.internal.config.TCPServerBridgeConfiguration;
import org.openhab.binding.dscalarm.internal.discovery.DSCAlarmDiscoveryService;
import org.openhab.binding.dscalarm.internal.handler.DSCAlarmBaseBridgeHandler;
import org.openhab.binding.dscalarm.internal.handler.EnvisalinkBridgeHandler;
import org.openhab.binding.dscalarm.internal.handler.IT100BridgeHandler;
import org.openhab.binding.dscalarm.internal.handler.KeypadThingHandler;
import org.openhab.binding.dscalarm.internal.handler.PanelThingHandler;
import org.openhab.binding.dscalarm.internal.handler.PartitionThingHandler;
import org.openhab.binding.dscalarm.internal.handler.TCPServerBridgeHandler;
import org.openhab.binding.dscalarm.internal.handler.ZoneThingHandler;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.config.discovery.DiscoveryService;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingTypeUID;
import org.openhab.core.thing.ThingUID;
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.thing.binding.ThingHandlerFactory;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The {@link DSCAlarmHandlerFactory} is responsible for creating things and thing. handlers.
*
* @author Russell Stephens - Initial Contribution
*/
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.dscalarm")
public class DSCAlarmHandlerFactory extends BaseThingHandlerFactory {
private final Logger logger = LoggerFactory.getLogger(DSCAlarmHandlerFactory.class);
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegistrations = new HashMap<>();
private final SerialPortManager serialPortManager;
@Activate
public DSCAlarmHandlerFactory(final @Reference SerialPortManager serialPortManager) {
this.serialPortManager = serialPortManager;
}
@Override
public Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration, ThingUID thingUID,
ThingUID bridgeUID) {
if (DSCAlarmBindingConstants.ENVISALINKBRIDGE_THING_TYPE.equals(thingTypeUID)) {
ThingUID envisalinkBridgeUID = getEnvisalinkBridgeThingUID(thingTypeUID, thingUID, configuration);
logger.debug("createThing(): ENVISALINK_BRIDGE: Creating an '{}' type Thing - {}", thingTypeUID,
envisalinkBridgeUID.getId());
return super.createThing(thingTypeUID, configuration, envisalinkBridgeUID, null);
} else if (DSCAlarmBindingConstants.IT100BRIDGE_THING_TYPE.equals(thingTypeUID)) {
ThingUID it100BridgeUID = getIT100BridgeThingUID(thingTypeUID, thingUID, configuration);
logger.debug("createThing(): IT100_BRIDGE: Creating an '{}' type Thing - {}", thingTypeUID,
it100BridgeUID.getId());
return super.createThing(thingTypeUID, configuration, it100BridgeUID, null);
} else if (DSCAlarmBindingConstants.TCPSERVERBRIDGE_THING_TYPE.equals(thingTypeUID)) {
ThingUID tcpServerBridgeUID = getTCPServerBridgeThingUID(thingTypeUID, thingUID, configuration);
logger.debug("createThing(): TCP_SERVER_BRIDGE: Creating an '{}' type Thing - {}", thingTypeUID,
tcpServerBridgeUID.getId());
return super.createThing(thingTypeUID, configuration, tcpServerBridgeUID, null);
} else if (DSCAlarmBindingConstants.PANEL_THING_TYPE.equals(thingTypeUID)) {
ThingUID panelThingUID = getDSCAlarmPanelUID(thingTypeUID, thingUID, configuration, bridgeUID);
logger.debug("createThing(): PANEL_THING: Creating '{}' type Thing - {}", thingTypeUID,
panelThingUID.getId());
return super.createThing(thingTypeUID, configuration, panelThingUID, bridgeUID);
} else if (DSCAlarmBindingConstants.PARTITION_THING_TYPE.equals(thingTypeUID)) {
ThingUID partitionThingUID = getDSCAlarmPartitionUID(thingTypeUID, thingUID, configuration, bridgeUID);
logger.debug("createThing(): PARTITION_THING: Creating '{}' type Thing - {}", thingTypeUID,
partitionThingUID.getId());
return super.createThing(thingTypeUID, configuration, partitionThingUID, bridgeUID);
} else if (DSCAlarmBindingConstants.ZONE_THING_TYPE.equals(thingTypeUID)) {
ThingUID zoneThingUID = getDSCAlarmZoneUID(thingTypeUID, thingUID, configuration, bridgeUID);
logger.debug("createThing(): ZONE_THING: Creating '{}' type Thing - {}", thingTypeUID,
zoneThingUID.getId());
return super.createThing(thingTypeUID, configuration, zoneThingUID, bridgeUID);
} else if (DSCAlarmBindingConstants.KEYPAD_THING_TYPE.equals(thingTypeUID)) {
ThingUID keypadThingUID = getDSCAlarmKeypadUID(thingTypeUID, thingUID, configuration, bridgeUID);
logger.debug("createThing(): KEYPAD_THING: Creating '{}' type Thing - {}", thingTypeUID,
keypadThingUID.getId());
return super.createThing(thingTypeUID, configuration, keypadThingUID, bridgeUID);
}
throw new IllegalArgumentException(
"createThing(): The thing type " + thingTypeUID + " is not supported by the DSC Alarm binding.");
}
@Override
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
}
/**
* Get the Envisalink Bridge Thing UID.
*
* @param thingTypeUID
* @param thingUID
* @param configuration
* @return thingUID
*/
private ThingUID getEnvisalinkBridgeThingUID(ThingTypeUID thingTypeUID, ThingUID thingUID,
Configuration configuration) {
if (thingUID == null) {
String ipAddress = (String) configuration.get(EnvisalinkBridgeConfiguration.IP_ADDRESS);
String bridgeID = ipAddress.replace('.', '_');
thingUID = new ThingUID(thingTypeUID, bridgeID);
}
return thingUID;
}
/**
* Get the IT-100 Bridge Thing UID.
*
* @param thingTypeUID
* @param thingUID
* @param configuration
* @return thingUID
*/
private ThingUID getIT100BridgeThingUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration) {
if (thingUID == null) {
String serialPort = (String) configuration.get(IT100BridgeConfiguration.SERIAL_PORT);
String bridgeID = serialPort.replace('.', '_');
thingUID = new ThingUID(thingTypeUID, bridgeID);
}
return thingUID;
}
/**
* Get the IT-100 Bridge Thing UID.
*
* @param thingTypeUID
* @param thingUID
* @param configuration
* @return thingUID
*/
private ThingUID getTCPServerBridgeThingUID(ThingTypeUID thingTypeUID, ThingUID thingUID,
Configuration configuration) {
if (thingUID == null) {
String ipAddress = (String) configuration.get(TCPServerBridgeConfiguration.IP_ADDRESS);
String port = (String) configuration.get(TCPServerBridgeConfiguration.PORT);
String bridgeID = ipAddress.replace('.', '_') + "_" + port;
thingUID = new ThingUID(thingTypeUID, bridgeID);
}
return thingUID;
}
/**
* Get the Panel Thing UID.
*
* @param thingTypeUID
* @param thingUID
* @param configuration
* @param bridgeUID
* @return thingUID
*/
private ThingUID getDSCAlarmPanelUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
ThingUID bridgeUID) {
if (thingUID == null) {
String panelId = "panel";
thingUID = new ThingUID(thingTypeUID, panelId, bridgeUID.getId());
}
return thingUID;
}
/**
* Get the Partition Thing UID.
*
* @param thingTypeUID
* @param thingUID
* @param configuration
* @param bridgeUID
* @return thingUID
*/
private ThingUID getDSCAlarmPartitionUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
ThingUID bridgeUID) {
if (thingUID == null) {
String partitionId = "partition"
+ (String) configuration.get(DSCAlarmPartitionConfiguration.PARTITION_NUMBER);
thingUID = new ThingUID(thingTypeUID, partitionId, bridgeUID.getId());
}
return thingUID;
}
/**
* Get the Zone Thing UID.
*
* @param thingTypeUID
* @param thingUID
* @param configuration
* @param bridgeUID
* @return thingUID
*/
private ThingUID getDSCAlarmZoneUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
ThingUID bridgeUID) {
if (thingUID == null) {
String zoneId = "zone" + (String) configuration.get(DSCAlarmZoneConfiguration.ZONE_NUMBER);
thingUID = new ThingUID(thingTypeUID, zoneId, bridgeUID.getId());
}
return thingUID;
}
/**
* Get the Keypad Thing UID.
*
* @param thingTypeUID
* @param thingUID
* @param configuration
* @param bridgeUID
* @return thingUID
*/
private ThingUID getDSCAlarmKeypadUID(ThingTypeUID thingTypeUID, ThingUID thingUID, Configuration configuration,
ThingUID bridgeUID) {
if (thingUID == null) {
String keypadId = "keypad";
thingUID = new ThingUID(thingTypeUID, keypadId, bridgeUID.getId());
}
return thingUID;
}
/**
* Register the Thing Discovery Service for a bridge.
*
* @param dscAlarmBridgeHandler
*/
private void registerDSCAlarmDiscoveryService(DSCAlarmBaseBridgeHandler dscAlarmBridgeHandler) {
DSCAlarmDiscoveryService discoveryService = new DSCAlarmDiscoveryService(dscAlarmBridgeHandler);
discoveryService.activate();
ServiceRegistration<?> discoveryServiceRegistration = bundleContext
.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>());
discoveryServiceRegistrations.put(dscAlarmBridgeHandler.getThing().getUID(), discoveryServiceRegistration);
logger.debug("registerDSCAlarmDiscoveryService(): Bridge Handler - {}, Class Name - {}, Discovery Service - {}",
dscAlarmBridgeHandler, DiscoveryService.class.getName(), discoveryService);
}
@Override
protected ThingHandler createHandler(Thing thing) {
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
if (thingTypeUID.equals(DSCAlarmBindingConstants.ENVISALINKBRIDGE_THING_TYPE)) {
EnvisalinkBridgeHandler handler = new EnvisalinkBridgeHandler((Bridge) thing);
registerDSCAlarmDiscoveryService(handler);
logger.debug("createHandler(): ENVISALINKBRIDGE_THING: ThingHandler created for {}", thingTypeUID);
return handler;
} else if (thingTypeUID.equals(DSCAlarmBindingConstants.IT100BRIDGE_THING_TYPE)) {
IT100BridgeHandler handler = new IT100BridgeHandler((Bridge) thing, serialPortManager);
registerDSCAlarmDiscoveryService(handler);
logger.debug("createHandler(): IT100BRIDGE_THING: ThingHandler created for {}", thingTypeUID);
return handler;
} else if (thingTypeUID.equals(DSCAlarmBindingConstants.TCPSERVERBRIDGE_THING_TYPE)) {
TCPServerBridgeHandler handler = new TCPServerBridgeHandler((Bridge) thing);
registerDSCAlarmDiscoveryService(handler);
logger.debug("createHandler(): TCPSERVERBRIDGE_THING: ThingHandler created for {}", thingTypeUID);
return handler;
} else if (thingTypeUID.equals(DSCAlarmBindingConstants.PANEL_THING_TYPE)) {
logger.debug("createHandler(): PANEL_THING: ThingHandler created for {}", thingTypeUID);
return new PanelThingHandler(thing);
} else if (thingTypeUID.equals(DSCAlarmBindingConstants.PARTITION_THING_TYPE)) {
logger.debug("createHandler(): PARTITION_THING: ThingHandler created for {}", thingTypeUID);
return new PartitionThingHandler(thing);
} else if (thingTypeUID.equals(DSCAlarmBindingConstants.ZONE_THING_TYPE)) {
logger.debug("createHandler(): ZONE_THING: ThingHandler created for {}", thingTypeUID);
return new ZoneThingHandler(thing);
} else if (thingTypeUID.equals(DSCAlarmBindingConstants.KEYPAD_THING_TYPE)) {
logger.debug("createHandler(): KEYPAD_THING: ThingHandler created for {}", thingTypeUID);
return new KeypadThingHandler(thing);
} else {
logger.debug("createHandler(): ThingHandler not found for {}", thingTypeUID);
return null;
}
}
@Override
protected void removeHandler(ThingHandler thingHandler) {
ServiceRegistration<?> discoveryServiceRegistration = discoveryServiceRegistrations
.get(thingHandler.getThing().getUID());
if (discoveryServiceRegistration != null) {
DSCAlarmDiscoveryService discoveryService = (DSCAlarmDiscoveryService) bundleContext
.getService(discoveryServiceRegistration.getReference());
discoveryService.deactivate();
discoveryServiceRegistration.unregister();
discoveryServiceRegistration = null;
discoveryServiceRegistrations.remove(thingHandler.getThing().getUID());
}
super.removeHandler(thingHandler);
}
}

View File

@@ -0,0 +1,845 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import static org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.openhab.binding.dscalarm.internal.DSCAlarmCode;
import org.openhab.binding.dscalarm.internal.DSCAlarmEvent;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageInfoType;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageType;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmPartitionConfiguration;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmZoneConfiguration;
import org.openhab.binding.dscalarm.internal.discovery.DSCAlarmDiscoveryService;
import org.openhab.core.config.core.Configuration;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.binding.BaseBridgeHandler;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract class for a DSC Alarm Bridge Handler.
*
* @author Russell Stephens - Initial Contribution
*/
public abstract class DSCAlarmBaseBridgeHandler extends BaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(DSCAlarmBaseBridgeHandler.class);
/** The DSC Alarm bridge type. */
private DSCAlarmBridgeType dscAlarmBridgeType = null;
/** The DSC Alarm bridge type. */
private DSCAlarmProtocol dscAlarmProtocol = null;
/** The DSC Alarm Discovery Service. */
private DSCAlarmDiscoveryService dscAlarmDiscoveryService = null;
/** The Panel Thing handler for the bridge. */
private DSCAlarmBaseThingHandler panelThingHandler = null;
/** Connection status for the bridge. */
private boolean connected = false;
/** Determines if things have changed. */
private boolean thingsHaveChanged = false;
/** Determines if all things have been initialized. */
private boolean allThingsInitialized = false;
/** Thing count. */
private int thingCount = 0;
/** Password for bridge connection authentication. */
private String password = null;
/** User Code for some DSC Alarm commands. */
private String userCode = null;
// Polling variables
protected int pollPeriod = 0;
private long pollElapsedTime = 0;
private long pollStartTime = 0;
private long refreshInterval = 5000;
private ScheduledFuture<?> pollingTask;
/**
* Constructor.
*
* @param bridge
* @param dscAlarmBridgeType
*/
DSCAlarmBaseBridgeHandler(Bridge bridge, DSCAlarmBridgeType dscAlarmBridgeType, DSCAlarmProtocol dscAlarmProtocol) {
super(bridge);
this.dscAlarmBridgeType = dscAlarmBridgeType;
this.dscAlarmProtocol = dscAlarmProtocol;
}
/**
* Returns the bridge type.
*/
public DSCAlarmBridgeType getBridgeType() {
return dscAlarmBridgeType;
}
/**
* Sets the protocol.
*
* @param dscAlarmProtocol
*/
public void setProtocol(DSCAlarmProtocol dscAlarmProtocol) {
this.dscAlarmProtocol = dscAlarmProtocol;
}
/**
* Returns the protocol.
*/
public DSCAlarmProtocol getProtocol() {
return dscAlarmProtocol;
}
/**
* Sets the bridge type.
*
* @param dscAlarmBridgeType
*/
public void setBridgeType(DSCAlarmBridgeType dscAlarmBridgeType) {
this.dscAlarmBridgeType = dscAlarmBridgeType;
}
@Override
public void initialize() {
if (this.pollPeriod > 15) {
this.pollPeriod = 15;
} else if (this.pollPeriod < 1) {
this.pollPeriod = 1;
}
updateStatus(ThingStatus.OFFLINE);
startPolling();
}
@Override
public void dispose() {
stopPolling();
closeConnection();
super.dispose();
}
/**
* Register the Discovery Service.
*
* @param discoveryService
*/
public void registerDiscoveryService(DSCAlarmDiscoveryService discoveryService) {
if (discoveryService == null) {
throw new IllegalArgumentException("registerDiscoveryService(): Illegal Argument. Not allowed to be Null!");
} else {
this.dscAlarmDiscoveryService = discoveryService;
logger.trace("registerDiscoveryService(): Discovery Service Registered!");
}
}
/**
* Unregister the Discovery Service.
*/
public void unregisterDiscoveryService() {
dscAlarmDiscoveryService = null;
logger.trace("unregisterDiscoveryService(): Discovery Service Unregistered!");
}
/**
* Connect The Bridge.
*/
private void connect() {
openConnection();
if (isConnected()) {
if (dscAlarmBridgeType != DSCAlarmBridgeType.Envisalink) {
onConnected();
}
}
}
/**
* Runs when connected.
*/
public void onConnected() {
logger.debug("onConnected(): Bridge Connected!");
setBridgeStatus(true);
thingsHaveChanged = true;
}
/**
* Disconnect The Bridge.
*/
private void disconnect() {
closeConnection();
if (!isConnected()) {
setBridgeStatus(false);
}
}
/**
* Returns Connected.
*/
public boolean isConnected() {
return this.connected;
}
/**
* Sets Connected.
*/
public void setConnected(boolean connected) {
this.connected = connected;
}
/**
* Set Bridge Status.
*
* @param isOnline
*/
public void setBridgeStatus(boolean isOnline) {
logger.debug("setBridgeStatus(): Setting Bridge to {}", isOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
updateStatus(isOnline ? ThingStatus.ONLINE : ThingStatus.OFFLINE);
ChannelUID channelUID = new ChannelUID(getThing().getUID(), BRIDGE_RESET);
updateState(channelUID, isOnline ? OnOffType.ON : OnOffType.OFF);
}
/**
* Method for opening a connection to DSC Alarm.
*/
abstract void openConnection();
/**
* Method for closing a connection to DSC Alarm.
*/
abstract void closeConnection();
/**
* Method for writing to an open DSC Alarm connection.
*
* @param writeString
* @param doNotLog
*/
public abstract void write(String writeString, boolean doNotLog);
/**
* Method for reading from an open DSC Alarm connection.
*/
public abstract String read();
/**
* Get Bridge Password.
*/
public String getPassword() {
return this.password;
}
/**
* Set Bridge Password.
*
* @param password
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Get Panel User Code.
*/
public String getUserCode() {
return this.userCode;
}
/**
* Set Panel User Code.
*
* @param userCode
*/
public void setUserCode(String userCode) {
this.userCode = userCode;
}
/**
* Method to start the polling task.
*/
private void startPolling() {
logger.debug("Starting DSC Alarm Polling Task.");
if (pollingTask == null || pollingTask.isCancelled()) {
pollingTask = scheduler.scheduleWithFixedDelay(this::polling, 0, refreshInterval, TimeUnit.MILLISECONDS);
}
}
/**
* Method to stop the polling task.
*/
private void stopPolling() {
logger.debug("Stopping DSC Alarm Polling Task.");
if (pollingTask != null && !pollingTask.isCancelled()) {
pollingTask.cancel(true);
pollingTask = null;
}
}
/**
* Method for polling the DSC Alarm System.
*/
public synchronized void polling() {
logger.debug("DSC Alarm Polling Task - '{}' is {}", getThing().getUID(), getThing().getStatus());
if (isConnected()) {
if (pollStartTime == 0) {
pollStartTime = System.currentTimeMillis();
}
pollElapsedTime = ((System.currentTimeMillis() - pollStartTime) / 1000) / 60;
// Send Poll command to the DSC Alarm if idle for 'pollPeriod'
// minutes
if (pollElapsedTime >= pollPeriod) {
sendCommand(DSCAlarmCode.Poll);
pollStartTime = 0;
}
checkThings();
if (thingsHaveChanged && allThingsInitialized) {
this.setBridgeStatus(isConnected());
thingsHaveChanged = false;
// Get a status report from DSC Alarm.
sendCommand(DSCAlarmCode.StatusReport);
}
} else {
logger.error("Not Connected to the DSC Alarm!");
connect();
}
}
/**
* Check if things have changed.
*/
public void checkThings() {
logger.debug("Checking Things!");
allThingsInitialized = true;
List<Thing> things = getThing().getThings();
if (things.size() != thingCount) {
thingsHaveChanged = true;
thingCount = things.size();
}
for (Thing thing : things) {
DSCAlarmBaseThingHandler handler = (DSCAlarmBaseThingHandler) thing.getHandler();
if (handler != null) {
logger.debug("***Checking '{}' - Status: {}, Initialized: {}", thing.getUID(), thing.getStatus(),
handler.isThingHandlerInitialized());
if (!handler.isThingHandlerInitialized() || thing.getStatus() != ThingStatus.ONLINE) {
allThingsInitialized = false;
}
if (handler.getDSCAlarmThingType().equals(DSCAlarmThingType.PANEL)) {
if (panelThingHandler == null) {
panelThingHandler = handler;
}
}
} else {
logger.error("checkThings(): Thing handler not found!");
}
}
}
/**
* Find a Thing.
*
* @param dscAlarmThingType
* @param partitionId
* @param zoneId
* @return thing
*/
public Thing findThing(DSCAlarmThingType dscAlarmThingType, int partitionId, int zoneId) {
List<Thing> things = getThing().getThings();
Thing thing = null;
for (Thing t : things) {
try {
Configuration config = t.getConfiguration();
DSCAlarmBaseThingHandler handler = (DSCAlarmBaseThingHandler) t.getHandler();
if (handler != null) {
DSCAlarmThingType handlerDSCAlarmThingType = handler.getDSCAlarmThingType();
if (handlerDSCAlarmThingType != null) {
if (handlerDSCAlarmThingType.equals(dscAlarmThingType)) {
switch (handlerDSCAlarmThingType) {
case PANEL:
case KEYPAD:
thing = t;
logger.debug("findThing(): Thing Found - {}, {}, {}", t, handler,
handlerDSCAlarmThingType);
return thing;
case PARTITION:
BigDecimal partitionNumber = (BigDecimal) config
.get(DSCAlarmPartitionConfiguration.PARTITION_NUMBER);
if (partitionId == partitionNumber.intValue()) {
thing = t;
logger.debug("findThing(): Thing Found - {}, {}, {}", t, handler,
handlerDSCAlarmThingType);
return thing;
}
break;
case ZONE:
BigDecimal zoneNumber = (BigDecimal) config
.get(DSCAlarmZoneConfiguration.ZONE_NUMBER);
if (zoneId == zoneNumber.intValue()) {
thing = t;
logger.debug("findThing(): Thing Found - {}, {}, {}", t, handler,
handlerDSCAlarmThingType);
return thing;
}
break;
default:
break;
}
}
}
}
} catch (Exception e) {
logger.debug("findThing(): Error Seaching Thing - {} ", e.getMessage(), e);
}
}
return thing;
}
/**
* Handles an incoming message from the DSC Alarm System.
*
* @param incomingMessage
*/
public synchronized void handleIncomingMessage(String incomingMessage) {
if (incomingMessage != null && !incomingMessage.isEmpty()) {
DSCAlarmMessage dscAlarmMessage = new DSCAlarmMessage(incomingMessage);
DSCAlarmMessageType dscAlarmMessageType = dscAlarmMessage.getDSCAlarmMessageType();
logger.debug("handleIncomingMessage(): Message received: {} - {}", incomingMessage,
dscAlarmMessage.toString());
DSCAlarmEvent event = new DSCAlarmEvent(this);
event.dscAlarmEventMessage(dscAlarmMessage);
DSCAlarmThingType dscAlarmThingType = null;
int partitionId = 0;
int zoneId = 0;
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
if (panelThingHandler != null) {
panelThingHandler.setPanelMessage(dscAlarmMessage);
}
if (dscAlarmCode == DSCAlarmCode.LoginResponse) {
String dscAlarmMessageData = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA);
if (dscAlarmMessageData.equals("3")) {
sendCommand(DSCAlarmCode.NetworkLogin);
// onConnected();
} else if (dscAlarmMessageData.equals("1")) {
onConnected();
}
return;
} else if (dscAlarmCode == DSCAlarmCode.CommandAcknowledge) {
String dscAlarmMessageData = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA);
if (dscAlarmMessageData.equals("000")) {
setBridgeStatus(true);
}
}
switch (dscAlarmMessageType) {
case PANEL_EVENT:
dscAlarmThingType = DSCAlarmThingType.PANEL;
break;
case PARTITION_EVENT:
dscAlarmThingType = DSCAlarmThingType.PARTITION;
partitionId = Integer
.parseInt(event.getDSCAlarmMessage().getMessageInfo(DSCAlarmMessageInfoType.PARTITION));
break;
case ZONE_EVENT:
dscAlarmThingType = DSCAlarmThingType.ZONE;
zoneId = Integer.parseInt(event.getDSCAlarmMessage().getMessageInfo(DSCAlarmMessageInfoType.ZONE));
break;
case KEYPAD_EVENT:
dscAlarmThingType = DSCAlarmThingType.KEYPAD;
break;
default:
break;
}
if (dscAlarmThingType != null) {
Thing thing = findThing(dscAlarmThingType, partitionId, zoneId);
logger.debug("handleIncomingMessage(): Thing Search - '{}'", thing);
if (thing != null) {
DSCAlarmBaseThingHandler thingHandler = (DSCAlarmBaseThingHandler) thing.getHandler();
if (thingHandler != null) {
if (thingHandler.isThingHandlerInitialized() && thing.getStatus() == ThingStatus.ONLINE) {
thingHandler.dscAlarmEventReceived(event, thing);
} else {
logger.debug("handleIncomingMessage(): Thing '{}' Not Refreshed!", thing.getUID());
}
}
} else {
logger.debug("handleIncomingMessage(): Thing Not Found! Send to Discovery Service!");
if (dscAlarmDiscoveryService != null) {
dscAlarmDiscoveryService.addThing(getThing(), dscAlarmThingType, event);
}
}
}
} else {
logger.debug("handleIncomingMessage(): No Message Received!");
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("handleCommand(): Command Received - {} {}.", channelUID, command);
if (command instanceof RefreshType) {
return;
}
if (isConnected()) {
switch (channelUID.getId()) {
case BRIDGE_RESET:
if (command == OnOffType.OFF) {
disconnect();
}
break;
case SEND_COMMAND:
if (!command.toString().isEmpty()) {
String[] tokens = command.toString().split(",");
String cmd = tokens[0];
String data = "";
if (tokens.length > 1) {
data = tokens[1];
}
sendDSCAlarmCommand(cmd, data);
updateState(channelUID, new StringType(""));
}
break;
default:
break;
}
}
}
/**
* 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 = sendCommand(DSCAlarmCode.KeyStroke, String.valueOf(key));
if (!sent) {
return sent;
}
}
return sent;
}
/**
* Sends a DSC Alarm command
*
* @param command
* @param data
*/
public boolean sendDSCAlarmCommand(String command, String data) {
logger.debug("sendDSCAlarmCommand(): Attempting to send DSC Alarm Command: command - {} - data: {}", command,
data);
DSCAlarmCode dscAlarmCode = DSCAlarmCode.getDSCAlarmCodeValue(command);
if (dscAlarmProtocol.equals(DSCAlarmProtocol.IT100_API) && dscAlarmCode.equals(DSCAlarmCode.KeySequence)) {
return sendKeySequence(data);
} else {
return sendCommand(dscAlarmCode, data);
}
}
/**
* Send an API command to the DSC Alarm system.
*
* @param dscAlarmCode
* @param dscAlarmData
* @return successful
*/
public boolean sendCommand(DSCAlarmCode dscAlarmCode, String... dscAlarmData) {
boolean successful = false;
boolean validCommand = false;
String command = dscAlarmCode.getCode();
String data = "";
boolean confidentialData = false;
switch (dscAlarmCode) {
case Poll: /* 000 */
case StatusReport: /* 001 */
validCommand = true;
break;
case LabelsRequest: /* 002 */
if (!dscAlarmProtocol.equals(DSCAlarmProtocol.IT100_API)) {
break;
}
validCommand = true;
break;
case NetworkLogin: /* 005 */
if (!dscAlarmProtocol.equals(DSCAlarmProtocol.ENVISALINK_TPI)) {
break;
}
if (password == null) {
logger.error("sendCommand(): No password!");
break;
}
data = password;
confidentialData = true;
validCommand = true;
break;
case DumpZoneTimers: /* 008 */
if (!dscAlarmProtocol.equals(DSCAlarmProtocol.ENVISALINK_TPI)) {
break;
}
validCommand = true;
break;
case SetTimeDate: /* 010 */
Date date = new Date();
SimpleDateFormat dateTime = new SimpleDateFormat("HHmmMMddYY");
data = dateTime.format(date);
validCommand = true;
break;
case CommandOutputControl: /* 020 */
if (dscAlarmData[0] == null || !dscAlarmData[0].matches("[1-8]")) {
logger.error(
"sendCommand(): Partition number must be a single character string from 1 to 8, it was: {}",
dscAlarmData[0]);
break;
}
if (dscAlarmData[1] == null || !dscAlarmData[1].matches("[1-4]")) {
logger.error(
"sendCommand(): Output number must be a single character string from 1 to 4, it was: {}",
dscAlarmData[1]);
break;
}
data = dscAlarmData[0];
validCommand = true;
break;
case KeepAlive: /* 074 */
if (!dscAlarmProtocol.equals(DSCAlarmProtocol.ENVISALINK_TPI)) {
break;
}
case PartitionArmControlAway: /* 030 */
case PartitionArmControlStay: /* 031 */
case PartitionArmControlZeroEntryDelay: /* 032 */
if (dscAlarmData[0] == null || !dscAlarmData[0].matches("[1-8]")) {
logger.error(
"sendCommand(): Partition number must be a single character string from 1 to 8, it was: {}",
dscAlarmData[0]);
break;
}
data = dscAlarmData[0];
validCommand = true;
break;
case PartitionArmControlWithUserCode: /* 033 */
case PartitionDisarmControl: /* 040 */
if (dscAlarmData[0] == null || !dscAlarmData[0].matches("[1-8]")) {
logger.error(
"sendCommand(): Partition number must be a single character string from 1 to 8, it was: {}",
dscAlarmData[0]);
break;
}
if (userCode == null || userCode.length() < 4 || userCode.length() > 6) {
logger.error("sendCommand(): User Code is invalid, must be between 4 and 6 chars");
break;
}
if (dscAlarmProtocol.equals(DSCAlarmProtocol.IT100_API)) {
data = dscAlarmData[0] + String.format("%-6s", userCode).replace(' ', '0');
} else {
data = dscAlarmData[0] + userCode;
}
confidentialData = true;
validCommand = true;
break;
case VirtualKeypadControl: /* 058 */
if (!dscAlarmProtocol.equals(DSCAlarmProtocol.IT100_API)) {
break;
}
case TimeStampControl: /* 055 */
case TimeDateBroadcastControl: /* 056 */
case TemperatureBroadcastControl: /* 057 */
if (dscAlarmData[0] == null || !dscAlarmData[0].matches("[0-1]")) {
logger.error("sendCommand(): Value must be a single character string of 0 or 1: {}",
dscAlarmData[0]);
break;
}
data = dscAlarmData[0];
validCommand = true;
break;
case TriggerPanicAlarm: /* 060 */
if (dscAlarmData[0] == null || !dscAlarmData[0].matches("[1-3]")) {
logger.error("sendCommand(): FAPcode must be a single character string from 1 to 3, it was: {}",
dscAlarmData[1]);
break;
}
data = dscAlarmData[0];
validCommand = true;
break;
case KeyStroke: /* 070 */
if (dscAlarmProtocol.equals(DSCAlarmProtocol.ENVISALINK_TPI)) {
if (dscAlarmData[0] == null || dscAlarmData[0].length() != 1
|| !dscAlarmData[0].matches("[0-9]|A|#|\\*")) {
logger.error(
"sendCommand(): \'keystroke\' must be a single character string from 0 to 9, *, #, or A, it was: {}",
dscAlarmData[0]);
break;
}
} else if (dscAlarmProtocol.equals(DSCAlarmProtocol.IT100_API)) {
if (dscAlarmData[0] == null || dscAlarmData[0].length() != 1
|| !dscAlarmData[0].matches("[0-9]|\\*|#|F|A|P|[a-e]|<|>|=|\\^|L")) {
logger.error(
"sendCommand(): \'keystroke\' must be a single character string from 0 to 9, *, #, F, A, P, a to e, <, >, =, or ^, it was: {}",
dscAlarmData[0]);
break;
} else if (dscAlarmData[0].equals("L")) { /* Long Key Press */
try {
Thread.sleep(1500);
data = "^";
validCommand = true;
break;
} catch (InterruptedException e) {
logger.error("sendCommand(): \'keystroke\': Error with Long Key Press!");
break;
}
}
} else {
break;
}
data = dscAlarmData[0];
validCommand = true;
break;
case KeySequence: /* 071 */
if (!dscAlarmProtocol.equals(DSCAlarmProtocol.ENVISALINK_TPI)) {
break;
}
if (dscAlarmData[0] == null || dscAlarmData[0].length() > 6
|| !dscAlarmData[0].matches("(\\d|#|\\*)+")) {
logger.error(
"sendCommand(): \'keysequence\' must be a string of up to 6 characters consiting of 0 to 9, *, or #, it was: {}",
dscAlarmData[0]);
break;
}
data = dscAlarmData[0];
validCommand = true;
break;
case CodeSend: /* 200 */
if (userCode == null || userCode.length() < 4 || userCode.length() > 6) {
logger.error("sendCommand(): Access Code is invalid, must be between 4 and 6 chars");
break;
}
data = userCode;
confidentialData = true;
validCommand = true;
break;
default:
validCommand = false;
break;
}
if (validCommand) {
String cmd = dscAlarmCommand(command, data);
write(cmd, confidentialData);
successful = true;
logger.debug("sendCommand(): '{}' Command Sent - {}", dscAlarmCode, confidentialData ? "***" : cmd);
} else {
logger.error("sendCommand(): Command '{}' Not Sent - Invalid!", dscAlarmCode);
}
return successful;
}
private String dscAlarmCommand(String command, String data) {
int sum = 0;
String cmd = command + data;
for (int i = 0; i < cmd.length(); i++) {
char c = cmd.charAt(i);
sum += c;
}
sum &= 0xFF;
String strChecksum = Integer.toHexString(sum >> 4) + Integer.toHexString(sum & 0xF);
return cmd + strChecksum.toUpperCase() + "\r\n";
}
}

View File

@@ -0,0 +1,371 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import static org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants.PANEL_MESSAGE;
import java.util.EventObject;
import java.util.List;
import org.openhab.binding.dscalarm.internal.DSCAlarmCode;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageInfoType;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmPanelConfiguration;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmPartitionConfiguration;
import org.openhab.binding.dscalarm.internal.config.DSCAlarmZoneConfiguration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.Channel;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.openhab.core.thing.ThingStatusInfo;
import org.openhab.core.thing.binding.BaseThingHandler;
import org.openhab.core.thing.binding.ThingHandler;
import org.openhab.core.types.Command;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Abstract class for a DSC Alarm Thing Handler.
*
* @author Russell Stephens - Initial Contribution
*/
public abstract class DSCAlarmBaseThingHandler extends BaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(DSCAlarmBaseThingHandler.class);
/** Bridge Handler for the Thing. */
public DSCAlarmBaseBridgeHandler dscAlarmBridgeHandler = null;
/** DSC Alarm Thing type. */
private DSCAlarmThingType dscAlarmThingType = null;
/** DSC Alarm Properties. */
private boolean thingHandlerInitialized = false;
/** User Code for some DSC Alarm commands. */
private String userCode = null;
/** Suppress Acknowledge messages when received. */
private boolean suppressAcknowledgementMsgs = false;
/** Partition Number. */
private int partitionNumber;
/** Zone Number. */
private int zoneNumber;
/**
* Constructor.
*
* @param thing
*/
public DSCAlarmBaseThingHandler(Thing thing) {
super(thing);
}
@Override
public void initialize() {
logger.debug("Initializing DSC Alarm Thing handler - Thing Type: {}; Thing ID: {}.", dscAlarmThingType,
this.getThing().getUID());
getConfiguration(dscAlarmThingType);
Bridge bridge = getBridge();
initializeThingHandler(bridge != null ? bridge.getStatus() : null);
this.setThingHandlerInitialized(true);
}
@Override
public void dispose() {
logger.debug("Thing {} disposed.", getThing().getUID());
this.setThingHandlerInitialized(false);
super.dispose();
}
/**
* Method to Initialize Thing Handler.
*/
private void initializeThingHandler(ThingStatus bridgeStatus) {
if (getDSCAlarmBridgeHandler() != null && bridgeStatus != null) {
if (bridgeStatus == ThingStatus.ONLINE) {
Thing thing = getThing();
List<Channel> channels = thing.getChannels();
logger.debug("initializeThingHandler(): Initialize Thing Handler - {}", thing.getUID());
for (Channel channel : channels) {
if (channel.getAcceptedItemType().equals("DateTime")) {
updateChannel(channel.getUID(), 0, "0000010100");
} else {
updateChannel(channel.getUID(), 0, "");
}
}
if (dscAlarmThingType.equals(DSCAlarmThingType.PANEL)) {
dscAlarmBridgeHandler.setUserCode(getUserCode());
}
updateStatus(ThingStatus.ONLINE);
logger.debug("initializeThingHandler(): Thing Handler Initialized - {}", thing.getUID());
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
logger.debug("initializeThingHandler(): Thing '{}' is set to OFFLINE because bridge is OFFLINE",
thing.getUID());
}
} else {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
logger.debug("initializeThingHandler(): Thing '{}' is set to OFFLINE because bridge is uninitialized",
thing.getUID());
}
}
/**
* Get the Bridge Handler for the DSC Alarm.
*
* @return dscAlarmBridgeHandler
*/
public synchronized DSCAlarmBaseBridgeHandler getDSCAlarmBridgeHandler() {
if (this.dscAlarmBridgeHandler == null) {
Bridge bridge = getBridge();
if (bridge == null) {
logger.debug("getDSCAlarmBridgeHandler(): Unable to get bridge!");
return null;
}
logger.debug("getDSCAlarmBridgeHandler(): Bridge for '{}' - '{}'", getThing().getUID(), bridge.getUID());
ThingHandler handler = bridge.getHandler();
if (handler instanceof DSCAlarmBaseBridgeHandler) {
this.dscAlarmBridgeHandler = (DSCAlarmBaseBridgeHandler) handler;
} else {
logger.debug("getDSCAlarmBridgeHandler(): Unable to get bridge handler!");
}
}
return this.dscAlarmBridgeHandler;
}
/**
* Method to Update a Channel
*
* @param channel
* @param state
* @param description
*/
public abstract void updateChannel(ChannelUID channel, int state, String description);
/**
* Receives DSC Alarm Events from the bridge.
*
* @param event.
* @param thing
*/
public abstract void dscAlarmEventReceived(EventObject event, Thing thing);
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
}
@Override
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
logger.debug("bridgeStatusChanged(): Bridge Status: '{}' - Thing '{}' Status: '{}'!", bridgeStatusInfo,
getThing().getUID(), getThing().getStatus());
initializeThingHandler(bridgeStatusInfo.getStatus());
}
/**
* Get the thing configuration.
*
* @param dscAlarmDeviceType
*/
private void getConfiguration(DSCAlarmThingType dscAlarmDeviceType) {
switch (dscAlarmDeviceType) {
case PANEL:
DSCAlarmPanelConfiguration panelConfiguration = getConfigAs(DSCAlarmPanelConfiguration.class);
setUserCode(panelConfiguration.userCode);
setSuppressAcknowledgementMsgs(panelConfiguration.suppressAcknowledgementMsgs);
break;
case PARTITION:
DSCAlarmPartitionConfiguration partitionConfiguration = getConfigAs(
DSCAlarmPartitionConfiguration.class);
setPartitionNumber(partitionConfiguration.partitionNumber.intValue());
break;
case ZONE:
DSCAlarmZoneConfiguration zoneConfiguration = getConfigAs(DSCAlarmZoneConfiguration.class);
setPartitionNumber(zoneConfiguration.partitionNumber.intValue());
setZoneNumber(zoneConfiguration.zoneNumber.intValue());
break;
case KEYPAD:
default:
break;
}
}
/**
* Get the DSC Alarm Thing type.
*
* @return dscAlarmThingType
*/
public DSCAlarmThingType getDSCAlarmThingType() {
return dscAlarmThingType;
}
/**
* Set the DSC Alarm Thing type.
*
* @param dscAlarmDeviceType
*/
public void setDSCAlarmThingType(DSCAlarmThingType dscAlarmDeviceType) {
if (dscAlarmDeviceType == null) {
String thingType = getThing().getThingTypeUID().toString().split(":")[1];
this.dscAlarmThingType = DSCAlarmThingType.getDSCAlarmThingType(thingType);
} else {
this.dscAlarmThingType = dscAlarmDeviceType;
}
}
/**
* Get suppressAcknowledgementMsgs.
*
* @return suppressAcknowledgementMsgs
*/
public boolean getSuppressAcknowledgementMsgs() {
return suppressAcknowledgementMsgs;
}
/**
* Set suppressAcknowledgementMsgs.
*
* @param suppressAckMsgs
*/
public void setSuppressAcknowledgementMsgs(boolean suppressAckMsgs) {
this.suppressAcknowledgementMsgs = suppressAckMsgs;
}
/**
* Get Partition Number.
*
* @return partitionNumber
*/
public int getPartitionNumber() {
return partitionNumber;
}
/**
* Set Partition Number.
*
* @param partitionNumber
*/
public void setPartitionNumber(int partitionNumber) {
this.partitionNumber = partitionNumber;
}
/**
* Get Zone Number.
*
* @return zoneNumber
*/
public int getZoneNumber() {
return zoneNumber;
}
/**
* Set Zone Number.
*
* @param zoneNumber
*/
public void setZoneNumber(int zoneNumber) {
this.zoneNumber = zoneNumber;
}
/**
* Get User Code.
*
* @return userCode
*/
public String getUserCode() {
return userCode;
}
/**
* Set User Code.
*
* @param userCode
*/
public void setUserCode(String userCode) {
this.userCode = userCode;
}
/**
* Get Channel by ChannelUID.
*
* @param channelUID
*/
public Channel getChannel(ChannelUID channelUID) {
Channel channel = null;
List<Channel> channels = getThing().getChannels();
for (Channel ch : channels) {
if (channelUID == ch.getUID()) {
channel = ch;
break;
}
}
return channel;
}
/**
* Get Thing Handler refresh status.
*
* @return thingRefresh
*/
public boolean isThingHandlerInitialized() {
return thingHandlerInitialized;
}
/**
* Set Thing Handler refresh status.
*
* @param deviceInitialized
*/
public void setThingHandlerInitialized(boolean refreshed) {
this.thingHandlerInitialized = refreshed;
}
/**
* Method to set the panel message.
*
* @param dscAlarmMessage
*/
public void setPanelMessage(DSCAlarmMessage dscAlarmMessage) {
ChannelUID channelUID = new ChannelUID(getThing().getUID(), PANEL_MESSAGE);
String message = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DESCRIPTION);
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
if ((dscAlarmCode == DSCAlarmCode.CommandAcknowledge || dscAlarmCode == DSCAlarmCode.TimeDateBroadcast)
&& getSuppressAcknowledgementMsgs()) {
return;
} else {
updateChannel(channelUID, 0, message);
logger.debug("setPanelMessage(): Panel Message Set to - {}", message);
}
}
}

View File

@@ -0,0 +1,24 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
/**
* Enum class for the different bridge types.
*
* @author Russell Stephens - Initial Contribution
*/
public enum DSCAlarmBridgeType {
Envisalink,
IT100,
TCPServer
}

View File

@@ -0,0 +1,23 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
/**
* Enum class for the different DSC Alarm Protocol types.
*
* @author Russell Stephens - Initial Contribution
*/
public enum DSCAlarmProtocol {
ENVISALINK_TPI,
IT100_API
}

View File

@@ -0,0 +1,76 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import java.util.HashMap;
import java.util.Map;
/**
* Used to map thing types from the binding string to a ENUM value.
*
* @author Russell Stephens - Initial Contribution
*/
public enum DSCAlarmThingType {
PANEL("panel"),
PARTITION("partition"),
ZONE("zone"),
KEYPAD("keypad");
private String label;
/**
* Lookup map to get a DSCAlarmDeviceType from its label.
*/
private static Map<String, DSCAlarmThingType> labelToDSCAlarmThingType;
/**
* Constructor.
*
* @param label
*/
private DSCAlarmThingType(String label) {
this.label = label;
}
/**
* Creates a HashMap that maps the string label to a DSCAlarmDeviceType enum value.
*/
private static void initMapping() {
labelToDSCAlarmThingType = new HashMap<>();
for (DSCAlarmThingType s : values()) {
labelToDSCAlarmThingType.put(s.label, s);
}
}
/**
* Returns the label of the DSCAlarmItemType Values enumeration.
*
* @return the label
*/
public String getLabel() {
return label;
}
/**
* Lookup function based on the binding type label. Returns null if the binding type is not found.
*
* @param label
* @return enum value
*/
public static DSCAlarmThingType getDSCAlarmThingType(String label) {
if (labelToDSCAlarmThingType == null) {
initMapping();
}
return labelToDSCAlarmThingType.get(label);
}
}

View File

@@ -0,0 +1,212 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import org.openhab.binding.dscalarm.internal.config.EnvisalinkBridgeConfiguration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The bridge handler for the EyezOn Envisalink 3/2DS Ethernet interface.
*
* @author Russell Stephens - Initial Contribution
*/
public class EnvisalinkBridgeHandler extends DSCAlarmBaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(EnvisalinkBridgeHandler.class);
/**
* Constructor.
*
* @param bridge
*/
public EnvisalinkBridgeHandler(Bridge bridge) {
super(bridge, DSCAlarmBridgeType.Envisalink, DSCAlarmProtocol.ENVISALINK_TPI);
}
// Variables for TCP connection.
private String ipAddress;
private int tcpPort;
private int connectionTimeout;
private Socket tcpSocket = null;
private OutputStreamWriter tcpOutput = null;
private BufferedReader tcpInput = null;
@Override
public void initialize() {
logger.debug("Initializing the Envisalink Bridge handler.");
EnvisalinkBridgeConfiguration configuration = getConfigAs(EnvisalinkBridgeConfiguration.class);
if (configuration.ipAddress == null || configuration.ipAddress.trim().isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Set an IP address in the thing configuration.");
} else if (configuration.port == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Set a TCP port in the thing configuration.");
} else {
ipAddress = configuration.ipAddress.trim();
tcpPort = configuration.port.intValue();
setPassword(configuration.password);
connectionTimeout = configuration.connectionTimeout.intValue();
pollPeriod = configuration.pollPeriod.intValue();
super.initialize();
logger.debug("Envisalink Bridge Handler Initialized");
logger.debug(" IP Address: {},", ipAddress);
logger.debug(" Port: {},", tcpPort);
logger.debug(" PollPeriod: {},", pollPeriod);
logger.debug(" Connection Timeout: {}.", connectionTimeout);
}
}
@Override
public void openConnection() {
try {
closeConnection();
logger.debug("openConnection(): Connecting to Envisalink ");
tcpSocket = new Socket();
SocketAddress tpiSocketAddress = new InetSocketAddress(ipAddress, tcpPort);
tcpSocket.connect(tpiSocketAddress, connectionTimeout);
tcpOutput = new OutputStreamWriter(tcpSocket.getOutputStream(), "US-ASCII");
tcpInput = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
Thread tcpListener = new Thread(new TCPListener());
tcpListener.start();
setConnected(true);
} catch (UnknownHostException unknownHostException) {
logger.error("openConnection(): Unknown Host Exception: {}", unknownHostException.getMessage());
setConnected(false);
} catch (SocketException socketException) {
logger.error("openConnection(): Socket Exception: {}", socketException.getMessage());
setConnected(false);
} catch (IOException ioException) {
logger.error("openConnection(): IO Exception: {}", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("openConnection(): Unable to open a connection: {} ", exception.getMessage(), exception);
setConnected(false);
}
}
@Override
public void write(String writeString, boolean doNotLog) {
try {
logger.debug("write(): Attempting to Send Message: {}", doNotLog ? "***" : writeString);
tcpOutput.write(writeString);
tcpOutput.flush();
} catch (IOException ioException) {
logger.error("write(): {}", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("write(): Unable to write to socket: {} ", exception.getMessage(), exception);
setConnected(false);
}
}
@Override
public String read() {
String message = "";
try {
message = tcpInput.readLine();
logger.debug("read(): Message Received: {}", message);
} catch (IOException ioException) {
logger.error("read(): IO Exception: {}", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("read(): Exception: {} ", exception.getMessage(), exception);
setConnected(false);
}
return message;
}
@Override
public void closeConnection() {
try {
if (tcpSocket != null) {
logger.debug("closeConnection(): Closing Socket!");
tcpSocket.close();
tcpSocket = null;
tcpInput = null;
tcpOutput = null;
}
setConnected(false);
logger.debug("closeConnection(): Closed TCP Connection!");
} catch (IOException ioException) {
logger.error("closeConnection(): Unable to close connection - {}", ioException.getMessage());
} catch (Exception exception) {
logger.error("closeConnection(): Error closing connection - {}", exception.getMessage());
}
}
/**
* Gets the IP Address of the Envisalink
*
* @return ipAddress
*/
public String getIPAddress() {
return ipAddress;
}
/**
* TCPMessageListener: Receives messages from the DSC Alarm Panel API.
*/
private class TCPListener implements Runnable {
private final Logger logger = LoggerFactory.getLogger(TCPListener.class);
/**
* Run method. Runs the MessageListener thread
*/
@Override
public void run() {
String messageLine;
try {
while (isConnected()) {
if ((messageLine = read()) != null) {
try {
handleIncomingMessage(messageLine);
} catch (Exception e) {
logger.error("TCPListener(): Message not handled by bridge: {}", e.getMessage());
}
} else {
setConnected(false);
}
}
} catch (Exception e) {
logger.error("TCPListener(): Unable to read message: {} ", e.getMessage(), e);
closeConnection();
}
}
}
}

View File

@@ -0,0 +1,244 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.TooManyListenersException;
import org.openhab.binding.dscalarm.internal.config.IT100BridgeConfiguration;
import org.openhab.core.io.transport.serial.PortInUseException;
import org.openhab.core.io.transport.serial.SerialPort;
import org.openhab.core.io.transport.serial.SerialPortEvent;
import org.openhab.core.io.transport.serial.SerialPortEventListener;
import org.openhab.core.io.transport.serial.SerialPortIdentifier;
import org.openhab.core.io.transport.serial.SerialPortManager;
import org.openhab.core.io.transport.serial.UnsupportedCommOperationException;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The bridge handler for the DSC IT100 RS232 Serial interface.
*
* @author Russell Stephens - Initial Contribution
*/
public class IT100BridgeHandler extends DSCAlarmBaseBridgeHandler implements SerialPortEventListener {
private final Logger logger = LoggerFactory.getLogger(IT100BridgeHandler.class);
private final SerialPortManager serialPortManager;
private String serialPortName = "";
private int baudRate;
private SerialPort serialPort = null;
private OutputStreamWriter serialOutput = null;
private BufferedReader serialInput = null;
public IT100BridgeHandler(Bridge bridge, SerialPortManager serialPortManager) {
super(bridge, DSCAlarmBridgeType.IT100, DSCAlarmProtocol.IT100_API);
this.serialPortManager = serialPortManager;
}
@Override
public void initialize() {
logger.debug("Initializing the DSC IT100 Bridge handler.");
IT100BridgeConfiguration configuration = getConfigAs(IT100BridgeConfiguration.class);
if (configuration.serialPort == null || configuration.serialPort.trim().isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Set a serial port in the thing configuration.");
} else {
serialPortName = configuration.serialPort.trim();
baudRate = configuration.baud.intValue();
pollPeriod = configuration.pollPeriod.intValue();
super.initialize();
logger.debug("IT100 Bridge Handler Initialized.");
logger.debug(" Serial Port: {},", serialPortName);
logger.debug(" Baud: {},", baudRate);
logger.debug(" PollPeriod: {},", pollPeriod);
}
}
@Override
public void openConnection() {
logger.debug("openConnection(): Connecting to IT-100");
SerialPortIdentifier portIdentifier = serialPortManager.getIdentifier(serialPortName);
if (portIdentifier == null) {
logger.error("openConnection(): No Such Port: {}", serialPort);
setConnected(false);
return;
}
try {
SerialPort commPort = portIdentifier.open(this.getClass().getName(), 2000);
serialPort = commPort;
serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
serialPort.enableReceiveThreshold(1);
serialPort.disableReceiveTimeout();
serialOutput = new OutputStreamWriter(serialPort.getOutputStream(), "US-ASCII");
serialInput = new BufferedReader(new InputStreamReader(serialPort.getInputStream()));
setSerialEventHandler(this);
setConnected(true);
} catch (PortInUseException portInUseException) {
logger.error("openConnection(): Port in Use Exception: {}", portInUseException.getMessage());
setConnected(false);
} catch (UnsupportedCommOperationException unsupportedCommOperationException) {
logger.error("openConnection(): Unsupported Comm Operation Exception: {}",
unsupportedCommOperationException.getMessage());
setConnected(false);
} catch (UnsupportedEncodingException unsupportedEncodingException) {
logger.error("openConnection(): Unsupported Encoding Exception: {}",
unsupportedEncodingException.getMessage());
setConnected(false);
} catch (IOException ioException) {
logger.error("openConnection(): IO Exception: {}", ioException.getMessage());
setConnected(false);
}
}
@Override
public void write(String writeString, boolean doNotLog) {
try {
serialOutput.write(writeString);
serialOutput.flush();
logger.debug("write(): Message Sent: {}", doNotLog ? "***" : writeString);
} catch (IOException ioException) {
logger.error("write(): {}", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("write(): Unable to write to serial port: {} ", exception.getMessage(), exception);
setConnected(false);
}
}
@Override
public String read() {
String message = "";
try {
message = readLine();
logger.debug("read(): Message Received: {}", message);
} catch (IOException ioException) {
logger.error("read(): IO Exception: {} ", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("read(): Exception: {} ", exception.getMessage(), exception);
setConnected(false);
}
return message;
}
/**
* Read a line from the Input Stream.
*
* @return
* @throws IOException
*/
private String readLine() throws IOException {
return serialInput.readLine();
}
@Override
public void closeConnection() {
logger.debug("closeConnection(): Closing Serial Connection!");
if (serialPort == null) {
setConnected(false);
return;
}
serialPort.removeEventListener();
if (serialInput != null) {
try {
serialInput.close();
} catch (IOException e) {
logger.debug("Error while closing the input stream: {}", e.getMessage());
}
serialInput = null;
}
if (serialOutput != null) {
try {
serialOutput.close();
} catch (IOException e) {
logger.debug("Error while closing the output stream: {}", e.getMessage());
}
serialOutput = null;
}
serialPort.close();
serialPort = null;
setConnected(false);
logger.debug("close(): Serial Connection Closed!");
}
/**
* Gets the Serial Port Name of the IT-100
*
* @return serialPortName
*/
public String getSerialPortName() {
return serialPortName;
}
/**
* Receives Serial Port Events and reads Serial Port Data.
*
* @param serialPortEvent
*/
@Override
public synchronized void serialEvent(SerialPortEvent serialPortEvent) {
if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
try {
String messageLine = serialInput.readLine();
handleIncomingMessage(messageLine);
} catch (IOException ioException) {
logger.error("serialEvent(): IO Exception: {}", ioException.getMessage());
}
}
}
/**
* Set the serial event handler.
*
* @param serialPortEventListenser
*/
private void setSerialEventHandler(SerialPortEventListener serialPortEventListenser) {
try {
// Add the serial port event listener
serialPort.addEventListener(serialPortEventListenser);
serialPort.notifyOnDataAvailable(true);
} catch (TooManyListenersException tooManyListenersException) {
logger.error("setSerialEventHandler(): Too Many Listeners Exception: {}",
tooManyListenersException.getMessage());
}
}
}

View File

@@ -0,0 +1,213 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import static org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants.*;
import java.util.EventObject;
import org.openhab.binding.dscalarm.internal.DSCAlarmCode;
import org.openhab.binding.dscalarm.internal.DSCAlarmEvent;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageInfoType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a class for handling a Zone type Thing.
*
* @author Russell Stephens - Initial Contribution
*/
public class KeypadThingHandler extends DSCAlarmBaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(KeypadThingHandler.class);
/**
* Constructor.
*
* @param thing
*/
public KeypadThingHandler(Thing thing) {
super(thing);
setDSCAlarmThingType(DSCAlarmThingType.KEYPAD);
}
@Override
public void updateChannel(ChannelUID channelUID, int state, String description) {
logger.debug("updateChannel(): Keypad Channel UID: {}", channelUID);
if (channelUID != null) {
switch (channelUID.getId()) {
case KEYPAD_READY_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_ARMED_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_MEMORY_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_BYPASS_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_TROUBLE_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_PROGRAM_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_FIRE_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_BACKLIGHT_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_AC_LED:
updateState(channelUID, new DecimalType(state));
break;
case KEYPAD_LCD_UPDATE:
case KEYPAD_LCD_CURSOR:
updateState(channelUID, new StringType(description));
break;
default:
logger.debug("updateChannel(): Keypad Channel not updated - {}.", channelUID);
break;
}
}
}
/**
* Handle Keypad LED events for the EyezOn Envisalink 3/2DS DSC Alarm Interface
*
* @param event
*/
private void keypadLEDStateEventHandler(EventObject event) {
DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event;
DSCAlarmMessage dscAlarmMessage = dscAlarmEvent.getDSCAlarmMessage();
String[] channelTypes = { KEYPAD_READY_LED, KEYPAD_ARMED_LED, KEYPAD_MEMORY_LED, KEYPAD_BYPASS_LED,
KEYPAD_TROUBLE_LED, KEYPAD_PROGRAM_LED, KEYPAD_FIRE_LED, KEYPAD_BACKLIGHT_LED };
String channel;
ChannelUID channelUID = null;
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
int bitField = Integer.decode("0x" + dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA));
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];
channel = channelTypes[i];
if (channel != "") {
channelUID = new ChannelUID(getThing().getUID(), channel);
switch (dscAlarmCode) {
case KeypadLEDState: /* 510 */
updateChannel(channelUID, bits[i] != 0 ? 1 : 0, "");
break;
case KeypadLEDFlashState: /* 511 */
if (bits[i] != 0) {
updateChannel(channelUID, 2, "");
}
break;
default:
break;
}
}
}
}
@Override
public void dscAlarmEventReceived(EventObject event, Thing thing) {
if (thing != null) {
if (getThing() == thing) {
DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event;
DSCAlarmMessage dscAlarmMessage = dscAlarmEvent.getDSCAlarmMessage();
ChannelUID channelUID = null;
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
String dscAlarmMessageData = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA);
logger.debug("dscAlarmEventRecieved(): Thing - {} Command - {}", thing.getUID(), dscAlarmCode);
switch (dscAlarmCode) {
case KeypadLEDState: /* 510 */
case KeypadLEDFlashState: /* 511 */
keypadLEDStateEventHandler(event);
break;
case LCDUpdate: /* 901 */
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_LCD_UPDATE);
updateChannel(channelUID, 0, dscAlarmMessageData);
break;
case LCDCursor: /* 902 */
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_LCD_CURSOR);
updateChannel(channelUID, 0, dscAlarmMessageData);
break;
case LEDStatus: /* 903 */
int data = Integer.parseInt(dscAlarmMessageData.substring(0, 1));
int state = Integer
.parseInt(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA).substring(1));
switch (data) {
case 1:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_READY_LED);
updateChannel(channelUID, state, "");
break;
case 2:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_ARMED_LED);
updateChannel(channelUID, state, "");
break;
case 3:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_MEMORY_LED);
updateChannel(channelUID, state, "");
break;
case 4:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_BYPASS_LED);
updateChannel(channelUID, state, "");
break;
case 5:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_TROUBLE_LED);
updateChannel(channelUID, state, "");
break;
case 6:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_PROGRAM_LED);
updateChannel(channelUID, state, "");
break;
case 7:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_FIRE_LED);
updateChannel(channelUID, state, "");
break;
case 8:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_BACKLIGHT_LED);
updateChannel(channelUID, state, "");
break;
case 9:
channelUID = new ChannelUID(getThing().getUID(), KEYPAD_AC_LED);
updateChannel(channelUID, state, "");
break;
default:
break;
}
default:
break;
}
}
}
}
}

View File

@@ -0,0 +1,585 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import static org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.EventObject;
import java.util.List;
import org.openhab.binding.dscalarm.internal.DSCAlarmCode;
import org.openhab.binding.dscalarm.internal.DSCAlarmEvent;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageInfoType;
import org.openhab.core.library.types.DateTimeType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a class for handling a Panel type Thing.
*
* @author Russell Stephens - Initial Contribution
*/
public class PanelThingHandler extends DSCAlarmBaseThingHandler {
private static final int PANEL_COMMAND_POLL = 0;
private static final int PANEL_COMMAND_STATUS_REPORT = 1;
private static final int PANEL_COMMAND_LABELS_REQUEST = 2;
private static final int PANEL_COMMAND_DUMP_ZONE_TIMERS = 8;
private static final int PANEL_COMMAND_SET_TIME_DATE = 10;
private static final int PANEL_COMMAND_CODE_SEND = 200;
private final Logger logger = LoggerFactory.getLogger(PanelThingHandler.class);
/**
* Constructor.
*
* @param thing
*/
public PanelThingHandler(Thing thing) {
super(thing);
setDSCAlarmThingType(DSCAlarmThingType.PANEL);
}
@Override
public void updateChannel(ChannelUID channelUID, int state, String description) {
logger.debug("updateChannel(): Panel Channel UID: {}", channelUID);
boolean trigger;
boolean trouble;
boolean boolState;
OnOffType onOffType;
if (channelUID != null) {
switch (channelUID.getId()) {
case PANEL_MESSAGE:
updateState(channelUID, new StringType(description));
break;
case PANEL_SYSTEM_ERROR:
updateState(channelUID, new StringType(description));
break;
case PANEL_TIME:
Date date = null;
SimpleDateFormat sdfReceived = new SimpleDateFormat("hhmmMMddyy");
try {
date = sdfReceived.parse(description);
} catch (ParseException e) {
logger.warn("updateChannel(): Parse Exception occurred while trying to parse date string: {}. ",
e.getMessage());
}
if (date != null) {
SimpleDateFormat sdfUpdate = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
String systemTime = sdfUpdate.format(date);
updateState(channelUID, new DateTimeType(systemTime));
}
break;
case PANEL_TIME_STAMP:
boolState = state != 0;
onOffType = boolState ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_TIME_BROADCAST:
boolState = state != 0;
onOffType = boolState ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_COMMAND:
updateState(channelUID, new DecimalType(state));
break;
case PANEL_TROUBLE_MESSAGE:
updateState(channelUID, new StringType(description));
break;
case PANEL_TROUBLE_LED:
boolState = state != 0;
onOffType = boolState ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_SERVICE_REQUIRED:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_AC_TROUBLE:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_TELEPHONE_TROUBLE:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_FTC_TROUBLE:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_ZONE_FAULT:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_ZONE_TAMPER:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_ZONE_LOW_BATTERY:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_TIME_LOSS:
trouble = state != 0;
onOffType = trouble ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_FIRE_KEY_ALARM:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_PANIC_KEY_ALARM:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_AUX_KEY_ALARM:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PANEL_AUX_INPUT_ALARM:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
default:
logger.debug("updateChannel(): Panel Channel not updated - {}.", channelUID);
break;
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("handleCommand(): Command Received - {} {}.", channelUID, command);
if (command instanceof RefreshType) {
return;
}
if (dscAlarmBridgeHandler != null && dscAlarmBridgeHandler.isConnected()) {
int cmd;
switch (channelUID.getId()) {
case PANEL_COMMAND:
cmd = Integer.parseInt(command.toString());
handlePanelCommand(cmd);
updateState(channelUID, new StringType(String.valueOf(-1)));
break;
case PANEL_TIME_STAMP:
if (command instanceof OnOffType) {
cmd = command == OnOffType.ON ? 1 : 0;
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.TimeStampControl, String.valueOf(cmd));
updateState(channelUID, (OnOffType) command);
}
break;
case PANEL_TIME_BROADCAST:
if (command instanceof OnOffType) {
cmd = command == OnOffType.ON ? 1 : 0;
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.TimeDateBroadcastControl, String.valueOf(cmd));
updateState(channelUID, (OnOffType) command);
}
break;
default:
break;
}
}
}
/**
* Method to handle PANEL_COMMAND
*
* @param cmd
*/
private void handlePanelCommand(int cmd) {
switch (cmd) {
case PANEL_COMMAND_POLL:
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.Poll);
break;
case PANEL_COMMAND_STATUS_REPORT:
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.StatusReport);
break;
case PANEL_COMMAND_LABELS_REQUEST:
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.LabelsRequest);
break;
case PANEL_COMMAND_DUMP_ZONE_TIMERS:
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.DumpZoneTimers);
break;
case PANEL_COMMAND_SET_TIME_DATE:
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.SetTimeDate);
break;
case PANEL_COMMAND_CODE_SEND:
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.CodeSend, getUserCode());
break;
default:
break;
}
}
/**
* Method to set the time stamp state.
*
* @param timeStamp
*/
private void setTimeStampState(String timeStamp) {
int state = 0;
ChannelUID channelUID = new ChannelUID(getThing().getUID(), PANEL_TIME_STAMP);
boolean isTimeStamp = timeStamp != "";
if ((timeStamp == "" && !isTimeStamp) || (timeStamp != "" && isTimeStamp)) {
logger.debug("setTimeStampState(): Already Set: {}", timeStamp);
return;
} else if (timeStamp != "") {
state = 1;
}
updateChannel(channelUID, state, "");
}
/**
* Method to set Channel PANEL_SYSTEM_ERROR.
*
* @param properties
* @param dscAlarmMessage
*/
private void panelSystemError(DSCAlarmMessage dscAlarmMessage) {
ChannelUID channelUID = new ChannelUID(getThing().getUID(), PANEL_SYSTEM_ERROR);
int systemErrorCode = 0;
String systemErrorDescription = "";
if (dscAlarmMessage != null) {
systemErrorCode = Integer.parseInt(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA));
switch (systemErrorCode) {
case 1:
systemErrorDescription = "Receive Buffer Overrun";
break;
case 2:
systemErrorDescription = "Receive Buffer Overflow";
break;
case 3:
systemErrorDescription = "Transmit Buffer Overflow";
break;
case 10:
systemErrorDescription = "Keybus Transmit Buffer Overrun";
break;
case 11:
systemErrorDescription = "Keybus Transmit Time Timeout";
break;
case 12:
systemErrorDescription = "Keybus Transmit Mode Timeout";
break;
case 13:
systemErrorDescription = "Keybus Transmit Keystring Timeout";
break;
case 14:
systemErrorDescription = "Keybus Interface Not Functioning";
break;
case 15:
systemErrorDescription = "Keybus Busy - Attempting to Disarm or Arm with user code";
break;
case 16:
systemErrorDescription = "Keybus Busy Lockout";
break;
case 17:
systemErrorDescription = "Keybus Busy Installers Mode";
break;
case 18:
systemErrorDescription = "Keybus Busy - General Busy";
break;
case 20:
systemErrorDescription = "API Command Syntax Error";
break;
case 21:
systemErrorDescription = "API Command Partition Error - Requested Partition is out of bounds";
break;
case 22:
systemErrorDescription = "API Command Not Supported";
break;
case 23:
systemErrorDescription = "API System Not Armed - Sent in response to a disarm command";
break;
case 24:
systemErrorDescription = "API System Not Ready to Arm - System is either not-secure, in exit-delay, or already armed";
break;
case 25:
systemErrorDescription = "API Command Invalid Length";
break;
case 26:
systemErrorDescription = "API User Code not Required";
break;
case 27:
systemErrorDescription = "API Invalid Characters in Command - No alpha characters are allowed except for checksum";
break;
case 28:
systemErrorDescription = "API Virtual Keypad is Disabled";
break;
case 29:
systemErrorDescription = "API Not Valid Parameter";
break;
case 30:
systemErrorDescription = "API Keypad Does Not Come Out of Blank Mode";
break;
case 31:
systemErrorDescription = "API IT-100 is Already in Thermostat Menu";
break;
case 32:
systemErrorDescription = "API IT-100 is NOT in Thermostat Menu";
break;
case 33:
systemErrorDescription = "API No Response From Thermostat or Escort Module";
break;
case 0:
default:
systemErrorDescription = "No Error";
break;
}
}
String errorMessage = String.format("%03d", systemErrorCode) + ": " + systemErrorDescription;
channelUID = new ChannelUID(getThing().getUID(), PANEL_SYSTEM_ERROR);
updateState(channelUID, new StringType(errorMessage));
}
/**
* 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;
DSCAlarmMessage dscAlarmMessage = dscAlarmEvent.getDSCAlarmMessage();
String[] channelTypes = { PANEL_SERVICE_REQUIRED, PANEL_AC_TROUBLE, PANEL_TELEPHONE_TROUBLE, PANEL_FTC_TROUBLE,
PANEL_ZONE_FAULT, PANEL_ZONE_TAMPER, PANEL_ZONE_LOW_BATTERY, PANEL_TIME_LOSS };
String channel;
ChannelUID channelUID = null;
int bitField = Integer.decode("0x" + dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA));
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];
channel = channelTypes[i];
if (channel != "") {
channelUID = new ChannelUID(getThing().getUID(), channel);
updateChannel(channelUID, bits[i] != 0 ? 1 : 0, "");
}
}
}
/**
* Restores all partitions that are in alarm after special panel alarm conditions have been restored.
*
* @param dscAlarmCode
*/
private void restorePartitionsInAlarm(DSCAlarmCode dscAlarmCode) {
logger.debug("restorePartitionsInAlarm(): DSC Alarm Code: {}!", dscAlarmCode.toString());
ChannelUID channelUID = null;
if (dscAlarmCode == DSCAlarmCode.FireKeyRestored || dscAlarmCode == DSCAlarmCode.AuxiliaryKeyRestored
|| dscAlarmCode == DSCAlarmCode.PanicKeyRestored
|| dscAlarmCode == DSCAlarmCode.AuxiliaryInputAlarmRestored) {
List<Thing> things = dscAlarmBridgeHandler.getThing().getThings();
for (Thing thg : things) {
if (thg.getThingTypeUID().equals(PARTITION_THING_TYPE)) {
DSCAlarmBaseThingHandler handler = (DSCAlarmBaseThingHandler) thg.getHandler();
if (handler != null) {
channelUID = new ChannelUID(thg.getUID(), PARTITION_IN_ALARM);
handler.updateChannel(channelUID, 0, "");
logger.debug("restorePartitionsInAlarm(): Partition In Alarm Restored: {}!", thg.getUID());
}
}
}
}
}
@Override
public void dscAlarmEventReceived(EventObject event, Thing thing) {
if (thing != null) {
DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event;
DSCAlarmMessage dscAlarmMessage = dscAlarmEvent.getDSCAlarmMessage();
String dscAlarmMessageData = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA);
setTimeStampState(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.TIME_STAMP));
if (getThing() == thing) {
ChannelUID channelUID = null;
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
logger.debug("dscAlarmEventRecieved(): Thing - {} Command - {}", thing.getUID(), dscAlarmCode);
int state = 0;
switch (dscAlarmCode) {
case CommandAcknowledge: /* 500 */
break;
case SystemError: /* 502 */
int errorCode = Integer.parseInt(dscAlarmMessageData);
if (errorCode == 23 || errorCode == 24) {
List<Thing> things = dscAlarmBridgeHandler.getThing().getThings();
for (Thing thg : things) {
if (thg.getThingTypeUID().equals(PARTITION_THING_TYPE)) {
DSCAlarmBaseThingHandler handler = (DSCAlarmBaseThingHandler) thg.getHandler();
if (handler != null) {
channelUID = new ChannelUID(thg.getUID(), PARTITION_ARM_MODE);
handler.updateChannel(channelUID, 0, "");
}
}
}
}
panelSystemError(dscAlarmMessage);
break;
case TimeDateBroadcast: /* 550 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_TIME);
String panelTime = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DATA);
updateChannel(channelUID, state, panelTime);
channelUID = new ChannelUID(getThing().getUID(), PANEL_TIME_BROADCAST);
updateChannel(channelUID, 1, "");
break;
case FireKeyAlarm: /* 621 */
state = 1;
case FireKeyRestored: /* 622 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_FIRE_KEY_ALARM);
updateChannel(channelUID, state, "");
restorePartitionsInAlarm(dscAlarmCode);
break;
case AuxiliaryKeyAlarm: /* 623 */
state = 1;
case AuxiliaryKeyRestored: /* 624 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_AUX_KEY_ALARM);
updateChannel(channelUID, state, "");
restorePartitionsInAlarm(dscAlarmCode);
break;
case PanicKeyAlarm: /* 625 */
state = 1;
case PanicKeyRestored: /* 626 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_PANIC_KEY_ALARM);
updateChannel(channelUID, state, "");
restorePartitionsInAlarm(dscAlarmCode);
break;
case AuxiliaryInputAlarm: /* 631 */
state = 1;
case AuxiliaryInputAlarmRestored: /* 632 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_AUX_INPUT_ALARM);
updateChannel(channelUID, state, "");
restorePartitionsInAlarm(dscAlarmCode);
break;
case TroubleLEDOn: /* 840 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_TROUBLE_LED);
updateChannel(channelUID, 1, "");
break;
case TroubleLEDOff: /* 841 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_SERVICE_REQUIRED);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_AC_TROUBLE);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_TELEPHONE_TROUBLE);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_FTC_TROUBLE);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_ZONE_FAULT);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_ZONE_TAMPER);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_ZONE_LOW_BATTERY);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_TIME_LOSS);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PANEL_TROUBLE_LED);
updateChannel(channelUID, 0, "");
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 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_TROUBLE_MESSAGE);
updateChannel(channelUID, 0,
dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DESCRIPTION));
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 */
channelUID = new ChannelUID(getThing().getUID(), PANEL_TROUBLE_MESSAGE);
updateChannel(channelUID, 0, "");
break;
case VerboseTroubleStatus: /* 849 */
verboseTroubleStatusHandler(event);
break;
case CodeRequired: /* 900 */
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.CodeSend, getUserCode());
break;
default:
break;
}
}
}
}
}

View File

@@ -0,0 +1,277 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import static org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants.*;
import java.util.EventObject;
import org.openhab.binding.dscalarm.internal.DSCAlarmCode;
import org.openhab.binding.dscalarm.internal.DSCAlarmEvent;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageInfoType;
import org.openhab.core.library.types.DecimalType;
import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.StringType;
import org.openhab.core.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a class for handling a Partition type Thing.
*
* @author Russell Stephens - Initial Contribution
*/
public class PartitionThingHandler extends DSCAlarmBaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(PartitionThingHandler.class);
/**
* Constructor.
*
* @param thing
*/
public PartitionThingHandler(Thing thing) {
super(thing);
setDSCAlarmThingType(DSCAlarmThingType.PARTITION);
}
@Override
public void updateChannel(ChannelUID channelUID, int state, String description) {
logger.debug("updateChannel(): Panel Channel UID: {}", channelUID);
boolean trigger;
OnOffType onOffType;
if (channelUID != null) {
switch (channelUID.getId()) {
case PARTITION_STATUS:
updateState(channelUID, new StringType(description));
break;
case PARTITION_ARM_MODE:
updateState(channelUID, new DecimalType(state));
break;
case PARTITION_ARMED:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PARTITION_ENTRY_DELAY:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PARTITION_EXIT_DELAY:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PARTITION_IN_ALARM:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case PARTITION_OPENING_CLOSING_MODE:
updateState(channelUID, new StringType(description));
break;
default:
logger.debug("updateChannel(): Partition Channel not updated - {}.", channelUID);
break;
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("handleCommand(): Command Received - {} {}.", channelUID, command);
if (command instanceof RefreshType) {
return;
}
if (dscAlarmBridgeHandler != null && dscAlarmBridgeHandler.isConnected()) {
switch (channelUID.getId()) {
case PARTITION_ARM_MODE:
int partitionNumber = getPartitionNumber();
if (command.toString().equals("0")) {
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.PartitionDisarmControl,
String.valueOf(partitionNumber));
} else if (command.toString().equals("1")) {
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.PartitionArmControlAway,
String.valueOf(partitionNumber));
} else if (command.toString().equals("2")) {
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.PartitionArmControlStay,
String.valueOf(partitionNumber));
} else if (command.toString().equals("3")) {
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.PartitionArmControlZeroEntryDelay,
String.valueOf(partitionNumber));
} else if (command.toString().equals("4")) {
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.PartitionArmControlZeroEntryDelay,
String.valueOf(partitionNumber));
} else if (command.toString().equals("5")) {
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.PartitionArmControlWithUserCode,
String.valueOf(partitionNumber));
}
break;
default:
break;
}
}
}
/**
* Method to set Partition Status.
*
* @param message
*/
private void partitionStatus(String message) {
updateState(new ChannelUID(getThing().getUID(), PARTITION_STATUS), new StringType(message));
}
/**
* Method to set Partition Close Open Mode.
*
* @param event
*/
private void partitionOpenCloseModeEventHandler(EventObject event) {
DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event;
DSCAlarmMessage dscAlarmMessage = dscAlarmEvent.getDSCAlarmMessage();
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
ChannelUID channelUID = null;
int state = 0; /*
* 0=None, 1=User Closing, 2=Special Closing, 3=Partial Closing, 4=User Opening, 5=Special
* Opening
*/
String strStatus = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.NAME);
switch (dscAlarmCode) {
case UserClosing: /* 700 */
state = 1;
break;
case SpecialClosing: /* 701 */
state = 2;
break;
case PartialClosing: /* 702 */
state = 3;
break;
case UserOpening: /* 750 */
state = 4;
break;
case SpecialOpening: /* 751 */
state = 5;
break;
default:
break;
}
channelUID = new ChannelUID(getThing().getUID(), PARTITION_OPENING_CLOSING_MODE);
updateChannel(channelUID, state, strStatus);
}
@Override
public void dscAlarmEventReceived(EventObject event, Thing thing) {
if (thing != null) {
if (getThing() == thing) {
DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event;
DSCAlarmMessage dscAlarmMessage = dscAlarmEvent.getDSCAlarmMessage();
ChannelUID channelUID = null;
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
String dscAlarmMessageName = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.NAME);
String dscAlarmMessageMode = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.MODE);
logger.debug("dscAlarmEventRecieved(): Thing - {} Command - {}", thing.getUID(), dscAlarmCode);
switch (dscAlarmCode) {
case PartitionReady: /* 650 */
case PartitionNotReady: /* 651 */
case PartitionReadyForceArming: /* 653 */
case SystemArmingInProgress: /* 674 */
partitionStatus(dscAlarmMessageName);
break;
case PartitionArmed: /* 652 */
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ARMED);
updateChannel(channelUID, 1, "");
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ENTRY_DELAY);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PARTITION_EXIT_DELAY);
updateChannel(channelUID, 0, "");
/*
* arm mode:0=disarmed, 1=away armed, 2=stay armed, 3=away no delay, 4=stay no delay, 5=with
* user code
*/
int armMode = Integer.parseInt(dscAlarmMessageMode) + 1;
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ARM_MODE);
updateChannel(channelUID, armMode, "");
partitionStatus(dscAlarmMessageName);
break;
case PartitionDisarmed: /* 655 */
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ARMED);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ENTRY_DELAY);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PARTITION_EXIT_DELAY);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PARTITION_IN_ALARM);
updateChannel(channelUID, 0, "");
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ARM_MODE);
updateChannel(channelUID, 0, "");
partitionStatus(dscAlarmMessageName);
break;
case PartitionInAlarm: /* 654 */
channelUID = new ChannelUID(getThing().getUID(), PARTITION_IN_ALARM);
updateChannel(channelUID, 1, "");
partitionStatus(dscAlarmMessageName);
break;
case ExitDelayInProgress: /* 656 */
channelUID = new ChannelUID(getThing().getUID(), PARTITION_EXIT_DELAY);
updateChannel(channelUID, 1, "");
break;
case EntryDelayInProgress: /* 657 */
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ENTRY_DELAY);
updateChannel(channelUID, 1, "");
break;
case FailureToArm: /* 672 */
channelUID = new ChannelUID(getThing().getUID(), PARTITION_ARM_MODE);
updateChannel(channelUID, 0, "");
partitionStatus(dscAlarmMessageName);
break;
case UserClosing: /* 700 */
case SpecialClosing: /* 701 */
case PartialClosing: /* 702 */
case UserOpening: /* 750 */
case SpecialOpening: /* 751 */
partitionOpenCloseModeEventHandler(event);
default:
break;
}
}
}
}
}

View File

@@ -0,0 +1,209 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import org.openhab.binding.dscalarm.internal.config.TCPServerBridgeConfiguration;
import org.openhab.core.thing.Bridge;
import org.openhab.core.thing.ThingStatus;
import org.openhab.core.thing.ThingStatusDetail;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The bridge handler for a TCP Server to connect to a DSC IT100 RS232 Serial interface over a network.
*
* @author Russell Stephens - Initial Contribution
*/
public class TCPServerBridgeHandler extends DSCAlarmBaseBridgeHandler {
private final Logger logger = LoggerFactory.getLogger(TCPServerBridgeHandler.class);
/**
* Constructor.
*
* @param bridge
*/
public TCPServerBridgeHandler(Bridge bridge) {
super(bridge, DSCAlarmBridgeType.TCPServer, DSCAlarmProtocol.IT100_API);
}
// Variables for TCP connection.
private String ipAddress;
private int tcpPort;
private int connectionTimeout;
private int protocol;
private Socket tcpSocket = null;
private OutputStreamWriter tcpOutput = null;
private BufferedReader tcpInput = null;
@Override
public void initialize() {
logger.debug("Initializing the TCP Server Bridge handler.");
TCPServerBridgeConfiguration configuration = getConfigAs(TCPServerBridgeConfiguration.class);
if (configuration.ipAddress == null || configuration.ipAddress.trim().isEmpty()) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Set an IP address in the thing configuration.");
} else if (configuration.port == null) {
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
"Set a TCP port in the thing configuration.");
} else {
ipAddress = configuration.ipAddress.trim();
tcpPort = configuration.port.intValue();
connectionTimeout = configuration.connectionTimeout.intValue();
pollPeriod = configuration.pollPeriod.intValue();
protocol = configuration.protocol.intValue();
if (this.protocol == 2) {
setProtocol(DSCAlarmProtocol.ENVISALINK_TPI);
} else {
setProtocol(DSCAlarmProtocol.IT100_API);
}
super.initialize();
logger.debug("TCP Server Bridge Handler Initialized");
logger.debug(" IP Address: {},", ipAddress);
logger.debug(" Port: {},", tcpPort);
logger.debug(" PollPeriod: {},", pollPeriod);
logger.debug(" Connection Timeout: {}.", connectionTimeout);
}
}
@Override
public void openConnection() {
try {
closeConnection();
logger.debug("openConnection(): Connecting to Envisalink ");
tcpSocket = new Socket();
SocketAddress tpiSocketAddress = new InetSocketAddress(ipAddress, tcpPort);
tcpSocket.connect(tpiSocketAddress, connectionTimeout);
tcpOutput = new OutputStreamWriter(tcpSocket.getOutputStream(), "US-ASCII");
tcpInput = new BufferedReader(new InputStreamReader(tcpSocket.getInputStream()));
Thread tcpListener = new Thread(new TCPListener());
tcpListener.start();
setConnected(true);
} catch (UnknownHostException unknownHostException) {
logger.error("openConnection(): Unknown Host Exception: {}", unknownHostException.getMessage());
setConnected(false);
} catch (SocketException socketException) {
logger.error("openConnection(): Socket Exception: {}", socketException.getMessage());
setConnected(false);
} catch (IOException ioException) {
logger.error("openConnection(): IO Exception: {}", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("openConnection(): Unable to open a connection: {} ", exception.getMessage(), exception);
setConnected(false);
}
}
@Override
public void write(String writeString, boolean doNotLog) {
try {
tcpOutput.write(writeString);
tcpOutput.flush();
logger.debug("write(): Message Sent: {}", doNotLog ? "***" : writeString);
} catch (IOException ioException) {
logger.error("write(): {}", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("write(): Unable to write to socket: {} ", exception.getMessage(), exception);
setConnected(false);
}
}
@Override
public String read() {
String message = "";
try {
message = tcpInput.readLine();
logger.debug("read(): Message Received: {}", message);
} catch (IOException ioException) {
logger.error("read(): IO Exception: {}", ioException.getMessage());
setConnected(false);
} catch (Exception exception) {
logger.error("read(): Exception: {} ", exception.getMessage(), exception);
setConnected(false);
}
return message;
}
@Override
public void closeConnection() {
try {
if (tcpSocket != null) {
tcpSocket.close();
tcpSocket = null;
tcpInput = null;
tcpOutput = null;
}
setConnected(false);
logger.debug("closeConnection(): Closed TCP Connection!");
} catch (IOException ioException) {
logger.error("closeConnection(): Unable to close connection - {}", ioException.getMessage());
} catch (Exception exception) {
logger.error("closeConnection(): Error closing connection - {}", exception.getMessage());
}
}
/**
* TCPMessageListener: Receives messages from the DSC Alarm Panel API.
*/
private class TCPListener implements Runnable {
private final Logger logger = LoggerFactory.getLogger(TCPListener.class);
/**
* Run method. Runs the MessageListener thread
*/
@Override
public void run() {
String messageLine;
try {
while (isConnected()) {
if ((messageLine = read()) != null) {
try {
handleIncomingMessage(messageLine);
} catch (Exception e) {
logger.error("TCPListener(): Message not handled by bridge: {}", e.getMessage());
}
} else {
setConnected(false);
}
}
} catch (Exception e) {
logger.error("TCPListener(): Unable to read message: {} ", e.getMessage(), e);
closeConnection();
}
}
}
}

View File

@@ -0,0 +1,182 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.dscalarm.internal.handler;
import static org.openhab.binding.dscalarm.internal.DSCAlarmBindingConstants.*;
import java.util.EventObject;
import org.openhab.binding.dscalarm.internal.DSCAlarmCode;
import org.openhab.binding.dscalarm.internal.DSCAlarmEvent;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage;
import org.openhab.binding.dscalarm.internal.DSCAlarmMessage.DSCAlarmMessageInfoType;
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.thing.ChannelUID;
import org.openhab.core.thing.Thing;
import org.openhab.core.types.Command;
import org.openhab.core.types.RefreshType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This is a class for handling a Zone type Thing.
*
* @author Russell Stephens - Initial Contribution
*/
public class ZoneThingHandler extends DSCAlarmBaseThingHandler {
private final Logger logger = LoggerFactory.getLogger(ZoneThingHandler.class);
/**
* Constructor.
*
* @param thing
*/
public ZoneThingHandler(Thing thing) {
super(thing);
setDSCAlarmThingType(DSCAlarmThingType.ZONE);
}
@Override
public void updateChannel(ChannelUID channelUID, int state, String description) {
logger.debug("updateChannel(): Zone Channel UID: {}", channelUID);
boolean trigger;
OnOffType onOffType;
OpenClosedType openClosedType;
if (channelUID != null) {
switch (channelUID.getId()) {
case ZONE_MESSAGE:
updateState(channelUID, new StringType(description));
break;
case ZONE_STATUS:
openClosedType = (state > 0) ? OpenClosedType.OPEN : OpenClosedType.CLOSED;
updateState(channelUID, openClosedType);
break;
case ZONE_BYPASS_MODE:
onOffType = (state > 0) ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case ZONE_IN_ALARM:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case ZONE_TAMPER:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case ZONE_FAULT:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
case ZONE_TRIPPED:
trigger = state != 0;
onOffType = trigger ? OnOffType.ON : OnOffType.OFF;
updateState(channelUID, onOffType);
break;
default:
logger.debug("updateChannel(): Zone Channel not updated - {}.", channelUID);
break;
}
}
}
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
logger.debug("handleCommand(): Command Received - {} {}.", channelUID, command);
if (command instanceof RefreshType) {
return;
}
if (dscAlarmBridgeHandler != null && dscAlarmBridgeHandler.isConnected()
&& channelUID.getId().equals(ZONE_BYPASS_MODE)) {
String data = String.valueOf(getPartitionNumber()) + "*1" + String.format("%02d", getZoneNumber()) + "#";
dscAlarmBridgeHandler.sendCommand(DSCAlarmCode.KeySequence, data);
}
}
/**
* Method to set Zone Message.
*
* @param message
*/
private void zoneMessage(String message) {
updateState(new ChannelUID(getThing().getUID(), ZONE_MESSAGE), new StringType(message));
}
@Override
public void dscAlarmEventReceived(EventObject event, Thing thing) {
if (thing != null) {
if (getThing().equals(thing)) {
DSCAlarmEvent dscAlarmEvent = (DSCAlarmEvent) event;
DSCAlarmMessage dscAlarmMessage = dscAlarmEvent.getDSCAlarmMessage();
ChannelUID channelUID = null;
DSCAlarmCode dscAlarmCode = DSCAlarmCode
.getDSCAlarmCodeValue(dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.CODE));
logger.debug("dscAlarmEventRecieved(): Thing - {} Command - {}", thing.getUID(), dscAlarmCode);
int state = 0;
String status = "";
switch (dscAlarmCode) {
case ZoneAlarm: /* 601 */
state = 1;
status = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DESCRIPTION);
case ZoneAlarmRestore: /* 602 */
channelUID = new ChannelUID(getThing().getUID(), ZONE_IN_ALARM);
updateChannel(channelUID, state, "");
zoneMessage(status);
break;
case ZoneTamper: /* 603 */
state = 1;
status = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DESCRIPTION);
case ZoneTamperRestore: /* 604 */
channelUID = new ChannelUID(getThing().getUID(), ZONE_TAMPER);
updateChannel(channelUID, state, "");
zoneMessage(status);
break;
case ZoneFault: /* 605 */
state = 1;
status = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DESCRIPTION);
case ZoneFaultRestore: /* 606 */
channelUID = new ChannelUID(getThing().getUID(), ZONE_FAULT);
updateChannel(channelUID, state, "");
zoneMessage(status);
break;
case ZoneOpen: /* 609 */
state = 1;
status = dscAlarmMessage.getMessageInfo(DSCAlarmMessageInfoType.DESCRIPTION);
case ZoneRestored: /* 610 */
channelUID = new ChannelUID(getThing().getUID(), ZONE_TRIPPED);
updateChannel(channelUID, state, "");
channelUID = new ChannelUID(getThing().getUID(), ZONE_STATUS);
updateChannel(channelUID, state, "");
zoneMessage(status);
break;
default:
break;
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<binding:binding id="dscalarm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
<name>DSCAlarm Binding</name>
<description>The DSCAlarm binding interfaces with a DSC PowerSeries Alarm System through the EyezOn Envisalink 3/2DS
interface or the DSC IT-100 RS-232 interface.</description>
<author>Russell Stephens</author>
</binding:binding>

View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<!-- bridge -->
<channel-type id="reset">
<item-type>Switch</item-type>
<label>Reset</label>
<description>Reset Switch</description>
</channel-type>
<channel-type id="command">
<item-type>String</item-type>
<label>Send Command</label>
<description>Sends a DSC Alarm Command</description>
</channel-type>
<!-- keypad -->
<channel-type id="led">
<item-type>Number</item-type>
<label>Keypad LED</label>
<description>Keypad LED (0=Off, 1=On, 2=Flashing)</description>
<state pattern="%d" readOnly="true">
<options>
<option value="0">Off</option>
<option value="1">On</option>
<option value="2">Flashing</option>
</options>
</state>
</channel-type>
<!-- panel -->
<channel-type id="panel_command">
<item-type>Number</item-type>
<label>Panel Command</label>
<description>Send Command</description>
<state pattern="%d">
<options>
<option value="-1">None</option>
<option value="0">Poll</option>
<option value="1">Status Report</option>
<option value="2">Labels Request (Serial Only)</option>
<option value="8">Dump Zone Timers (TCP Only)</option>
<option value="10">Set Time/Date</option>
<option value="200">Send User Code</option>
</options>
</state>
</channel-type>
<channel-type id="time">
<item-type>DateTime</item-type>
<label>Time</label>
<description>Time</description>
</channel-type>
<channel-type id="state">
<item-type>Switch</item-type>
<label>State</label>
<description>State (On/Off)</description>
</channel-type>
<!-- partition -->
<channel-type id="arm_mode">
<item-type>Number</item-type>
<label>Arm Mode</label>
<description>Arm Mode</description>
<state pattern="%d">
<options>
<option value="0">Disarm</option>
<option value="1">Away</option>
<option value="2">Stay</option>
<option value="3">Zero</option>
</options>
</state>
</channel-type>
<!-- zone -->
<channel-type id="zone_status">
<item-type>Contact</item-type>
<label>Zone Status</label>
<description>Zone Status (Open/Closed)</description>
<state readOnly="true"></state>
</channel-type>
<channel-type id="bypass_mode">
<item-type>Switch</item-type>
<label>Bypass Mode</label>
<description>Bypass Mode (OFF=Armed, ON=Bypassed)</description>
</channel-type>
<!-- common -->
<channel-type id="message">
<item-type>String</item-type>
<label>Message</label>
<description>Message Received</description>
<state pattern="%s" readOnly="true"></state>
</channel-type>
<channel-type id="status">
<item-type>Switch</item-type>
<label>Status</label>
<description>Status</description>
<state readOnly="true"></state>
</channel-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="envisalink">
<label>EyezOn Envisalink</label>
<description>This bridge represents the EyezOn Envlisalink 3/2D
Ethernet interface.</description>
<channels>
<channel id="bridge_reset" typeId="reset">
<label>Reset Envisalink</label>
<description>Resets the Envisalink</description>
</channel>
<channel id="send_command" typeId="command">
<label>Send Command</label>
<description>Sends a DSC Alarm Command</description>
</channel>
</channels>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>IP Address</label>
<description>The IP address of the EyezOn Envlisalink 3/2D Ethernet
interface.</description>
</parameter>
<parameter name="port" type="integer" required="false">
<label>Port</label>
<description>The TCP port to the EyezOn Envlisalink 3/2D Ethernet
interface.</description>
<default>4025</default>
</parameter>
<parameter name="password" type="text" required="false">
<context>password</context>
<label>Password</label>
<description>The Password to login to the EyezOn Envlisalink 3/2D
Ethernet interface.</description>
<default>user</default>
</parameter>
<parameter name="connectionTimeout" type="integer" required="false">
<label>Connection Timeout</label>
<description>TCP Socket Connection Timeout (milliseconds).</description>
<default>5000</default>
</parameter>
<parameter name="pollPeriod" type="integer" required="false" min="1" max="15">
<label>Poll Period</label>
<description>The Poll Period (minutes).</description>
<default>1</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="it100">
<label>DSC IT-100</label>
<description>This bridge represents the DSC IT-100 Serial interface.</description>
<channels>
<channel id="bridge_reset" typeId="reset">
<label>Reset IT100</label>
<description>Resets the IT100</description>
</channel>
<channel id="send_command" typeId="command">
<label>Send Command</label>
<description>Sends a DSC Alarm Command</description>
</channel>
</channels>
<config-description>
<parameter name="serialPort" type="text" required="true">
<context>serial-port</context>
<limitToOptions>false</limitToOptions>
<label>IT-100 Bridge Serial Port</label>
<description>The serial port name for the DSC IT-100. Valid values
are e.g. COM1 for Windows and /dev/ttyS0 or
/dev/ttyUSB0 for Linux.</description>
</parameter>
<parameter name="baud" type="integer" required="false">
<label>Baud Rate</label>
<description>The baud rate of the DSC IT-100. Valid values are 9600
(default), 19200, 38400, 57600, and 115200.</description>
<default>9600</default>
</parameter>
<parameter name="pollPeriod" type="integer" required="false" min="1" max="15">
<label>Poll Period</label>
<description>The Poll Period.</description>
<default>1</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="keypad">
<supported-bridge-type-refs>
<bridge-type-ref id="envisalink"/>
<bridge-type-ref id="it100"/>
<bridge-type-ref id="tcpserver"/>
</supported-bridge-type-refs>
<label>DSC Alarm Keypad</label>
<description>Represents the central administrative unit of the DSC Alarm System.</description>
<channels>
<channel id="keypad_ready_led" typeId="led">
<label>Keypad Ready LED</label>
<description>Keypad Ready LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_armed_led" typeId="led">
<label>Keypad Armed LED</label>
<description>Keypad Armed LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_memory_led" typeId="led">
<label>Keypad Memory LED</label>
<description>Keypad Memory LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_bypass_led" typeId="led">
<label>Keypad Bypass LED</label>
<description>Keypad Bypass LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_trouble_led" typeId="led">
<label>Keypad Trouble LED</label>
<description>Keypad Trouble LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_program_led" typeId="led">
<label>Keypad Program LED</label>
<description>Keypad Program LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_fire_led" typeId="led">
<label>Keypad Fire LED</label>
<description>Keypad Fire LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_backlight_led" typeId="led">
<label>Keypad Backlight LED</label>
<description>Keypad Backlight LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_ac_led" typeId="led">
<label>Keypad AC LED</label>
<description>Keypad AC LED (0=Off, 1=On, 2=Flashing)</description>
</channel>
<channel id="keypad_lcd_update" typeId="message">
<label>Keypad LCD Update</label>
<description>Keypad LCD Menu Changes</description>
</channel>
<channel id="keypad_lcd_cursor" typeId="message">
<label>Keypad LCD Cursor</label>
<description>Keypad LCD Cursor Position Changes</description>
</channel>
</channels>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="panel">
<supported-bridge-type-refs>
<bridge-type-ref id="envisalink"/>
<bridge-type-ref id="it100"/>
<bridge-type-ref id="tcpserver"/>
</supported-bridge-type-refs>
<label>DSC Alarm Panel</label>
<description>The basic representation of the DSC Alarm System.</description>
<channels>
<channel id="panel_message" typeId="message">
<label>Panel Message</label>
<description>Message Received</description>
</channel>
<channel id="panel_command" typeId="panel_command">
<label>Panel Command</label>
<description>Send Selected Command</description>
</channel>
<channel id="panel_system_error" typeId="message">
<label>Panel System Error</label>
<description>System Error</description>
</channel>
<channel id="panel_trouble_message" typeId="message">
<label>Panel Trouble Message</label>
<description>Trouble Message</description>
</channel>
<channel id="panel_trouble_led" typeId="status">
<label>Panel Trouble LED</label>
<description>Trouble LED State</description>
</channel>
<channel id="panel_service_required" typeId="status">
<label>Panel Service Required</label>
<description>Service Required Trouble Condition</description>
</channel>
<channel id="panel_ac_trouble" typeId="status">
<label>Panel AC Trouble</label>
<description>Service AC Trouble Condition</description>
</channel>
<channel id="panel_telephone_trouble" typeId="status">
<label>Panel Telephone Line Trouble</label>
<description>Service Telephone Line Trouble Condition</description>
</channel>
<channel id="panel_ftc_trouble" typeId="status">
<label>Panel FTC Trouble</label>
<description>Service Fail to Communicate Trouble Condition</description>
</channel>
<channel id="panel_zone_fault" typeId="status">
<label>Panel Zone Fault</label>
<description>Service Zone Fault Trouble Condition</description>
</channel>
<channel id="panel_zone_tamper" typeId="status">
<label>Panel Zone Tamper</label>
<description>Service Zone Tamper Trouble Condition</description>
</channel>
<channel id="panel_zone_low_battery" typeId="status">
<label>Panel Zone Low Battery</label>
<description>Service Zone Low Battery Trouble Condition</description>
</channel>
<channel id="panel_time_loss" typeId="status">
<label>Panel Time Loss</label>
<description>Service Time Loss Trouble Condition</description>
</channel>
<channel id="panel_time" typeId="time">
<label>Panel Time</label>
<description>Panel Time</description>
</channel>
<channel id="panel_time_stamp" typeId="state">
<label>Panel Time Stamp</label>
<description>Panel Time Stamp</description>
</channel>
<channel id="panel_time_broadcast" typeId="state">
<label>Panel Time Broadcast</label>
<description>Panel Time Broadcast</description>
</channel>
<channel id="panel_fire_key_alarm" typeId="status">
<label>Panel Fire Key Alarm</label>
<description>Panel Fire Key Alarm</description>
</channel>
<channel id="panel_panic_key_alarm" typeId="status">
<label>Panel Panic Key Alarm</label>
<description>Panel Panic Key Alarm</description>
</channel>
<channel id="panel_aux_key_alarm" typeId="status">
<label>Panel Auxiliary Key Alarm</label>
<description>Panel Auxiliary Key Alarm</description>
</channel>
<channel id="panel_aux_input_alarm" typeId="status">
<label>Panel Auxiliary Input Alarm</label>
<description>Panel Auxiliary Input Alarm</description>
</channel>
</channels>
<config-description>
<parameter name="userCode" type="text" required="false">
<context>password</context>
<label>User Code</label>
<description>The User Code.</description>
<default>1234</default>
</parameter>
<parameter name="suppressAcknowledgementMsgs" type="boolean" required="false">
<label>Suppress Acknowledgement Messages</label>
<description>Suppress Acknowledgement Messages When Received.</description>
<default>false</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="partition">
<supported-bridge-type-refs>
<bridge-type-ref id="envisalink"/>
<bridge-type-ref id="it100"/>
<bridge-type-ref id="tcpserver"/>
</supported-bridge-type-refs>
<label>DSC Alarm Partition</label>
<description>Represents a controllable area within a DSC Alarm System.</description>
<channels>
<channel id="partition_status" typeId="message">
<label>Partition Status</label>
<description>Partition Status</description>
</channel>
<channel id="partition_arm_mode" typeId="arm_mode">
<label>Partition Arm Mode</label>
<description>Partition Arm Mode</description>
</channel>
<channel id="partition_armed" typeId="status">
<label>Partition Armed Status</label>
<description>Partition Armed Status (ON=Armed, OFF=Disarmed)</description>
</channel>
<channel id="partition_entry_delay" typeId="status">
<label>Partition Entry Delay</label>
<description>Partition In Entry Delay Mode</description>
</channel>
<channel id="partition_exit_delay" typeId="status">
<label>Partition Exit Delay</label>
<description>Partition In Exit Delay Mode</description>
</channel>
<channel id="partition_in_alarm" typeId="status">
<label>Partition in Alarm</label>
<description>Partition In Alarm</description>
</channel>
<channel id="partition_opening_closing_mode" typeId="message">
<label>Partition Opening/Closing Mode</label>
<description>Partition Opening/Closing Mode ("User Closing", "Special Closing", "Partial Closing", "User Opening",
"Special Opening")</description>
</channel>
</channels>
<config-description>
<parameter name="partitionNumber" type="integer" required="true" min="1" max="8">
<label>Partition Number</label>
<description>The Partition Number (1-8).</description>
<default>1</default>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<bridge-type id="tcpserver">
<label>TCP Server</label>
<description>This bridge represents a TCP Server
Ethernet interface.
</description>
<channels>
<channel id="bridge_reset" typeId="reset">
<label>Reset TCP Server</label>
<description>Resets the TCP Server</description>
</channel>
<channel id="send_command" typeId="command">
<label>Send Command</label>
<description>Sends a DSC Alarm Command</description>
</channel>
</channels>
<config-description>
<parameter name="ipAddress" type="text" required="true">
<context>network-address</context>
<label>IP Address</label>
<description>The IP address of the TCP Server.</description>
</parameter>
<parameter name="port" type="integer" required="true">
<label>Port</label>
<description>The TCP port to the TCP Server.</description>
</parameter>
<parameter name="connectionTimeout" type="integer" required="false">
<label>Connection Timeout</label>
<description>TCP Socket Connection Timeout (milliseconds).</description>
<default>5000</default>
</parameter>
<parameter name="pollPeriod" type="integer" required="false" min="1" max="15">
<label>Poll Period</label>
<description>The Poll Period (minutes).</description>
<default>1</default>
</parameter>
<parameter name="protocol" type="integer" required="false" min="1" max="2">
<label>Protocol</label>
<description>The protocol used to interact with the DSC Alarm. Valid options are 'IT100 API' and 'Envisalink TPI'.
The default is 'IT100 API'.</description>
<options>
<option value="1">IT100 API</option>
<option value="2">Envisalink TPI</option>
</options>
<default>1</default>
</parameter>
</config-description>
</bridge-type>
</thing:thing-descriptions>

View File

@@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="dscalarm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="zone">
<supported-bridge-type-refs>
<bridge-type-ref id="envisalink"/>
<bridge-type-ref id="it100"/>
<bridge-type-ref id="tcpserver"/>
</supported-bridge-type-refs>
<label>DSC Alarm Zone</label>
<description>Represents a physical device such as a door, window, or motion sensor.</description>
<channels>
<channel id="zone_status" typeId="zone_status">
<label>Zone Status</label>
<description>Zone Status (Open/Closed)</description>
</channel>
<channel id="zone_message" typeId="message">
<label>Zone Message</label>
<description>Zone Message</description>
</channel>
<channel id="zone_bypass_mode" typeId="bypass_mode">
<label>Zone Bypass Mode</label>
<description>Zone Bypass Mode (OFF=Armed, ON=Bypassed)</description>
</channel>
<channel id="zone_in_alarm" typeId="status">
<label>Zone in Alarm</label>
<description>Zone In Alarm</description>
</channel>
<channel id="zone_tamper" typeId="status">
<label>Zone Tamper</label>
<description>Zone Tamper</description>
</channel>
<channel id="zone_fault" typeId="status">
<label>Zone Fault</label>
<description>Zone Fault</description>
</channel>
<channel id="zone_tripped" typeId="status">
<label>Zone Tripped</label>
<description>Zone Tripped</description>
</channel>
</channels>
<config-description>
<parameter name="partitionNumber" type="integer" min="1" max="8">
<label>Partition Number</label>
<description>The Partition Number (1-8).</description>
<default>1</default>
</parameter>
<parameter name="zoneNumber" type="integer" required="true" min="1" max="64">
<label>Zone Number</label>
<description>The Zone Number (1-64).</description>
</parameter>
</config-description>
</thing-type>
</thing:thing-descriptions>