mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[qolsysiq] Initial contribution of the Qolsys IQ Binding (#13699)
* [qolsysiq] Initial contribution of the Qolsys IQ Binding Signed-off-by: Dan Cunningham <dan@digitaldan.com>
This commit is contained in:
parent
22ea587d20
commit
1d9bf63d5e
@ -272,6 +272,7 @@
|
|||||||
/bundles/org.openhab.binding.pushover/ @cweitkamp
|
/bundles/org.openhab.binding.pushover/ @cweitkamp
|
||||||
/bundles/org.openhab.binding.pushsafer/ @appzer @cweitkamp
|
/bundles/org.openhab.binding.pushsafer/ @appzer @cweitkamp
|
||||||
/bundles/org.openhab.binding.qbus/ @QbusKoen
|
/bundles/org.openhab.binding.qbus/ @QbusKoen
|
||||||
|
/bundles/org.openhab.binding.qolsysiq/ @digitaldan
|
||||||
/bundles/org.openhab.binding.radiothermostat/ @mlobstein
|
/bundles/org.openhab.binding.radiothermostat/ @mlobstein
|
||||||
/bundles/org.openhab.binding.regoheatpump/ @crnjan
|
/bundles/org.openhab.binding.regoheatpump/ @crnjan
|
||||||
/bundles/org.openhab.binding.revogi/ @andibraeu
|
/bundles/org.openhab.binding.revogi/ @andibraeu
|
||||||
|
@ -1356,6 +1356,11 @@
|
|||||||
<artifactId>org.openhab.binding.qbus</artifactId>
|
<artifactId>org.openhab.binding.qbus</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
|
<artifactId>org.openhab.binding.qolsysiq</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.openhab.addons.bundles</groupId>
|
<groupId>org.openhab.addons.bundles</groupId>
|
||||||
<artifactId>org.openhab.binding.radiothermostat</artifactId>
|
<artifactId>org.openhab.binding.radiothermostat</artifactId>
|
||||||
|
13
bundles/org.openhab.binding.qolsysiq/NOTICE
Normal file
13
bundles/org.openhab.binding.qolsysiq/NOTICE
Normal 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
|
125
bundles/org.openhab.binding.qolsysiq/README.md
Normal file
125
bundles/org.openhab.binding.qolsysiq/README.md
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
# Qolsys IQ Binding
|
||||||
|
|
||||||
|
This binding directly controls a [Qolsys IQ](https://qolsys.com/security/) security panel.
|
||||||
|
This allows for local monitoring of alarm and zone statuses as well as arming, disarming and triggering alarms.
|
||||||
|
|
||||||
|
Qolsys (a division of Johnson Controls) is a popular manufacturer of alarm systems.
|
||||||
|
The Qolsys IQ line of panels supports both wireless and hard wire sensors and features built in Cellular and Wi-Fi dual path communication that natively integrates with Alarm.com monitoring and supervision.
|
||||||
|
|
||||||
|
This binding directly interfaces with the panel and does not require cloud access.
|
||||||
|
|
||||||
|
![Qolsys IQ 4](doc/qolsysiq4.png)
|
||||||
|
|
||||||
|
## Supported Things
|
||||||
|
|
||||||
|
| Thing | Description | Thing Type | Thing UID |
|
||||||
|
|---------------------|-------------------------------------------------------------------------------------------|------------|-----------|
|
||||||
|
| Qolsys IQ Panel | A Qolsys IQ security panel (all current models, which is 2+ and 4 at the time of writing) | Bridge | panel |
|
||||||
|
| Qolsys IQ Partition | A logical partition which can be armed, disarmed, and is responsible for managing zones | Bridge | partition |
|
||||||
|
| Qolsys IQ Zone | A generic zone sensor | Thing | zone |
|
||||||
|
|
||||||
|
## Discovery
|
||||||
|
|
||||||
|
### Qolsys IQ Panel (Bridge)
|
||||||
|
|
||||||
|
The Qolsys IQ Panel must be manually added using a host name or ip address along with a secure access token from the panel settings.
|
||||||
|
To enable 3rd party control and retrieve the access token follow the following steps on the security panel touch screen:
|
||||||
|
|
||||||
|
`Settings` --> `Advanced Settings` --> `Installation` --> `Dealer Settings` -> `6 Digit User Code` (set to enabled)
|
||||||
|
|
||||||
|
`Settings` --> `Advanced Settings` --> `Installation` --> `Devices` --> `Wi-Fi Devices` --> `Control4` (set to enabled)
|
||||||
|
|
||||||
|
*Panel will reboot*
|
||||||
|
|
||||||
|
`Settings` --> `Advanced Settings` --> `Installation` --> `Devices` --> `Wi-Fi Devices` --> `Reveal Secure Token` (copy token to use in panel configuration)
|
||||||
|
|
||||||
|
At this point you may add the panel thing in openHAB using the secure token along with the IP or host name of the panel.
|
||||||
|
|
||||||
|
### Partition (Bridge)
|
||||||
|
|
||||||
|
Once a panel is added, partitions will be automatically discovered and appear in the inbox.
|
||||||
|
|
||||||
|
### Zone (Thing)
|
||||||
|
|
||||||
|
Once a partition is added, zones will be automatically discovered and appear in the inbox.
|
||||||
|
|
||||||
|
## Thing Configuration
|
||||||
|
|
||||||
|
### `panel` Thing Configuration
|
||||||
|
|
||||||
|
| Name | Type | Description | Default | Required | Advanced |
|
||||||
|
|-------------------|---------|-----------------------------------------------------|---------|----------|----------|
|
||||||
|
| hostname | text | Hostname or IP address of the device | N/A | yes | no |
|
||||||
|
| port | integer | Port the device is listening on | 12345 | no | no |
|
||||||
|
| key | text | Access token / key found in the panel settings menu | N/A | yes | no |
|
||||||
|
|
||||||
|
### `partition` Thing Configuration
|
||||||
|
|
||||||
|
| Name | Type | Description | Default | Required | Advanced |
|
||||||
|
|------------|---------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|----------|----------|
|
||||||
|
| id | integer | Partition id of the panel, staring with '0' for the first partition | N/A | yes | no |
|
||||||
|
| disarmCode | text | Optional disarm code to use when receiving a disarm command without a code. Required for integrations like Alexa and Homekit who do not provide codes when disarming. Leave blank to always require a code | blank | no | no |
|
||||||
|
| armCode | text | Optional arm code to use when receiving arm commands without a code. Only required if the panel has been configured to require arm codes. Leave blank to always require a code | blank | no | yes |
|
||||||
|
|
||||||
|
### `zone` Thing Configuration
|
||||||
|
|
||||||
|
| Name | Type | Description | Default | Required | Advanced |
|
||||||
|
|---------|---------|---------------------------------------------------------------------------------------------------------|---------|----------|----------|
|
||||||
|
| id | integer | Id of the zone, staring with '1' for the first zone | N/A | yes | no |
|
||||||
|
|
||||||
|
## Channels
|
||||||
|
|
||||||
|
### Panel Channels
|
||||||
|
|
||||||
|
None.
|
||||||
|
|
||||||
|
### Partition Channels
|
||||||
|
|
||||||
|
| Channel | Type | Read/Write | Description | State Options | Command Options |
|
||||||
|
|-------------|--------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|----------------------------|
|
||||||
|
| armState | String | RW | Reports the current partition arm state or sends an arm or disarm command to the system. Security codes can be appended to the command using a colon delimiter (e.g. 'DISARM:123456'). Codes appended to the command will be used in place of the `armCode` configuration property if set. | ALARM, ARM_AWAY, ARM_STAY, DISARM, ENTRY_DELAY, EXIT_DELAY | ARM_AWAY, ARM_STAY, DISARM |
|
||||||
|
| alarmState | String | RW | Reports on the current alarm state, or triggers an instant alarm | AUXILIARY, FIRE, POLICE, ZONEOPEN, NONE | AUXILIARY, FIRE, POLICE |
|
||||||
|
| armingDelay | Number | R | The arming delay countdown currently in progress | Seconds remaining | N/A |
|
||||||
|
| errorEvent | String | R | Last error event message reported by the partition. Clears after 30 seconds | Error text | N/A |
|
||||||
|
|
||||||
|
### Zone Channels
|
||||||
|
|
||||||
|
| Channel | Type | Read/Write | Description | State Options |
|
||||||
|
|---------|---------|------------|------------------------|---------------------------------------------|
|
||||||
|
| status | String | R | The zone status | ACTIVE, CLOSED, OPEN, FAILURE, IDLE, TAMPER |
|
||||||
|
| state | Number | R | The zone state | Number |
|
||||||
|
| contact | Contact | R | The zone contact state | OPEN, CLOSED |
|
||||||
|
|
||||||
|
## Full Example
|
||||||
|
|
||||||
|
### qolsysiq.things
|
||||||
|
|
||||||
|
```
|
||||||
|
Bridge qolsysiq:panel:home "Home Security Panel" [ hostname="192.168.3.123", port=12345, key="AAABBB00" ] {
|
||||||
|
Bridge partition 0 "Partition Main" [ id=0, armCode="123456" ] {
|
||||||
|
Thing zone 1 "Window" [ id=1 ]
|
||||||
|
Thing zone 2 "Motion" [ id=2 ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### qolsysiq.items
|
||||||
|
|
||||||
|
Sample items file with both Alexa and Homekit voice control
|
||||||
|
|
||||||
|
```
|
||||||
|
Group PartitionMain "Alarm System" ["Equipment"] {alexa="SecurityPanel", homekit = "SecuritySystem"}
|
||||||
|
String PartitionMain_PartitionArmState "Partition Arm State" <Alarm> (PartitionMain) ["Point"] {channel="qolsysiq:partition:home:0:armState", alexa="ArmState" [DISARMED="DISARM",ARMED_STAY="ARM_STAY",ARMED_AWAY="ARM_AWAY:EXIT_DELAY"], homekit = "SecuritySystem.CurrentSecuritySystemState,SecuritySystem.TargetSecuritySystemState" [STAY_ARM="ARM_STAY", AWAY_ARM="ARM_AWAY", DISARM="DISARM", DISARMED="DISARM", TRIGGERED="ALARM"]}
|
||||||
|
String PartitionMain_PartitionAlarmState "Partition Alarm State" <Alarm> (PartitionMain) ["Point"] {channel="qolsysiq:partition:home:0:alarmState"}
|
||||||
|
Number PartitionMain_PartitionArmingDelay "Partition Arming Delay" (PartitionMain) ["Point"] {channel="qolsysiq:partition:home:0:armingDelay"}
|
||||||
|
String PartitionMain_ErrorEvent "Error Event" (PartitionMain) ["Point"] {channel="qolsysiq:partition:home:0:errorEvent" }
|
||||||
|
|
||||||
|
Group ZoneKitchenWindows "Qolsys IQ Zone: Kitchen Windows" ["Equipment"]
|
||||||
|
Number ZoneKitchenWindows_ZoneState "Kitchen Windows Zone State" (ZoneKitchenWindows) ["Point"] {channel="qolsysiq:zone:home:0:1:state"}
|
||||||
|
String ZoneKitchenWindows_ZoneStatus "Kitchen Windows Zone Status" (ZoneKitchenWindows) ["Point"] {channel="qolsysiq:zone:home:0:1:status"}
|
||||||
|
Contact ZoneKitchenWindows_ZoneContact "Kitchen Windows Zone Contact" (ZoneKitchenWindows) ["Point"] {channel="qolsysiq:zone:home:0:1:contact"}
|
||||||
|
|
||||||
|
Group ZoneMotionDetector1 "Motion Detector 1" ["Equipment"]
|
||||||
|
Number ZoneMotionDetector_ZoneState1 "Motion Detector 1 Zone State" (ZoneMotionDetector1) ["Point"] {channel="qolsysiq:zone:home:0:2:state"}
|
||||||
|
String ZoneMotionDetector_ZoneStatus1 "Motion Detector 1 Zone Status" (ZoneMotionDetector1) ["Point"] {channel="qolsysiq:zone:home:0:2:status"}
|
||||||
|
```
|
BIN
bundles/org.openhab.binding.qolsysiq/doc/qolsysiq4.png
Normal file
BIN
bundles/org.openhab.binding.qolsysiq/doc/qolsysiq4.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
17
bundles/org.openhab.binding.qolsysiq/pom.xml
Normal file
17
bundles/org.openhab.binding.qolsysiq/pom.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://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.4.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>org.openhab.binding.qolsysiq</artifactId>
|
||||||
|
|
||||||
|
<name>openHAB Add-ons :: Bundles :: QolsysIQ Binding</name>
|
||||||
|
|
||||||
|
</project>
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<features name="org.openhab.binding.qolsysiq-${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-qolsysiq" description="QolsysIQ Binding" version="${project.version}">
|
||||||
|
<feature>openhab-runtime-base</feature>
|
||||||
|
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.qolsysiq/${project.version}</bundle>
|
||||||
|
</feature>
|
||||||
|
</features>
|
@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQBindingConstants} class defines common constants, which are
|
||||||
|
* used across the whole binding.
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQBindingConstants {
|
||||||
|
|
||||||
|
public static final String BINDING_ID = "qolsysiq";
|
||||||
|
|
||||||
|
public static final ThingTypeUID THING_TYPE_PANEL = new ThingTypeUID(BINDING_ID, "panel");
|
||||||
|
public static final ThingTypeUID THING_TYPE_PARTITION = new ThingTypeUID(BINDING_ID, "partition");
|
||||||
|
public static final ThingTypeUID THING_TYPE_ZONE = new ThingTypeUID(BINDING_ID, "zone");
|
||||||
|
|
||||||
|
public static final String CHANNEL_PARTITION_ARM_STATE = "armState";
|
||||||
|
public static final String CHANNEL_PARTITION_ALARM_STATE = "alarmState";
|
||||||
|
public static final String CHANNEL_PARTITION_COMMAND_DELAY = "armingDelay";
|
||||||
|
public static final String CHANNEL_PARTITION_ERROR_EVENT = "errorEvent";
|
||||||
|
|
||||||
|
public static final String CHANNEL_ZONE_STATE = "state";
|
||||||
|
public static final String CHANNEL_ZONE_STATUS = "status";
|
||||||
|
public static final String CHANNEL_ZONE_CONTACT = "contact";
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal;
|
||||||
|
|
||||||
|
import static org.openhab.binding.qolsysiq.internal.QolsysIQBindingConstants.*;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.handler.QolsysIQPanelHandler;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.handler.QolsysIQPartitionHandler;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.handler.QolsysIQZoneHandler;
|
||||||
|
import org.openhab.core.thing.Bridge;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||||
|
import org.osgi.service.component.annotations.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQHandlerFactory} is responsible for creating things and thing
|
||||||
|
* handlers.
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
@Component(configurationPid = "binding.qolsysiq", service = ThingHandlerFactory.class)
|
||||||
|
public class QolsysIQHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
|
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_PANEL, THING_TYPE_PARTITION,
|
||||||
|
THING_TYPE_ZONE);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||||
|
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
|
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||||
|
|
||||||
|
if (THING_TYPE_PANEL.equals(thingTypeUID)) {
|
||||||
|
return new QolsysIQPanelHandler((Bridge) thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (THING_TYPE_PARTITION.equals(thingTypeUID)) {
|
||||||
|
return new QolsysIQPartitionHandler((Bridge) thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (THING_TYPE_ZONE.equals(thingTypeUID)) {
|
||||||
|
return new QolsysIQZoneHandler(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,93 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.AlarmEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ArmingEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ErrorEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.SecureArmInfoEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.SummaryInfoEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneActiveEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneAddEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneUpdateEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public interface QolsysIQClientListener {
|
||||||
|
/**
|
||||||
|
* Callback when the connection has been disconnected
|
||||||
|
*
|
||||||
|
* @param reason
|
||||||
|
*/
|
||||||
|
void disconnected(Exception reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link AlarmEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void alarmEvent(AlarmEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ArmingEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void armingEvent(ArmingEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ErrorEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void errorEvent(ErrorEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SummaryInfoEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void summaryInfoEvent(SummaryInfoEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link SecureArmInfoEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void secureArmInfoEvent(SecureArmInfoEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ZoneActiveEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void zoneActiveEvent(ZoneActiveEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ZoneUpdateEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void zoneUpdateEvent(ZoneUpdateEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ZoneAddEvent} message callback
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
void zoneAddEvent(ZoneAddEvent event);
|
||||||
|
}
|
@ -0,0 +1,390 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.security.KeyManagementException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLContext;
|
||||||
|
import javax.net.ssl.SSLSocket;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
import javax.net.ssl.TrustManager;
|
||||||
|
import javax.net.ssl.X509TrustManager;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.Action;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.AlarmEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ArmingEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ErrorEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.Event;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.EventType;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.InfoEventType;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.SecureArmInfoEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.SummaryInfoEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneActiveEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneAddEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneEventType;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneUpdateEvent;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.FieldNamingPolicy;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client that can communicate with a Qolsys IQ Panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysiqClient {
|
||||||
|
private static final String MESSAGE_ACK = "ACK";
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(QolsysiqClient.class);
|
||||||
|
private final Gson gson = new GsonBuilder().registerTypeAdapter(Event.class, new EventDeserializer())
|
||||||
|
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
|
||||||
|
private List<QolsysIQClientListener> listeners = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
private @Nullable SSLSocket socket;
|
||||||
|
private @Nullable BufferedReader reader;
|
||||||
|
private @Nullable BufferedWriter writer;
|
||||||
|
private @Nullable Thread readerThread;
|
||||||
|
private @Nullable ScheduledFuture<?> heartBeatFuture;
|
||||||
|
private ScheduledExecutorService scheduler;
|
||||||
|
private Object writeLock = new Object();
|
||||||
|
private long lastResponseTime;
|
||||||
|
private boolean hasACK = false;
|
||||||
|
private boolean connected;
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private int heartbeatSeconds;
|
||||||
|
private String threadName;
|
||||||
|
private SSLSocketFactory sslsocketfactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new QolsysiqClient
|
||||||
|
*
|
||||||
|
* @param host
|
||||||
|
* @param port
|
||||||
|
* @param heartbeatSeconds
|
||||||
|
* @param scheduler for the heart beat task
|
||||||
|
* @param threadName
|
||||||
|
*/
|
||||||
|
public QolsysiqClient(String host, int port, int heartbeatSeconds, ScheduledExecutorService scheduler,
|
||||||
|
String threadName) throws IOException {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
this.heartbeatSeconds = heartbeatSeconds;
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.threadName = threadName;
|
||||||
|
|
||||||
|
try {
|
||||||
|
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||||
|
sslContext.init(null, acceptAlltrustManagers(), null);
|
||||||
|
sslsocketfactory = sslContext.getSocketFactory();
|
||||||
|
} catch (KeyManagementException | NoSuchAlgorithmException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connects to the panel
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized void connect() throws IOException {
|
||||||
|
logger.debug("connect");
|
||||||
|
if (connected) {
|
||||||
|
logger.debug("connect: already connected, ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SSLSocket socket = (SSLSocket) sslsocketfactory.createSocket(host, port);
|
||||||
|
socket.startHandshake();
|
||||||
|
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||||
|
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
this.socket = socket;
|
||||||
|
|
||||||
|
Thread readerThread = new Thread(this::readEvents, threadName);
|
||||||
|
readerThread.setDaemon(true);
|
||||||
|
readerThread.start();
|
||||||
|
this.readerThread = readerThread;
|
||||||
|
connected = true;
|
||||||
|
try {
|
||||||
|
// send an initial message to confirm a connection and record a response time
|
||||||
|
writeMessage("");
|
||||||
|
} catch (IOException e) {
|
||||||
|
// clean up before bubbling up exception
|
||||||
|
disconnect();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
heartBeatFuture = scheduler.scheduleWithFixedDelay(() -> {
|
||||||
|
if (connected) {
|
||||||
|
try {
|
||||||
|
if (System.currentTimeMillis() - lastResponseTime > (heartbeatSeconds + 5) * 1000) {
|
||||||
|
throw new IOException("No responses received");
|
||||||
|
}
|
||||||
|
writeMessage("");
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Problem sending heartbeat", e);
|
||||||
|
disconnectAndNotify(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, heartbeatSeconds, heartbeatSeconds, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects from the panel
|
||||||
|
*/
|
||||||
|
public void disconnect() {
|
||||||
|
connected = false;
|
||||||
|
|
||||||
|
ScheduledFuture<?> heartbeatFuture = this.heartBeatFuture;
|
||||||
|
if (heartbeatFuture != null) {
|
||||||
|
heartbeatFuture.cancel(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread readerThread = this.readerThread;
|
||||||
|
if (readerThread != null && readerThread.isAlive()) {
|
||||||
|
readerThread.interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
SSLSocket socket = this.socket;
|
||||||
|
if (socket != null) {
|
||||||
|
try {
|
||||||
|
socket.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Error closing SSL socket: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
this.socket = null;
|
||||||
|
}
|
||||||
|
BufferedReader reader = this.reader;
|
||||||
|
if (reader != null) {
|
||||||
|
try {
|
||||||
|
reader.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Error closing reader: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
this.reader = null;
|
||||||
|
}
|
||||||
|
BufferedWriter writer = this.writer;
|
||||||
|
if (writer != null) {
|
||||||
|
try {
|
||||||
|
writer.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Error closing writer: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
this.writer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends an Action message to the panel
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public void sendAction(Action action) throws IOException {
|
||||||
|
logger.debug("sendAction {}", action.type);
|
||||||
|
writeMessage(gson.toJson(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a QolsysIQClientListener
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
public void addListener(QolsysIQClientListener listener) {
|
||||||
|
synchronized (listeners) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a QolsysIQClientListener
|
||||||
|
*
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
public void removeListener(QolsysIQClientListener listener) {
|
||||||
|
synchronized (listeners) {
|
||||||
|
listeners.remove(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void writeMessage(String message) throws IOException {
|
||||||
|
if (!connected) {
|
||||||
|
logger.debug("writeMessage: not connected, ignoring {}", message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
synchronized (writeLock) {
|
||||||
|
hasACK = false;
|
||||||
|
logger.trace("writeMessage: {}", message);
|
||||||
|
BufferedWriter writer = this.writer;
|
||||||
|
if (writer != null) {
|
||||||
|
writer.write(message);
|
||||||
|
writer.newLine();
|
||||||
|
writer.flush();
|
||||||
|
try {
|
||||||
|
writeLock.wait(5000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
logger.debug("write lock interupted");
|
||||||
|
}
|
||||||
|
if (!hasACK) {
|
||||||
|
logger.trace("writeMessage: no ACK for {}", message);
|
||||||
|
throw new IOException("No response to message: " + message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readEvents() {
|
||||||
|
String message;
|
||||||
|
BufferedReader reader = this.reader;
|
||||||
|
try {
|
||||||
|
while (connected && reader != null && (message = reader.readLine()) != null) {
|
||||||
|
logger.trace("Message: {}", message);
|
||||||
|
lastResponseTime = System.currentTimeMillis();
|
||||||
|
if (MESSAGE_ACK.equals(message)) {
|
||||||
|
synchronized (writeLock) {
|
||||||
|
hasACK = true;
|
||||||
|
writeLock.notify();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Event event = gson.fromJson(message, Event.class);
|
||||||
|
if (event == null) {
|
||||||
|
logger.debug("Could not deserialize message: {}", message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
synchronized (listeners) {
|
||||||
|
if (event instanceof AlarmEvent) {
|
||||||
|
listeners.forEach(listener -> listener.alarmEvent((AlarmEvent) event));
|
||||||
|
} else if (event instanceof ArmingEvent) {
|
||||||
|
listeners.forEach(listener -> listener.armingEvent((ArmingEvent) event));
|
||||||
|
} else if (event instanceof ErrorEvent) {
|
||||||
|
listeners.forEach(listener -> listener.errorEvent((ErrorEvent) event));
|
||||||
|
} else if (event instanceof SecureArmInfoEvent) {
|
||||||
|
listeners.forEach(listener -> listener.secureArmInfoEvent((SecureArmInfoEvent) event));
|
||||||
|
} else if (event instanceof SummaryInfoEvent) {
|
||||||
|
listeners.forEach(listener -> listener.summaryInfoEvent((SummaryInfoEvent) event));
|
||||||
|
} else if (event instanceof ZoneActiveEvent) {
|
||||||
|
listeners.forEach(listener -> listener.zoneActiveEvent((ZoneActiveEvent) event));
|
||||||
|
} else if (event instanceof ZoneUpdateEvent) {
|
||||||
|
listeners.forEach(listener -> listener.zoneUpdateEvent((ZoneUpdateEvent) event));
|
||||||
|
} else if (event instanceof ZoneAddEvent) {
|
||||||
|
listeners.forEach(listener -> listener.zoneAddEvent((ZoneAddEvent) event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (JsonSyntaxException e) {
|
||||||
|
logger.debug("Could not parse messge", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (connected) {
|
||||||
|
throw new IOException("socket disconencted");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
disconnectAndNotify(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disconnectAndNotify(Exception e) {
|
||||||
|
if (connected) {
|
||||||
|
disconnect();
|
||||||
|
synchronized (listeners) {
|
||||||
|
listeners.forEach(listener -> listener.disconnected(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TrustManager[] acceptAlltrustManagers() {
|
||||||
|
return new TrustManager[] { new X509TrustManager() {
|
||||||
|
@Override
|
||||||
|
public void checkClientTrusted(final X509Certificate @Nullable [] chain, final @Nullable String authType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkServerTrusted(final X509Certificate @Nullable [] chain, final @Nullable String authType) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509Certificate @Nullable [] getAcceptedIssuers() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} };
|
||||||
|
}
|
||||||
|
|
||||||
|
class EventDeserializer implements JsonDeserializer<Event> {
|
||||||
|
@Override
|
||||||
|
public @Nullable Event deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||||
|
throws JsonParseException {
|
||||||
|
JsonObject jsonObject = json.getAsJsonObject();
|
||||||
|
JsonElement event = jsonObject.get("event");
|
||||||
|
if (event != null) {
|
||||||
|
switch (EventType.valueOf(event.getAsString())) {
|
||||||
|
case ALARM:
|
||||||
|
return context.deserialize(jsonObject, AlarmEvent.class);
|
||||||
|
case ARMING:
|
||||||
|
return context.deserialize(jsonObject, ArmingEvent.class);
|
||||||
|
case ERROR:
|
||||||
|
return context.deserialize(jsonObject, ErrorEvent.class);
|
||||||
|
case INFO:
|
||||||
|
JsonElement infoType = jsonObject.get("info_type");
|
||||||
|
if (infoType != null) {
|
||||||
|
switch (InfoEventType.valueOf(infoType.getAsString())) {
|
||||||
|
case SECURE_ARM:
|
||||||
|
return context.deserialize(jsonObject, SecureArmInfoEvent.class);
|
||||||
|
case SUMMARY:
|
||||||
|
return context.deserialize(jsonObject, SummaryInfoEvent.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZONE_EVENT:
|
||||||
|
JsonElement zoneEventType = jsonObject.get("zone_event_type");
|
||||||
|
if (zoneEventType != null) {
|
||||||
|
switch (ZoneEventType.valueOf(zoneEventType.getAsString())) {
|
||||||
|
case ZONE_ACTIVE:
|
||||||
|
return context.deserialize(jsonObject, ZoneActiveEvent.class);
|
||||||
|
case ZONE_UPDATE:
|
||||||
|
return context.deserialize(jsonObject, ZoneUpdateEvent.class);
|
||||||
|
case ZONE_ADD:
|
||||||
|
return context.deserialize(jsonObject, ZoneAddEvent.class);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base type for various action messages sent to a panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public abstract class Action {
|
||||||
|
@SerializedName("action")
|
||||||
|
public ActionType type;
|
||||||
|
public Integer version = 0;
|
||||||
|
public String source = "C4";
|
||||||
|
public String token;
|
||||||
|
|
||||||
|
public Action(ActionType type) {
|
||||||
|
this(type, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action(ActionType type, String token) {
|
||||||
|
this.type = type;
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of {@link Action} sent to a panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum ActionType {
|
||||||
|
ALARM,
|
||||||
|
ARMING,
|
||||||
|
INFO
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ActionType.ALARM} type of {@link Action} message sent to the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class AlarmAction extends Action {
|
||||||
|
public AlarmActionType alarmType;
|
||||||
|
|
||||||
|
public AlarmAction(AlarmActionType alarmType) {
|
||||||
|
this(alarmType, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AlarmAction(AlarmActionType alarmType, String token) {
|
||||||
|
super(ActionType.ALARM, token);
|
||||||
|
this.alarmType = alarmType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of {@link AlarmAction} sent to a panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum AlarmActionType {
|
||||||
|
AUXILIARY,
|
||||||
|
FIRE,
|
||||||
|
POLCIE
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ArmingActionType.ARM_AWAY} type of {@link ArmingAction} message sent to the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ArmAwayArmingAction extends ArmingAction {
|
||||||
|
public Integer delay;
|
||||||
|
|
||||||
|
public ArmAwayArmingAction(String token, Integer partitionId, Integer delay) {
|
||||||
|
super(ArmingActionType.ARM_AWAY, token, partitionId);
|
||||||
|
this.delay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmAwayArmingAction(String token, Integer partitionId) {
|
||||||
|
this(token, partitionId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmAwayArmingAction(Integer partitionId) {
|
||||||
|
this("", partitionId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmAwayArmingAction(Integer partitionId, Integer delay) {
|
||||||
|
this("", partitionId, delay);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ActionType.ARMING} type of {@link ArmingAction} message sent to the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ArmingAction extends Action {
|
||||||
|
public ArmingActionType armingType;
|
||||||
|
public Integer partitionId;
|
||||||
|
public String usercode;
|
||||||
|
|
||||||
|
public ArmingAction(ArmingActionType armingType, Integer partitionId) {
|
||||||
|
this(armingType, "", partitionId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmingAction(ArmingActionType armingType, Integer partitionId, String usercode) {
|
||||||
|
this(armingType, "", partitionId, usercode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmingAction(ArmingActionType armingType, String token, Integer partitionId) {
|
||||||
|
this(armingType, token, partitionId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArmingAction(ArmingActionType armingType, String token, Integer partitionId, String usercode) {
|
||||||
|
super(ActionType.ARMING, token);
|
||||||
|
this.armingType = armingType;
|
||||||
|
this.partitionId = partitionId;
|
||||||
|
this.usercode = usercode;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of {@link ArmingAction} sent to a panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum ArmingActionType {
|
||||||
|
ARM_AWAY,
|
||||||
|
ARM_STAY,
|
||||||
|
DISARM;
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ActionType.INFO} type of {@link InfoAction} message sent to the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class InfoAction extends Action {
|
||||||
|
public InfoActionType infoType;
|
||||||
|
|
||||||
|
public InfoAction(InfoActionType infoType) {
|
||||||
|
this(infoType, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoAction(InfoActionType infoType, String token) {
|
||||||
|
super(ActionType.INFO, token);
|
||||||
|
this.infoType = infoType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.action;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of {@link InfoAction} sent to a panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum InfoActionType {
|
||||||
|
SUMMARY,
|
||||||
|
SECURE_ARM
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.AlarmType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link EventType.ALARM} type of {@link Event} message sent from the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class AlarmEvent extends Event {
|
||||||
|
public AlarmType alarmType;
|
||||||
|
public Integer partitionId;
|
||||||
|
|
||||||
|
public AlarmEvent() {
|
||||||
|
super(EventType.ALARM);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.PartitionStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link EventType.ARMING} type of {@link Event} message sent from the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ArmingEvent extends Event {
|
||||||
|
public PartitionStatus armingType;
|
||||||
|
public Integer partitionId;
|
||||||
|
public Integer delay;
|
||||||
|
|
||||||
|
public ArmingEvent() {
|
||||||
|
super(EventType.ARMING);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link EventType.ERROR} type of {@link Event} message sent from the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ErrorEvent extends Event {
|
||||||
|
public String errorType;
|
||||||
|
public String description;
|
||||||
|
public Integer partitionId;
|
||||||
|
|
||||||
|
public ErrorEvent() {
|
||||||
|
super(EventType.ERROR);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The base type for various event messages sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public abstract class Event {
|
||||||
|
@SerializedName("event")
|
||||||
|
public EventType eventType;
|
||||||
|
public String nonce;
|
||||||
|
@SerializedName("requestID")
|
||||||
|
public String requestID;
|
||||||
|
|
||||||
|
public Event(EventType eventType) {
|
||||||
|
this.eventType = eventType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of {@link Event} sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum EventType {
|
||||||
|
ALARM,
|
||||||
|
ARMING,
|
||||||
|
ERROR,
|
||||||
|
INFO,
|
||||||
|
ZONE_EVENT;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link EventType.INFO} type of {@link Event} message sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public abstract class InfoEvent extends Event {
|
||||||
|
public InfoEventType infoType;
|
||||||
|
|
||||||
|
public InfoEvent(InfoEventType infoType) {
|
||||||
|
super(EventType.INFO);
|
||||||
|
this.infoType = infoType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of {@link InfoEvent} sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum InfoEventType {
|
||||||
|
SUMMARY,
|
||||||
|
SECURE_ARM;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link InfoEventType.SECURE_ARM} type of {@link InfoEvent} message sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class SecureArmInfoEvent extends InfoEvent {
|
||||||
|
public Integer partitionId;
|
||||||
|
public Boolean value;
|
||||||
|
|
||||||
|
public SecureArmInfoEvent() {
|
||||||
|
super(InfoEventType.SECURE_ARM);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.Partition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link InfoEventType.SUMMARY} type of {@link InfoEvent} message sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class SummaryInfoEvent extends InfoEvent {
|
||||||
|
public List<Partition> partitionList;
|
||||||
|
|
||||||
|
public SummaryInfoEvent() {
|
||||||
|
super(InfoEventType.SUMMARY);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.ZoneActiveState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ZoneEventType.ZONE_ACTIVE} type of {@link ZoneEvent} message sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ZoneActiveEvent extends ZoneEvent {
|
||||||
|
public ZoneActiveState zone;
|
||||||
|
|
||||||
|
public ZoneActiveEvent() {
|
||||||
|
super(ZoneEventType.ZONE_ACTIVE);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.Zone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ZoneEventType.ZONE_ADD} type of {@link ZoneEvent} message sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ZoneAddEvent extends ZoneEvent {
|
||||||
|
public Zone zone;
|
||||||
|
|
||||||
|
public ZoneAddEvent() {
|
||||||
|
super(ZoneEventType.ZONE_ADD);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Zone {@link Event} message sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public abstract class ZoneEvent extends Event {
|
||||||
|
@SerializedName("zone_event_type")
|
||||||
|
public ZoneEventType type;
|
||||||
|
|
||||||
|
public ZoneEvent(ZoneEventType type) {
|
||||||
|
super(EventType.ZONE_EVENT);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of {@link ZoneEvent} sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum ZoneEventType {
|
||||||
|
ZONE_ACTIVE,
|
||||||
|
ZONE_ADD,
|
||||||
|
ZONE_UPDATE;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.event;
|
||||||
|
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.Zone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ZoneEventType.ZONE_UPDATE} type of {@link ZoneEvent} message sent by the panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ZoneUpdateEvent extends ZoneEvent {
|
||||||
|
public Zone zone;
|
||||||
|
|
||||||
|
public ZoneUpdateEvent() {
|
||||||
|
super(ZoneEventType.ZONE_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.model;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of alarm
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum AlarmType {
|
||||||
|
AUXILIARY,
|
||||||
|
FIRE,
|
||||||
|
POLICE,
|
||||||
|
@SerializedName("")
|
||||||
|
ZONEOPEN,
|
||||||
|
NONE;
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.model;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A logical alarm partition that can be armed, report state and contain zones
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class Partition {
|
||||||
|
public Integer partitionId;
|
||||||
|
public String name;
|
||||||
|
public PartitionStatus status;
|
||||||
|
public Boolean secureArm;
|
||||||
|
public List<Zone> zoneList;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current status of an alarm panel
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum PartitionStatus {
|
||||||
|
ALARM,
|
||||||
|
ARM_AWAY,
|
||||||
|
ARM_STAY,
|
||||||
|
DISARM,
|
||||||
|
ENTRY_DELAY,
|
||||||
|
EXIT_DELAY;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zone sensor
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class Zone {
|
||||||
|
public String id;
|
||||||
|
public String type;
|
||||||
|
public String name;
|
||||||
|
public String group;
|
||||||
|
public ZoneStatus status;
|
||||||
|
public Integer state;
|
||||||
|
public Integer zoneId;
|
||||||
|
public Integer zonePhysicalType;
|
||||||
|
public Integer zoneAlarmType;
|
||||||
|
public ZoneType zoneType;
|
||||||
|
public Integer partitionId;
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The active state of a zone
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public class ZoneActiveState {
|
||||||
|
public Integer zoneId;
|
||||||
|
public ZoneStatus status;
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.model;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the status of a zone
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum ZoneStatus {
|
||||||
|
@SerializedName("Active")
|
||||||
|
ACTIVE,
|
||||||
|
@SerializedName("Closed")
|
||||||
|
CLOSED,
|
||||||
|
@SerializedName("Open")
|
||||||
|
OPEN,
|
||||||
|
@SerializedName("Failure")
|
||||||
|
FAILURE,
|
||||||
|
@SerializedName("Idle")
|
||||||
|
IDlE,
|
||||||
|
@SerializedName("Tamper")
|
||||||
|
TAMPER;
|
||||||
|
}
|
@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.client.dto.model;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The zone physical type
|
||||||
|
*
|
||||||
|
* Big thanks to the folks at https://community.home-assistant.io/t/qolsys-iq-panel-2-and-3rd-party-integration/231405
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
public enum ZoneType {
|
||||||
|
@SerializedName("0")
|
||||||
|
UNKNOWN,
|
||||||
|
@SerializedName("1")
|
||||||
|
CONTACT,
|
||||||
|
@SerializedName("2")
|
||||||
|
MOTION,
|
||||||
|
@SerializedName("3")
|
||||||
|
SOUND,
|
||||||
|
@SerializedName("4")
|
||||||
|
BREAKAGE,
|
||||||
|
@SerializedName("5")
|
||||||
|
SMOKE_HEAT,
|
||||||
|
@SerializedName("6")
|
||||||
|
CARBON_MONOXIDE,
|
||||||
|
@SerializedName("7")
|
||||||
|
RADON,
|
||||||
|
@SerializedName("8")
|
||||||
|
TEMPERATURE,
|
||||||
|
@SerializedName("9")
|
||||||
|
PANIC_BUTTON,
|
||||||
|
@SerializedName("10")
|
||||||
|
CONTROL,
|
||||||
|
@SerializedName("11")
|
||||||
|
CAMERA,
|
||||||
|
@SerializedName("12")
|
||||||
|
LIGHT,
|
||||||
|
@SerializedName("13")
|
||||||
|
GPS,
|
||||||
|
@SerializedName("14")
|
||||||
|
SIREN,
|
||||||
|
@SerializedName("15")
|
||||||
|
WATER,
|
||||||
|
@SerializedName("16")
|
||||||
|
TILT,
|
||||||
|
@SerializedName("17")
|
||||||
|
FREEZE,
|
||||||
|
@SerializedName("18")
|
||||||
|
TAKEOVER_MODULE,
|
||||||
|
@SerializedName("19")
|
||||||
|
GLASSBREAK,
|
||||||
|
@SerializedName("20")
|
||||||
|
TRANSLATOR,
|
||||||
|
@SerializedName("21")
|
||||||
|
MEDICAL_PENDANT,
|
||||||
|
@SerializedName("22")
|
||||||
|
WATER_IQ_FLOOD,
|
||||||
|
@SerializedName("23")
|
||||||
|
WATER_OTHER_FLOOD,
|
||||||
|
@SerializedName("30")
|
||||||
|
IMAGE_SENSOR,
|
||||||
|
@SerializedName("100")
|
||||||
|
WIRED_SENSOR,
|
||||||
|
@SerializedName("101")
|
||||||
|
RF_SENSOR,
|
||||||
|
@SerializedName("102")
|
||||||
|
KEYFOB,
|
||||||
|
@SerializedName("103")
|
||||||
|
WALLFOB,
|
||||||
|
@SerializedName("104")
|
||||||
|
RF_KEYPAD,
|
||||||
|
@SerializedName("105")
|
||||||
|
PANEL,
|
||||||
|
@SerializedName("106")
|
||||||
|
WTTS_OR_SECONDARY,
|
||||||
|
@SerializedName("107")
|
||||||
|
SHOCK,
|
||||||
|
@SerializedName("108")
|
||||||
|
SHOCK_SENSOR_MULTI_FUNCTION,
|
||||||
|
@SerializedName("109")
|
||||||
|
DOOR_BELL,
|
||||||
|
@SerializedName("110")
|
||||||
|
CONTACT_MULTI_FUNCTION,
|
||||||
|
@SerializedName("111")
|
||||||
|
SMOKE_MULTI_FUNCTION,
|
||||||
|
@SerializedName("112")
|
||||||
|
TEMPERATURE_MULTI_FUNCTION,
|
||||||
|
@SerializedName("113")
|
||||||
|
SHOCK_OTHERS,
|
||||||
|
@SerializedName("114")
|
||||||
|
OCCUPANCY_SENSOR,
|
||||||
|
@SerializedName("115")
|
||||||
|
BLUETOOTH,
|
||||||
|
@SerializedName("116")
|
||||||
|
PANEL_GLASS_BREAK,
|
||||||
|
@SerializedName("117")
|
||||||
|
POWERG_SIREN,
|
||||||
|
@SerializedName("118")
|
||||||
|
BLUETOOTH_SPEAKER,
|
||||||
|
@SerializedName("119")
|
||||||
|
PANEL_MOTION,
|
||||||
|
@SerializedName("120")
|
||||||
|
ZWAVE_SIREN,
|
||||||
|
@SerializedName("121")
|
||||||
|
COUNT;
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQPanelConfiguration} class contains fields mapping thing configuration parameters.
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQPanelConfiguration {
|
||||||
|
public String hostname = "";
|
||||||
|
public int port = 12345;
|
||||||
|
public String key = "";
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQPartitionConfiguration} class contains fields mapping thing configuration parameters.
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQPartitionConfiguration {
|
||||||
|
public int id = 0;
|
||||||
|
public String armCode = "";
|
||||||
|
public String disarmCode = "";
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.config;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQZoneConfiguration} class contains fields mapping thing configuration parameters.
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQZoneConfiguration {
|
||||||
|
public int id = 0;
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.discovery;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.QolsysIQBindingConstants;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.handler.QolsysIQChildDiscoveryHandler;
|
||||||
|
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.config.discovery.DiscoveryService;
|
||||||
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple discovery service that can be used by Partition and Zone Handlers
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQChildDiscoveryService extends AbstractDiscoveryService
|
||||||
|
implements DiscoveryService, ThingHandlerService {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(QolsysIQChildDiscoveryService.class);
|
||||||
|
|
||||||
|
private static final Set<ThingTypeUID> SUPPORTED_DISCOVERY_THING_TYPES_UIDS = Set
|
||||||
|
.of(QolsysIQBindingConstants.THING_TYPE_PARTITION, QolsysIQBindingConstants.THING_TYPE_ZONE);
|
||||||
|
|
||||||
|
private @Nullable ThingHandler thingHandler;
|
||||||
|
|
||||||
|
public QolsysIQChildDiscoveryService() throws IllegalArgumentException {
|
||||||
|
super(SUPPORTED_DISCOVERY_THING_TYPES_UIDS, 5, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setThingHandler(ThingHandler handler) {
|
||||||
|
if (handler instanceof QolsysIQChildDiscoveryHandler) {
|
||||||
|
((QolsysIQChildDiscoveryHandler) handler).setDiscoveryService(this);
|
||||||
|
this.thingHandler = handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ThingHandler getThingHandler() {
|
||||||
|
return thingHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void startScan() {
|
||||||
|
ThingHandler handler = this.thingHandler;
|
||||||
|
if (handler != null) {
|
||||||
|
((QolsysIQChildDiscoveryHandler) handler).startDiscovery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void activate() {
|
||||||
|
super.activate(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deactivate() {
|
||||||
|
super.deactivate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void discoverQolsysIQChildThing(ThingUID thingUID, ThingUID bridgeUID, Integer id, String label) {
|
||||||
|
logger.trace("discoverQolsysIQChildThing: {} {} {} {}", thingUID, bridgeUID, id, label);
|
||||||
|
DiscoveryResult result = DiscoveryResultBuilder.create(thingUID).withLabel(label).withProperty("id", id)
|
||||||
|
.withRepresentationProperty("id").withBridge(bridgeUID).build();
|
||||||
|
thingDiscovered(result);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.handler;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.discovery.QolsysIQChildDiscoveryService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for our custom discovery service
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public interface QolsysIQChildDiscoveryHandler {
|
||||||
|
/**
|
||||||
|
* Sets a {@link QolsysIQChildDiscoveryService} to call when device information is received
|
||||||
|
*
|
||||||
|
* @param service
|
||||||
|
*/
|
||||||
|
public void setDiscoveryService(QolsysIQChildDiscoveryService service);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates the discovery process
|
||||||
|
*/
|
||||||
|
public void startDiscovery();
|
||||||
|
}
|
@ -0,0 +1,327 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.handler;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.QolsysIQBindingConstants;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.QolsysIQClientListener;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.QolsysiqClient;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.Action;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.InfoAction;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.InfoActionType;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.AlarmEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ArmingEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ErrorEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.SecureArmInfoEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.SummaryInfoEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneActiveEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneAddEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneUpdateEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.Partition;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.config.QolsysIQPanelConfiguration;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.discovery.QolsysIQChildDiscoveryService;
|
||||||
|
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.ThingStatusDetail;
|
||||||
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.RefreshType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQPanelHandler} connects to a security panel and routes messages to child partitions.
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQPanelHandler extends BaseBridgeHandler
|
||||||
|
implements QolsysIQClientListener, QolsysIQChildDiscoveryHandler {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(QolsysIQPanelHandler.class);
|
||||||
|
private static final int QUICK_RETRY_SECONDS = 1;
|
||||||
|
private static final int LONG_RETRY_SECONDS = 30;
|
||||||
|
private static final int HEARTBEAT_SECONDS = 30;
|
||||||
|
private @Nullable QolsysiqClient apiClient;
|
||||||
|
private @Nullable ScheduledFuture<?> retryFuture;
|
||||||
|
private @Nullable QolsysIQChildDiscoveryService discoveryService;
|
||||||
|
private List<Partition> partitions = Collections.synchronizedList(new LinkedList<Partition>());
|
||||||
|
private String key = "";
|
||||||
|
|
||||||
|
public QolsysIQPanelHandler(Bridge bridge) {
|
||||||
|
super(bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
logger.debug("handleCommand {}", command);
|
||||||
|
if (command instanceof RefreshType) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
logger.debug("initialize");
|
||||||
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
scheduler.execute(() -> {
|
||||||
|
connect();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
stopRetryFuture();
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||||
|
return Collections.singleton(QolsysIQChildDiscoveryService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDiscoveryService(QolsysIQChildDiscoveryService service) {
|
||||||
|
this.discoveryService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startDiscovery() {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnected(Exception reason) {
|
||||||
|
logger.debug("disconnected", reason);
|
||||||
|
setOfflineAndReconnect(reason, QUICK_RETRY_SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void alarmEvent(AlarmEvent event) {
|
||||||
|
logger.debug("AlarmEvent {}", event.partitionId);
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(event.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.alarmEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void armingEvent(ArmingEvent event) {
|
||||||
|
logger.debug("ArmingEvent {}", event.partitionId);
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(event.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.armingEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void errorEvent(ErrorEvent event) {
|
||||||
|
logger.debug("ErrorEvent {}", event.partitionId);
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(event.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.errorEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void summaryInfoEvent(SummaryInfoEvent event) {
|
||||||
|
logger.debug("SummaryInfoEvent");
|
||||||
|
synchronized (partitions) {
|
||||||
|
partitions.clear();
|
||||||
|
partitions.addAll(event.partitionList);
|
||||||
|
}
|
||||||
|
updatePartitions();
|
||||||
|
discoverChildDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void secureArmInfoEvent(SecureArmInfoEvent event) {
|
||||||
|
logger.debug("ArmingEvent {}", event.value);
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(event.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.secureArmInfoEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoneActiveEvent(ZoneActiveEvent event) {
|
||||||
|
logger.debug("ZoneActiveEvent {} {}", event.zone.zoneId, event.zone.status);
|
||||||
|
partitions.forEach(p -> {
|
||||||
|
if (p.zoneList.stream().filter(z -> z.zoneId.equals(event.zone.zoneId)).findAny().isPresent()) {
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(p.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.zoneActiveEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoneUpdateEvent(ZoneUpdateEvent event) {
|
||||||
|
logger.debug("ZoneUpdateEvent {}", event.zone.name);
|
||||||
|
partitions.forEach(p -> {
|
||||||
|
if (p.zoneList.stream().filter(z -> z.zoneId.equals(event.zone.zoneId)).findAny().isPresent()) {
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(p.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.zoneUpdateEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void zoneAddEvent(ZoneAddEvent event) {
|
||||||
|
logger.debug("ZoneAddEvent {}", event.zone.name);
|
||||||
|
partitions.forEach(p -> {
|
||||||
|
if (p.zoneList.stream().filter(z -> z.zoneId.equals(event.zone.zoneId)).findAny().isPresent()) {
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(p.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.zoneAddEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the action to the panel. This will replace the token of the action passed in with the one configured here
|
||||||
|
*
|
||||||
|
* @param action
|
||||||
|
*/
|
||||||
|
protected void sendAction(Action action) {
|
||||||
|
action.token = key;
|
||||||
|
QolsysiqClient client = this.apiClient;
|
||||||
|
if (client != null) {
|
||||||
|
try {
|
||||||
|
client.sendAction(action);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Could not send action", e);
|
||||||
|
setOfflineAndReconnect(e, QUICK_RETRY_SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void refresh() {
|
||||||
|
sendAction(new InfoAction(InfoActionType.SUMMARY));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect the client
|
||||||
|
*/
|
||||||
|
private synchronized void connect() {
|
||||||
|
if (getThing().getStatus() == ThingStatus.ONLINE) {
|
||||||
|
logger.debug("connect: Bridge is already connected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QolsysIQPanelConfiguration config = getConfigAs(QolsysIQPanelConfiguration.class);
|
||||||
|
key = config.key;
|
||||||
|
|
||||||
|
try {
|
||||||
|
QolsysiqClient apiClient = new QolsysiqClient(config.hostname, config.port, HEARTBEAT_SECONDS, scheduler,
|
||||||
|
"OH-binding-" + getThing().getUID().getAsString());
|
||||||
|
apiClient.connect();
|
||||||
|
apiClient.addListener(this);
|
||||||
|
this.apiClient = apiClient;
|
||||||
|
refresh();
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.debug("Could not connect");
|
||||||
|
setOfflineAndReconnect(e, LONG_RETRY_SECONDS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnects the client and removes listeners
|
||||||
|
*/
|
||||||
|
private void disconnect() {
|
||||||
|
logger.debug("disconnect");
|
||||||
|
QolsysiqClient apiClient = this.apiClient;
|
||||||
|
if (apiClient != null) {
|
||||||
|
apiClient.removeListener(this);
|
||||||
|
apiClient.disconnect();
|
||||||
|
this.apiClient = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startRetryFuture(int seconds) {
|
||||||
|
stopRetryFuture();
|
||||||
|
logger.debug("startRetryFuture");
|
||||||
|
this.retryFuture = scheduler.schedule(this::connect, seconds, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopRetryFuture() {
|
||||||
|
logger.debug("stopRetryFuture");
|
||||||
|
ScheduledFuture<?> retryFuture = this.retryFuture;
|
||||||
|
if (retryFuture != null) {
|
||||||
|
retryFuture.cancel(true);
|
||||||
|
this.retryFuture = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOfflineAndReconnect(Exception reason, int seconds) {
|
||||||
|
logger.debug("setOfflineAndReconnect");
|
||||||
|
disconnect();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, reason.getMessage());
|
||||||
|
startRetryFuture(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePartitions() {
|
||||||
|
synchronized (partitions) {
|
||||||
|
partitions.forEach(p -> {
|
||||||
|
QolsysIQPartitionHandler handler = partitionHandler(p.partitionId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.updatePartition(p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void discoverChildDevices() {
|
||||||
|
synchronized (partitions) {
|
||||||
|
QolsysIQChildDiscoveryService discoveryService = this.discoveryService;
|
||||||
|
if (discoveryService != null) {
|
||||||
|
partitions.forEach(p -> {
|
||||||
|
ThingUID bridgeUID = getThing().getUID();
|
||||||
|
ThingUID thingUID = new ThingUID(QolsysIQBindingConstants.THING_TYPE_PARTITION, bridgeUID,
|
||||||
|
String.valueOf(p.partitionId));
|
||||||
|
discoveryService.discoverQolsysIQChildThing(thingUID, bridgeUID, p.partitionId,
|
||||||
|
"Qolsys IQ Partition: " + p.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable QolsysIQPartitionHandler partitionHandler(int partitionId) {
|
||||||
|
for (Thing thing : getThing().getThings()) {
|
||||||
|
ThingHandler handler = thing.getHandler();
|
||||||
|
if (handler instanceof QolsysIQPartitionHandler) {
|
||||||
|
if (((QolsysIQPartitionHandler) handler).getPartitionId() == partitionId) {
|
||||||
|
return (QolsysIQPartitionHandler) handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,369 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.handler;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.QolsysIQBindingConstants;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.AlarmAction;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.AlarmActionType;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.ArmingAction;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.action.ArmingActionType;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.AlarmEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ArmingEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ErrorEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.SecureArmInfoEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneActiveEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneAddEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneUpdateEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.AlarmType;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.Partition;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.PartitionStatus;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.Zone;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.config.QolsysIQPartitionConfiguration;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.discovery.QolsysIQChildDiscoveryService;
|
||||||
|
import org.openhab.core.library.types.DecimalType;
|
||||||
|
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.ThingStatusDetail;
|
||||||
|
import org.openhab.core.thing.ThingStatusInfo;
|
||||||
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||||
|
import org.openhab.core.thing.binding.BridgeHandler;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.RefreshType;
|
||||||
|
import org.openhab.core.types.UnDefType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQPartitionHandler} manages security partitions
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQPartitionHandler extends BaseBridgeHandler implements QolsysIQChildDiscoveryHandler {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(QolsysIQPartitionHandler.class);
|
||||||
|
private static final int CLEAR_ERROR_MESSSAGE_TIME = 30;
|
||||||
|
private @Nullable QolsysIQChildDiscoveryService discoveryService;
|
||||||
|
private @Nullable ScheduledFuture<?> delayFuture;
|
||||||
|
private @Nullable ScheduledFuture<?> errorFuture;
|
||||||
|
private @Nullable String armCode;
|
||||||
|
private @Nullable String disarmCode;
|
||||||
|
private List<Zone> zones = Collections.synchronizedList(new LinkedList<Zone>());
|
||||||
|
private int partitionId;
|
||||||
|
|
||||||
|
public QolsysIQPartitionHandler(Bridge bridge) {
|
||||||
|
super(bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
QolsysIQPartitionConfiguration config = getConfigAs(QolsysIQPartitionConfiguration.class);
|
||||||
|
partitionId = config.id;
|
||||||
|
armCode = config.armCode.isBlank() ? null : config.armCode;
|
||||||
|
disarmCode = config.disarmCode.isBlank() ? null : config.disarmCode;
|
||||||
|
logger.debug("initialize partition {}", partitionId);
|
||||||
|
initializePartition();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dispose() {
|
||||||
|
cancelExitDelayJob();
|
||||||
|
cancelErrorDelayJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
|
||||||
|
if (bridgeStatusInfo.getStatus() != ThingStatus.ONLINE) {
|
||||||
|
cancelExitDelayJob();
|
||||||
|
cancelErrorDelayJob();
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||||
|
} else {
|
||||||
|
initializePartition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
if (command instanceof RefreshType) {
|
||||||
|
refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QolsysIQPanelHandler panel = panelHandler();
|
||||||
|
if (panel != null) {
|
||||||
|
if (channelUID.getId().equals(QolsysIQBindingConstants.CHANNEL_PARTITION_ALARM_STATE)) {
|
||||||
|
try {
|
||||||
|
panel.sendAction(new AlarmAction(AlarmActionType.valueOf(command.toString())));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
logger.debug("Unknown alarm type {} to channel {}", command, channelUID);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// support ARM_AWAY and ARM_AWAY:123456 , same for other arm / disarm modes
|
||||||
|
if (channelUID.getId().equals(QolsysIQBindingConstants.CHANNEL_PARTITION_ARM_STATE)) {
|
||||||
|
String armingTypeName = command.toString();
|
||||||
|
String code = null;
|
||||||
|
if (armingTypeName.contains(":")) {
|
||||||
|
String[] split = armingTypeName.split(":");
|
||||||
|
armingTypeName = split[0];
|
||||||
|
if (split.length > 1 && split[1].length() > 0) {
|
||||||
|
code = split[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ArmingActionType armingType = ArmingActionType.valueOf(armingTypeName);
|
||||||
|
if (code == null) {
|
||||||
|
if (armingType == ArmingActionType.DISARM) {
|
||||||
|
code = disarmCode;
|
||||||
|
} else {
|
||||||
|
code = armCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panel.sendAction(new ArmingAction(armingType, getPartitionId(), code));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
logger.debug("Unknown arm type {} to channel {}", armingTypeName, channelUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||||
|
return Collections.singleton(QolsysIQChildDiscoveryService.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDiscoveryService(QolsysIQChildDiscoveryService service) {
|
||||||
|
this.discoveryService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startDiscovery() {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The partition id
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getPartitionId() {
|
||||||
|
return partitionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void zoneActiveEvent(ZoneActiveEvent event) {
|
||||||
|
QolsysIQZoneHandler handler = zoneHandler(event.zone.zoneId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.zoneActiveEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void zoneUpdateEvent(ZoneUpdateEvent event) {
|
||||||
|
QolsysIQZoneHandler handler = zoneHandler(event.zone.zoneId);
|
||||||
|
if (handler != null) {
|
||||||
|
handler.zoneUpdateEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void alarmEvent(AlarmEvent event) {
|
||||||
|
if (event.alarmType != AlarmType.NONE && event.alarmType != AlarmType.ZONEOPEN) {
|
||||||
|
updatePartitionStatus(PartitionStatus.ALARM);
|
||||||
|
}
|
||||||
|
updateAlarmState(event.alarmType);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void armingEvent(ArmingEvent event) {
|
||||||
|
updatePartitionStatus(event.armingType);
|
||||||
|
updateDelay(event.delay == null ? 0 : event.delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void errorEvent(ErrorEvent event) {
|
||||||
|
cancelErrorDelayJob();
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_PARTITION_ERROR_EVENT, new StringType(event.description));
|
||||||
|
errorFuture = scheduler.schedule(this::clearErrorEvent, CLEAR_ERROR_MESSSAGE_TIME, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void secureArmInfoEvent(SecureArmInfoEvent event) {
|
||||||
|
setSecureArm(event.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void zoneAddEvent(ZoneAddEvent event) {
|
||||||
|
discoverZone(event.zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updatePartition(Partition partition) {
|
||||||
|
updatePartitionStatus(partition.status);
|
||||||
|
setSecureArm(partition.secureArm);
|
||||||
|
if (partition.status != PartitionStatus.ALARM) {
|
||||||
|
updateAlarmState(AlarmType.NONE);
|
||||||
|
}
|
||||||
|
synchronized (zones) {
|
||||||
|
zones.clear();
|
||||||
|
zones.addAll(partition.zoneList);
|
||||||
|
zones.forEach(z -> {
|
||||||
|
QolsysIQZoneHandler zoneHandler = zoneHandler(z.zoneId);
|
||||||
|
if (zoneHandler != null) {
|
||||||
|
zoneHandler.updateZone(z);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (getThing().getStatus() != ThingStatus.ONLINE) {
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
}
|
||||||
|
discoverChildDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected @Nullable Zone getZone(Integer zoneId) {
|
||||||
|
synchronized (zones) {
|
||||||
|
return zones.stream().filter(z -> z.zoneId.equals(zoneId)).findAny().orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializePartition() {
|
||||||
|
QolsysIQPanelHandler panel = panelHandler();
|
||||||
|
if (panel == null) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||||
|
} else if (panel.getThing().getStatus() != ThingStatus.ONLINE) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||||
|
} else {
|
||||||
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
scheduler.execute(() -> {
|
||||||
|
panel.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh() {
|
||||||
|
QolsysIQPanelHandler panel = panelHandler();
|
||||||
|
if (panel != null) {
|
||||||
|
panel.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updatePartitionStatus(PartitionStatus status) {
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_PARTITION_ARM_STATE, new StringType(status.toString()));
|
||||||
|
cancelErrorDelayJob();
|
||||||
|
if (status == PartitionStatus.DISARM) {
|
||||||
|
updateAlarmState(AlarmType.NONE);
|
||||||
|
updateDelay(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSecureArm(Boolean secure) {
|
||||||
|
Map<String, String> props = new HashMap<String, String>();
|
||||||
|
props.put("secureArm", String.valueOf(secure));
|
||||||
|
getThing().setProperties(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDelay(Integer delay) {
|
||||||
|
cancelExitDelayJob();
|
||||||
|
if (delay <= 0) {
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_PARTITION_COMMAND_DELAY, new DecimalType(0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final long endTime = System.currentTimeMillis() + (delay * 1000);
|
||||||
|
delayFuture = scheduler.scheduleAtFixedRate(() -> {
|
||||||
|
long remaining = endTime - System.currentTimeMillis();
|
||||||
|
logger.debug("updateDelay remaining {}", remaining / 1000);
|
||||||
|
if (remaining <= 0) {
|
||||||
|
cancelExitDelayJob();
|
||||||
|
} else {
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_PARTITION_COMMAND_DELAY,
|
||||||
|
new DecimalType(remaining / 1000));
|
||||||
|
}
|
||||||
|
}, 1, 1, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAlarmState(AlarmType alarmType) {
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_PARTITION_ALARM_STATE, new StringType(alarmType.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearErrorEvent() {
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_PARTITION_ERROR_EVENT, UnDefType.NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelExitDelayJob() {
|
||||||
|
ScheduledFuture<?> delayFuture = this.delayFuture;
|
||||||
|
if (delayFuture != null) {
|
||||||
|
delayFuture.cancel(true);
|
||||||
|
this.delayFuture = null;
|
||||||
|
}
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_PARTITION_COMMAND_DELAY, new DecimalType(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cancelErrorDelayJob() {
|
||||||
|
ScheduledFuture<?> errorFuture = this.errorFuture;
|
||||||
|
if (errorFuture != null) {
|
||||||
|
errorFuture.cancel(true);
|
||||||
|
this.errorFuture = null;
|
||||||
|
}
|
||||||
|
clearErrorEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void discoverChildDevices() {
|
||||||
|
synchronized (zones) {
|
||||||
|
zones.forEach(z -> discoverZone(z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void discoverZone(Zone z) {
|
||||||
|
QolsysIQChildDiscoveryService discoveryService = this.discoveryService;
|
||||||
|
if (discoveryService != null) {
|
||||||
|
ThingUID bridgeUID = getThing().getUID();
|
||||||
|
ThingUID thingUID = new ThingUID(QolsysIQBindingConstants.THING_TYPE_ZONE, bridgeUID,
|
||||||
|
String.valueOf(z.zoneId));
|
||||||
|
discoveryService.discoverQolsysIQChildThing(thingUID, bridgeUID, z.zoneId, "Qolsys IQ Zone: " + z.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable QolsysIQZoneHandler zoneHandler(int zoneId) {
|
||||||
|
for (Thing thing : getThing().getThings()) {
|
||||||
|
ThingHandler handler = thing.getHandler();
|
||||||
|
if (handler instanceof QolsysIQZoneHandler) {
|
||||||
|
if (((QolsysIQZoneHandler) handler).getZoneId() == zoneId) {
|
||||||
|
return (QolsysIQZoneHandler) handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable QolsysIQPanelHandler panelHandler() {
|
||||||
|
Bridge bridge = getBridge();
|
||||||
|
if (bridge != null) {
|
||||||
|
BridgeHandler handler = bridge.getHandler();
|
||||||
|
if (handler instanceof QolsysIQPanelHandler) {
|
||||||
|
return (QolsysIQPanelHandler) handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,135 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 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.qolsysiq.internal.handler;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.QolsysIQBindingConstants;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneActiveEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.event.ZoneUpdateEvent;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.Zone;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.client.dto.model.ZoneStatus;
|
||||||
|
import org.openhab.binding.qolsysiq.internal.config.QolsysIQZoneConfiguration;
|
||||||
|
import org.openhab.core.library.types.DecimalType;
|
||||||
|
import org.openhab.core.library.types.OpenClosedType;
|
||||||
|
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.ThingStatusDetail;
|
||||||
|
import org.openhab.core.thing.ThingStatusInfo;
|
||||||
|
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||||
|
import org.openhab.core.thing.binding.BridgeHandler;
|
||||||
|
import org.openhab.core.types.Command;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link QolsysIQZoneHandler} manages security zones.
|
||||||
|
*
|
||||||
|
* @author Dan Cunningham - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class QolsysIQZoneHandler extends BaseThingHandler {
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(QolsysIQZoneHandler.class);
|
||||||
|
|
||||||
|
private int zoneId;
|
||||||
|
|
||||||
|
public QolsysIQZoneHandler(Thing thing) {
|
||||||
|
super(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize() {
|
||||||
|
logger.debug("initialize");
|
||||||
|
zoneId = getConfigAs(QolsysIQZoneConfiguration.class).id;
|
||||||
|
initializeZone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusChanged) {
|
||||||
|
logger.debug("bridgeStatusChanged {}", bridgeStatusChanged);
|
||||||
|
initializeZone();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getZoneId() {
|
||||||
|
return zoneId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateZone(Zone zone) {
|
||||||
|
logger.debug("updateZone {}", zone.zoneId);
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_ZONE_STATE, new DecimalType(zone.state));
|
||||||
|
updateZoneStatus(zone.status);
|
||||||
|
Map<String, String> props = new HashMap<String, String>();
|
||||||
|
props.put("type", zone.type);
|
||||||
|
props.put("name", zone.name);
|
||||||
|
props.put("group", zone.group);
|
||||||
|
props.put("zoneID", zone.id);
|
||||||
|
props.put("zonePhysicalType", String.valueOf(zone.zonePhysicalType));
|
||||||
|
props.put("zoneAlarmType", String.valueOf(zone.zoneAlarmType));
|
||||||
|
props.put("zoneType", zone.zoneType.toString());
|
||||||
|
props.put("partitionId", String.valueOf(zone.partitionId));
|
||||||
|
getThing().setProperties(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void zoneActiveEvent(ZoneActiveEvent event) {
|
||||||
|
if (event.zone.zoneId == getZoneId()) {
|
||||||
|
updateZoneStatus(event.zone.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void zoneUpdateEvent(ZoneUpdateEvent event) {
|
||||||
|
if (event.zone.zoneId == getZoneId()) {
|
||||||
|
updateZone(event.zone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeZone() {
|
||||||
|
Bridge bridge = getBridge();
|
||||||
|
BridgeHandler handler = bridge == null ? null : bridge.getHandler();
|
||||||
|
if (bridge != null && handler instanceof QolsysIQPartitionHandler) {
|
||||||
|
if (handler.getThing().getStatus() != ThingStatus.ONLINE) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Zone z = ((QolsysIQPartitionHandler) handler).getZone(getZoneId());
|
||||||
|
if (z == null) {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Zone not found in partition");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateZone(z);
|
||||||
|
updateStatus(ThingStatus.ONLINE);
|
||||||
|
} else {
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateZoneStatus(@Nullable ZoneStatus status) {
|
||||||
|
if (status != null) {
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_ZONE_STATUS, new StringType(status.toString()));
|
||||||
|
updateState(QolsysIQBindingConstants.CHANNEL_ZONE_CONTACT,
|
||||||
|
status == ZoneStatus.CLOSED || status == ZoneStatus.IDlE ? OpenClosedType.CLOSED
|
||||||
|
: OpenClosedType.OPEN);
|
||||||
|
} else {
|
||||||
|
logger.debug("updateZoneStatus: null status");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<binding:binding id="qolsysiq" 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>QolsysIQ Binding</name>
|
||||||
|
<description>This is the binding for Qolsys IQ Alarm Systems.</description>
|
||||||
|
|
||||||
|
</binding:binding>
|
@ -0,0 +1,72 @@
|
|||||||
|
## mvn i18n:generate-default-translations
|
||||||
|
|
||||||
|
# binding
|
||||||
|
|
||||||
|
binding.qolsysiq.name = QolsysIQ Binding
|
||||||
|
binding.qolsysiq.description = This is the binding for Qolsys IQ Alarm Systems.
|
||||||
|
|
||||||
|
# thing types
|
||||||
|
|
||||||
|
thing-type.qolsysiq.panel.label = Qolsys IQ Panel
|
||||||
|
thing-type.qolsysiq.panel.description = A Qolsys IQ Panel Bridge
|
||||||
|
thing-type.qolsysiq.partition.label = Partition
|
||||||
|
thing-type.qolsysiq.partition.description = A Qolsys IQ Partition
|
||||||
|
thing-type.qolsysiq.zone.label = Zone
|
||||||
|
thing-type.qolsysiq.zone.description = A Qolsys IQ Zone
|
||||||
|
|
||||||
|
# thing types config
|
||||||
|
|
||||||
|
thing-type.config.qolsysiq.panel.hostname.label = Hostname
|
||||||
|
thing-type.config.qolsysiq.panel.hostname.description = Hostname or IP address of the panel
|
||||||
|
thing-type.config.qolsysiq.panel.key.label = key
|
||||||
|
thing-type.config.qolsysiq.panel.key.description = Key to access the device
|
||||||
|
thing-type.config.qolsysiq.panel.port.label = Port
|
||||||
|
thing-type.config.qolsysiq.panel.port.description = The port to connect to on the panel.
|
||||||
|
thing-type.config.qolsysiq.partition.armCode.label = Arm Code
|
||||||
|
thing-type.config.qolsysiq.partition.armCode.description = Optional arm code to use when receiving arm commands without a code. Only required if the panel has been configured to require arm codes. Leave blank to always require a code
|
||||||
|
thing-type.config.qolsysiq.partition.disarmCode.label = Disarm Code
|
||||||
|
thing-type.config.qolsysiq.partition.disarmCode.description = Optional disarm code to use when receiving a disarm command without a code. Required for integrations like Alexa and Homekit who do not provide codes when disarming. Leave blank to always require a code
|
||||||
|
thing-type.config.qolsysiq.partition.id.label = Partition ID
|
||||||
|
thing-type.config.qolsysiq.partition.id.description = The Partition ID.
|
||||||
|
thing-type.config.qolsysiq.zone.id.label = Zone ID
|
||||||
|
thing-type.config.qolsysiq.zone.id.description = The Zone ID.
|
||||||
|
|
||||||
|
# channel types
|
||||||
|
|
||||||
|
channel-type.qolsysiq.alarmState.label = Partition Alarm State
|
||||||
|
channel-type.qolsysiq.alarmState.description = Reports on the current alarm state, or triggers an instant alarm.
|
||||||
|
channel-type.qolsysiq.alarmState.state.option.AUXILIARY = Auxiliary
|
||||||
|
channel-type.qolsysiq.alarmState.state.option.FIRE = Fire
|
||||||
|
channel-type.qolsysiq.alarmState.state.option.POLICE = Police
|
||||||
|
channel-type.qolsysiq.alarmState.state.option.ZONEOPEN = Zone Open
|
||||||
|
channel-type.qolsysiq.alarmState.state.option.NONE = None
|
||||||
|
channel-type.qolsysiq.alarmState.command.option.AUXILIARY = Auxiliary
|
||||||
|
channel-type.qolsysiq.alarmState.command.option.FIRE = Fire
|
||||||
|
channel-type.qolsysiq.alarmState.command.option.POLICE = Police
|
||||||
|
channel-type.qolsysiq.armState.label = Partition Arm State
|
||||||
|
channel-type.qolsysiq.armState.description = Reports the current partition arm state or sends a arm or disarm command to the system. For security codes, append the 6 digit code to the command separated by a colon (e.g. 'DISARM:123456')
|
||||||
|
channel-type.qolsysiq.armState.state.option.ALARM = In Alarm
|
||||||
|
channel-type.qolsysiq.armState.state.option.ARM_AWAY = Armed Away
|
||||||
|
channel-type.qolsysiq.armState.state.option.ARM_STAY = Armed Stay
|
||||||
|
channel-type.qolsysiq.armState.state.option.DISARM = Disarmed
|
||||||
|
channel-type.qolsysiq.armState.state.option.ENTRY_DELAY = Entry Delay
|
||||||
|
channel-type.qolsysiq.armState.state.option.EXIT_DELAY = Exit Delay
|
||||||
|
channel-type.qolsysiq.armState.command.option.ARM_AWAY = Arm Away
|
||||||
|
channel-type.qolsysiq.armState.command.option.ARM_STAY = Arm Stay
|
||||||
|
channel-type.qolsysiq.armState.command.option.DISARM = Disarm
|
||||||
|
channel-type.qolsysiq.armingDelay.label = Partition Arming Delay
|
||||||
|
channel-type.qolsysiq.armingDelay.description = The arming delay currently in progress
|
||||||
|
channel-type.qolsysiq.contact.label = Zone Contact
|
||||||
|
channel-type.qolsysiq.contact.description = The zone contact state.
|
||||||
|
channel-type.qolsysiq.errorEvent.label = Error Event
|
||||||
|
channel-type.qolsysiq.errorEvent.description = Last error event message reported by the partition. Clears after 30 seconds
|
||||||
|
channel-type.qolsysiq.zoneState.label = Zone State
|
||||||
|
channel-type.qolsysiq.zoneState.description = The zone state.
|
||||||
|
channel-type.qolsysiq.zoneStatus.label = Zone Status
|
||||||
|
channel-type.qolsysiq.zoneStatus.description = The zone status.
|
||||||
|
channel-type.qolsysiq.zoneStatus.state.option.ACTIVE = Active
|
||||||
|
channel-type.qolsysiq.zoneStatus.state.option.CLOSED = Closed
|
||||||
|
channel-type.qolsysiq.zoneStatus.state.option.OPEN = Open
|
||||||
|
channel-type.qolsysiq.zoneStatus.state.option.FAILURE = Failure
|
||||||
|
channel-type.qolsysiq.zoneStatus.state.option.IDlE = Idle
|
||||||
|
channel-type.qolsysiq.zoneStatus.state.option.TAMPER = Tamper
|
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<thing:thing-descriptions bindingId="qolsysiq"
|
||||||
|
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="panel">
|
||||||
|
<label>Qolsys IQ Panel</label>
|
||||||
|
<description>A Qolsys IQ Panel Bridge</description>
|
||||||
|
<config-description>
|
||||||
|
<parameter name="hostname" type="text" required="true">
|
||||||
|
<context>network-address</context>
|
||||||
|
<label>Hostname</label>
|
||||||
|
<description>Hostname or IP address of the panel</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="port" type="integer">
|
||||||
|
<label>Port</label>
|
||||||
|
<description>The port to connect to on the panel.</description>
|
||||||
|
<default>12345</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="key" type="text" required="true">
|
||||||
|
<context>password</context>
|
||||||
|
<label>key</label>
|
||||||
|
<description>Key to access the device</description>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</bridge-type>
|
||||||
|
</thing:thing-descriptions>
|
@ -0,0 +1,103 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<thing:thing-descriptions bindingId="qolsysiq"
|
||||||
|
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="partition">
|
||||||
|
<supported-bridge-type-refs>
|
||||||
|
<bridge-type-ref id="panel"/>
|
||||||
|
</supported-bridge-type-refs>
|
||||||
|
<label>Partition</label>
|
||||||
|
<description>A Qolsys IQ Partition</description>
|
||||||
|
<channels>
|
||||||
|
<channel id="armState" typeId="armState"/>
|
||||||
|
<channel id="alarmState" typeId="alarmState"/>
|
||||||
|
<channel id="armingDelay" typeId="armingDelay"/>
|
||||||
|
<channel id="errorEvent" typeId="errorEvent"/>
|
||||||
|
</channels>
|
||||||
|
<properties>
|
||||||
|
<property name="secureArm">false</property>
|
||||||
|
</properties>
|
||||||
|
<representation-property>id</representation-property>
|
||||||
|
<config-description>
|
||||||
|
<parameter name="id" type="integer" required="true">
|
||||||
|
<label>Partition ID</label>
|
||||||
|
<description>The Partition ID.</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="disarmCode" type="text" required="false">
|
||||||
|
<default></default>
|
||||||
|
<label>Disarm Code</label>
|
||||||
|
<description>Optional disarm code to use when receiving a disarm command without a code. Required for integrations
|
||||||
|
like Alexa and Homekit who do not provide codes when disarming. Leave blank to always require a code</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="armCode" type="text" required="false">
|
||||||
|
<default></default>
|
||||||
|
<label>Arm Code</label>
|
||||||
|
<description>Optional arm code to use when receiving arm commands without a code. Only required if the panel has
|
||||||
|
been configured to require arm codes. Leave blank to always require a code</description>
|
||||||
|
<advanced>true</advanced>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</bridge-type>
|
||||||
|
<channel-type id="armState">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Partition Arm State</label>
|
||||||
|
<description>Reports the current partition arm state or sends a arm or disarm command to the system. For security
|
||||||
|
codes, append the 6 digit code to the command separated by a colon (e.g. 'DISARM:123456')</description>
|
||||||
|
<category>Alarm</category>
|
||||||
|
<state>
|
||||||
|
<options>
|
||||||
|
<option value="ALARM">In Alarm</option>
|
||||||
|
<option value="ARM_AWAY">Armed Away</option>
|
||||||
|
<option value="ARM_STAY">Armed Stay</option>
|
||||||
|
<option value="DISARM">Disarmed</option>
|
||||||
|
<option value="ENTRY_DELAY">Entry Delay</option>
|
||||||
|
<option value="EXIT_DELAY">Exit Delay</option>
|
||||||
|
</options>
|
||||||
|
</state>
|
||||||
|
<command>
|
||||||
|
<options>
|
||||||
|
<option value="ARM_AWAY">Arm Away</option>
|
||||||
|
<option value="ARM_STAY">Arm Stay</option>
|
||||||
|
<option value="DISARM">Disarm</option>
|
||||||
|
</options>
|
||||||
|
</command>
|
||||||
|
<autoUpdatePolicy>veto</autoUpdatePolicy>
|
||||||
|
</channel-type>
|
||||||
|
<channel-type id="alarmState">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Partition Alarm State</label>
|
||||||
|
<description>Reports on the current alarm state, or triggers an instant alarm.</description>
|
||||||
|
<category>Alarm</category>
|
||||||
|
<state>
|
||||||
|
<options>
|
||||||
|
<option value="AUXILIARY">Auxiliary</option>
|
||||||
|
<option value="FIRE">Fire</option>
|
||||||
|
<option value="POLICE">Police</option>
|
||||||
|
<option value="ZONEOPEN">Zone Open</option>
|
||||||
|
<option value="NONE">None</option>
|
||||||
|
</options>
|
||||||
|
</state>
|
||||||
|
<command>
|
||||||
|
<options>
|
||||||
|
<option value="AUXILIARY">Auxiliary</option>
|
||||||
|
<option value="FIRE">Fire</option>
|
||||||
|
<option value="POLICE">Police</option>
|
||||||
|
</options>
|
||||||
|
</command>
|
||||||
|
<autoUpdatePolicy>veto</autoUpdatePolicy>
|
||||||
|
</channel-type>
|
||||||
|
<channel-type id="armingDelay">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Partition Arming Delay</label>
|
||||||
|
<description>The arming delay currently in progress</description>
|
||||||
|
<category>Alarm</category>
|
||||||
|
<state readOnly="true"></state>
|
||||||
|
</channel-type>
|
||||||
|
<channel-type id="errorEvent" advanced="true">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Error Event</label>
|
||||||
|
<description>Last error event message reported by the partition. Clears after 30 seconds</description>
|
||||||
|
<state readOnly="true"></state>
|
||||||
|
</channel-type>
|
||||||
|
</thing:thing-descriptions>
|
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<thing:thing-descriptions bindingId="qolsysiq"
|
||||||
|
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="partition"/>
|
||||||
|
</supported-bridge-type-refs>
|
||||||
|
<label>Zone</label>
|
||||||
|
<description>A Qolsys IQ Zone</description>
|
||||||
|
<channels>
|
||||||
|
<channel id="state" typeId="zoneState"/>
|
||||||
|
<channel id="status" typeId="zoneStatus"/>
|
||||||
|
<channel id="contact" typeId="contact"/>
|
||||||
|
</channels>
|
||||||
|
<properties>
|
||||||
|
<property name="type"></property>
|
||||||
|
<property name="name"></property>
|
||||||
|
<property name="group"></property>
|
||||||
|
<property name="zoneId"></property>
|
||||||
|
<property name="zonePhysicalType"></property>
|
||||||
|
<property name="zoneAlarmType"></property>
|
||||||
|
<property name="zoneType"></property>
|
||||||
|
<property name="partitionId"></property>
|
||||||
|
</properties>
|
||||||
|
<representation-property>id</representation-property>
|
||||||
|
<config-description>
|
||||||
|
<parameter name="id" type="integer" required="true">
|
||||||
|
<label>Zone ID</label>
|
||||||
|
<description>The Zone ID.</description>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
</thing-type>
|
||||||
|
<channel-type id="zoneStatus">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Zone Status</label>
|
||||||
|
<description>The zone status.</description>
|
||||||
|
<state readOnly="true">
|
||||||
|
<options>
|
||||||
|
<option value="ACTIVE">Active</option>
|
||||||
|
<option value="CLOSED">Closed</option>
|
||||||
|
<option value="OPEN">Open</option>
|
||||||
|
<option value="FAILURE">Failure</option>
|
||||||
|
<option value="IDlE">Idle</option>
|
||||||
|
<option value="TAMPER">Tamper</option>
|
||||||
|
</options>
|
||||||
|
</state>
|
||||||
|
</channel-type>
|
||||||
|
<channel-type id="zoneState" advanced="true">
|
||||||
|
<item-type>Number</item-type>
|
||||||
|
<label>Zone State</label>
|
||||||
|
<description>The zone state.</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="contact">
|
||||||
|
<item-type>Contact</item-type>
|
||||||
|
<label>Zone Contact</label>
|
||||||
|
<description>The zone contact state.</description>
|
||||||
|
<state readOnly="true"/>
|
||||||
|
</channel-type>
|
||||||
|
</thing:thing-descriptions>
|
@ -305,6 +305,7 @@
|
|||||||
<module>org.openhab.binding.pushover</module>
|
<module>org.openhab.binding.pushover</module>
|
||||||
<module>org.openhab.binding.pushsafer</module>
|
<module>org.openhab.binding.pushsafer</module>
|
||||||
<module>org.openhab.binding.qbus</module>
|
<module>org.openhab.binding.qbus</module>
|
||||||
|
<module>org.openhab.binding.qolsysiq</module>
|
||||||
<module>org.openhab.binding.radiothermostat</module>
|
<module>org.openhab.binding.radiothermostat</module>
|
||||||
<module>org.openhab.binding.regoheatpump</module>
|
<module>org.openhab.binding.regoheatpump</module>
|
||||||
<module>org.openhab.binding.revogi</module>
|
<module>org.openhab.binding.revogi</module>
|
||||||
|
Loading…
Reference in New Issue
Block a user