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,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>org.openhab.binding.dscalarm</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,13 @@
This content is produced and maintained by the openHAB project.
* Project home: https://www.openhab.org
== Declared Project Licenses
This program and the accompanying materials are made available under the terms
of the Eclipse Public License 2.0 which is available at
https://www.eclipse.org/legal/epl-2.0/.
== Source Code
https://github.com/openhab/openhab-addons

View File

@@ -0,0 +1,621 @@
# DSC Alarm Binding
The DSC PowerSeries Alarm System is a popular do-it-yourself home security system, which can be monitored and controlled remotely through a standard web-browser or mobile device.
This is the binding for the DSC PowerSeries Alarm System, utilizing either the EyezOn Envisalink 4/3/2DS interface or the DSC IT-100 RS-232 interface.
It provides connectivity to the DSC Alarm panel via a TCP socket connection to the EyesOn Envisalink 4/3/2DS interface or a RS-232 serial connection to the DSC IT-100 interface.
Additionally, their is provision to connect to the DSC IT-100 interface through a TCP serial server.
## Supported Things
This binding supports the following Thing types
| Thing | Thing Type | Description |
|------------|------------|------------------------------------------------------------------------|
| envisalink | Bridge | The EyezOn Envisalink 3/2DS interface. |
| it100 | Bridge | The DSC IT-100 RS-232 interface. |
| tcpserver | Bridge | The DSC IT-100 TCP Server network interface. |
| panel | Thing | The basic representation of the DSC Alarm System. |
| partition | Thing | Represents a controllable area within a DSC Alarm system. |
| zone | Thing | Represents a physical device such as a door, window, or motion sensor. |
| keypad | Thing | Represents the central administrative unit. |
## Binding Configuration
There are essentially no overall binding configuration settings that need to be set.
Most settings are through thing configuration parameters.
## Discovery
The DSC Alarm binding incorporates a discovery modes in order to find DSC Alarm systems.
There is the Envisalink bridge discovery mode which performs a network query for any Envisalink adapters and adds them to the discovery inbox.
This bridge discovery mode is started manually through Paper UI.
After a bridge is discovered and available to openHAB, the binding will attempt to discover DSC Alarm things and add them to the discovery inbox.
The TCP Server bridge does not implement bridge discovery but will utilize thing discovery once it is online.
Note:
The Envisalink Bridge discovery does a TCP scan across your local network to find the interface.
This may create issues on the network so it is suggested that caution be used when trying this discovery.
The recommended method would be to manually add and configure the bridge through the 'dscalarm.thing' file or the Paper UI.
And then allow the binding to discover the DSC Alarm things.
## Thing Configuration
DSC Alarm things can be configured either through the online configuration utility via discovery, or manually through the 'dscalarm.things' configuration file.
The following table shows the available configuration parameters for each thing.
<table>
<tr><td><b>Thing</b></td><td><b>Configuration Parameters</b></td></tr>
<tr><td>envisalink</td><td><table><tr><td><b>ipAddress</b> - IP address for the Envisalink adapter - Required.</td></tr><tr><td><b>port</b> - TCP port for the Envisalink adapter - Not Required - default = 4025.</td></tr><tr><td><b>password</b> - Password to login to the Envisalink bridge - Not Required.</td></tr><tr><td><b>connectionTimeout</b> - TCP socket connection timeout in milliseconds - Not Required - default=5000.<br/></td></tr><tr><td><b>pollPeriod</b> - Period of time in minutes between the poll command being sent to the Envisalink bridge - Not Required - default=1.</td></tr></table></td></tr>
<tr><td>it100</td><td><table><tr><td><b>serialPort</b> - Serial port for the IT-100s bridge - Required.</td></tr><tr><td><b>baud</b> - Baud rate of the IT-100 bridge - Not Required - default = 9600.</td></tr><tr><td><b>pollPeriod</b> - Period of time in minutes between the poll command being sent to the IT-100 bridge - Not Required - default=1.</td></tr></table></td></tr>
<tr><td>tcpserver</td><td><table><tr><td><b>ipAddress</b> - IP address for the TCP Server - Required.</td></tr><tr><td><b>port</b> - TCP port for the TCP Server - Required.</td></tr><tr><td><b>connectionTimeout</b> - TCP socket connection timeout in milliseconds - Not Required - default=5000.<br/></td></tr><tr><td><b>pollPeriod</b> - Period of time in minutes between the poll command being sent to the TCP Server bridge - Not Required - default=1.</td></tr><tr><td><b>protocol</b> - The protocol used to interact with the DSC Alarm. Valid values are 1 for IT100 API or 2 for Envisalink TPI. The default is 1. - Not Required.</td></tr></table></td></tr>
<tr><td>panel</td><td><table><tr><td><b>userCode</b> - User code for the DSC alarm panel - Not Required.</td></tr><tr><td><b>suppressAcknowledgementMsgs</b> - Suppress the display of acknowledgement messages when received - Not Required - default = false.</td></tr></table></td></tr>
<tr><td>partition</td><td><b>partitionNumber</b> - Partition number (1-8) - Required.</td></tr>
<tr><td>zone</td><td><table><tr><td><b>partitionNumber</b> - Partition number (1-8) - Not Required - default=1.</td></tr><tr><td><b>zoneNumber</b> - Zone number (1-64) - Required.</td></tr></table></td></tr>
<tr><td>keypad</td><td>No parameters</td></tr>
</table>
The binding can be configured manually if discovery is not used.
A thing configuration file in the format 'bindingName.things' would need to be created, and placed in the 'conf/things' folder.
Here is an example of a thing configuration file called 'dscalarm.things':
```perl
Bridge dscalarm:envisalink:MyBridgeName [ ipAddress="192.168.0.100" ] {
Thing panel panel
Thing partition partition1 [ partitionNumber=1 ]
Thing zone zone1 [ partitionNumber=1, zoneNumber=1 ]
Thing zone zone9 [ partitionNumber=1, zoneNumber=9 ]
Thing zone zone10 [ partitionNumber=1, zoneNumber=10 ]
Thing zone zone11 [ partitionNumber=1, zoneNumber=11 ]
Thing zone zone12 [ partitionNumber=1, zoneNumber=12 ]
Thing zone zone13 [ partitionNumber=1, zoneNumber=13 ]
Thing zone zone14 [ partitionNumber=1, zoneNumber=14 ]
Thing zone zone15 [ partitionNumber=1, zoneNumber=15 ]
Thing zone zone21 [ partitionNumber=1, zoneNumber=21 ]
Thing zone zone22 [ partitionNumber=1, zoneNumber=22 ]
Thing zone zone23 [ partitionNumber=1, zoneNumber=23 ]
Thing zone zone24 [ partitionNumber=1, zoneNumber=24 ]
Thing zone zone25 [ partitionNumber=1, zoneNumber=25 ]
Thing keypad keypad
}
```
## Channels
DSC Alarm things support a variety of channels as seen below in the following table:
<table>
<tr><td><b>Channel</b></td><td><b>Item Type</b></td><td><b>Description</b></td></tr>
<tr><td>bridge_reset</td><td>Switch</td><td>Reset the bridge connection.</td></tr>
<tr><td>send_command</td><td>Switch</td><td>Send a DSC Alarm command.</td></tr>
<tr><td>panel_message</td><td>String</td><td>Event messages received from the DSC Alarm system.</td></tr>
<tr><td>panel_system_error</td><td>String</td><td>DSC Alarm system error.</td></tr>
<tr><td>panel_trouble_message</td><td>String</td><td>Displays any trouble messages the panel might send.</td></tr>
<tr><td>panel_trouble_led</td><td>Switch</td><td>The panel trouble LED is on.</td></tr>
<tr><td>panel_service_required</td><td>Switch</td><td>Service is required on the panel.</td></tr>
<tr><td>panel_ac_trouble</td><td>Switch</td><td>The panel has lost AC power.</td></tr>
<tr><td>panel_telephone_trouble</td><td>Switch</td><td>Telephone line fault.</td></tr>
<tr><td>panel_ftc_trouble</td><td>Switch</td><td>Failure to communicate with monitoring station.</td></tr>
<tr><td>panel_zone_fault</td><td>Switch</td><td>There is a fault condition on a zone/sensor.</td></tr>
<tr><td>panel_zone_tamper</td><td>Switch</td><td>There is a tamper condition on a zone/sensor.</td></tr>
<tr><td>panel_zone_low_battery</td><td>Switch</td><td>There is a low battery condition on a zone/sensor.</td></tr>
<tr><td>panel_time_loss</td><td>Switch</td><td>Loss of time on the panel.</td></tr>
<tr><td>panel_time</td><td>DateTime</td><td>DSC Alarm system time and date.</td></tr>
<tr><td>panel_time_stamp</td><td>Switch</td><td>Turn DSC Alarm message time stamping ON/OFF.</td></tr>
<tr><td>panel_time_broadcast</td><td>Switch</td><td>Turn DSC Alarm time broadcasting ON/OFF.</td></tr>
<tr><td>panel_fire_key_alarm</td><td>Switch</td><td>A fire key alarm has happened.</td></tr>
<tr><td>panel_panic_key_alarm</td><td>Switch</td><td>A panic key alarm has happened.</td></tr>
<tr><td>panel_aux_key_alarm</td><td>Switch</td><td>An auxiliary key alarm has happened.</td></tr>
<tr><td>panel_aux_input_alarm</td><td>Switch</td><td>An auxiliary input alarm has happened.</td></tr>
<tr><td>partition_status</td><td>String</td><td>A partitions current status.</td></tr>
<tr><td>partition_arm_mode</td><td>Number</td><td>A partitions current arm mode. The possible values are:
<br/>
0=disarmed<br/>
1=armed away<br/>
2=armed stay<br/>
3=away no delay<br/>
4=stay no delay<br/>
</td></tr>
<tr><td>partition_armed</td><td>Switch</td><td>A partition has been armed.</td></tr>
<tr><td>partition_entry_delay</td><td>Switch</td><td>A partition is in entry delay mode.</td></tr>
<tr><td>partition_exit_delay</td><td>Switch</td><td>A partition is in exit delay mode.</td></tr>
<tr><td>partition_in_alarm</td><td>Switch</td><td>A partition is in alarm.</td></tr>
<tr><td>partition_opening_closing_mode</td><td>String</td><td>Displays the opening/closing mode of a partition.</td></tr>
<tr><td>zone_status</td><td>Contact</td><td>A zones general (open/closed) status.</td></tr>
<tr><td>zone_message</td><td>String</td><td>A zone status message.</td></tr>
<tr><td>zone_bypass_mode</td><td>Switch</td><td>A zone bypass mode (OFF=Armed, ON=Bypassed).</td></tr>
<tr><td>zone_in_alarm</td><td>Switch</td><td>A zone is in alarm.</td></tr>
<tr><td>zone_tamper</td><td>Switch</td><td>A zone tamper condition has happened.</td></tr>
<tr><td>zone_fault</td><td>Switch</td><td>A zone fault condition has happened.</td></tr>
<tr><td>zone_tripped</td><td>Switch</td><td>A zone has tripped.</td></tr>
<tr><td>keypad_ready_led</td><td>Number</td><td>Keypad Ready LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/>
</td></tr>
<tr><td>keypad_armed_led</td><td>Number</td><td>Keypad Armed LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_memory_led</td><td>Number</td><td>Keypad Memory LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_bypass_led</td><td>Number</td><td>Keypad Bypass LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_trouble_led</td><td>Number</td><td>Keypad Trouble LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_program_led</td><td>Number</td><td>Keypad Program LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_fire_led</td><td>Number</td><td>Keypad Fire LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_backlight_led</td><td>Number</td><td>Keypad Backlight LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_ac_led</td><td>Number</td><td>Keypad AC LED Status. The values are:
<br/>
0=OFF<br/>
1=ON<br/>
2=Flashing<br/></td></tr>
<tr><td>keypad_lcd_update</td><td>String</td><td>Text Changes of the IT-100 LCD Menu.</td></tr>
<tr><td>keypad_lcd_cursor</td><td>String</td><td>LCD Cursor Position for The IT-100</td></tr>
</table>
##Example
The following is an example of an item file (dscalarm.items):
```java
Group DSCAlarm
Group DSCAlarmPanel (DSCAlarm)
Group DSCAlarmPartitions (DSCAlarm)
Group DSCAlarmZones (DSCAlarm)
Group DSCAlarmKeypads (DSCAlarm)
/* Groups By Device Type */
Group:Contact:OR(OPEN, CLOSED) DSCAlarmDoorWindow <door>
Group:Contact:OR(OPEN, CLOSED) DSCAlarmMotion <motionDetector>
Group:Contact:OR(OPEN, CLOSED) DSCAlarmSmoke <smokeDetector>
/* DSC Alarm Items */
Switch BRIDGE_CONNECTION {channel="dscalarm:envisalink:MyBridgeName:bridge_reset"}
String SEND_DSC_ALARM_COMMAND "Send a DSC Alarm Command" {channel="dscalarm:envisalink:MyBridgeName:send_command"}
/* DSC Alarm Panel Items */
String PANEL_MESSAGE "Panel Message: [%s]" (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_message"}
Number PANEL_COMMAND "Panel Commands" (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_command"}
String PANEL_SYSTEM_ERROR "Panel System Error: [%s]" (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_system_error"}
String PANEL_TROUBLE_MESSAGE "Panel Trouble Message: [%s]" <"shieldGreen"> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_trouble_message"}
Switch PANEL_TROUBLE_LED "Panel Trouble LED" <warning> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_trouble_led"}
Switch PANEL_SERVICE_REQUIRED <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_service_required"}
Switch PANEL_AC_TROUBLE <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_ac_trouble"}
Switch PANEL_TELEPHONE_TROUBLE <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_telephone_trouble"}
Switch PANEL_FTC_TROUBLE <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_ftc_trouble"}
Switch PANEL_ZONE_FAULT <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_zone_fault"}
Switch PANEL_ZONE_TAMPER <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_zone_tamper"}
Switch PANEL_ZONE_LOW_BATTERY <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_zone_low_battery"}
Switch PANEL_TIME_LOSS <yellowLED> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_time_loss"}
DateTime PANEL_TIME "Panel Time [%1$tA, %1$tm/%1$td/%1$tY %1tT]" <calendar> (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_time"}
Switch PANEL_TIME_STAMP (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_time_stamp"}
Switch PANEL_TIME_BROADCAST (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_time_broadcast"}
Switch PANEL_FIRE_KEY_ALARM (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_fire_key_alarm"}
Switch PANEL_PANIC_KEY_ALARM (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_panic_key_alarm"}
Switch PANEL_AUX_KEY_ALARM (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_aux_key_alarm"}
Switch PANEL_AUX_INPUT_ALARM (DSCAlarmPanel) {channel="dscalarm:panel:MyBridgeName:panel:panel_aux_input_alarm"}
/* DSC Alarm Partition Items */
String PARTITION1_STATUS "Partition 1 Status: [%s]" (DSCAlarmPartitions) {channel="dscalarm:partition:MyBridgeName:partition1:partition_status"}
Number PARTITION1_ARM_MODE "Partition 1 Arm Mode: [%d]" (DSCAlarmPartitions) {channel="dscalarm:partition:MyBridgeName:partition1:partition_arm_mode"}
Switch PARTITION1_ARMED (DSCAlarmPartitions) {channel="dscalarm:partition:MyBridgeName:partition1:partition_armed"}
Switch PARTITION1_ENTRY_DELAY (DSCAlarmPartitions) {channel="dscalarm:partition:MyBridgeName:partition1:partition_entry_delay"}
Switch PARTITION1_EXIT_DELAY (DSCAlarmPartitions) {channel="dscalarm:partition:MyBridgeName:partition1:partition_exit_delay"}
Switch PARTITION1_IN_ALARM (DSCAlarmPartitions) {channel="dscalarm:partition:MyBridgeName:partition1:partition_in_alarm"}
String PARTITION1_OPENING_CLOSING_MODE "Opening/Closing Mode: [%s]" (DSCAlarmPartitions) {channel="dscalarm:partition:MyBridgeName:partition1:partition_opening_closing_mode"}
/* DSC Alarm Zones Items */
Contact ZONE1_STATUS "Tamper Switch (Zone 1)" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone1:zone_status"}
String ZONE1_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone1:zone_message"}
Switch ZONE1_BYPASS_MODE "Tamper Switch Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone1:zone_bypass_mode"}
Switch ZONE1_IN_ALARM "Zone 1 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone1:zone_in_alarm"}
Switch ZONE1_TAMPER "Zone 1 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone1:zone_tamper"}
Switch ZONE1_FAULT "Zone 1 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone1:zone_fault"}
Switch ZONE1_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone1:zone_tripped"}
Contact ZONE9_STATUS "Front Door Sensor (Zone 9)" <door> (DSCAlarmZones, FrontFoyer, DSCAlarmDoorWindow) {channel="dscalarm:zone:MyBridgeName:zone9:zone_status"}
String ZONE9_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone9:zone_message"}
Switch ZONE9_BYPASS_MODE "Front Door Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone9:zone_bypass_mode"}
Switch ZONE9_IN_ALARM "Zone 9 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone9:zone_in_alarm"}
Switch ZONE9_TAMPER "Zone 9 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone9:zone_tamper"}
Switch ZONE9_FAULT "Zone 9 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone9:zone_fault"}
Switch ZONE9_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone9:zone_tripped"}
Contact ZONE10_STATUS "Deck Door Sensor (Zone 10)" <door> (DSCAlarmZones, FamilyRoom, DSCAlarmDoorWindow) {channel="dscalarm:zone:MyBridgeName:zone10:zone_status"}
String ZONE10_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone10:zone_message"}
Switch ZONE10_BYPASS_MODE "Deck Door Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone10:zone_bypass_mode"}
Switch ZONE10_IN_ALARM "Zone 10 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone10:zone_in_alarm"}
Switch ZONE10_TAMPER "Zone 10 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone10:zone_tamper"}
Switch ZONE10_FAULT "Zone 10 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone10:zone_fault"}
Switch ZONE10_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone10:zone_tripped"}
Contact ZONE11_STATUS "Back Door Sensor (Zone 11)" <door> (DSCAlarmZones, UtilityRoom, DSCAlarmDoorWindow) {channel="dscalarm:zone:MyBridgeName:zone11:zone_status"}
String ZONE11_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone11:zone_message"}
Switch ZONE11_BYPASS_MODE "Back Door Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone11:zone_bypass_mode"}
Switch ZONE11_IN_ALARM "Zone 11 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone11:zone_in_alarm"}
Switch ZONE11_TAMPER "Zone 11 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone11:zone_tamper"}
Switch ZONE11_FAULT "Zone 11 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone11:zone_fault"}
Switch ZONE11_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone11:zone_tripped"}
Contact ZONE12_STATUS "Side Door Sensor (Zone 12)" <door> (DSCAlarmZones, SideFoyer, DSCAlarmDoorWindow) {channel="dscalarm:zone:MyBridgeName:zone12:zone_status"}
String ZONE12_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone12:zone_message"}
Switch ZONE12_BYPASS_MODE "Side Door Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone12:zone_bypass_mode"}
Switch ZONE12_IN_ALARM "Zone 12 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone12:zone_in_alarm"}
Switch ZONE12_TAMPER "Zone 12 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone12:zone_tamper"}
Switch ZONE12_FAULT "Zone 12 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone12:zone_fault"}
Switch ZONE12_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone12:zone_tripped"}
Contact ZONE13_STATUS "Garage Door 1 Sensor (Zone 13)" <door> (DSCAlarmZones, Garage, DSCAlarmDoorWindow) {channel="dscalarm:zone:MyBridgeName:zone13:zone_status"}
String ZONE13_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone13:zone_message"}
Switch ZONE13_BYPASS_MODE "Garage Door 1 Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone13:zone_bypass_mode"}
Switch ZONE13_IN_ALARM "Zone 13 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone13:zone_in_alarm"}
Switch ZONE13_TAMPER "Zone 13 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone13:zone_tamper"}
Switch ZONE13_FAULT "Zone 13 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone13:zone_fault"}
Switch ZONE13_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone13:zone_tripped"}
Contact ZONE14_STATUS "Garage Door 2 Sensor (Zone 14)" <garagedoor> (DSCAlarmZones, Garage, DSCAlarmDoorWindow) {channel="dscalarm:zone:MyBridgeName:zone14:zone_status"}
String ZONE14_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone14:zone_message"}
Switch ZONE14_BYPASS_MODE "Garage Door 2 Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone14:zone_bypass_mode"}
Switch ZONE14_IN_ALARM "Zone 14 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone14:zone_in_alarm"}
Switch ZONE14_TAMPER "Zone 14 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone14:zone_tamper"}
Switch ZONE14_FAULT "Zone 14 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone14:zone_fault"}
Switch ZONE14_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone14:zone_tripped"}
Contact ZONE15_STATUS "Garage Window Sensor (Zone 15)" (DSCAlarmZones, Garage, DSCAlarmDoorWindow) {channel="dscalarm:zone:MyBridgeName:zone15:zone_status"}
String ZONE15_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone15:zone_message"}
Switch ZONE15_BYPASS_MODE "Garage Window Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone15:zone_bypass_mode"}
Switch ZONE15_IN_ALARM "Zone 15 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone15:zone_in_alarm"}
Switch ZONE15_TAMPER "Zone 15 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone15:zone_tamper"}
Switch ZONE15_FAULT "Zone 15 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone15:zone_fault"}
Switch ZONE15_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone15:zone_tripped"}
Contact ZONE21_STATUS "Family Room Motion Sensor (Zone 21)" <motionDetector> (DSCAlarmZones, FamilyRoom, DSCAlarmMotion) {channel="dscalarm:zone:MyBridgeName:zone21:zone_status"}
String ZONE21_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone21:zone_message"}
Switch ZONE21_BYPASS_MODE "Family Room Motion Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone21:zone_bypass_mode"}
Switch ZONE21_IN_ALARM "Zone 21 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone21:zone_in_alarm"}
Switch ZONE21_TAMPER "Zone 21 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone21:zone_tamper"}
Switch ZONE21_FAULT "Zone 21 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone21:zone_fault"}
Switch ZONE21_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone21:zone_tripped"}
Contact ZONE22_STATUS "Office Motion Sensor (Zone 22)" <motionDetector> (DSCAlarmZones, Office, DSCAlarmMotion) {channel="dscalarm:zone:MyBridgeName:zone22:zone_status"}
String ZONE22_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone22:zone_message"}
Switch ZONE22_BYPASS_MODE "Office Motion Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone22:zone_bypass_mode"}
Switch ZONE22_IN_ALARM "Zone 22 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone22:zone_in_alarm"}
Switch ZONE22_TAMPER "Zone 22 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone22:zone_tamper"}
Switch ZONE22_FAULT "Zone 22 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone22:zone_fault"}
Switch ZONE22_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone22:zone_tripped"}
Contact ZONE23_STATUS "Dining Room Motion Sensor (Zone 23)" <motionDetector> (DSCAlarmZones, DiningRoom, DSCAlarmMotion) {channel="dscalarm:zone:MyBridgeName:zone23:zone_status"}
String ZONE23_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone23:zone_message"}
Switch ZONE23_BYPASS_MODE "Dining Room Motion Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone23:zone_bypass_mode"}
Switch ZONE23_IN_ALARM "Zone 23 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone23:zone_in_alarm"}
Switch ZONE23_TAMPER "Zone 23 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone23:zone_tamper"}
Switch ZONE23_FAULT "Zone 23 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone23:zone_fault"}
Switch ZONE23_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone23:zone_tripped"}
Contact ZONE24_STATUS "Living Room Motion Sensor (Zone 24)" <motionDetector> (DSCAlarmZones, LivingRoom, DSCAlarmMotion) {channel="dscalarm:zone:MyBridgeName:zone24:zone_status"}
String ZONE24_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone24:zone_message"}
Switch ZONE24_BYPASS_MODE "Living Room Motion Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone24:zone_bypass_mode"}
Switch ZONE24_IN_ALARM "Zone 24 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone24:zone_in_alarm"}
Switch ZONE24_TAMPER "Zone 24 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone24:zone_tamper"}
Switch ZONE24_FAULT "Zone 24 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone24:zone_fault"}
Switch ZONE24_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone24:zone_tripped"}
Contact ZONE25_STATUS "Utility Room Motion Sensor (Zone 25)" <motionDetector> (DSCAlarmZones, UtilityRoom, DSCAlarmMotion) {channel="dscalarm:zone:MyBridgeName:zone25:zone_status"}
String ZONE25_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone25:zone_message"}
Switch ZONE25_BYPASS_MODE "Utility Room Motion Sensor Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone25:zone_bypass_mode"}
Switch ZONE25_IN_ALARM "Zone 25 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone25:zone_in_alarm"}
Switch ZONE25_TAMPER "Zone 25 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone25:zone_tamper"}
Switch ZONE25_FAULT "Zone 25 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone25:zone_fault"}
Switch ZONE25_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone25:zone_tripped"}
Contact ZONE51_STATUS "Utility Room Smoke Detector (Zone 51)" <smokeDetector> (DSCAlarmZones, UtilityRoom, DSCAlarmSmoke) {channel="dscalarm:zone:MyBridgeName:zone51:zone_status"}
String ZONE51_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone51:zone_message"}
Switch ZONE51_BYPASS_MODE "Utility Room Smoke Detector Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone51:zone_bypass_mode"}
Switch ZONE51_IN_ALARM "Zone 51 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone51:zone_in_alarm"}
Switch ZONE51_TAMPER "Zone 51 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone51:zone_tamper"}
Switch ZONE51_FAULT "Zone 51 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone51:zone_fault"}
Switch ZONE51_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone51:zone_tripped"}
Contact ZONE52_STATUS "Dining Room Smoke Detector (Zone 52)" <smokeDetector> (DSCAlarmZones, DiningRoom, DSCAlarmSmoke) {channel="dscalarm:zone:MyBridgeName:zone52:zone_status"}
String ZONE52_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone52:zone_message"}
Switch ZONE52_BYPASS_MODE "Dining Room Smoke Detector Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone52:zone_bypass_mode"}
Switch ZONE52_IN_ALARM "Zone 52 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone52:zone_in_alarm"}
Switch ZONE52_TAMPER "Zone 52 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone52:zone_tamper"}
Switch ZONE52_FAULT "Zone 52 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone52:zone_fault"}
Switch ZONE52_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone52:zone_tripped"}
Contact ZONE53_STATUS "Front Foyer Smoke Detector (Zone 53)" <smokeDetector> (DSCAlarmZones, FrontFoyer, DSCAlarmSmoke) {channel="dscalarm:zone:MyBridgeName:zone53:zone_status"}
String ZONE53_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone53:zone_message"}
Switch ZONE53_BYPASS_MODE "Front Foyer Smoke Detector Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone53:zone_bypass_mode"}
Switch ZONE53_IN_ALARM "Zone 53 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone53:zone_in_alarm"}
Switch ZONE53_TAMPER "Zone 53 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone53:zone_tamper"}
Switch ZONE53_FAULT "Zone 53 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone53:zone_fault"}
Switch ZONE53_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone53:zone_tripped"}
Contact ZONE54_STATUS "Upstairs Hall Smoke Detector (Zone 54)" <smokeDetector> (DSCAlarmZones, UpstairsHall, DSCAlarmSmoke) {channel="dscalarm:zone:MyBridgeName:zone54:zone_status"}
String ZONE54_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone54:zone_message"}
Switch ZONE54_BYPASS_MODE "Upstairs Hall Smoke Detector Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone54:zone_bypass_mode"}
Switch ZONE54_IN_ALARM "Zone 54 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone54:zone_in_alarm"}
Switch ZONE54_TAMPER "Zone 54 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone54:zone_tamper"}
Switch ZONE54_FAULT "Zone 54 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone54:zone_fault"}
Switch ZONE54_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone54:zone_tripped"}
Contact ZONE55_STATUS "Master Bedroom Smoke Detector (Zone 55)" <smokeDetector> (DSCAlarmZones, Bedroom, DSCAlarmSmoke) {channel="dscalarm:zone:MyBridgeName:zone55:zone_status"}
String ZONE55_MESSAGE "Zone Message: [%s]" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone55:zone_message"}
Switch ZONE55_BYPASS_MODE "Master Bedroom Smoke Detector Bypass Mode" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone55:zone_bypass_mode"}
Switch ZONE55_IN_ALARM "Zone 55 Alarm Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone55:zone_in_alarm"}
Switch ZONE55_TAMPER "Zone 55 Tamper Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone55:zone_tamper"}
Switch ZONE55_FAULT "Zone 55 Fault Condition" (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone55:zone_fault"}
Switch ZONE55_TRIPPED (DSCAlarmZones) {channel="dscalarm:zone:MyBridgeName:zone55:zone_tripped"}
/* DSC Alarm Keypad Items */
Number KEYPAD_READY_LED "Ready LED Status" <readyLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_ready_led"}
Number KEYPAD_ARMED_LED "Armed LED Status" <armedLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_armed_led"}
Number KEYPAD_MEMORY_LED "Memory LED Status" <memoryLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_memory_led"}
Number KEYPAD_BYPASS_LED "Bypass LED Status" <bypassLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_bypass_led"}
Number KEYPAD_TROUBLE_LED "Trouble LED Status" <troubleLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_trouble_led"}
Number KEYPAD_PROGRAM_LED "Program LED Status" <programLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_program_led"}
Number KEYPAD_FIRE_LED "Fire LED Status" <fireLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_fire_led"}
Number KEYPAD_BACKLIGHT_LED "Backlight LED Status" <backlightLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_backlight_led"}
Number KEYPAD_AC_LED "AC LED Status" <acLED> (DSCAlarmKeypads) {channel="dscalarm:keypad:MyBridgeName:keypad:keypad_ac_led"}
```
Here is an example sitemap:
```perl
Frame label="Alarm System" {
Text label="DSC Alarm System" {
Frame label="Panel" {
Switch item=BRIDGE_CONNECTION label="Panel Connection" mappings=[ON="Connected", OFF="Disconnected"]
Text item=PANEL_MESSAGE
Selection item=PANEL_COMMAND mappings=[0="Poll", 1="Status Report", 2="Labels Request (Serial Only)", 8="Dump Zone Timers (TCP Only)", 10="Set Time/Date", 200="Send User Code"]
Text item=PANEL_TIME {
Switch item=PANEL_TIME_STAMP label="Panel Time Stamp"
Switch item=PANEL_TIME_BROADCAST label="Panel Time Broadcast"
}
Text item=PANEL_SYSTEM_ERROR
Text item=PANEL_TROUBLE_LED label="Panel Trouble Condition" {
Text item=PANEL_TROUBLE_MESSAGE
Text item=PANEL_SERVICE_REQUIRED label="Service Required"
Text item=PANEL_AC_TROUBLE label="AC Trouble"
Text item=PANEL_TELEPHONE_TROUBLE label="Telephone Line Trouble"
Text item=PANEL_FTC_TROUBLE label="Failed to Communicate Trouble"
Text item=PANEL_ZONE_FAULT label="Zone Fault"
Text item=PANEL_ZONE_TAMPER label="Zone Tamper"
Text item=PANEL_ZONE_LOW_BATTERY label="Zone Low Battery"
Text item=PANEL_TIME_LOSS label="Panel Time Loss"
}
}
Frame label="Partitions" {
Text item=PARTITION1_STATUS {
Switch item=PARTITION1_ARM_MODE label="Partition 1 Arm Options" mappings=[0="Disarm", 1="Away", 2="Stay", 3="No Entry Delay", 4="With User Code"]
Text item=PARTITION1_OPENING_CLOSING_MODE
}
}
Frame label="Keypad" {
Text label="Keypad LED Status" {
Text item=KEYPAD_READY_LED label="Ready LED Status"
Text item=KEYPAD_ARMED_LED label="Armed LED Status"
Text item=KEYPAD_MEMORY_LED label="Memory LED Status"
Text item=KEYPAD_BYPASS_LED label="Bypass LED Status"
Text item=KEYPAD_TROUBLE_LED label="Trouble LED Status"
Text item=KEYPAD_PROGRAM_LED label="Program LED Status"
Text item=KEYPAD_FIRE_LED label="Fire LED Status"
Text item=KEYPAD_BACKLIGHT_LED label="Backlight LED Status"
Text item=KEYPAD_AC_LED label="AC LED Status"
}
}
Frame label="Zones" {
Text label="All Zones" {
Text item=ZONE1_STATUS {
Switch item=ZONE1_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE1_IN_ALARM
Switch item=ZONE1_TAMPER
Switch item=ZONE1_FAULT
}
}
Text item=ZONE9_STATUS {
Switch item=ZONE9_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE9_IN_ALARM
Switch item=ZONE9_TAMPER
Switch item=ZONE9_FAULT
}
}
Text item=ZONE10_STATUS {
Switch item=ZONE10_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE10_IN_ALARM
Switch item=ZONE10_TAMPER
Switch item=ZONE10_FAULT
}
}
Text item=ZONE11_STATUS {
Switch item=ZONE11_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE11_IN_ALARM
Switch item=ZONE11_TAMPER
Switch item=ZONE11_FAULT
}
}
Text item=ZONE12_STATUS {
Switch item=ZONE12_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE12_IN_ALARM
Switch item=ZONE12_TAMPER
Switch item=ZONE12_FAULT
}
}
Text item=ZONE13_STATUS {
Switch item=ZONE13_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE13_IN_ALARM
Switch item=ZONE13_TAMPER
Switch item=ZONE13_FAULT
}
}
Text item=ZONE14_STATUS {
Switch item=ZONE14_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE14_IN_ALARM
Switch item=ZONE14_TAMPER
Switch item=ZONE14_FAULT
}
}
Text item=ZONE15_STATUS {
Switch item=ZONE15_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE15_IN_ALARM
Switch item=ZONE15_TAMPER
Switch item=ZONE15_FAULT
}
}
Text item=ZONE21_STATUS {
Switch item=ZONE21_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE21_IN_ALARM
Switch item=ZONE21_TAMPER
Switch item=ZONE21_FAULT
}
}
Text item=ZONE22_STATUS {
Switch item=ZONE22_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE22_IN_ALARM
Switch item=ZONE22_TAMPER
Switch item=ZONE22_FAULT
}
}
Text item=ZONE23_STATUS {
Switch item=ZONE23_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE23_IN_ALARM
Switch item=ZONE23_TAMPER
Switch item=ZONE23_FAULT
}
}
Text item=ZONE24_STATUS {
Switch item=ZONE24_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE24_IN_ALARM
Switch item=ZONE24_TAMPER
Switch item=ZONE24_FAULT
}
}
Text item=ZONE25_STATUS {
Switch item=ZONE25_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE25_IN_ALARM
Switch item=ZONE25_TAMPER
Switch item=ZONE25_FAULT
}
}
Text item=ZONE51_STATUS {
Switch item=ZONE51_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE51_IN_ALARM
Switch item=ZONE51_TAMPER
Switch item=ZONE51_FAULT
}
}
Text item=ZONE52_STATUS {
Switch item=ZONE52_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE52_IN_ALARM
Switch item=ZONE52_TAMPER
Switch item=ZONE52_FAULT
}
}
Text item=ZONE53_STATUS {
Switch item=ZONE53_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE53_IN_ALARM
Switch item=ZONE53_TAMPER
Switch item=ZONE53_FAULT
}
}
Text item=ZONE54_STATUS {
Switch item=ZONE54_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE54_IN_ALARM
Switch item=ZONE54_TAMPER
Switch item=ZONE54_FAULT
}
}
Text item=ZONE55_STATUS {
Switch item=ZONE55_BYPASS_MODE mappings=[OFF="Armed", ON="Bypassed"]
Frame label="Other Status:" {
Switch item=ZONE55_IN_ALARM
Switch item=ZONE55_TAMPER
Switch item=ZONE55_FAULT
}
}
}
Group item=DSCAlarmDoorWindow label="Door/Window Sensors"
Group item=DSCAlarmMotion label="Motion Sensors"
Group item=DSCAlarmSmoke label="Smoke Detectors"
}
}
}
```
Sample Rules for Sending a DSC Alarm Command
```javascript
rule "SendKeystrokeStringCommand"
when
Item SwitchItemName received command ON
then
SEND_DSC_ALARM_COMMAND.sendCommand("071,1*101#")
end
rule "SendPollingCommand"
when
Item SwitchItemName received command ON
then
SEND_DSC_ALARM_COMMAND.sendCommand("000")
end
```
Notice the command variations in the examples.
If a command has data, there needs to be a comma between the command and the data as seen above in the first example.
If there is no data then it would only require the command itself as in the second example.

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.openhab.addons.bundles</groupId>
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>
<artifactId>org.openhab.binding.dscalarm</artifactId>
<name>openHAB Add-ons :: Bundles :: DSCAlarm Binding</name>
</project>

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>