mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[omnilink] Initial contribution (#8922)
Signed-off-by: Ethan Dye <mrtops03@gmail.com> Co-authored-by: Dan Cunningham <dan@digitaldan.com> Co-authored-by: Craig Hamilton <craigh@quailholdings.com> Co-authored-by: Brian O'Connell <boc@us.ibm.com> Co-authored-by: Dan Cunningham <dan@digitaldan.com> Co-authored-by: Craig Hamilton <craigh@quailholdings.com> Co-authored-by: Brian O'Connell <boc@us.ibm.com>
This commit is contained in:
parent
25434a7f18
commit
63b81792a3
@ -185,6 +185,7 @@
|
||||
/bundles/org.openhab.binding.oceanic/ @kgoderis
|
||||
/bundles/org.openhab.binding.ojelectronics/ @EvilPingu
|
||||
/bundles/org.openhab.binding.omnikinverter/ @hansbogert
|
||||
/bundles/org.openhab.binding.omnilink/ @ecdye
|
||||
/bundles/org.openhab.binding.onebusaway/ @sdwilsh
|
||||
/bundles/org.openhab.binding.onewire/ @J-N-K
|
||||
/bundles/org.openhab.binding.onewiregpio/ @aogorek
|
||||
|
@ -911,6 +911,11 @@
|
||||
<artifactId>org.openhab.binding.omnikinverter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.omnilink</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.onebusaway</artifactId>
|
||||
|
20
bundles/org.openhab.binding.omnilink/NOTICE
Normal file
20
bundles/org.openhab.binding.omnilink/NOTICE
Normal file
@ -0,0 +1,20 @@
|
||||
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
|
||||
|
||||
== Third-party Content
|
||||
|
||||
jomnilink
|
||||
* License: EPL-2.0
|
||||
* Project: https://github.com/digitaldan/jomnilink
|
||||
* Source: https://github.com/digitaldan/jomnilink
|
321
bundles/org.openhab.binding.omnilink/README.md
Normal file
321
bundles/org.openhab.binding.omnilink/README.md
Normal file
@ -0,0 +1,321 @@
|
||||
# HAI/Leviton OmniLink Binding
|
||||
|
||||
This binding integrates the [OmniPro and Lumina](http://www.leviton.com/en/products/security-automation/automation-av-controllers/omni-security-systems) line of home automation systems.
|
||||
At its core the OmniPro is a hardware board that provides security and access features.
|
||||
It connects to many other devices through serial ports or wired contacts and exposes them through a single TCP based API.
|
||||
|
||||
## Supported Things
|
||||
|
||||
The OmniPro/Lumina controller acts as a "bridge" for accessing other connected devices.
|
||||
|
||||
|
||||
| Omni type | Hardware Type | Things |
|
||||
|:---------------------------|:-------------------------------------------------|:----------------------------------|
|
||||
| Controller | Omni (Pro II, IIe, LTe), Lumina | `controller` (omni, lumina) |
|
||||
| Lights | Built-in, UPB, HLC | `unit`, `dimmable`, `upb`, `room` |
|
||||
| Thermostats | Omnistat, Omnistat2 | `thermostat` |
|
||||
| Temperature Sensors | 31A00-1/31A00-7 | `temp_sensor` |
|
||||
| Humidity Sensors | 31A00-2 | `humidity_sensor` |
|
||||
| Zones | Built-in/Hardwire, GE Wireless | `zone` |
|
||||
| Audio Zones/Sources | HAI Hi-Fi, Russound, NuVo, Xantech, Speakercraft | `audio_zone`, `audio_source` |
|
||||
| Consoles | HAI Omni Console, HAI Lumina Console | `console` |
|
||||
| Areas | Built-in | `area`, `lumina_area` |
|
||||
| Buttons | Built-in | `button` |
|
||||
| Flags | Built-in | `flag` |
|
||||
| Output | Built-in/Hardwire | `output` |
|
||||
| Access Control Reader Lock | Leviton Access Control Reader | `lock` |
|
||||
|
||||
|
||||
|
||||
## Discovery
|
||||
|
||||
### Controller
|
||||
|
||||
Omni and Lumina controllers must be manually added using the IP and port of the controller as well as the 2 encryption keys required for network access.
|
||||
|
||||
### Devices
|
||||
|
||||
Once a connection can be established to a controller, all connected devices will be automatically discovered and added to the inbox.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
An Omni or Lumina controller requires the IP address (`ipAddress`), optional port (`port` defaults to 4369), and 2 encryption keys (`key1`, `key2`).
|
||||
The hexadecimal pairs in the encryption keys are typically delimited using a colon`:`, but dashes `-`, spaces ` ` or no delimiter may be used.
|
||||
|
||||
In the thing file, this looks like:
|
||||
|
||||
```
|
||||
Bridge omnilink:controller:home [ ipAddress="127.0.0.1", port=4369, key1="XXXXXXXXXXXXXXXX", key2="XXXXXXXXXXXXXXXX" ] {
|
||||
// Add your things here
|
||||
}
|
||||
```
|
||||
|
||||
The devices are identified by the device number that the OmniLink bridge assigns to them, see the [Full Example](#full-example) section below for a manual configuration example.
|
||||
|
||||
## Channels
|
||||
|
||||
The devices support some of the following channels:
|
||||
|
||||
| Channel Type ID | Item Type | Description | Thing types supporting this channel |
|
||||
|-----------------------------|----------------------|--------------------------------------------------------------------------------------|-----------------------------------------------------|
|
||||
| `activate_keypad_emergency` | Number | Activate a burglary, fire, or auxiliary keypad emergency alarm on Omni based models. | `area` |
|
||||
| `alarm_burglary` | Switch | Indicates if a burglary alarm is active. | `area` |
|
||||
| `alarm_fire` | Switch | Indicates if a fire alarm is active. | `area` |
|
||||
| `alarm_gas` | Switch | Indicates if a gas alarm is active. | `area` |
|
||||
| `alarm_auxiliary` | Switch | Indicates if a auxiliary alarm is active. | `area` |
|
||||
| `alarm_freeze` | Switch | Indicates if a freeze alarm is active. | `area` |
|
||||
| `alarm_water` | Switch | Indicates if a water alarm is active. | `area` |
|
||||
| `alarm_duress` | Switch | Indicates if a duress alarm is active. | `area` |
|
||||
| `alarm_temperature` | Switch | Indicates if a temperature alarm is active. | `area` |
|
||||
| `mode` | Number | Represents the area security mode. | `area`, `lumina_area` |
|
||||
| `disarm` | String | Send a 4 digit user code to disarm the system. | `area` |
|
||||
| `day` | String | Send a 4 digit user code to arm the system to day. | `area` |
|
||||
| `night` | String | Send a 4 digit user code to arm the system to night. | `area` |
|
||||
| `away` | String | Send a 4 digit user code to arm the system to away. | `area` |
|
||||
| `vacation` | String | Send a 4 digit user code to arm the system to vacation. | `area` |
|
||||
| `day_instant` | String | Send a 4 digit user code to arm the system to day instant. | `area` |
|
||||
| `night_delayed` | String | Send a 4 digit user code to arm the system to night delayed. | `area` |
|
||||
| `home` | String | Send a 4 digit user code to set the system to home. | `lumina_area` |
|
||||
| `sleep` | String | Send a 4 digit user code to set the system to sleep. | `lumina_area` |
|
||||
| `away` | String | Send a 4 digit user code to set the system to away. | `lumina_area` |
|
||||
| `vacation` | String | Send a 4 digit user code to set the system to vacation. | `lumina_area` |
|
||||
| `party` | String | Send a 4 digit user code to set the system to party. | `lumina_area` |
|
||||
| `special` | String | Send a 4 digit user code to set the system to special. | `lumina_area` |
|
||||
| `source_text_{1,2,3,4,5,6}` | String | A line of metadata from this audio source. | `audio_source` |
|
||||
| `polling` | Switch | Enable or disable polling of this audio source. | `audio_source` |
|
||||
| `zone_power` | Switch | Power status of this audio zone. | `audio_zone` |
|
||||
| `zone_mute` | Switch | Mute status of this audio zone. | `audio_zone` |
|
||||
| `zone_volume` | Dimmer | Volume level of this audio zone. | `audio_zone` |
|
||||
| `zone_source` | Number | Source for this audio zone. | `audio_zone` |
|
||||
| `zone_control` | Player | Control the audio zone, e.g. start/stop/next/previous. | `audio_zone` |
|
||||
| `sysdate` | DateTime | Set controller date/time. | `controller` |
|
||||
| `last_log` | String | Last log message on the controller, represented in JSON. | `controller` |
|
||||
| `enable_disable_beeper` | Switch | Enable/Disable the beeper for this/all console(s). | `controller`, `console` |
|
||||
| `beep` | Switch | Send a beep command to this/all console(s). | `controller`, `console` |
|
||||
| `press` | Switch | Sends a button event to the controller. | `button` |
|
||||
| `low_setpoint` | Number | The current low setpoint for this humidity/temperature sensor. | `temp_sensor`, `humidity_sensor` |
|
||||
| `high_setpoint` | Number | The current high setpoint for this humidity/temperature sensor. | `temp_sensor`, `humidity_sensor` |
|
||||
| `temperature` | Number:Temperature | The current temperature at this thermostat/temperature sensor. | `thermostat`, `temp_sensor` |
|
||||
| `humidity` | Number:Dimensionless | The current relative humidity at this thermostat/humidity sensor. | `thermostat`, `humidity_sensor` |
|
||||
| `freeze_alarm` | Contact | Closed when freeze alarm is triggered by this thermostat. | `thermostat` |
|
||||
| `comm_failure` | Contact | Closed during a communications failure with this thermostat. | `thermostat` |
|
||||
| `outdoor_temperature` | Number:Temperature | The current outdoor temperature detected by this thermostat. | `thermostat` |
|
||||
| `heat_setpoint` | Number:Temperature | The current low/heating setpoint of this thermostat. | `thermostat` |
|
||||
| `cool_setpoint` | Number:Temperature | The current high/cooling setpoint of this thermostat. | `thermostat` |
|
||||
| `humidify_setpoint` | Number:Dimensionless | The current low/humidify setpoint for this thermostat. | `thermostat` |
|
||||
| `dehumidify_setpoint` | Number:Dimensionless | The current high/dehumidify setpoint for this thermostat. | `thermostat` |
|
||||
| `system_mode` | Number | The current system mode of this thermostat. | `thermostat` |
|
||||
| `fan_mode` | Number | The current fan mode of this thermostat. | `thermostat` |
|
||||
| `hold_status` | Number | The current hold status of this thermostat. | `thermostat` |
|
||||
| `status` | Number | The current numeric status of this thermostat. | `thermostat` |
|
||||
| `level` | Dimmer | Increase/Decrease the level of this unit/dimmable unit/UPB unit. | `unit`, `dimmable`, `upb` |
|
||||
| `switch` | Switch | Turn this unit/dimmable unit/flag/output/room on/off. | `unit`, `dimmable`, `upb`, `flag`, `output`, `room` |
|
||||
| `on_for_seconds` | Number | Turn on this unit for a specified number of seconds. | `unit`, `dimmable`, `upb`, `flag`, `output` |
|
||||
| `off_for_seconds` | Number | Turn off this unit for a specified number of seconds. | `unit`, `dimmable`, `upb`, `flag`, `output` |
|
||||
| `on_for_minutes` | Number | Turn on this unit for a specified number of minutes. | `unit`, `dimmable`, `upb`, `flag`, `output` |
|
||||
| `off_for_minutes` | Number | Turn off this unit for a specified number of minutes. | `unit`, `dimmable`, `upb`, `flag`, `output` |
|
||||
| `on_for_hours` | Number | Turn on this unit for a specified number of hours. | `unit`, `dimmable`, `upb`, `flag`, `output` |
|
||||
| `off_for_hours` | Number | Turn off this unit for a specified number of hours. | `unit`, `dimmable`, `upb`, `flag`, `output` |
|
||||
| `upb_status` | String | Send a UPB status request message for this UPB unit to the controller. | `upb` |
|
||||
| `value` | Number | Numeric value of this flag. | `flag` |
|
||||
| `scene_{a,b,c,d}` | Switch | Turn this scene on/off. | `room` |
|
||||
| `state` | Number | The current state of this room. | `room` |
|
||||
| `contact` | Contact | Contact state information of this zone. | `zone` |
|
||||
| `current_condition` | Number | Current condition of this zone. | `zone` |
|
||||
| `latched_alarm_status` | Number | Latched alarm status of this zone. | `zone` |
|
||||
| `arming_status` | Number | Arming status of this zone. | `zone` |
|
||||
| `bypass` | String | Send a 4 digit user code to bypass this zone. | `zone` |
|
||||
| `restore` | String | Send a 4 digit user code to restore this zone. | `zone` |
|
||||
|
||||
|
||||
### Trigger Channels
|
||||
|
||||
The devices support some of the following trigger channels:
|
||||
|
||||
| Channel Type ID | Description | Thing types supporting this channel |
|
||||
|-------------------------------|--------------------------------------------------------------------------------------|-------------------------------------|
|
||||
| `all_on_off_event` | Event sent when an all on/off event occurs. | `area`, `lumina_area` |
|
||||
| `phone_line_event` | Event sent when the phone line changes state. | `controller` |
|
||||
| `ac_power_event` | Event sent when AC trouble conditions are detected. | `controller` |
|
||||
| `battery_event` | Event sent when battery trouble conditions are detected. | `controller` |
|
||||
| `dcm_event` | Event sent when digital communicator trouble conditions are detected. | `controller` |
|
||||
| `energy_cost_event` | Event sent when the cost of energy changes. | `controller` |
|
||||
| `camera_trigger_event` | Event sent when a camera trigger is detected. | `controller` |
|
||||
| `upb_link_activated_event` | Event sent when a UPB link is activated. | `controller` |
|
||||
| `upb_link_deactivated_event` | Event sent when a UPB link is deactivated. | `controller` |
|
||||
| `activated_event` | Event sent when a button is activated. | `button` |
|
||||
| `switch_press_event` | Event sent when an ALC, UPB, Radio RA, or Starlite switch is pressed. | `dimmable`, `upb` |
|
||||
|
||||
|
||||
## Full Example
|
||||
|
||||
### Example `omnilink.things`
|
||||
|
||||
```
|
||||
Bridge omnilink:controller:home [ ipAddress="127.0.0.1", port=4369, key1="XXXXXXXXXXXXXXXX", key2="XXXXXXXXXXXXXXXX" ] {
|
||||
Thing area MainArea "Main Area" @ "Home" [ number=1 ]
|
||||
Thing upb UpKitTable "Table Lights" @ "Upstairs Kitchen" [ number=4 ]
|
||||
Thing upb UpOfcDesk "Desk Lights" @ "Upstairs Office" [ number=10 ]
|
||||
Thing thermostat UpstrsThermo "Upstairs Temperature" @ "Upstairs Entry" [ number=1 ]
|
||||
Thing zone FrontDoor "Front Door" @ "Upstairs Entry" [ number=2 ]
|
||||
Thing zone GarageDoor "Garage Door" @ "Laundry Room" [ number=3 ]
|
||||
Thing zone BackDoor "Back Door" @ "Upstairs Kitchen" [ number=4 ]
|
||||
Thing zone OneCarGarageDo "One Car Garage" @ "Garage" [ number=5 ]
|
||||
Thing zone TwoCarGarageDo "Two Car Garage" @ "Garage" [ number=6 ]
|
||||
Thing zone BsmtBackDoor "Back Door" @ "Basement Workout Room" [ number=8 ]
|
||||
Thing zone MBRDeckDoor "Deck Door" @ "Master Bedroom" [ number=9 ]
|
||||
Thing zone MBRMotion "Motion" @ "Master Bedroom" [ number=10 ]
|
||||
Thing zone PorchDoor "Porch Door" @ "Upstairs Office" [ number=11 ]
|
||||
Thing zone UpOffMotion "Motion" @ "Upstairs Office" [ number=12 ]
|
||||
Thing zone UpLivMotion "Motion" @ "Upstairs Living Room" [ number=13 ]
|
||||
Thing zone BsmtWORMotion "Motion" @ "Basement Workout Room" [ number=14 ]
|
||||
Thing zone GarageMotion "Motion" @ "Garage" [ number=15 ]
|
||||
Thing console UpstrsConsole "Console" @ "Laundry Room" [ number=1 ]
|
||||
Thing button MainButton "Button" @ "Home" [ number=1 ]
|
||||
}
|
||||
```
|
||||
|
||||
### Example `omnilink.items`
|
||||
|
||||
```
|
||||
/*
|
||||
* Alarms / Areas
|
||||
*/
|
||||
Group:Switch:OR(ON, OFF) Alarms "All Alarms [%s]"
|
||||
String AlarmMode "Alarm [%s]" <alarm> {channel="omnilink:area:home:MainArea:mode" [profile="transform:MAP", function="area-modes.map", sourceFormat="%s"]}
|
||||
Switch AlarmBurglary "Burglary Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_burglary"}
|
||||
Switch AlarmFire "Fire Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_fire"}
|
||||
Switch alarm_gas "Gas Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_gas"}
|
||||
Switch AlarmAuxiliary "Auxiliary Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_auxiliary"}
|
||||
Switch AlarmFreeze "Freeze Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_freeze"}
|
||||
Switch AlarmWater "Water Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_water"}
|
||||
Switch AlarmDuress "Duress Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_duress"}
|
||||
Switch AlarmTemperature "Temperature Alarm [%s]" (Alarms) {channel="omnilink:area:home:MainArea:alarm_temperature"}
|
||||
Number AlarmModeDisarm {channel="omnilink:area:home:MainArea:disarm"}
|
||||
Number AlarmModeDay {channel="omnilink:area:home:MainArea:day"}
|
||||
Number AlarmModeNight {channel="omnilink:area:home:MainArea:night"}
|
||||
Number AlarmModeAway {channel="omnilink:area:home:MainArea:away"}
|
||||
Number AlarmModeVacation {channel="omnilink:area:home:MainArea:vacation"}
|
||||
Number AlarmModeDayInstant {channel="omnilink:area:home:MainArea:day_instant"}
|
||||
Number AlarmModeNightDelayed {channel="omnilink:area:home:MainArea:night_delayed"}
|
||||
|
||||
/*
|
||||
* Lights
|
||||
*/
|
||||
Switch UpKitTable "Table Lights [%s]" <switch> {channel="omnilink:upb:home:UpKitTable:level"}
|
||||
Dimmer UpOfcDesk "Desk Lights [%d]" <slider> {channel="omnilink:upb:home:UpOfcDesk:level"}
|
||||
|
||||
/*
|
||||
* Thermostat
|
||||
*/
|
||||
Group UpstrsThermo "Upstairs Thermostat"
|
||||
Number:Temperature UpstrsThermo_Temp "Temperature [%.1f %unit%]" <temperature> (UpstrsThermo) {channel="omnilink:thermostat:home:UpstrsThermo:temperature"}
|
||||
Number UpstrsThermo_Status "Status [MAP(therm-status.map):%s]" <heating> (UpstrsThermo) {channel="omnilink:thermostat:home:UpstrsThermo:status"}
|
||||
Number UpstrsThermo_System "System Mode [MAP(therm-tempmode.map):%s]" <temperature> (UpstrsThermo) {channel="omnilink:thermostat:home:UpstrsThermo:system_mode"}
|
||||
Number UpstrsThermo_Fan "Fan Mode [MAP(therm-fanmode.map):%s]" <fan> (UpstrsThermo) {channel="omnilink:thermostat:home:UpstrsThermo:fan_mode"}
|
||||
Number UpstrsThermo_Hold "Hold Mode [MAP(therm-holdmode.map):%s]" <fan> (UpstrsThermo) {channel="omnilink:thermostat:home:UpstrsThermo:hold_mode"}
|
||||
Number UpstrsThermo_HeatPoint "System HeatPoint [%d]" <temperature_hot> (UpstrsThermo) {channel="omnilink:thermostat:home:UpstrsThermo:heat_setpoint"}
|
||||
Number UpstrsThermo_CoolPoint "System CoolPoint [%d]" <temperature_cool> (UpstrsThermo) {channel="omnilink:thermostat:home:UpstrsThermo:cool_setpoint"}
|
||||
|
||||
/*
|
||||
* Motion and Doors
|
||||
*/
|
||||
Group:Contact:OR(OPEN, CLOSED) Doors "All Doors [%s]"
|
||||
Contact FrontDoor "Front Door" <door> (Doors) {channel="omnilink:zone:home:FrontDoor:contact"}
|
||||
Contact GarageDoor "Garage Door" <door> (Doors) {channel="omnilink:zone:home:GarageDoor:contact"}
|
||||
Contact BackDoor "Back Door" <door> (Doors) {channel="omnilink:zone:home:BackDoor:contact"}
|
||||
Contact BsmtBackDoor "Back Door" <door> (Doors) {channel="omnilink:zone:home:BsmtBackDoor:contact"}
|
||||
Contact MBRDeckDoor "Deck Door" <door> (Doors) {channel="omnilink:zone:home:MBRDeckDoor:contact"}
|
||||
Contact PorchDoor "Porch Door" <door> (Doors) {channel="omnilink:zone:home:PorchDoor:contact"}
|
||||
|
||||
Group:Contact:OR(OPEN, CLOSED) GarageDoors "All Garage Doors [%s]"
|
||||
Contact TwoCarGarageDo "Two Car Garage Door" <garagedoor> (GarageDoors) {channel="omnilink:zone:home:TwoCarGarageDo:contact"}
|
||||
Contact OneCarGarageDo "One Car Garage Door" <garagedoor> (GarageDoors) {channel="omnilink:zone:home:OneCarGarageDo:contact"}
|
||||
|
||||
Group:Contact:OR(OPEN, CLOSED) Motion "All Motion Sensors [%s]"
|
||||
Contact MBRMotion "Motion" <presence> (Motion) {homekit="MotionSensor", channel="omnilink:zone:home:MBRMotion:contact"}
|
||||
Contact UpOffMotion "Motion" <presence> (Motion) {homekit="MotionSensor", channel="omnilink:zone:home:UpOffMotion:contact"}
|
||||
Contact UpLivMotion "Motion" <presence> (Motion) {homekit="MotionSensor", channel="omnilink:zone:home:UpLivMotion:contact"}
|
||||
Contact BsmtWORMotion "Motion" <presence> (Motion) {homekit="MotionSensor", channel="omnilink:zone:home:BsmtWORMotion:contact"}
|
||||
Contact GarageMotion "Motion" <presence> (Motion) {homekit="MotionSensor", channel="omnilink:zone:home:GarageMotion:contact"}
|
||||
|
||||
/*
|
||||
* Console
|
||||
*/
|
||||
String UpstrsConsole_Beeper "Enable/Disable Beeper [%s]" {channel="omnilink:console:home:UpstrsConsole:enable_disable_beeper"}
|
||||
Number UpstrsConsole_Beep "Beep Console" {channel="omnilink:console:home:UpstrsConsole:beep"}
|
||||
|
||||
/*
|
||||
* Button
|
||||
*/
|
||||
Switch MainButton "Toggle button [%s]" <switch> {channel="omnilink:button:home:MainButton:press"}
|
||||
|
||||
/*
|
||||
* Other OmniPro items
|
||||
*/
|
||||
DateTime OmniProTime "Last Time Update [%1$ta %1$tR]" <time> {channel="omnilink:controller:home:sysdate"}
|
||||
```
|
||||
|
||||
### Example `therm-status.map`
|
||||
|
||||
```
|
||||
0=Idle
|
||||
1=Heating
|
||||
2=Cooling
|
||||
```
|
||||
|
||||
### Example `therm-tempmode.map`
|
||||
|
||||
```
|
||||
0=Off
|
||||
1=Heat
|
||||
2=Cool
|
||||
3=Auto
|
||||
5=Emergency heat
|
||||
```
|
||||
|
||||
### Example `therm-fanmode.map`
|
||||
|
||||
```
|
||||
0=Auto
|
||||
1=On
|
||||
2=Cycle
|
||||
```
|
||||
|
||||
### Example `therm-holdmode.map`
|
||||
|
||||
```
|
||||
0=Off
|
||||
1=Hold
|
||||
2=Vacation hold
|
||||
```
|
||||
|
||||
### Example `area-modes.map`
|
||||
|
||||
```
|
||||
0=Off
|
||||
1=Day
|
||||
2=Night
|
||||
3=Away
|
||||
4=Vacation
|
||||
5=Day instant
|
||||
6=Night delayed
|
||||
9=Arming day
|
||||
10=Arming night
|
||||
11=Arming away
|
||||
12=Arming vacation
|
||||
13=Arming day instant
|
||||
14=Arming night delay
|
||||
=Unknown
|
||||
```
|
||||
|
||||
### Example `omnilink.rules`
|
||||
|
||||
```
|
||||
rule "Update OmniPro Time"
|
||||
when
|
||||
Time cron "0 0 0/1 1/1 * ? *"
|
||||
then
|
||||
OmniProTime.sendCommand( new DateTimeType() )
|
||||
end
|
||||
```
|
26
bundles/org.openhab.binding.omnilink/pom.xml
Normal file
26
bundles/org.openhab.binding.omnilink/pom.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.omnilink</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: OmniLink Binding</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.github.digitaldan</groupId>
|
||||
<artifactId>jomnilink</artifactId>
|
||||
<version>1.4.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2010-2021 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
|
||||
|
||||
-->
|
||||
<features name="org.openhab.binding.omnilink-${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-omnilink" description="OmniLink Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.omnilink/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link AreaAlarm} class defines the different types of alarms supported
|
||||
* by the OmniLink Protocol.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum AreaAlarm {
|
||||
BURGLARY(CHANNEL_AREA_ALARM_BURGLARY, 0),
|
||||
FIRE(CHANNEL_AREA_ALARM_FIRE, 1),
|
||||
GAS(CHANNEL_AREA_ALARM_GAS, 2),
|
||||
AUXILIARY(CHANNEL_AREA_ALARM_AUXILIARY, 3),
|
||||
FREEZE(CHANNEL_AREA_ALARM_FREEZE, 4),
|
||||
WATER(CHANNEL_AREA_ALARM_WATER, 5),
|
||||
DURESS(CHANNEL_AREA_ALARM_DURESS, 6),
|
||||
TEMPERATURE(CHANNEL_AREA_ALARM_TEMPERATURE, 7);
|
||||
|
||||
private final String channelUID;
|
||||
private final int bit;
|
||||
|
||||
AreaAlarm(String channelUID, int bit) {
|
||||
this.channelUID = channelUID;
|
||||
this.bit = bit;
|
||||
}
|
||||
|
||||
public boolean isSet(BigInteger alarmBits) {
|
||||
return alarmBits.testBit(bit);
|
||||
}
|
||||
|
||||
public boolean isSet(int alarmBits) {
|
||||
return isSet(BigInteger.valueOf(alarmBits));
|
||||
}
|
||||
|
||||
public String getChannelUID() {
|
||||
return channelUID;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link AudioPlayer} defines some methods that are used to
|
||||
* interface with an OmniLink Audio Player.
|
||||
*
|
||||
* @author Brian O'Connell - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum AudioPlayer {
|
||||
NUVO(1, 6, 8, 7, 9, 10),
|
||||
NUVO_GRAND_ESSENTIA_SIMPLESE(2, 6, 8, 7, 9, 10),
|
||||
NUVO_GRAND_GRAND_CONCERTO(3, 6, 6, 6, 9, 10),
|
||||
RUSSOUND(4, 6, 8, 7, 11, 12),
|
||||
XANTECH(6, 13, 15, 14, 16, 17),
|
||||
SPEAKERCRAFT(7, 45, 44, 46, 42, 43),
|
||||
PROFICIENT(8, 45, 44, 46, 42, 43);
|
||||
|
||||
private final int featureCode;
|
||||
private final int playCommand;
|
||||
private final int pauseCommand;
|
||||
private final int stopCommand;
|
||||
private final int previousCommand;
|
||||
private final int nextCommand;
|
||||
|
||||
AudioPlayer(int featureCode, int playCommand, int pauseCommand, int stopCommand, int previousCommand,
|
||||
int nextCommand) {
|
||||
this.featureCode = featureCode;
|
||||
this.playCommand = playCommand;
|
||||
this.pauseCommand = pauseCommand;
|
||||
this.stopCommand = stopCommand;
|
||||
this.previousCommand = previousCommand;
|
||||
this.nextCommand = nextCommand;
|
||||
}
|
||||
|
||||
public int getPlayCommand() {
|
||||
return playCommand;
|
||||
}
|
||||
|
||||
public int getPauseCommand() {
|
||||
return pauseCommand;
|
||||
}
|
||||
|
||||
public int getStopCommand() {
|
||||
return stopCommand;
|
||||
}
|
||||
|
||||
public int getPreviousCommand() {
|
||||
return previousCommand;
|
||||
}
|
||||
|
||||
public int getNextCommand() {
|
||||
return nextCommand;
|
||||
}
|
||||
|
||||
public static Optional<AudioPlayer> getAudioPlayerForFeatureCode(int featureCode) {
|
||||
return Arrays.stream(values()).filter(v -> v.featureCode == featureCode).findAny();
|
||||
}
|
||||
}
|
@ -0,0 +1,188 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link OmnilinkBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OmnilinkBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "omnilink";
|
||||
|
||||
// List of all Thing Type UIDs
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "controller");
|
||||
public static final ThingTypeUID THING_TYPE_OMNI_AREA = new ThingTypeUID(BINDING_ID, "area");
|
||||
public static final ThingTypeUID THING_TYPE_LUMINA_AREA = new ThingTypeUID(BINDING_ID, "lumina_area");
|
||||
public static final ThingTypeUID THING_TYPE_ZONE = new ThingTypeUID(BINDING_ID, "zone");
|
||||
public static final ThingTypeUID THING_TYPE_LOCK = new ThingTypeUID(BINDING_ID, "lock");
|
||||
public static final ThingTypeUID THING_TYPE_UNIT_UPB = new ThingTypeUID(BINDING_ID, "upb");
|
||||
public static final ThingTypeUID THING_TYPE_UNIT = new ThingTypeUID(BINDING_ID, "unit");
|
||||
public static final ThingTypeUID THING_TYPE_DIMMABLE = new ThingTypeUID(BINDING_ID, "dimmable");
|
||||
public static final ThingTypeUID THING_TYPE_FLAG = new ThingTypeUID(BINDING_ID, "flag");
|
||||
public static final ThingTypeUID THING_TYPE_OUTPUT = new ThingTypeUID(BINDING_ID, "output");
|
||||
public static final ThingTypeUID THING_TYPE_ROOM = new ThingTypeUID(BINDING_ID, "room");
|
||||
public static final ThingTypeUID THING_TYPE_BUTTON = new ThingTypeUID(BINDING_ID, "button");
|
||||
public static final ThingTypeUID THING_TYPE_THERMOSTAT = new ThingTypeUID(BINDING_ID, "thermostat");
|
||||
public static final ThingTypeUID THING_TYPE_AUDIO_ZONE = new ThingTypeUID(BINDING_ID, "audio_zone");
|
||||
public static final ThingTypeUID THING_TYPE_AUDIO_SOURCE = new ThingTypeUID(BINDING_ID, "audio_source");
|
||||
public static final ThingTypeUID THING_TYPE_CONSOLE = new ThingTypeUID(BINDING_ID, "console");
|
||||
public static final ThingTypeUID THING_TYPE_TEMP_SENSOR = new ThingTypeUID(BINDING_ID, "temp_sensor");
|
||||
public static final ThingTypeUID THING_TYPE_HUMIDITY_SENSOR = new ThingTypeUID(BINDING_ID, "humidity_sensor");
|
||||
|
||||
// List of all Channel ids
|
||||
|
||||
// zones
|
||||
public static final String CHANNEL_ZONE_CONTACT = "contact";
|
||||
public static final String CHANNEL_ZONE_CURRENT_CONDITION = "current_condition";
|
||||
public static final String CHANNEL_ZONE_LATCHED_ALARM_STATUS = "latched_alarm_status";
|
||||
public static final String CHANNEL_ZONE_ARMING_STATUS = "arming_status";
|
||||
public static final String CHANNEL_ZONE_BYPASS = "bypass";
|
||||
public static final String CHANNEL_ZONE_RESTORE = "restore";
|
||||
|
||||
// areas
|
||||
public static final String CHANNEL_AREA_MODE = "mode";
|
||||
public static final String CHANNEL_AREA_ACTIVATE_KEYPAD_EMERGENCY = "activate_keypad_emergency";
|
||||
public static final String CHANNEL_AREA_ALARM_BURGLARY = "alarm_burglary";
|
||||
public static final String CHANNEL_AREA_ALARM_FIRE = "alarm_fire";
|
||||
public static final String CHANNEL_AREA_ALARM_GAS = "alarm_gas";
|
||||
public static final String CHANNEL_AREA_ALARM_AUXILIARY = "alarm_auxiliary";
|
||||
public static final String CHANNEL_AREA_ALARM_FREEZE = "alarm_freeze";
|
||||
public static final String CHANNEL_AREA_ALARM_WATER = "alarm_water";
|
||||
public static final String CHANNEL_AREA_ALARM_DURESS = "alarm_duress";
|
||||
public static final String CHANNEL_AREA_ALARM_TEMPERATURE = "alarm_temperature";
|
||||
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_DISARM = "disarm";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_DAY = "day";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_NIGHT = "night";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_AWAY = "away";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_VACATION = "vacation";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_DAY_INSTANT = "day_instant";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_NIGHT_DELAYED = "night_delayed";
|
||||
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_HOME = "home";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_SLEEP = "sleep";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_PARTY = "party";
|
||||
public static final String CHANNEL_AREA_SECURITY_MODE_SPECIAL = "special";
|
||||
|
||||
// units
|
||||
public static final String CHANNEL_UNIT_LEVEL = "level";
|
||||
public static final String CHANNEL_UNIT_SWITCH = "switch";
|
||||
public static final String CHANNEL_UNIT_ON_FOR_SECONDS = "on_for_seconds";
|
||||
public static final String CHANNEL_UNIT_ON_FOR_MINUTES = "on_for_minutes";
|
||||
public static final String CHANNEL_UNIT_ON_FOR_HOURS = "on_for_hours";
|
||||
public static final String CHANNEL_UNIT_OFF_FOR_SECONDS = "off_for_seconds";
|
||||
public static final String CHANNEL_UNIT_OFF_FOR_MINUTES = "off_for_minutes";
|
||||
public static final String CHANNEL_UNIT_OFF_FOR_HOURS = "off_for_hours";
|
||||
public static final String CHANNEL_FLAG_VALUE = "value";
|
||||
public static final String CHANNEL_FLAG_SWITCH = "switch";
|
||||
public static final String CHANNEL_UPB_STATUS = "upb_status";
|
||||
|
||||
public static final String CHANNEL_ROOM_SWITCH = "switch";
|
||||
public static final String CHANNEL_ROOM_SCENE_A = "scene_a";
|
||||
public static final String CHANNEL_ROOM_SCENE_B = "scene_b";
|
||||
public static final String CHANNEL_ROOM_SCENE_C = "scene_c";
|
||||
public static final String CHANNEL_ROOM_SCENE_D = "scene_d";
|
||||
public static final String CHANNEL_ROOM_STATE = "state";
|
||||
|
||||
public static final String CHANNEL_SYSTEMDATE = "sysdate";
|
||||
public static final String CHANNEL_EVENT_LOG = "last_log";
|
||||
|
||||
// buttons
|
||||
public static final String CHANNEL_BUTTON_PRESS = "press";
|
||||
|
||||
// locks
|
||||
public static final String CHANNEL_LOCK_SWITCH = "switch";
|
||||
|
||||
// thermostats
|
||||
public static final String CHANNEL_THERMO_FREEZE_ALARM = "freeze_alarm";
|
||||
public static final String CHANNEL_THERMO_COMM_FAILURE = "comm_failure";
|
||||
public static final String CHANNEL_THERMO_STATUS = "status";
|
||||
public static final String CHANNEL_THERMO_CURRENT_TEMP = "temperature";
|
||||
public static final String CHANNEL_THERMO_OUTDOOR_TEMP = "outdoor_temperature";
|
||||
public static final String CHANNEL_THERMO_HUMIDITY = "humidity";
|
||||
public static final String CHANNEL_THERMO_HUMIDIFY_SETPOINT = "humidify_setpoint";
|
||||
public static final String CHANNEL_THERMO_DEHUMIDIFY_SETPOINT = "dehumidify_setpoint";
|
||||
public static final String CHANNEL_THERMO_SYSTEM_MODE = "system_mode";
|
||||
public static final String CHANNEL_THERMO_FAN_MODE = "fan_mode";
|
||||
public static final String CHANNEL_THERMO_HOLD_STATUS = "hold_status";
|
||||
public static final String CHANNEL_THERMO_COOL_SETPOINT = "cool_setpoint";
|
||||
public static final String CHANNEL_THERMO_HEAT_SETPOINT = "heat_setpoint";
|
||||
|
||||
// temp / humidity sensors
|
||||
public static final String CHANNEL_AUX_TEMP = "temperature";
|
||||
public static final String CHANNEL_AUX_HUMIDITY = "humidity";
|
||||
public static final String CHANNEL_AUX_LOW_SETPOINT = "low_setpoint";
|
||||
public static final String CHANNEL_AUX_HIGH_SETPOINT = "high_setpoint";
|
||||
|
||||
// consoles
|
||||
public static final String CHANNEL_CONSOLE_BEEP = "beep";
|
||||
public static final String CHANNEL_CONSOLE_ENABLE_DISABLE_BEEPER = "enable_disable_beeper";
|
||||
|
||||
// audio zones
|
||||
public static final String CHANNEL_AUDIO_ZONE_POWER = "zone_power";
|
||||
public static final String CHANNEL_AUDIO_ZONE_MUTE = "zone_mute";
|
||||
public static final String CHANNEL_AUDIO_ZONE_VOLUME = "zone_volume";
|
||||
public static final String CHANNEL_AUDIO_ZONE_SOURCE = "zone_source";
|
||||
public static final String CHANNEL_AUDIO_ZONE_CONTROL = "zone_control";
|
||||
|
||||
// audio sources
|
||||
public static final String CHANNEL_AUDIO_SOURCE_TEXT1 = "source_text_1";
|
||||
public static final String CHANNEL_AUDIO_SOURCE_TEXT2 = "source_text_2";
|
||||
public static final String CHANNEL_AUDIO_SOURCE_TEXT3 = "source_text_3";
|
||||
public static final String CHANNEL_AUDIO_SOURCE_TEXT4 = "source_text_4";
|
||||
public static final String CHANNEL_AUDIO_SOURCE_TEXT5 = "source_text_5";
|
||||
public static final String CHANNEL_AUDIO_SOURCE_TEXT6 = "source_text_6";
|
||||
public static final String CHANNEL_AUDIO_SOURCE_POLLING = "polling";
|
||||
|
||||
// trigger channels
|
||||
public static final String TRIGGER_CHANNEL_BUTTON_ACTIVATED_EVENT = "activated_event";
|
||||
public static final String TRIGGER_CHANNEL_PHONE_LINE_EVENT = "phone_line_event";
|
||||
public static final String TRIGGER_CHANNEL_AC_POWER_EVENT = "ac_power_event";
|
||||
public static final String TRIGGER_CHANNEL_BATTERY_EVENT = "battery_event";
|
||||
public static final String TRIGGER_CHANNEL_DCM_EVENT = "dcm_event";
|
||||
public static final String TRIGGER_CHANNEL_ENERGY_COST_EVENT = "energy_cost_event";
|
||||
public static final String TRIGGER_CHANNEL_CAMERA_TRIGGER_EVENT = "camera_trigger_event";
|
||||
public static final String TRIGGER_CHANNEL_ACCESS_CONTROL_READER_EVENT = "access_control_reader_event";
|
||||
public static final String TRIGGER_CHANNEL_AREA_ALL_ON_OFF_EVENT = "all_on_off_Event";
|
||||
public static final String TRIGGER_CHANNEL_ZONE_STATE_EVENT = "zone_state_Event";
|
||||
public static final String TRIGGER_CHANNEL_SWITCH_PRESS_EVENT = "switch_press_event";
|
||||
public static final String TRIGGER_CHANNEL_UPB_LINK_ACTIVATED_EVENT = "upb_link_activated_event";
|
||||
public static final String TRIGGER_CHANNEL_UPB_LINK_DEACTIVATED_EVENT = "upb_link_deactivated_event";
|
||||
|
||||
// thing configuration and properties keys
|
||||
public static final String THING_PROPERTIES_NAME = "name";
|
||||
public static final String THING_PROPERTIES_NUMBER = "number";
|
||||
public static final String THING_PROPERTIES_AREA = "area";
|
||||
public static final String THING_PROPERTIES_AUTO_START = "autostart";
|
||||
public static final String THING_PROPERTIES_MODEL_NUMBER = "modelNumber";
|
||||
public static final String THING_PROPERTIES_MAJOR_VERSION = "majorVersion";
|
||||
public static final String THING_PROPERTIES_MINOR_VERSION = "minorVersion";
|
||||
public static final String THING_PROPERTIES_REVISION = "revision";
|
||||
public static final String THING_PROPERTIES_PHONE_NUMBER = "phoneNumber";
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Set.of(THING_TYPE_OMNI_AREA,
|
||||
THING_TYPE_LUMINA_AREA, THING_TYPE_ZONE, THING_TYPE_BRIDGE, THING_TYPE_FLAG, THING_TYPE_ROOM,
|
||||
THING_TYPE_BUTTON, THING_TYPE_UNIT_UPB, THING_TYPE_THERMOSTAT, THING_TYPE_CONSOLE, THING_TYPE_AUDIO_ZONE,
|
||||
THING_TYPE_AUDIO_SOURCE, THING_TYPE_TEMP_SENSOR, THING_TYPE_HUMIDITY_SENSOR, THING_TYPE_LOCK,
|
||||
THING_TYPE_OUTPUT, THING_TYPE_UNIT, THING_TYPE_DIMMABLE);
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.handler.AudioSourceHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.AudioZoneHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.ButtonHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.ConsoleHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.HumiditySensorHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.LockHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.LuminaAreaHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmniAreaHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmnilinkBridgeHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.TempSensorHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.ThermostatHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.UnitHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.ZoneHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.units.DimmableUnitHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.units.FlagHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.units.OutputHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.units.UpbRoomHandler;
|
||||
import org.openhab.binding.omnilink.internal.handler.units.dimmable.UpbUnitHandler;
|
||||
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 OmnilinkHandlerFactory} is responsible for creating things and thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.omnilink")
|
||||
public class OmnilinkHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
@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 (thingTypeUID.equals(THING_TYPE_AUDIO_SOURCE)) {
|
||||
return new AudioSourceHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_AUDIO_ZONE)) {
|
||||
return new AudioZoneHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_BRIDGE)) {
|
||||
return new OmnilinkBridgeHandler((Bridge) thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_BUTTON)) {
|
||||
return new ButtonHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_CONSOLE)) {
|
||||
return new ConsoleHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_DIMMABLE)) {
|
||||
return new DimmableUnitHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_FLAG)) {
|
||||
return new FlagHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_HUMIDITY_SENSOR)) {
|
||||
return new HumiditySensorHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_LOCK)) {
|
||||
return new LockHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_LUMINA_AREA)) {
|
||||
return new LuminaAreaHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_OMNI_AREA)) {
|
||||
return new OmniAreaHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_OUTPUT)) {
|
||||
return new OutputHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_ROOM)) {
|
||||
return new UpbRoomHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_TEMP_SENSOR)) {
|
||||
return new TempSensorHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_THERMOSTAT)) {
|
||||
return new ThermostatHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_UNIT)) {
|
||||
return new UnitHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_UNIT_UPB)) {
|
||||
return new UpbUnitHandler(thing);
|
||||
} else if (thingTypeUID.equals(THING_TYPE_ZONE)) {
|
||||
return new ZoneHandler(thing);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link SystemType} enum defines the two supported system types which can
|
||||
* interface with the binding
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum SystemType {
|
||||
OMNI(16, 30, 38),
|
||||
LUMINA(36, 37);
|
||||
|
||||
private final Set<Integer> modelNumbers;
|
||||
|
||||
SystemType(Integer... modelNumbers) {
|
||||
this.modelNumbers = Set.of(modelNumbers);
|
||||
}
|
||||
|
||||
public static SystemType getType(int modelNumber) {
|
||||
return Arrays.stream(values()).filter(s -> s.modelNumbers.contains(modelNumber)).findFirst()
|
||||
.orElseThrow(IllegalArgumentException::new);
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* The {@link OmnilinkBridgeConfig} sets the authentication settings of the
|
||||
* OmniLink Controller that will allow for proper communication.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OmnilinkBridgeConfig {
|
||||
|
||||
private @Nullable String key1;
|
||||
private @Nullable String key2;
|
||||
private @Nullable String ipAddress;
|
||||
private int port;
|
||||
private int logPollingInterval;
|
||||
|
||||
public int getLogPollingInterval() {
|
||||
return logPollingInterval;
|
||||
}
|
||||
|
||||
public void setLogPollingInterval(int logPollingInterval) {
|
||||
this.logPollingInterval = logPollingInterval;
|
||||
}
|
||||
|
||||
public @Nullable String getKey1() {
|
||||
return key1;
|
||||
}
|
||||
|
||||
public void setKey1(String key1) {
|
||||
this.key1 = key1;
|
||||
}
|
||||
|
||||
public @Nullable String getKey2() {
|
||||
return key2;
|
||||
}
|
||||
|
||||
public void setKey2(String key2) {
|
||||
this.key2 = key2;
|
||||
}
|
||||
|
||||
public @Nullable String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.discovery;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.omnilink.internal.handler.BridgeOfflineException;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmnilinkBridgeHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectProperties;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ObjectPropertyRequest<T extends ObjectProperties> implements Iterable<T> {
|
||||
private final Logger logger = LoggerFactory.getLogger(ObjectPropertyRequest.class);
|
||||
|
||||
public static <T extends ObjectProperties, U extends ObjectPropertyRequests<T>> Builder<T> builder(
|
||||
OmnilinkBridgeHandler bridgeHandler, U request, int objectNumber, int offset) {
|
||||
return new Builder<>(bridgeHandler, request, objectNumber, offset);
|
||||
}
|
||||
|
||||
private final OmnilinkBridgeHandler bridgeHandler;
|
||||
private final ObjectPropertyRequests<T> request;
|
||||
private final int objectNumber;
|
||||
private final int filter1;
|
||||
private final int filter2;
|
||||
private final int filter3;
|
||||
private final int offset;
|
||||
|
||||
private ObjectPropertyRequest(OmnilinkBridgeHandler bridgeHandler, ObjectPropertyRequests<T> request,
|
||||
int objectNumber, int filter1, int filter2, int filter3, int offset) {
|
||||
this.bridgeHandler = bridgeHandler;
|
||||
this.request = request;
|
||||
this.objectNumber = objectNumber;
|
||||
this.filter1 = filter1;
|
||||
this.filter2 = filter2;
|
||||
this.filter3 = filter3;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
List<T> messages = new ArrayList<T>();
|
||||
int currentObjectNumber = objectNumber;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
Message message = bridgeHandler.reqObjectProperties(request.getPropertyRequest(), currentObjectNumber,
|
||||
offset, filter1, filter2, filter3);
|
||||
if (message.getMessageType() == Message.MESG_TYPE_OBJ_PROP) {
|
||||
ObjectProperties objectProperties = (ObjectProperties) message;
|
||||
messages.add(request.getResponseType().cast(objectProperties));
|
||||
if (offset == 0) {
|
||||
break;
|
||||
} else if (offset == 1) {
|
||||
currentObjectNumber++;
|
||||
} else if (offset == -1) {
|
||||
currentObjectNumber--;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.warn("Error retrieving object properties: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
return messages.iterator();
|
||||
}
|
||||
|
||||
public static class Builder<T extends ObjectProperties> {
|
||||
private final OmnilinkBridgeHandler bridgeHandler;
|
||||
private final ObjectPropertyRequests<T> request;
|
||||
private final int objectNumber;
|
||||
private final int offset;
|
||||
private int filter1 = ObjectProperties.FILTER_1_NONE;
|
||||
private int filter2 = ObjectProperties.FILTER_2_NONE;
|
||||
private int filter3 = ObjectProperties.FILTER_3_NONE;
|
||||
|
||||
private Builder(OmnilinkBridgeHandler bridgeHandler, ObjectPropertyRequests<T> request, int objectNumber,
|
||||
int offset) {
|
||||
this.bridgeHandler = bridgeHandler;
|
||||
this.request = request;
|
||||
this.objectNumber = objectNumber;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
public Builder<T> selectNamed() {
|
||||
this.filter1 = ObjectProperties.FILTER_1_NAMED;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> areaFilter(int area) {
|
||||
this.filter2 = area;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> selectAnyLoad() {
|
||||
this.filter3 = ObjectProperties.FILTER_3_ANY_LOAD;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ObjectPropertyRequest<T> build() {
|
||||
return new ObjectPropertyRequest<T>(bridgeHandler, request, objectNumber, filter1, filter2, filter3,
|
||||
offset);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.discovery;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AccessControlReaderProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioSourceProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioZoneProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AuxSensorProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ButtonProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ThermostatProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.UnitProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ZoneProperties;
|
||||
|
||||
/**
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ObjectPropertyRequests<T extends ObjectProperties> {
|
||||
|
||||
public static final ObjectPropertyRequests<ThermostatProperties> THERMOSTAT = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_THERMO, ThermostatProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<ButtonProperties> BUTTONS = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_BUTTON, ButtonProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<AreaProperties> AREA = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_AREA, AreaProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<ZoneProperties> ZONE = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_ZONE, ZoneProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<UnitProperties> UNIT = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_UNIT, UnitProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<AudioZoneProperties> AUDIO_ZONE = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_AUDIO_ZONE, AudioZoneProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<AudioSourceProperties> AUDIO_SOURCE = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_AUDIO_SOURCE, AudioSourceProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<AuxSensorProperties> AUX_SENSORS = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_AUX_SENSOR, AuxSensorProperties.class);
|
||||
|
||||
public static final ObjectPropertyRequests<AccessControlReaderProperties> LOCK = new ObjectPropertyRequests<>(
|
||||
Message.OBJ_TYPE_CONTROL_READER, AccessControlReaderProperties.class);
|
||||
|
||||
private final int propertyRequest;
|
||||
private final Class<T> responseType;
|
||||
|
||||
private ObjectPropertyRequests(int propertyRequest, Class<T> type) {
|
||||
this.propertyRequest = propertyRequest;
|
||||
this.responseType = type;
|
||||
}
|
||||
|
||||
public int getPropertyRequest() {
|
||||
return propertyRequest;
|
||||
}
|
||||
|
||||
public Class<T> getResponseType() {
|
||||
return responseType;
|
||||
}
|
||||
}
|
@ -0,0 +1,542 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.discovery;
|
||||
|
||||
import static com.digitaldan.jomnilinkII.MessageTypes.properties.AuxSensorProperties.*;
|
||||
import static com.digitaldan.jomnilinkII.MessageTypes.properties.UnitProperties.*;
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.SystemType;
|
||||
import org.openhab.binding.omnilink.internal.handler.BridgeOfflineException;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmnilinkBridgeHandler;
|
||||
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.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SystemInformation;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AccessControlReaderProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioSourceProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioZoneProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AuxSensorProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ButtonProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ThermostatProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.UnitProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ZoneProperties;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link OmnilinkDiscoveryService} creates things based on the configured bridge.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OmnilinkDiscoveryService extends AbstractDiscoveryService
|
||||
implements DiscoveryService, ThingHandlerService {
|
||||
private final Logger logger = LoggerFactory.getLogger(OmnilinkDiscoveryService.class);
|
||||
private static final int DISCOVER_TIMEOUT_SECONDS = 30;
|
||||
private @Nullable OmnilinkBridgeHandler bridgeHandler;
|
||||
private @Nullable SystemType systemType;
|
||||
private @Nullable List<AreaProperties> areas;
|
||||
|
||||
/**
|
||||
* Creates an OmnilinkDiscoveryService.
|
||||
*/
|
||||
public OmnilinkDiscoveryService() {
|
||||
super(SUPPORTED_THING_TYPES_UIDS, DISCOVER_TIMEOUT_SECONDS, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
if (handler instanceof OmnilinkBridgeHandler) {
|
||||
bridgeHandler = (OmnilinkBridgeHandler) handler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return bridgeHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void startScan() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
logger.debug("Starting scan");
|
||||
try {
|
||||
SystemInformation systemInformation = handler.reqSystemInformation();
|
||||
this.systemType = SystemType.getType(systemInformation.getModel());
|
||||
this.areas = discoverAreas();
|
||||
discoverUnits();
|
||||
discoverZones();
|
||||
discoverButtons();
|
||||
discoverThermostats();
|
||||
discoverAudioZones();
|
||||
discoverAudioSources();
|
||||
discoverTempSensors();
|
||||
discoverHumiditySensors();
|
||||
discoverLocks();
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received error during discovery: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
super.stopScan();
|
||||
removeOlderResults(getTimestampOfLastScan());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the area filter the a supplied area
|
||||
*
|
||||
* @param area Area to calculate filter for.
|
||||
* @return Calculated Bit Filter for the supplied area. Bit 0 is area 1, bit 2 is area 2 and so on.
|
||||
*/
|
||||
private static int bitFilterForArea(AreaProperties areaProperties) {
|
||||
return BigInteger.ZERO.setBit(areaProperties.getNumber() - 1).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink buttons
|
||||
*/
|
||||
private void discoverButtons() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
final List<AreaProperties> areas = this.areas;
|
||||
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<ButtonProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.BUTTONS, 0, 1).selectNamed().areaFilter(areaFilter)
|
||||
.build();
|
||||
|
||||
for (ButtonProperties buttonProperties : objectPropertyRequest) {
|
||||
String thingName = buttonProperties.getName();
|
||||
String thingID = Integer.toString(buttonProperties.getNumber());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(THING_PROPERTIES_NAME, thingName);
|
||||
properties.put(THING_PROPERTIES_AREA, areaProperties.getNumber());
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_BUTTON, bridgeUID, thingID);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withProperties(properties).withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID)
|
||||
.withLabel(thingName).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink locks
|
||||
*/
|
||||
private void discoverLocks() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
|
||||
ObjectPropertyRequest<AccessControlReaderProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.LOCK, 0, 1).selectNamed().build();
|
||||
|
||||
for (AccessControlReaderProperties lockProperties : objectPropertyRequest) {
|
||||
String thingName = lockProperties.getName();
|
||||
String thingID = Integer.toString(lockProperties.getNumber());
|
||||
|
||||
Map<String, Object> properties = Map.of(THING_PROPERTIES_NAME, thingName);
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_LOCK, bridgeUID, thingID);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||
.withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID).withLabel(thingName)
|
||||
.build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink audio zones
|
||||
*/
|
||||
private void discoverAudioZones() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
|
||||
ObjectPropertyRequest<AudioZoneProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.AUDIO_ZONE, 0, 1).selectNamed().build();
|
||||
|
||||
for (AudioZoneProperties audioZoneProperties : objectPropertyRequest) {
|
||||
String thingName = audioZoneProperties.getName();
|
||||
String thingID = Integer.toString(audioZoneProperties.getNumber());
|
||||
|
||||
Map<String, Object> properties = Map.of(THING_PROPERTIES_NAME, thingName);
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_AUDIO_ZONE, bridgeUID, thingID);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||
.withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID).withLabel(thingName)
|
||||
.build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink audio sources
|
||||
*/
|
||||
private void discoverAudioSources() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
|
||||
ObjectPropertyRequest<AudioSourceProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.AUDIO_SOURCE, 0, 1).selectNamed().build();
|
||||
|
||||
for (AudioSourceProperties audioSourceProperties : objectPropertyRequest) {
|
||||
String thingName = audioSourceProperties.getName();
|
||||
String thingID = Integer.toString(audioSourceProperties.getNumber());
|
||||
|
||||
Map<String, Object> properties = Map.of(THING_PROPERTIES_NAME, thingName);
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_AUDIO_SOURCE, bridgeUID, thingID);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||
.withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID).withLabel(thingName)
|
||||
.build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink temperature sensors
|
||||
*/
|
||||
private void discoverTempSensors() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
final List<AreaProperties> areas = this.areas;
|
||||
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<AuxSensorProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.AUX_SENSORS, 0, 1).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (AuxSensorProperties auxSensorProperties : objectPropertyRequest) {
|
||||
if (auxSensorProperties.getSensorType() != SENSOR_TYPE_PROGRAMMABLE_ENERGY_SAVER_MODULE
|
||||
&& auxSensorProperties.getSensorType() != SENSOR_TYPE_HUMIDITY) {
|
||||
String thingName = auxSensorProperties.getName();
|
||||
String thingID = Integer.toString(auxSensorProperties.getNumber());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(THING_PROPERTIES_NAME, thingName);
|
||||
properties.put(THING_PROPERTIES_AREA, areaProperties.getNumber());
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_TEMP_SENSOR, bridgeUID, thingID);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withProperties(properties).withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID)
|
||||
.withLabel(thingName).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink humidity sensors
|
||||
*/
|
||||
private void discoverHumiditySensors() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
final List<AreaProperties> areas = this.areas;
|
||||
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<AuxSensorProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.AUX_SENSORS, 0, 1).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (AuxSensorProperties auxSensorProperties : objectPropertyRequest) {
|
||||
if (auxSensorProperties.getSensorType() == SENSOR_TYPE_HUMIDITY) {
|
||||
String thingName = auxSensorProperties.getName();
|
||||
String thingID = Integer.toString(auxSensorProperties.getNumber());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(THING_PROPERTIES_NAME, thingName);
|
||||
properties.put(THING_PROPERTIES_AREA, areaProperties.getNumber());
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_HUMIDITY_SENSOR, bridgeUID, thingID);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withProperties(properties).withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID)
|
||||
.withLabel(thingName).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink thermostats
|
||||
*/
|
||||
private void discoverThermostats() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
final List<AreaProperties> areas = this.areas;
|
||||
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<ThermostatProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.THERMOSTAT, 0, 1).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (ThermostatProperties thermostatProperties : objectPropertyRequest) {
|
||||
String thingName = thermostatProperties.getName();
|
||||
String thingID = Integer.toString(thermostatProperties.getNumber());
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_THERMOSTAT, bridgeUID, thingID);
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(THING_PROPERTIES_NAME, thingName);
|
||||
properties.put(THING_PROPERTIES_AREA, areaProperties.getNumber());
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withProperties(properties).withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID)
|
||||
.withLabel(thingName).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink areas
|
||||
*/
|
||||
private @Nullable List<AreaProperties> discoverAreas() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
List<AreaProperties> areas = new LinkedList<>();
|
||||
|
||||
ObjectPropertyRequest<AreaProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.AREA, 0, 1).build();
|
||||
|
||||
for (AreaProperties areaProperties : objectPropertyRequest) {
|
||||
int thingNumber = areaProperties.getNumber();
|
||||
String thingName = areaProperties.getName();
|
||||
String thingID = Integer.toString(thingNumber);
|
||||
ThingUID thingUID = null;
|
||||
|
||||
/*
|
||||
* It seems that for simple OmniLink Controller configurations there
|
||||
* is only 1 area, without a name. So if there is no name for the
|
||||
* first area, we will call that Main Area. If other area's name is
|
||||
* blank, we will not create a thing.
|
||||
*/
|
||||
if (thingNumber == 1 && "".equals(thingName)) {
|
||||
thingName = "Main Area";
|
||||
} else if ("".equals(thingName)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Map<String, Object> properties = Map.of(THING_PROPERTIES_NAME, thingName);
|
||||
|
||||
final SystemType systemType = this.systemType;
|
||||
if (systemType != null) {
|
||||
switch (systemType) {
|
||||
case LUMINA:
|
||||
thingUID = new ThingUID(THING_TYPE_LUMINA_AREA, bridgeUID, thingID);
|
||||
break;
|
||||
case OMNI:
|
||||
thingUID = new ThingUID(THING_TYPE_OMNI_AREA, bridgeUID, thingID);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown System Type");
|
||||
}
|
||||
}
|
||||
|
||||
if (thingUID != null) {
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties)
|
||||
.withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID)
|
||||
.withLabel(thingName).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
areas.add(areaProperties);
|
||||
}
|
||||
return areas;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers OmniLink supported units
|
||||
*/
|
||||
private void discoverUnits() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
final List<AreaProperties> areas = this.areas;
|
||||
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<UnitProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.UNIT, 0, 1).selectNamed().areaFilter(areaFilter)
|
||||
.selectAnyLoad().build();
|
||||
|
||||
for (UnitProperties unitProperties : objectPropertyRequest) {
|
||||
int thingType = unitProperties.getUnitType();
|
||||
String thingName = unitProperties.getName();
|
||||
String thingID = Integer.toString(unitProperties.getNumber());
|
||||
ThingUID thingUID = null;
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(THING_PROPERTIES_NAME, thingName);
|
||||
properties.put(THING_PROPERTIES_AREA, areaProperties.getNumber());
|
||||
|
||||
switch (thingType) {
|
||||
case UNIT_TYPE_HLC_ROOM:
|
||||
case UNIT_TYPE_VIZIARF_ROOM:
|
||||
thingUID = new ThingUID(THING_TYPE_ROOM, bridgeUID, thingID);
|
||||
break;
|
||||
case UNIT_TYPE_FLAG:
|
||||
thingUID = new ThingUID(THING_TYPE_FLAG, bridgeUID, thingID);
|
||||
break;
|
||||
case UNIT_TYPE_OUTPUT:
|
||||
thingUID = new ThingUID(THING_TYPE_OUTPUT, bridgeUID, thingID);
|
||||
break;
|
||||
case UNIT_TYPE_UPB:
|
||||
case UNIT_TYPE_HLC_LOAD:
|
||||
thingUID = new ThingUID(THING_TYPE_UNIT_UPB, bridgeUID, thingID);
|
||||
break;
|
||||
case UNIT_TYPE_CENTRALITE:
|
||||
case UNIT_TYPE_RADIORA:
|
||||
case UNIT_TYPE_VIZIARF_LOAD:
|
||||
case UNIT_TYPE_COMPOSE:
|
||||
thingUID = new ThingUID(THING_TYPE_DIMMABLE, bridgeUID, thingID);
|
||||
break;
|
||||
default:
|
||||
thingUID = new ThingUID(THING_TYPE_UNIT, bridgeUID, thingID);
|
||||
logger.debug("Generic unit type: {}", thingType);
|
||||
break;
|
||||
}
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withProperties(properties).withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID)
|
||||
.withLabel(thingName).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates zone items
|
||||
*/
|
||||
private void discoverZones() {
|
||||
final OmnilinkBridgeHandler handler = bridgeHandler;
|
||||
if (handler != null) {
|
||||
final ThingUID bridgeUID = handler.getThing().getUID();
|
||||
final List<AreaProperties> areas = this.areas;
|
||||
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<ZoneProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(handler, ObjectPropertyRequests.ZONE, 0, 1).selectNamed().areaFilter(areaFilter)
|
||||
.build();
|
||||
|
||||
for (ZoneProperties zoneProperties : objectPropertyRequest) {
|
||||
if (zoneProperties.getZoneType() <= SENSOR_TYPE_PROGRAMMABLE_ENERGY_SAVER_MODULE) {
|
||||
String thingName = zoneProperties.getName();
|
||||
String thingID = Integer.toString(zoneProperties.getNumber());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(THING_PROPERTIES_NAME, thingName);
|
||||
properties.put(THING_PROPERTIES_AREA, areaProperties.getNumber());
|
||||
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_ZONE, bridgeUID, thingID);
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID)
|
||||
.withProperties(properties).withProperty(THING_PROPERTIES_NUMBER, thingID)
|
||||
.withRepresentationProperty(THING_PROPERTIES_NUMBER).withBridge(bridgeUID)
|
||||
.withLabel(thingName).build();
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,240 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.omnilink.internal.AreaAlarm;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
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;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SecurityCodeValidation;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAreaStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.systemevents.AllOnOffEvent;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link AbstractAreaHandler} defines some methods that can be used across
|
||||
* the many different areas defined in an OmniLink Controller.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractAreaHandler extends AbstractOmnilinkStatusHandler<ExtendedAreaStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractAreaHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
|
||||
public AbstractAreaHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
|
||||
super.initialize();
|
||||
if (bridgeHandler != null) {
|
||||
updateAreaProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Area!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAreaProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
final List<AreaProperties> areas = getAreaProperties();
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
String thingName = areaProperties.getName();
|
||||
if (areaProperties.getNumber() == 1 && "".equals(thingName)) {
|
||||
thingName = "Main Area";
|
||||
}
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, thingName);
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_AREA_ACTIVATE_KEYPAD_EMERGENCY:
|
||||
handleKeypadEmergency(channelUID, command);
|
||||
break;
|
||||
default:
|
||||
handleSecurityMode(channelUID, command);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSecurityMode(ChannelUID channelUID, Command command) {
|
||||
int mode = getMode(channelUID);
|
||||
|
||||
if (!(command instanceof StringType)) {
|
||||
logger.debug("Invalid command: {}, must be StringType", command);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Received mode: {}, on area: {}", mode, thingID);
|
||||
|
||||
char[] code = command.toFullString().toCharArray();
|
||||
if (code.length != 4) {
|
||||
logger.warn("Invalid code length, code must be 4 digits");
|
||||
} else {
|
||||
// mode, codeNum, areaNum
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridge = getOmnilinkBridgeHandler();
|
||||
if (bridge != null) {
|
||||
SecurityCodeValidation codeValidation = bridge.reqSecurityCodeValidation(thingID,
|
||||
Character.getNumericValue(code[0]), Character.getNumericValue(code[1]),
|
||||
Character.getNumericValue(code[2]), Character.getNumericValue(code[3]));
|
||||
/*
|
||||
* 0 Invalid code
|
||||
* 1 Master
|
||||
* 2 Manager
|
||||
* 3 User
|
||||
*/
|
||||
logger.debug("User code number: {}, level: {}", codeValidation.getCodeNumber(),
|
||||
codeValidation.getAuthorityLevel());
|
||||
|
||||
/*
|
||||
* Valid user code number are 1-99, 251 is duress code, 0 means code does not exist
|
||||
*/
|
||||
if ((codeValidation.getCodeNumber() > 0 && codeValidation.getCodeNumber() <= 99)
|
||||
&& codeValidation.getAuthorityLevel() > 0) {
|
||||
sendOmnilinkCommand(mode, codeValidation.getCodeNumber(), thingID);
|
||||
} else {
|
||||
logger.warn("System reported an invalid code");
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null bridge while sending area command!");
|
||||
}
|
||||
} catch (OmniInvalidResponseException e) {
|
||||
logger.debug("Could not arm area: {}, are all zones closed?", e.getMessage());
|
||||
} catch (OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Could not send area command: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
// This is a send only channel, so don't store the user code
|
||||
updateState(channelUID, UnDefType.UNDEF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the specific mode for the OmniLink type
|
||||
*
|
||||
* @param channelUID Channel that maps to a mode
|
||||
* @return OmniLink representation of mode.
|
||||
*/
|
||||
protected abstract int getMode(ChannelUID channelUID);
|
||||
|
||||
/**
|
||||
* Get the set of alarms supported by this area handler.
|
||||
*
|
||||
* @return Set of alarms for this handler.
|
||||
*/
|
||||
protected abstract EnumSet<AreaAlarm> getAlarms();
|
||||
|
||||
private void handleKeypadEmergency(ChannelUID channelUID, Command command) {
|
||||
if (command instanceof DecimalType) {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridge = getOmnilinkBridgeHandler();
|
||||
if (bridge != null) {
|
||||
bridge.activateKeypadEmergency(thingID, ((DecimalType) command).intValue());
|
||||
} else {
|
||||
logger.debug("Received null bridge while sending Keypad Emergency command!");
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while sending command to OmniLink Controller: {}", e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DecimalType", command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedAreaStatus status) {
|
||||
logger.debug("Handle area event: mode: {}, alarms: {}, entryTimer: {}, exitTimer: {}", status.getMode(),
|
||||
status.getAlarms(), status.getEntryTimer(), status.getExitTimer());
|
||||
|
||||
/*
|
||||
* According to the specification, if the 3rd bit is set on a area mode, then that mode is in a delayed state.
|
||||
* Unfortunately, this is not the case, but we can fix that by looking to see if the exit timer
|
||||
* is set and do this manually.
|
||||
*/
|
||||
int mode = status.getExitTimer() > 0 ? status.getMode() | 1 << 3 : status.getMode();
|
||||
updateState(new ChannelUID(thing.getUID(), CHANNEL_AREA_MODE), new DecimalType(mode));
|
||||
|
||||
/*
|
||||
* Alarm status is actually 8 status, packed into each bit, so we loop through to see if a bit is set, note that
|
||||
* this means you can have multiple alarms set at once
|
||||
*/
|
||||
BigInteger alarmBits = BigInteger.valueOf(status.getAlarms());
|
||||
for (AreaAlarm alarm : getAlarms()) {
|
||||
OnOffType alarmState = OnOffType.from(alarm.isSet(alarmBits));
|
||||
updateState(new ChannelUID(thing.getUID(), alarm.getChannelUID()), alarmState);
|
||||
}
|
||||
}
|
||||
|
||||
public void handleAllOnOffEvent(AllOnOffEvent event) {
|
||||
ChannelUID activateChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_AREA_ALL_ON_OFF_EVENT);
|
||||
triggerChannel(activateChannel, event.isOn() ? "ON" : "OFF");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedAreaStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridge = getOmnilinkBridgeHandler();
|
||||
if (bridge != null) {
|
||||
ObjectStatus objStatus = bridge.requestObjectStatus(Message.OBJ_TYPE_AREA, thingID, thingID, true);
|
||||
return Optional.of((ExtendedAreaStatus) objStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Area status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Area status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link AbstractOmnilinkHandler} defines some methods that can be used across
|
||||
* the many different things exposed by the OmniLink protocol
|
||||
*
|
||||
* @author Brian O'Connell - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractOmnilinkHandler extends BaseThingHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(AbstractOmnilinkHandler.class);
|
||||
|
||||
public AbstractOmnilinkHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
public @Nullable OmnilinkBridgeHandler getOmnilinkBridgeHandler() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null) {
|
||||
return (OmnilinkBridgeHandler) bridge.getHandler();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendOmnilinkCommand(int message, int param1, int param2) {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridge = getOmnilinkBridgeHandler();
|
||||
if (bridge != null) {
|
||||
bridge.sendOmnilinkCommand(message, param1, param2);
|
||||
} else {
|
||||
logger.debug("Received null bridge while sending OmniLink command!");
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Could not send command to OmniLink Controller: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the area filter the a supplied area
|
||||
*
|
||||
* @param area Area to calculate filter for.
|
||||
* @return Calculated Bit Filter for the supplied area. Bit 0 is area 1, bit 2 is area 2 and so on.
|
||||
*/
|
||||
protected static int bitFilterForArea(AreaProperties areaProperties) {
|
||||
return BigInteger.ZERO.setBit(areaProperties.getNumber() - 1).intValue();
|
||||
}
|
||||
|
||||
protected @Nullable List<AreaProperties> getAreaProperties() {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
List<AreaProperties> areas = new LinkedList<>();
|
||||
|
||||
if (bridgeHandler != null) {
|
||||
ObjectPropertyRequest<AreaProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.AREA, 0, 1).build();
|
||||
|
||||
for (AreaProperties areaProperties : objectPropertyRequest) {
|
||||
String thingName = areaProperties.getName();
|
||||
if (areaProperties.getNumber() == 1 && "".equals(thingName)) {
|
||||
areas.add(areaProperties);
|
||||
break;
|
||||
} else if ("".equals(thingName)) {
|
||||
break;
|
||||
} else {
|
||||
areas.add(areaProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
return areas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured number for a thing.
|
||||
*
|
||||
* @return Configured number for a thing.
|
||||
*/
|
||||
protected int getThingNumber() {
|
||||
return ((Number) getThing().getConfiguration().get(THING_PROPERTIES_NUMBER)).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the configured area number for a thing.
|
||||
*
|
||||
* @return Configured area number for a thing.
|
||||
*/
|
||||
protected int getAreaNumber() {
|
||||
return ((Number) getThing().getConfiguration().get(THING_PROPERTIES_AREA)).intValue();
|
||||
}
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
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 com.digitaldan.jomnilinkII.MessageTypes.statuses.Status;
|
||||
|
||||
/**
|
||||
* The {@link AbstractOmnilinkStatusHandler} defines some methods that can be used across
|
||||
* the many different units exposed by the OmniLink protocol to retrive updated status information.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class AbstractOmnilinkStatusHandler<T extends Status> extends AbstractOmnilinkHandler {
|
||||
public AbstractOmnilinkStatusHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
private volatile Optional<T> status = Optional.empty();
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
updateHandlerStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to retrieve an updated status for this handler type.
|
||||
*
|
||||
* @return Optional with updated status if possible, empty optional otherwise.
|
||||
*/
|
||||
protected abstract Optional<T> retrieveStatus();
|
||||
|
||||
/**
|
||||
* Update channels associated with handler
|
||||
*
|
||||
* @param t Status object to update channels with
|
||||
*/
|
||||
protected abstract void updateChannels(T t);
|
||||
|
||||
/**
|
||||
* Process a status update for this handler. This will dispatch updateChannels where appropriate.
|
||||
*
|
||||
* @param t Status to process.
|
||||
*/
|
||||
public void handleStatus(T t) {
|
||||
this.status = Optional.of(t);
|
||||
updateChannels(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelLinked(ChannelUID channelUID) {
|
||||
status.ifPresent(this::updateChannels);
|
||||
}
|
||||
|
||||
private void updateHandlerStatus() {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
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.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.AudioSourceStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioSourceProperties;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link AudioSourceHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Audio Source. This by extension also defines the
|
||||
* Audio Source thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Brian O'Connell - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AudioSourceHandler extends AbstractOmnilinkHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(AudioSourceHandler.class);
|
||||
private final int POLL_DELAY_SECONDS = 5;
|
||||
private final int thingID = getThingNumber();
|
||||
private @Nullable ScheduledFuture<?> scheduledPolling = null;
|
||||
public @Nullable String number;
|
||||
|
||||
public AudioSourceHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
if (((Boolean) getThing().getConfiguration().get(THING_PROPERTIES_AUTO_START)).booleanValue()) {
|
||||
logger.debug("Autostart enabled, scheduling polling for Audio Source: {}", thingID);
|
||||
schedulePolling();
|
||||
} else {
|
||||
logger.debug("Autostart disabled, not scheduling polling for Audio Source: {}", thingID);
|
||||
cancelPolling();
|
||||
}
|
||||
updateAudioSourceProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Audio Source!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAudioSourceProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
ObjectPropertyRequest<AudioSourceProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.AUDIO_SOURCE, thingID, 0).selectNamed().build();
|
||||
|
||||
for (AudioSourceProperties audioSourceProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, audioSourceProperties.getName());
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void dispose() {
|
||||
cancelPolling();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private synchronized void cancelPolling() {
|
||||
final ScheduledFuture<?> scheduledPolling = this.scheduledPolling;
|
||||
if (scheduledPolling != null) {
|
||||
logger.debug("Cancelling polling for Audio Source: {}", thingID);
|
||||
scheduledPolling.cancel(false);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void schedulePolling() {
|
||||
cancelPolling();
|
||||
logger.debug("Scheduling polling for Audio Source: {}", thingID);
|
||||
scheduledPolling = super.scheduler.scheduleWithFixedDelay(this::pollAudioSource, 0, POLL_DELAY_SECONDS,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
final ScheduledFuture<?> scheduledPolling = this.scheduledPolling;
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_AUDIO_SOURCE_POLLING:
|
||||
if (command instanceof RefreshType) {
|
||||
updateState(CHANNEL_AUDIO_SOURCE_POLLING,
|
||||
OnOffType.from((scheduledPolling != null && !scheduledPolling.isDone())));
|
||||
} else if (command instanceof OnOffType) {
|
||||
handlePolling(channelUID, (OnOffType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be RefreshType or OnOffType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Audio Source thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePolling(ChannelUID channelUID, OnOffType command) {
|
||||
logger.debug("handlePolling called for channel: {}, command: {}", channelUID, command);
|
||||
if (OnOffType.ON.equals(command)) {
|
||||
schedulePolling();
|
||||
} else {
|
||||
cancelPolling();
|
||||
}
|
||||
}
|
||||
|
||||
public void pollAudioSource() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridge = getOmnilinkBridgeHandler();
|
||||
if (bridge != null) {
|
||||
Message message;
|
||||
int position = 0;
|
||||
while ((message = bridge.requestAudioSourceStatus(thingID, position))
|
||||
.getMessageType() == Message.MESG_TYPE_AUDIO_SOURCE_STATUS) {
|
||||
logger.trace("Polling for Audio Source statuses on thing: {}", thingID);
|
||||
AudioSourceStatus audioSourceStatus = (AudioSourceStatus) message;
|
||||
position = audioSourceStatus.getPosition();
|
||||
switch (position) {
|
||||
case 1:
|
||||
updateState(CHANNEL_AUDIO_SOURCE_TEXT1, new StringType(audioSourceStatus.getSourceData()));
|
||||
break;
|
||||
case 2:
|
||||
updateState(CHANNEL_AUDIO_SOURCE_TEXT2, new StringType(audioSourceStatus.getSourceData()));
|
||||
break;
|
||||
case 3:
|
||||
updateState(CHANNEL_AUDIO_SOURCE_TEXT3, new StringType(audioSourceStatus.getSourceData()));
|
||||
break;
|
||||
case 4:
|
||||
updateState(CHANNEL_AUDIO_SOURCE_TEXT4, new StringType(audioSourceStatus.getSourceData()));
|
||||
break;
|
||||
case 5:
|
||||
updateState(CHANNEL_AUDIO_SOURCE_TEXT5, new StringType(audioSourceStatus.getSourceData()));
|
||||
break;
|
||||
case 6:
|
||||
updateState(CHANNEL_AUDIO_SOURCE_TEXT6, new StringType(audioSourceStatus.getSourceData()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null bridge while polling Audio Source statuses!");
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Exception recieved while polling for Audio Source statuses: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,208 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.AudioPlayer;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.NextPreviousType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.PlayPauseType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AudioZoneProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAudioZoneStatus;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link AudioZoneHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Audio Zone. This by extension also defines the
|
||||
* Audio Zone thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class AudioZoneHandler extends AbstractOmnilinkStatusHandler<ExtendedAudioZoneStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(AudioZoneHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public AudioZoneHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateAudioZoneProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Audio Zone!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAudioZoneProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
ObjectPropertyRequest<AudioZoneProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.AUDIO_ZONE, thingID, 0).selectNamed().build();
|
||||
|
||||
for (AudioZoneProperties audioZoneProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, audioZoneProperties.getName());
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_AUDIO_ZONE_POWER:
|
||||
if (command instanceof OnOffType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_ON_MUTE.getNumber(),
|
||||
OnOffType.OFF.equals(command) ? 0 : 1, thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_AUDIO_ZONE_MUTE:
|
||||
if (command instanceof OnOffType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_ON_MUTE.getNumber(),
|
||||
OnOffType.OFF.equals(command) ? 2 : 3, thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_AUDIO_ZONE_VOLUME:
|
||||
if (command instanceof PercentType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_VOLUME.getNumber(),
|
||||
((PercentType) command).intValue(), thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be PercentType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_AUDIO_ZONE_SOURCE:
|
||||
if (command instanceof DecimalType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_SOURCE.getNumber(),
|
||||
((DecimalType) command).intValue(), thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DecimalType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_AUDIO_ZONE_CONTROL:
|
||||
if (command instanceof PlayPauseType) {
|
||||
handlePlayPauseCommand(channelUID, (PlayPauseType) command);
|
||||
} else if (command instanceof NextPreviousType) {
|
||||
handleNextPreviousCommand(channelUID, (NextPreviousType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be PlayPauseType or NextPreviousType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Audio Zone thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePlayPauseCommand(ChannelUID channelUID, PlayPauseType command) {
|
||||
logger.debug("handlePlayPauseCommand called for channel: {}, command: {}", channelUID, command);
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
|
||||
if (bridgeHandler != null) {
|
||||
Optional<AudioPlayer> audioPlayer = bridgeHandler.getAudioPlayer();
|
||||
if (audioPlayer.isPresent()) {
|
||||
AudioPlayer player = audioPlayer.get();
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_SOURCE.getNumber(),
|
||||
PlayPauseType.PLAY.equals(command) ? player.getPlayCommand() : player.getPauseCommand(),
|
||||
thingID);
|
||||
} else {
|
||||
logger.warn("No Audio Player was detected!");
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null bridge while sending Audio Zone command!");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNextPreviousCommand(ChannelUID channelUID, NextPreviousType command) {
|
||||
logger.debug("handleNextPreviousCommand called for channel: {}, command: {}", channelUID, command);
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
|
||||
if (bridgeHandler != null) {
|
||||
Optional<AudioPlayer> audioPlayer = bridgeHandler.getAudioPlayer();
|
||||
if (audioPlayer.isPresent()) {
|
||||
AudioPlayer player = audioPlayer.get();
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_AUDIO_ZONE_SET_SOURCE.getNumber(),
|
||||
NextPreviousType.NEXT.equals(command) ? player.getNextCommand() : player.getPreviousCommand(),
|
||||
thingID);
|
||||
} else {
|
||||
logger.warn("Audio Player could not be found!");
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null bridge while sending Audio Zone command!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedAudioZoneStatus status) {
|
||||
logger.debug("updateChannels called for Audio Zone status: {}", status);
|
||||
updateState(CHANNEL_AUDIO_ZONE_POWER, OnOffType.from(status.isPower()));
|
||||
updateState(CHANNEL_AUDIO_ZONE_MUTE, OnOffType.from(status.isMute()));
|
||||
updateState(CHANNEL_AUDIO_ZONE_VOLUME, new PercentType(status.getVolume()));
|
||||
updateState(CHANNEL_AUDIO_ZONE_SOURCE, new DecimalType(status.getSource()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedAudioZoneStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
ObjectStatus objStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_AUDIO_ZONE, thingID,
|
||||
thingID, true);
|
||||
return Optional.of((ExtendedAudioZoneStatus) objStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Audio Zone status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Audio Zone status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* The {@link BridgeOfflineException} defines an exception for when the OmniLink
|
||||
* Bridge is offline or unavailable.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class BridgeOfflineException extends Exception {
|
||||
private static final long serialVersionUID = -9081729691518514097L;
|
||||
|
||||
public BridgeOfflineException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ButtonProperties;
|
||||
|
||||
/**
|
||||
* The {@link ButtonHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Button. This by extension also defines the
|
||||
* Button thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ButtonHandler extends AbstractOmnilinkHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(ButtonHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public ButtonHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
updateChannels();
|
||||
updateButtonProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Button!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateButtonProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
final List<AreaProperties> areas = getAreaProperties();
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<ButtonProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.BUTTONS, thingID, 0).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (ButtonProperties buttonProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, buttonProperties.getName());
|
||||
properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
updateChannels();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_BUTTON_PRESS:
|
||||
if (command instanceof OnOffType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_BUTTON.getNumber(), 0, thingID);
|
||||
updateChannels();
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Button thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
public void buttonActivated() {
|
||||
ChannelUID activateChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_BUTTON_ACTIVATED_EVENT);
|
||||
triggerChannel(activateChannel);
|
||||
}
|
||||
|
||||
public void updateChannels() {
|
||||
updateState(CHANNEL_BUTTON_PRESS, OnOffType.OFF);
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
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 ConsoleHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Console. This by extension also defines the
|
||||
* Console thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ConsoleHandler extends AbstractOmnilinkHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(ConsoleHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
|
||||
public ConsoleHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
if (getOmnilinkBridgeHandler() != null) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
updateChannels();
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Console!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
updateChannels();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_CONSOLE_ENABLE_DISABLE_BEEPER:
|
||||
if (command instanceof StringType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_CONSOLE_ENABLE_DISABLE_BEEPER.getNumber(),
|
||||
((StringType) command).equals(StringType.valueOf("OFF")) ? 0 : 1, thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be StringType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONSOLE_BEEP:
|
||||
if (command instanceof DecimalType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_CONSOLE_BEEP.getNumber(), ((DecimalType) command).intValue(),
|
||||
thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DecimalType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Console thing: {}", channelUID);
|
||||
}
|
||||
updateChannels();
|
||||
}
|
||||
|
||||
public void updateChannels() {
|
||||
updateState(CHANNEL_CONSOLE_ENABLE_DISABLE_BEEPER, UnDefType.UNDEF);
|
||||
updateState(CHANNEL_CONSOLE_BEEP, UnDefType.UNDEF);
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AuxSensorProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAuxSensorStatus;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link HumiditySensorHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Humidity Sensor. This by extension also defines
|
||||
* the Humidity Sensor thing that openHAB will be able to pick up and interface
|
||||
* with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HumiditySensorHandler extends AbstractOmnilinkStatusHandler<ExtendedAuxSensorStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(HumiditySensorHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public HumiditySensorHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateHumiditySensorProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Humidity Sensor!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateHumiditySensorProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
final List<AreaProperties> areas = getAreaProperties();
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<AuxSensorProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.AUX_SENSORS, thingID, 0).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (AuxSensorProperties auxSensorProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, auxSensorProperties.getName());
|
||||
properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(command instanceof QuantityType)) {
|
||||
logger.debug("Invalid command: {}, must be QuantityType", command);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_AUX_LOW_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_HEAT_LOW_POINT.getNumber(),
|
||||
TemperatureFormat.FAHRENHEIT.formatToOmni(((QuantityType<Dimensionless>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
case CHANNEL_AUX_HIGH_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_COOL_HIGH_POINT.getNumber(),
|
||||
TemperatureFormat.FAHRENHEIT.formatToOmni(((QuantityType<Dimensionless>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Humdity Sensor thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedAuxSensorStatus status) {
|
||||
logger.debug("updateChannels called for Humidity Sensor status: {}", status);
|
||||
updateState(CHANNEL_AUX_HUMIDITY,
|
||||
new QuantityType<>(TemperatureFormat.FAHRENHEIT.omniToFormat(status.getTemperature()), Units.PERCENT));
|
||||
updateState(CHANNEL_AUX_LOW_SETPOINT,
|
||||
new QuantityType<>(TemperatureFormat.FAHRENHEIT.omniToFormat(status.getHeatSetpoint()), Units.PERCENT));
|
||||
updateState(CHANNEL_AUX_HIGH_SETPOINT,
|
||||
new QuantityType<>(TemperatureFormat.FAHRENHEIT.omniToFormat(status.getCoolSetpoint()), Units.PERCENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedAuxSensorStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
ObjectStatus objStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_AUX_SENSOR, thingID,
|
||||
thingID, true);
|
||||
return Optional.of((ExtendedAuxSensorStatus) objStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Humidity Sensor status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Humidity Sensor status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AccessControlReaderProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAccessControlReaderLockStatus;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link LockHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Lock. This by extension also defines the
|
||||
* Lock thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Brian O'Connell - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LockHandler extends AbstractOmnilinkStatusHandler<ExtendedAccessControlReaderLockStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(LockHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public LockHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateLockProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Lock!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLockProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
ObjectPropertyRequest<AccessControlReaderProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.LOCK, thingID, 0).selectNamed().build();
|
||||
|
||||
for (AccessControlReaderProperties lockProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, lockProperties.getName());
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_LOCK_SWITCH:
|
||||
if (command instanceof OnOffType) {
|
||||
sendOmnilinkCommand(OnOffType.OFF.equals(command) ? OmniLinkCmd.CMD_UNLOCK_DOOR.getNumber()
|
||||
: OmniLinkCmd.CMD_LOCK_DOOR.getNumber(), 0, thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Lock thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedAccessControlReaderLockStatus status) {
|
||||
logger.debug("updateChannels called for Lock status: {}", status);
|
||||
updateState(CHANNEL_LOCK_SWITCH, OnOffType.from(status.isLocked()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedAccessControlReaderLockStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
ObjectStatus objStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_CONTROL_LOCK, thingID,
|
||||
thingID, true);
|
||||
return Optional.of((ExtendedAccessControlReaderLockStatus) objStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Lock status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Lock status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.AreaAlarm.*;
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.AreaAlarm;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* The {@link LuminaAreaHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Lumina Area. This by extension also defines the
|
||||
* Lumina Area thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LuminaAreaHandler extends AbstractAreaHandler {
|
||||
private static final EnumSet<AreaAlarm> LUMINA_ALARMS = EnumSet.of(FREEZE, WATER, TEMPERATURE);
|
||||
public @Nullable String number;
|
||||
|
||||
public LuminaAreaHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMode(ChannelUID channelUID) {
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_AREA_SECURITY_MODE_HOME:
|
||||
return OmniLinkCmd.CMD_SECURITY_LUMINA_HOME_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_SLEEP:
|
||||
return OmniLinkCmd.CMD_SECURITY_LUMINA_SLEEP_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_AWAY:
|
||||
return OmniLinkCmd.CMD_SECURITY_LUMINA_AWAY_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_VACATION:
|
||||
return OmniLinkCmd.CMD_SECURITY_LUMINA_VACATION_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_PARTY:
|
||||
return OmniLinkCmd.CMD_SECURITY_LUMINA_PARTY_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_SPECIAL:
|
||||
return OmniLinkCmd.CMD_SECURITY_LUMINA_SPECIAL_MODE.getNumber();
|
||||
default:
|
||||
throw new IllegalStateException("Unknown channel for area thing " + channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnumSet<AreaAlarm> getAlarms() {
|
||||
return LUMINA_ALARMS;
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.AreaAlarm.*;
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.AreaAlarm;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* The {@link OmniAreaHandler} defines some methods that are used to
|
||||
* interface with an OmniLink OmniPro Area. This by extension also defines the
|
||||
* OmniPro Area thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OmniAreaHandler extends AbstractAreaHandler {
|
||||
private static final EnumSet<AreaAlarm> OMNI_ALARMS = EnumSet.of(BURGLARY, FIRE, GAS, AUXILIARY, FREEZE, WATER,
|
||||
DURESS, TEMPERATURE);
|
||||
public @Nullable String number;
|
||||
|
||||
public OmniAreaHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMode(ChannelUID channelUID) {
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_AREA_SECURITY_MODE_DISARM:
|
||||
return OmniLinkCmd.CMD_SECURITY_OMNI_DISARM.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_DAY:
|
||||
return OmniLinkCmd.CMD_SECURITY_OMNI_DAY_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_NIGHT:
|
||||
return OmniLinkCmd.CMD_SECURITY_OMNI_NIGHT_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_AWAY:
|
||||
return OmniLinkCmd.CMD_SECURITY_OMNI_AWAY_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_VACATION:
|
||||
return OmniLinkCmd.CMD_SECURITY_OMNI_VACATION_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_DAY_INSTANT:
|
||||
return OmniLinkCmd.CMD_SECURITY_OMNI_DAY_INSTANCE_MODE.getNumber();
|
||||
case CHANNEL_AREA_SECURITY_MODE_NIGHT_DELAYED:
|
||||
return OmniLinkCmd.CMD_SECURITY_OMNI_NIGHT_DELAYED_MODE.getNumber();
|
||||
default:
|
||||
throw new IllegalStateException("Unknown channel for area thing " + channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EnumSet<AreaAlarm> getAlarms() {
|
||||
return OMNI_ALARMS;
|
||||
}
|
||||
}
|
@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* OmniLink commands
|
||||
*
|
||||
* @author Dan Cunningham - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
* @since 1.5.0
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum OmniLinkCmd {
|
||||
CMD_UNIT_OFF(0),
|
||||
CMD_UNIT_ON(1),
|
||||
CMD_UNIT_AREA_ALL_OFF(2),
|
||||
CMD_UNIT_AREA_ALL_ON(3),
|
||||
CMD_UNIT_PERCENT(9),
|
||||
CMD_UNIT_LO9_LEVEL_HIGH7(101),
|
||||
CMD_UNIT_DECREMENT_COUNTER(10),
|
||||
CMD_UNIT_INCREMENT_COUNTER(11),
|
||||
CMD_UNIT_SET_COUNTER(12),
|
||||
CMD_UNIT_LO9_RAMP_HIGH7(13),
|
||||
CMD_UNIT_LIGHTOLIER(14),
|
||||
CMD_UNIT_UPB_REQ_STATUS(15),
|
||||
CMD_UNIT_UNIT_DIM_STEP_1(17),
|
||||
CMD_UNIT_UNIT_DIM_STEP_2(18),
|
||||
CMD_UNIT_UNIT_DIM_STEP_3(19),
|
||||
CMD_UNIT_UNIT_DIM_STEP_4(20),
|
||||
CMD_UNIT_UNIT_DIM_STEP_5(21),
|
||||
CMD_UNIT_UNIT_DIM_STEP_6(22),
|
||||
CMD_UNIT_UNIT_DIM_STEP_7(23),
|
||||
CMD_UNIT_UNIT_DIM_STEP_8(24),
|
||||
CMD_UNIT_UNIT_DIM_STEP_9(25),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_1(33),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_2(34),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_3(35),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_4(36),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_5(37),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_6(38),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_7(39),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_8(40),
|
||||
CMD_UNIT_UNIT_BRIGHTEN_STEP_9(41),
|
||||
CMD_UNIT_UPB_LO9_BLINK_HIGH7(26),
|
||||
CMD_UNIT_UPB_STOP_BLINK(27),
|
||||
CMD_UNIT_UPB_LINK_OFF(28),
|
||||
CMD_UNIT_UPB_LINK_ON(29),
|
||||
CMD_UNIT_UPB_LINK_SET(30),
|
||||
CMD_UNIT_CENTRALITE_SCENE_OFF(42),
|
||||
CMD_UNIT_CENTRALITE_SCENE_ON(43),
|
||||
CMD_UNIT_UPB_LED_OFF(44),
|
||||
CMD_UNIT_UPB_LED_ON(45),
|
||||
CMD_UNIT_RADIORA_PHANTOM_BUTTON_OFF(46),
|
||||
CMD_UNIT_RADIORA_PHANTM_BUTTON_ON(46),
|
||||
CMD_UNIT_LEVITON_SCENE_OFF(60),
|
||||
CMD_UNIT_LEVITON_SCENE_ON(61),
|
||||
CMD_UNIT_LEVITON_SCENE_SET(62),
|
||||
|
||||
CMD_SECURITY_OMNI_DISARM(48),
|
||||
CMD_SECURITY_OMNI_DAY_MODE(49),
|
||||
CMD_SECURITY_OMNI_NIGHT_MODE(50),
|
||||
CMD_SECURITY_OMNI_AWAY_MODE(51),
|
||||
CMD_SECURITY_OMNI_VACATION_MODE(52),
|
||||
CMD_SECURITY_OMNI_DAY_INSTANCE_MODE(53),
|
||||
CMD_SECURITY_OMNI_NIGHT_DELAYED_MODE(54),
|
||||
CMD_SECURITY_BYPASS_ZONE(4),
|
||||
CMD_SECURITY_RESTORE_ZONE(5),
|
||||
CMD_SECURITY_RESTORE_ALL_ZONES(6),
|
||||
CMD_SECURITY_LUMINA_HOME_MODE(49),
|
||||
CMD_SECURITY_LUMINA_SLEEP_MODE(50),
|
||||
CMD_SECURITY_LUMINA_AWAY_MODE(51),
|
||||
CMD_SECURITY_LUMINA_VACATION_MODE(52),
|
||||
CMD_SECURITY_LUMINA_PARTY_MODE(53),
|
||||
CMD_SECURITY_LUMINA_SPECIAL_MODE(54),
|
||||
|
||||
CMD_BUTTON(7),
|
||||
|
||||
CMD_ENERGY_SAVER_OFF(64),
|
||||
CMD_ENERGY_SAVER_ON(65),
|
||||
|
||||
CMD_THERMO_SET_HEAT_LOW_POINT(66),
|
||||
CMD_THERMO_SET_COOL_HIGH_POINT(67),
|
||||
CMD_THERMO_SET_SYSTEM_MODE(68),
|
||||
CMD_THERMO_SET_FAN_MODE(69),
|
||||
CMD_THERMO_SET_HOLD_MODE(70),
|
||||
CMD_THERMO_RAISE_LOWER_HEAT(71),
|
||||
CMD_THERMO_RAISE_LOWER_COOL(72),
|
||||
CMD_THERMO_SET_HUMDIFY_POINT(73),
|
||||
CMD_THERMO_SET_DEHUMIDIFY_POINT(74),
|
||||
|
||||
CMD_MESSAGE_SHOW_MESSAGE_WITH_BEEP_AND_LED(80),
|
||||
CMD_MESSAGE_SHOW_MESSAGE_WITH_BEEP_OR_LED(86),
|
||||
CMD_MESSAGE_LOG_MESSAGE(81),
|
||||
CMD_MESSAGE_CLEAR_MESSAGE(82),
|
||||
CMD_MESSAGE_SAY_MESSAGE(83),
|
||||
CMD_MESSAGE_PHONE_AND_SAY_MESSAGE(84),
|
||||
CMD_MESSAGE_SEND_MESSAGE_TO_SERIAL_PORT(85),
|
||||
|
||||
CMD_CONSOLE_ENABLE_DISABLE_BEEPER(102),
|
||||
CMD_CONSOLE_BEEP(103),
|
||||
|
||||
CMD_LOCK_DOOR(105),
|
||||
CMD_UNLOCK_DOOR(106),
|
||||
|
||||
CMD_AUDIO_ZONE_SET_ON_MUTE(112),
|
||||
CMD_AUDIO_ZONE_SET_VOLUME(113),
|
||||
CMD_AUDIO_ZONE_SET_SOURCE(114),
|
||||
CMD_AUDIO_ZONE_SELECT_KEY(115),
|
||||
|
||||
SENSOR_UNIT_POWER(1001),
|
||||
SENSOR_UNIT_LEVEL(1002),
|
||||
SENSOR_UNIT_DISPLAY(1003),
|
||||
SENSOR_THERMO_HEAT_POINTC(2001),
|
||||
SENSOR_THERMO_HEAT_POINTF(2002),
|
||||
SENSOR_THERMO_COOL_POINTC(2003),
|
||||
SENSOR_THERMO_COOL_POINTF(2004),
|
||||
SENSOR_THERMO_SYSTEM_MODE(2005),
|
||||
SENSOR_THERMO_FAN_MODE(2006),
|
||||
SENSOR_THERMO_HOLD_MODE(2007),
|
||||
SENSOR_THERMO_TEMPC(2006),
|
||||
SENSOR_THERMO_TEMPF(2007),
|
||||
SENSOR_ZONE_STATUS_CURRENT(3001),
|
||||
SENSOR_ZONE_STATUS_LATCHED(3002),
|
||||
SENSOR_ZONE_STATUS_ARMING(3003),
|
||||
SENSOR_AREA_STATUS_MODE(4001),
|
||||
SENSOR_AREA_STATUS_ALARM(4002),
|
||||
SENSOR_AREA_STATUS_EXIT_DELAY(4003),
|
||||
SENSOR_AREA_STATUS_ENTRY_DELAY(4003),
|
||||
SENSOR_AREA_EXIT_TIMER(4004),
|
||||
SENSOR_AREA_ENTRY_TIMER(4005),
|
||||
SENSOR_AUX_STATUS(5001),
|
||||
SENSOR_AUX_CURRENTC(5002),
|
||||
SENSOR_AUX_CURRENTF(5003),
|
||||
SENSOR_AUX_LOWC(5004),
|
||||
SENSOR_AUX_LOWF(5005),
|
||||
SENSOR_AUX_HIGHC(5006),
|
||||
SENSOR_AUX_HIGHF(5007),
|
||||
SENSOR_AUDIOZONE_POWER(6001),
|
||||
SENSOR_AUDIOZONE_SOURCE(6002),
|
||||
SENSOR_AUDIOZONE_VOLUME(6003),
|
||||
SENSOR_AUDIOZONE_MUTE(6004),
|
||||
SENSOR_AUDIOZONE_TEXT(6005),
|
||||
SENSOR_AUDIOZONE_TEXT_FIELD1(6006),
|
||||
SENSOR_AUDIOZONE_TEXT_FIELD2(6007),
|
||||
SENSOR_AUDIOZONE_TEXT_FIELD3(6008),
|
||||
SENSOR_AUDIOSOURCE_TEXT(7001),
|
||||
SENSOR_AUDIOSOURCE_TEXT_FIELD1(7002),
|
||||
SENSOR_AUDIOSOURCE_TEXT_FIELD2(7003),
|
||||
SENSOR_AUDIOSOURCE_TEXT_FIELD3(7004);
|
||||
|
||||
private int number;
|
||||
|
||||
OmniLinkCmd(int number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public int getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public static @Nullable OmniLinkCmd getCommand(String name) {
|
||||
for (OmniLinkCmd command : OmniLinkCmd.values()) {
|
||||
if (name.equals(command.toString())) {
|
||||
return command;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @Nullable OmniLinkCmd getCommand(int ordinal) {
|
||||
OmniLinkCmd[] values = OmniLinkCmd.values();
|
||||
if (ordinal < values.length) {
|
||||
return values[ordinal];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String toList() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (OmniLinkCmd command : OmniLinkCmd.values()) {
|
||||
sb.append(command.toString()).append(",");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,696 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
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.omnilink.internal.AudioPlayer;
|
||||
import org.openhab.binding.omnilink.internal.SystemType;
|
||||
import org.openhab.binding.omnilink.internal.config.OmnilinkBridgeConfig;
|
||||
import org.openhab.binding.omnilink.internal.discovery.OmnilinkDiscoveryService;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
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.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseBridgeHandler;
|
||||
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;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Connection;
|
||||
import com.digitaldan.jomnilinkII.DisconnectListener;
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.EventLogData;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SecurityCodeValidation;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SystemFeatures;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SystemFormats;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SystemInformation;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SystemStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAccessControlReaderLockStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAreaStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAudioZoneStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAuxSensorStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedThermostatStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedUnitStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedZoneStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.Status;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.systemevents.AllOnOffEvent;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.systemevents.ButtonEvent;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.systemevents.SwitchPressEvent;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.systemevents.SystemEvent;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.systemevents.UPBLinkEvent;
|
||||
import com.digitaldan.jomnilinkII.NotificationListener;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniNotConnectedException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
* The {@link OmnilinkBridgeHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Controller. This by extension also defines the
|
||||
* OmniLink bridge that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OmnilinkBridgeHandler extends BaseBridgeHandler implements NotificationListener, DisconnectListener {
|
||||
private final Logger logger = LoggerFactory.getLogger(OmnilinkBridgeHandler.class);
|
||||
private @Nullable Connection omniConnection = null;
|
||||
private @Nullable ScheduledFuture<?> connectJob;
|
||||
private @Nullable ScheduledFuture<?> eventPollingJob;
|
||||
private final int autoReconnectPeriod = 60;
|
||||
private Optional<AudioPlayer> audioPlayer = Optional.empty();
|
||||
private @Nullable SystemType systemType = null;
|
||||
private final Gson gson = new Gson();
|
||||
private int eventLogNumber = 0;
|
||||
|
||||
public OmnilinkBridgeHandler(Bridge bridge) {
|
||||
super(bridge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singleton(OmnilinkDiscoveryService.class);
|
||||
}
|
||||
|
||||
public void sendOmnilinkCommand(final int message, final int param1, final int param2)
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
getOmniConnection().controllerCommand(message, param1, param2);
|
||||
} catch (IOException | OmniNotConnectedException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public SecurityCodeValidation reqSecurityCodeValidation(int area, int digit1, int digit2, int digit3, int digit4)
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().reqSecurityCodeValidation(area, digit1, digit2, digit3, digit4);
|
||||
} catch (IOException | OmniNotConnectedException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void activateKeypadEmergency(int area, int emergencyType)
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
getOmniConnection().activateKeypadEmergency(area, emergencyType);
|
||||
} catch (IOException | OmniNotConnectedException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public SystemInformation reqSystemInformation()
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().reqSystemInformation();
|
||||
} catch (IOException | OmniNotConnectedException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public SystemFormats reqSystemFormats()
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().reqSystemFormats();
|
||||
} catch (IOException | OmniNotConnectedException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private SystemFeatures reqSystemFeatures()
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().reqSystemFeatures();
|
||||
} catch (IOException | OmniNotConnectedException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
updateChannels();
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_SYSTEMDATE:
|
||||
if (command instanceof DateTimeType) {
|
||||
ZonedDateTime zdt = ((DateTimeType) command).getZonedDateTime();
|
||||
boolean inDaylightSavings = zdt.getZone().getRules().isDaylightSavings(zdt.toInstant());
|
||||
try {
|
||||
getOmniConnection().setTimeCommand(zdt.getYear() - 2000, zdt.getMonthValue(),
|
||||
zdt.getDayOfMonth(), zdt.getDayOfWeek().getValue(), zdt.getHour(), zdt.getMinute(),
|
||||
inDaylightSavings);
|
||||
} catch (IOException | OmniNotConnectedException | OmniInvalidResponseException
|
||||
| OmniUnknownMessageTypeException e) {
|
||||
logger.debug("Could not send Set Time command to OmniLink Controller: {}", e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DateTimeType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONSOLE_ENABLE_DISABLE_BEEPER:
|
||||
if (command instanceof StringType) {
|
||||
try {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_CONSOLE_ENABLE_DISABLE_BEEPER.getNumber(),
|
||||
((StringType) command).equals(StringType.valueOf("OFF")) ? 0 : 1, 0);
|
||||
updateState(CHANNEL_CONSOLE_ENABLE_DISABLE_BEEPER, UnDefType.UNDEF);
|
||||
} catch (NumberFormatException | OmniInvalidResponseException | OmniUnknownMessageTypeException
|
||||
| BridgeOfflineException e) {
|
||||
logger.debug("Could not send Console command to OmniLink Controller: {}", e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be StringType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_CONSOLE_BEEP:
|
||||
if (command instanceof DecimalType) {
|
||||
try {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_CONSOLE_BEEP.getNumber(),
|
||||
((DecimalType) command).intValue(), 0);
|
||||
updateState(CHANNEL_CONSOLE_BEEP, UnDefType.UNDEF);
|
||||
} catch (NumberFormatException | OmniInvalidResponseException | OmniUnknownMessageTypeException
|
||||
| BridgeOfflineException e) {
|
||||
logger.debug("Could not send Console command to OmniLink Controller: {}", e.getMessage());
|
||||
}
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DecimalType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Bridge thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
private void makeOmnilinkConnection() {
|
||||
final Connection connection = omniConnection;
|
||||
if (connection != null && connection.connected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Attempting to connect to controller!");
|
||||
try {
|
||||
OmnilinkBridgeConfig config = getConfigAs(OmnilinkBridgeConfig.class);
|
||||
|
||||
this.omniConnection = new Connection(config.getIpAddress(), config.getPort(),
|
||||
config.getKey1() + ":" + config.getKey2());
|
||||
|
||||
/*
|
||||
* HAI only supports one audio player - cycle through features until we find a feature that is an audio
|
||||
* player.
|
||||
*/
|
||||
audioPlayer = reqSystemFeatures().getFeatures().stream()
|
||||
.map(featureCode -> AudioPlayer.getAudioPlayerForFeatureCode(featureCode))
|
||||
.filter(Optional::isPresent).findFirst().orElse(Optional.empty());
|
||||
|
||||
systemType = SystemType.getType(reqSystemInformation().getModel());
|
||||
|
||||
if (config.getLogPollingInterval() > 0) {
|
||||
startEventPolling(config.getLogPollingInterval());
|
||||
}
|
||||
|
||||
final Connection connectionNew = omniConnection;
|
||||
if (connectionNew != null) {
|
||||
connectionNew.enableNotifications();
|
||||
connectionNew.addNotificationListener(OmnilinkBridgeHandler.this);
|
||||
connectionNew.addDisconnectListener(this);
|
||||
}
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
cancelReconnectJob(false);
|
||||
updateChannels();
|
||||
updateBridgeProperties();
|
||||
} catch (UnknownHostException e) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
} catch (IOException e) {
|
||||
final Throwable cause = e.getCause();
|
||||
if (cause != null) {
|
||||
final String causeMessage = cause.getMessage();
|
||||
|
||||
if (causeMessage != null && causeMessage.contains("Connection timed out")) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||
"IP Address probably incorrect, timed out creating connection!");
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, causeMessage);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
logger.debug("Error connecting to OmniLink Controller: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void objectStatusNotification(@Nullable ObjectStatus objectStatus) {
|
||||
if (objectStatus != null) {
|
||||
Status[] statuses = objectStatus.getStatuses();
|
||||
for (Status status : statuses) {
|
||||
if (status instanceof ExtendedUnitStatus) {
|
||||
ExtendedUnitStatus unitStatus = (ExtendedUnitStatus) status;
|
||||
int unitNumber = unitStatus.getNumber();
|
||||
|
||||
logger.debug("Received status update for Unit: {}, status: {}", unitNumber, unitStatus);
|
||||
Optional<Thing> theThing = getUnitThing(unitNumber);
|
||||
theThing.map(Thing::getHandler)
|
||||
.ifPresent(theHandler -> ((UnitHandler) theHandler).handleStatus(unitStatus));
|
||||
} else if (status instanceof ExtendedZoneStatus) {
|
||||
ExtendedZoneStatus zoneStatus = (ExtendedZoneStatus) status;
|
||||
int zoneNumber = zoneStatus.getNumber();
|
||||
|
||||
logger.debug("Received status update for Zone: {}, status: {}", zoneNumber, zoneStatus);
|
||||
Optional<Thing> theThing = getChildThing(THING_TYPE_ZONE, zoneNumber);
|
||||
theThing.map(Thing::getHandler)
|
||||
.ifPresent(theHandler -> ((ZoneHandler) theHandler).handleStatus(zoneStatus));
|
||||
} else if (status instanceof ExtendedAreaStatus) {
|
||||
final SystemType systemType = this.systemType;
|
||||
ExtendedAreaStatus areaStatus = (ExtendedAreaStatus) status;
|
||||
int areaNumber = areaStatus.getNumber();
|
||||
|
||||
if (systemType != null) {
|
||||
logger.debug("Received status update for Area: {}, status: {}", areaNumber, areaStatus);
|
||||
Optional<Thing> theThing;
|
||||
switch (systemType) {
|
||||
case OMNI:
|
||||
theThing = getChildThing(THING_TYPE_OMNI_AREA, areaNumber);
|
||||
break;
|
||||
case LUMINA:
|
||||
theThing = getChildThing(THING_TYPE_LUMINA_AREA, areaNumber);
|
||||
break;
|
||||
default:
|
||||
theThing = Optional.empty();
|
||||
}
|
||||
theThing.map(Thing::getHandler)
|
||||
.ifPresent(theHandler -> ((AbstractAreaHandler) theHandler).handleStatus(areaStatus));
|
||||
} else {
|
||||
logger.debug("Received null System Type!");
|
||||
}
|
||||
} else if (status instanceof ExtendedAccessControlReaderLockStatus) {
|
||||
ExtendedAccessControlReaderLockStatus lockStatus = (ExtendedAccessControlReaderLockStatus) status;
|
||||
int lockNumber = lockStatus.getNumber();
|
||||
|
||||
logger.debug("Received status update for Lock: {}, status: {}", lockNumber, lockStatus);
|
||||
Optional<Thing> theThing = getChildThing(THING_TYPE_LOCK, lockNumber);
|
||||
theThing.map(Thing::getHandler)
|
||||
.ifPresent(theHandler -> ((LockHandler) theHandler).handleStatus(lockStatus));
|
||||
} else if (status instanceof ExtendedThermostatStatus) {
|
||||
ExtendedThermostatStatus thermostatStatus = (ExtendedThermostatStatus) status;
|
||||
int thermostatNumber = thermostatStatus.getNumber();
|
||||
|
||||
logger.debug("Received status update for Thermostat: {}, status: {}", thermostatNumber,
|
||||
thermostatStatus);
|
||||
Optional<Thing> theThing = getChildThing(THING_TYPE_THERMOSTAT, thermostatNumber);
|
||||
theThing.map(Thing::getHandler)
|
||||
.ifPresent(theHandler -> ((ThermostatHandler) theHandler).handleStatus(thermostatStatus));
|
||||
} else if (status instanceof ExtendedAudioZoneStatus) {
|
||||
ExtendedAudioZoneStatus audioZoneStatus = (ExtendedAudioZoneStatus) status;
|
||||
int audioZoneNumber = audioZoneStatus.getNumber();
|
||||
|
||||
logger.debug("Received status update for Audio Zone: {}, status: {}", audioZoneNumber,
|
||||
audioZoneStatus);
|
||||
Optional<Thing> theThing = getChildThing(THING_TYPE_AUDIO_ZONE, audioZoneNumber);
|
||||
theThing.map(Thing::getHandler)
|
||||
.ifPresent(theHandler -> ((AudioZoneHandler) theHandler).handleStatus(audioZoneStatus));
|
||||
} else if (status instanceof ExtendedAuxSensorStatus) {
|
||||
ExtendedAuxSensorStatus auxSensorStatus = (ExtendedAuxSensorStatus) status;
|
||||
int auxSensorNumber = auxSensorStatus.getNumber();
|
||||
|
||||
// Aux Sensors can be either temperature or humidity, need to check both.
|
||||
Optional<Thing> tempThing = getChildThing(THING_TYPE_TEMP_SENSOR, auxSensorNumber);
|
||||
Optional<Thing> humidityThing = getChildThing(THING_TYPE_HUMIDITY_SENSOR, auxSensorNumber);
|
||||
if (tempThing.isPresent()) {
|
||||
logger.debug("Received status update for Temperature Sensor: {}, status: {}", auxSensorNumber,
|
||||
auxSensorStatus);
|
||||
tempThing.map(Thing::getHandler).ifPresent(
|
||||
theHandler -> ((TempSensorHandler) theHandler).handleStatus(auxSensorStatus));
|
||||
}
|
||||
if (humidityThing.isPresent()) {
|
||||
logger.debug("Received status update for Humidity Sensor: {}, status: {}", auxSensorNumber,
|
||||
auxSensorStatus);
|
||||
humidityThing.map(Thing::getHandler).ifPresent(
|
||||
theHandler -> ((HumiditySensorHandler) theHandler).handleStatus(auxSensorStatus));
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received Object Status Notification that was not processed: {}", objectStatus);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null Object Status Notification!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void systemEventNotification(@Nullable SystemEvent event) {
|
||||
if (event != null) {
|
||||
logger.debug("Received System Event Notification of type: {}", event.getType());
|
||||
switch (event.getType()) {
|
||||
case PHONE_LINE_DEAD:
|
||||
case PHONE_LINE_OFF_HOOK:
|
||||
case PHONE_LINE_ON_HOOK:
|
||||
case PHONE_LINE_RING:
|
||||
ChannelUID channel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_PHONE_LINE_EVENT);
|
||||
triggerChannel(channel, event.getType().toString().replaceAll("^PHONE_LINE_", ""));
|
||||
break;
|
||||
case AC_POWER_OFF:
|
||||
case AC_POWER_RESTORED:
|
||||
ChannelUID acChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_AC_POWER_EVENT);
|
||||
triggerChannel(acChannel, event.getType().toString().replaceAll("^AC_POWER_", ""));
|
||||
break;
|
||||
case BATTERY_LOW:
|
||||
case BATTERY_OK:
|
||||
ChannelUID batteryChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_BATTERY_EVENT);
|
||||
triggerChannel(batteryChannel, event.getType().toString().replaceAll("^BATTERY_", ""));
|
||||
break;
|
||||
case DCM_OK:
|
||||
case DCM_TROUBLE:
|
||||
ChannelUID dcmChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_DCM_EVENT);
|
||||
triggerChannel(dcmChannel, event.getType().toString().replaceAll("^DCM_", ""));
|
||||
break;
|
||||
case ENERGY_COST_CRITICAL:
|
||||
case ENERGY_COST_HIGH:
|
||||
case ENERGY_COST_LOW:
|
||||
case ENERGY_COST_MID:
|
||||
ChannelUID energyChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_ENERGY_COST_EVENT);
|
||||
triggerChannel(energyChannel, event.getType().toString().replaceAll("^ENERGY_COST_", ""));
|
||||
break;
|
||||
case CAMERA_1_TRIGGER:
|
||||
case CAMERA_2_TRIGGER:
|
||||
case CAMERA_3_TRIGGER:
|
||||
case CAMERA_4_TRIGGER:
|
||||
case CAMERA_5_TRIGGER:
|
||||
case CAMERA_6_TRIGGER:
|
||||
ChannelUID cameraChannel = new ChannelUID(getThing().getUID(),
|
||||
TRIGGER_CHANNEL_CAMERA_TRIGGER_EVENT);
|
||||
triggerChannel(cameraChannel, String.valueOf(event.getType().toString().charAt(8)));
|
||||
break;
|
||||
case BUTTON:
|
||||
Optional<Thing> buttonThing = getChildThing(THING_TYPE_BUTTON,
|
||||
((ButtonEvent) event).getButtonNumber());
|
||||
buttonThing.map(Thing::getHandler)
|
||||
.ifPresent(theHandler -> ((ButtonHandler) theHandler).buttonActivated());
|
||||
break;
|
||||
case ALL_ON_OFF:
|
||||
Optional<Thing> areaThing = getChildThing(THING_TYPE_OMNI_AREA, ((AllOnOffEvent) event).getArea());
|
||||
if (areaThing.isPresent()) {
|
||||
logger.debug("Thing for allOnOff event: {}", areaThing.get().getUID());
|
||||
areaThing.map(Thing::getHandler).ifPresent(theHandler -> ((AbstractAreaHandler) theHandler)
|
||||
.handleAllOnOffEvent((AllOnOffEvent) event));
|
||||
}
|
||||
break;
|
||||
case UPB_LINK:
|
||||
UPBLinkEvent linkEvent = (UPBLinkEvent) event;
|
||||
UPBLinkEvent.Command command = linkEvent.getLinkCommand();
|
||||
int link = linkEvent.getLinkNumber();
|
||||
handleUPBLink(link, command);
|
||||
break;
|
||||
case ALC_UPB_RADIORA_STARLITE_SWITCH_PRESS:
|
||||
SwitchPressEvent switchPressEvent = (SwitchPressEvent) event;
|
||||
int unitNumber = switchPressEvent.getUnitNumber();
|
||||
|
||||
Optional<Thing> unitThing = getUnitThing(unitNumber);
|
||||
unitThing.map(Thing::getHandler).ifPresent(
|
||||
theHandler -> ((UnitHandler) theHandler).handleSwitchPressEvent(switchPressEvent));
|
||||
break;
|
||||
default:
|
||||
logger.warn("Ignoring System Event Notification of type: {}", event.getType());
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null System Event Notification!");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUPBLink(int link, UPBLinkEvent.Command command) {
|
||||
final ChannelUID activateChannel;
|
||||
|
||||
if (command == UPBLinkEvent.Command.ACTIVATED) {
|
||||
activateChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_UPB_LINK_ACTIVATED_EVENT);
|
||||
} else if (command == UPBLinkEvent.Command.DEACTIVATED) {
|
||||
activateChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_UPB_LINK_DEACTIVATED_EVENT);
|
||||
} else {
|
||||
logger.debug("Received unsupported UPB link event: {}", command);
|
||||
return;
|
||||
}
|
||||
triggerChannel(activateChannel, Integer.toString(link));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notConnectedEvent(@Nullable Exception e) {
|
||||
if (e != null) {
|
||||
logger.debug("Received an OmniLink Controller not connected event: {}", e.getMessage());
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void getSystemStatus() throws IOException, OmniNotConnectedException, OmniInvalidResponseException,
|
||||
OmniUnknownMessageTypeException {
|
||||
SystemStatus status = getOmniConnection().reqSystemStatus();
|
||||
logger.debug("Received system status: {}", status);
|
||||
// Let's update system time
|
||||
String dateString = new StringBuilder().append(2000 + status.getYear()).append("-")
|
||||
.append(String.format("%02d", status.getMonth())).append("-")
|
||||
.append(String.format("%02d", status.getDay())).append("T")
|
||||
.append(String.format("%02d", status.getHour())).append(":")
|
||||
.append(String.format("%02d", status.getMinute())).append(":")
|
||||
.append(String.format("%02d", status.getSecond())).toString();
|
||||
updateState(CHANNEL_SYSTEMDATE, new DateTimeType(dateString));
|
||||
}
|
||||
|
||||
public Message reqObjectProperties(int objectType, int objectNum, int direction, int filter1, int filter2,
|
||||
int filter3) throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().reqObjectProperties(objectType, objectNum, direction, filter1, filter2, filter3);
|
||||
} catch (OmniNotConnectedException | IOException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Message requestAudioSourceStatus(final int source, final int position)
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().reqAudioSourceStatus(source, position);
|
||||
} catch (OmniNotConnectedException | IOException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectStatus requestObjectStatus(final int objType, final int startObject, final int endObject,
|
||||
boolean extended)
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().reqObjectStatus(objType, startObject, endObject, extended);
|
||||
} catch (OmniNotConnectedException | IOException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<TemperatureFormat> getTemperatureFormat() {
|
||||
try {
|
||||
return Optional.of(TemperatureFormat.valueOf(reqSystemFormats().getTempFormat()));
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Could not request temperature format from controller: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateChannels() {
|
||||
try {
|
||||
getSystemStatus();
|
||||
updateState(CHANNEL_CONSOLE_ENABLE_DISABLE_BEEPER, UnDefType.UNDEF);
|
||||
updateState(CHANNEL_CONSOLE_BEEP, UnDefType.UNDEF);
|
||||
} catch (IOException | OmniNotConnectedException | OmniInvalidResponseException
|
||||
| OmniUnknownMessageTypeException e) {
|
||||
logger.warn("Unable to update bridge channels: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
cancelReconnectJob(true);
|
||||
cancelEventPolling();
|
||||
final Connection connection = omniConnection;
|
||||
if (connection != null) {
|
||||
connection.removeDisconnectListener(this);
|
||||
connection.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Thing> getChildThing(ThingTypeUID type, int number) {
|
||||
Bridge bridge = getThing();
|
||||
return bridge.getThings().stream().filter(t -> t.getThingTypeUID().equals(type))
|
||||
.filter(t -> ((Number) t.getConfiguration().get(THING_PROPERTIES_NUMBER)).intValue() == number)
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private Optional<Thing> getUnitThing(int unitId) {
|
||||
Optional<Thing> theThing = getChildThing(THING_TYPE_UNIT_UPB, unitId);
|
||||
if (!(theThing.isPresent())) {
|
||||
theThing = getChildThing(THING_TYPE_ROOM, unitId);
|
||||
}
|
||||
if (!(theThing.isPresent())) {
|
||||
theThing = getChildThing(THING_TYPE_FLAG, unitId);
|
||||
}
|
||||
if (!(theThing.isPresent())) {
|
||||
theThing = getChildThing(THING_TYPE_OUTPUT, unitId);
|
||||
}
|
||||
if (!(theThing.isPresent())) {
|
||||
theThing = getChildThing(THING_TYPE_DIMMABLE, unitId);
|
||||
}
|
||||
if (!(theThing.isPresent())) {
|
||||
theThing = getChildThing(THING_TYPE_UNIT, unitId);
|
||||
}
|
||||
|
||||
return theThing;
|
||||
}
|
||||
|
||||
public Optional<AudioPlayer> getAudioPlayer() {
|
||||
return audioPlayer;
|
||||
}
|
||||
|
||||
public Message readEventRecord(int eventNumber, int direction)
|
||||
throws OmniInvalidResponseException, OmniUnknownMessageTypeException, BridgeOfflineException {
|
||||
try {
|
||||
return getOmniConnection().readEventRecord(eventNumber, direction);
|
||||
} catch (OmniNotConnectedException | IOException e) {
|
||||
setOfflineAndReconnect(e.getMessage());
|
||||
throw new BridgeOfflineException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBridgeProperties() {
|
||||
try {
|
||||
SystemInformation systemInformation = reqSystemInformation();
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_MODEL_NUMBER, Integer.toString(systemInformation.getModel()));
|
||||
properties.put(THING_PROPERTIES_MAJOR_VERSION, Integer.toString(systemInformation.getMajor()));
|
||||
properties.put(THING_PROPERTIES_MINOR_VERSION, Integer.toString(systemInformation.getMinor()));
|
||||
properties.put(THING_PROPERTIES_REVISION, Integer.toString(systemInformation.getRevision()));
|
||||
properties.put(THING_PROPERTIES_PHONE_NUMBER, systemInformation.getPhone());
|
||||
updateProperties(properties);
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Could not request system information from OmniLink Controller: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
scheduleReconnectJob();
|
||||
}
|
||||
|
||||
private void scheduleReconnectJob() {
|
||||
ScheduledFuture<?> currentReconnectJob = connectJob;
|
||||
if (currentReconnectJob == null || currentReconnectJob.isDone()) {
|
||||
connectJob = super.scheduler.scheduleWithFixedDelay(this::makeOmnilinkConnection, 0, autoReconnectPeriod,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelReconnectJob(boolean kill) {
|
||||
ScheduledFuture<?> currentReconnectJob = connectJob;
|
||||
if (currentReconnectJob != null) {
|
||||
currentReconnectJob.cancel(kill);
|
||||
}
|
||||
}
|
||||
|
||||
private void setOfflineAndReconnect(@Nullable String message) {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
|
||||
cancelEventPolling();
|
||||
final Connection connection = omniConnection;
|
||||
if (connection != null) {
|
||||
connection.removeDisconnectListener(this);
|
||||
}
|
||||
scheduleReconnectJob();
|
||||
}
|
||||
|
||||
private void startEventPolling(int interval) {
|
||||
ScheduledFuture<?> eventPollingJobFuture = eventPollingJob;
|
||||
if (eventPollingJobFuture == null || eventPollingJobFuture.isDone()) {
|
||||
eventLogNumber = 0;
|
||||
eventPollingJob = super.scheduler.scheduleWithFixedDelay(this::pollEvents, 0, interval, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelEventPolling() {
|
||||
ScheduledFuture<?> eventPollingJobFuture = eventPollingJob;
|
||||
if (eventPollingJobFuture != null) {
|
||||
eventPollingJobFuture.cancel(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void pollEvents() {
|
||||
// On first run, direction is -1 (most recent event), after its 1 for the next log message
|
||||
try {
|
||||
Message message;
|
||||
do {
|
||||
logger.trace("Polling for event log messages.");
|
||||
int direction = eventLogNumber == 0 ? -1 : 1;
|
||||
message = readEventRecord(eventLogNumber, direction);
|
||||
if (message.getMessageType() == Message.MESG_TYPE_EVENT_LOG_DATA) {
|
||||
EventLogData logData = (EventLogData) message;
|
||||
logger.debug("Processing event log message number: {}", logData.getEventNumber());
|
||||
eventLogNumber = logData.getEventNumber();
|
||||
String json = gson.toJson(logData);
|
||||
logger.debug("Receieved event log message: {}", json);
|
||||
updateState(CHANNEL_EVENT_LOG, new StringType(json));
|
||||
}
|
||||
} while (message.getMessageType() != Message.MESG_TYPE_END_OF_DATA);
|
||||
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Exception recieved while polling for event log messages: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private Connection getOmniConnection() throws OmniNotConnectedException {
|
||||
final Connection connection = omniConnection;
|
||||
if (connection != null) {
|
||||
return connection;
|
||||
} else {
|
||||
throw new OmniNotConnectedException("Connection not yet established!");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.ImperialUnits;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AuxSensorProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedAuxSensorStatus;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link TempSensorHandler} defines some methods that are used to interface
|
||||
* with an OmniLink Temperature Sensor. This by extension also defines the
|
||||
* Temperature Sensor thing that openHAB will be able to pick up and interface
|
||||
* with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TempSensorHandler extends AbstractOmnilinkStatusHandler<ExtendedAuxSensorStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(TempSensorHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public TempSensorHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateTempSensorProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Temperature Sensor!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTempSensorProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
final List<AreaProperties> areas = getAreaProperties();
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<AuxSensorProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.AUX_SENSORS, thingID, 0).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (AuxSensorProperties auxSensorProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, auxSensorProperties.getName());
|
||||
properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
Optional<TemperatureFormat> temperatureFormat = Optional.empty();
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(command instanceof QuantityType)) {
|
||||
logger.debug("Invalid command: {}, must be QuantityType", command);
|
||||
return;
|
||||
}
|
||||
if (bridgeHandler != null) {
|
||||
temperatureFormat = bridgeHandler.getTemperatureFormat();
|
||||
if (!temperatureFormat.isPresent()) {
|
||||
logger.warn("Receieved null temperature format!");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logger.warn("Could not connect to Bridge, failed to get temperature format!");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_AUX_LOW_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_HEAT_LOW_POINT.getNumber(),
|
||||
temperatureFormat.get().formatToOmni(((QuantityType<Temperature>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
case CHANNEL_AUX_HIGH_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_COOL_HIGH_POINT.getNumber(),
|
||||
temperatureFormat.get().formatToOmni(((QuantityType<Temperature>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Temperature Sensor thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedAuxSensorStatus status) {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
Optional<TemperatureFormat> temperatureFormat = bridgeHandler.getTemperatureFormat();
|
||||
if (temperatureFormat.isPresent()) {
|
||||
updateState(CHANNEL_AUX_TEMP, new QuantityType<>(
|
||||
temperatureFormat.get().omniToFormat(status.getTemperature()),
|
||||
temperatureFormat.get().getFormatNumber() == 1 ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS));
|
||||
updateState(CHANNEL_AUX_LOW_SETPOINT, new QuantityType<>(
|
||||
temperatureFormat.get().omniToFormat(status.getCoolSetpoint()),
|
||||
temperatureFormat.get().getFormatNumber() == 1 ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS));
|
||||
updateState(CHANNEL_AUX_HIGH_SETPOINT, new QuantityType<>(
|
||||
temperatureFormat.get().omniToFormat(status.getHeatSetpoint()),
|
||||
temperatureFormat.get().getFormatNumber() == 1 ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS));
|
||||
} else {
|
||||
logger.warn("Receieved null temperature format, could not update Temperature Sensor channels!");
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Temperature Sensor channels!");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedAuxSensorStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
ObjectStatus objStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_AUX_SENSOR, thingID,
|
||||
thingID, true);
|
||||
return Optional.of((ExtendedAuxSensorStatus) objStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Temperature Sensor status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Temperature Sensor status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
import com.digitaldan.jomnilinkII.MessageUtils;
|
||||
|
||||
/**
|
||||
* The {@link TemperatureFormat} defines some methods that are used to
|
||||
* convert OmniLink temperature values into Fahrenheit or Celsius.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public enum TemperatureFormat {
|
||||
// Don't convert zero - it appears that is what omni returns when there is no value.
|
||||
CELSIUS(2) {
|
||||
@Override
|
||||
public float omniToFormat(int omniNumber) {
|
||||
return MessageUtils.omniToC(omniNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int formatToOmni(int celsius) {
|
||||
return MessageUtils.CToOmni(celsius);
|
||||
}
|
||||
},
|
||||
FAHRENHEIT(1) {
|
||||
@Override
|
||||
public float omniToFormat(int omniNumber) {
|
||||
return MessageUtils.omniToF(omniNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int formatToOmni(int fahrenheit) {
|
||||
return MessageUtils.FtoOmni(fahrenheit);
|
||||
}
|
||||
};
|
||||
|
||||
private final int formatNumber;
|
||||
|
||||
private TemperatureFormat(int formatNumber) {
|
||||
this.formatNumber = formatNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a number represented by the omni to the format.
|
||||
*
|
||||
* @param omniNumber Number to convert
|
||||
* @return Number converted to appropriate format.
|
||||
*/
|
||||
public abstract float omniToFormat(int omniNumber);
|
||||
|
||||
/**
|
||||
* Convert a number from this format into an omni number.
|
||||
*
|
||||
* @param format Number in the current format.
|
||||
* @return Omni formatted number.
|
||||
*/
|
||||
public abstract int formatToOmni(int format);
|
||||
|
||||
/**
|
||||
* Get the number which identifies this format as defined by the omniprotocol.
|
||||
*
|
||||
* @return Number which identifies this temperature format.
|
||||
*/
|
||||
public int getFormatNumber() {
|
||||
return formatNumber;
|
||||
}
|
||||
|
||||
public static TemperatureFormat valueOf(int tempFormat) {
|
||||
if (tempFormat == CELSIUS.formatNumber) {
|
||||
return CELSIUS;
|
||||
} else if (tempFormat == FAHRENHEIT.formatNumber) {
|
||||
return FAHRENHEIT;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid temperature format!");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,265 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.measure.quantity.Dimensionless;
|
||||
import javax.measure.quantity.Temperature;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OpenClosedType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.ImperialUnits;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ThermostatProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedThermostatStatus;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link ThermostatHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Thermostat. This by extension also defines the
|
||||
* Thermostat thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ThermostatHandler extends AbstractOmnilinkStatusHandler<ExtendedThermostatStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(ThermostatHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
private enum ThermostatStatus {
|
||||
HEATING(0, 1),
|
||||
COOLING(1, 2),
|
||||
HUMIDIFYING(2, 3),
|
||||
DEHUMIDIFYING(3, 4);
|
||||
|
||||
private final int bit;
|
||||
private final int modeValue;
|
||||
|
||||
private ThermostatStatus(int bit, int modeValue) {
|
||||
this.bit = bit;
|
||||
this.modeValue = modeValue;
|
||||
}
|
||||
}
|
||||
|
||||
public ThermostatHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateThermostatProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Thermostat!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateThermostatProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
final List<AreaProperties> areas = getAreaProperties();
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<ThermostatProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.THERMOSTAT, thingID, 0).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (ThermostatProperties thermostatProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, thermostatProperties.getName());
|
||||
properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
Optional<TemperatureFormat> temperatureFormat = Optional.empty();
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(command instanceof DecimalType) && !(command instanceof QuantityType)) {
|
||||
logger.debug("Invalid command: {}, must be DecimalType or QuantityType", command);
|
||||
return;
|
||||
}
|
||||
if (bridgeHandler != null) {
|
||||
temperatureFormat = bridgeHandler.getTemperatureFormat();
|
||||
if (!temperatureFormat.isPresent()) {
|
||||
logger.warn("Receieved null temperature format!");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
logger.warn("Could not connect to Bridge, failed to get temperature format!");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_THERMO_SYSTEM_MODE:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_SYSTEM_MODE.getNumber(),
|
||||
((DecimalType) command).intValue(), thingID);
|
||||
break;
|
||||
case CHANNEL_THERMO_FAN_MODE:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_FAN_MODE.getNumber(), ((DecimalType) command).intValue(),
|
||||
thingID);
|
||||
break;
|
||||
case CHANNEL_THERMO_HOLD_STATUS:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_HOLD_MODE.getNumber(),
|
||||
((DecimalType) command).intValue(), thingID);
|
||||
break;
|
||||
case CHANNEL_THERMO_HEAT_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_HEAT_LOW_POINT.getNumber(),
|
||||
temperatureFormat.get().formatToOmni(((QuantityType<Temperature>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
case CHANNEL_THERMO_COOL_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_COOL_HIGH_POINT.getNumber(),
|
||||
temperatureFormat.get().formatToOmni(((QuantityType<Temperature>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
case CHANNEL_THERMO_HUMIDIFY_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_HUMDIFY_POINT.getNumber(),
|
||||
TemperatureFormat.FAHRENHEIT.formatToOmni(((QuantityType<Dimensionless>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
case CHANNEL_THERMO_DEHUMIDIFY_SETPOINT:
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_THERMO_SET_DEHUMIDIFY_POINT.getNumber(),
|
||||
TemperatureFormat.FAHRENHEIT.formatToOmni(((QuantityType<Dimensionless>) command).intValue()),
|
||||
thingID);
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Thermostat thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChannels(ExtendedThermostatStatus status) {
|
||||
logger.debug("updateChannels called for Thermostat status: {}", status);
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
|
||||
// Thermostat communication status
|
||||
BigInteger thermostatAlarms = BigInteger.valueOf(status.getStatus());
|
||||
updateState(CHANNEL_THERMO_COMM_FAILURE,
|
||||
thermostatAlarms.testBit(0) ? OpenClosedType.CLOSED : OpenClosedType.OPEN);
|
||||
updateState(CHANNEL_THERMO_FREEZE_ALARM,
|
||||
thermostatAlarms.testBit(1) ? OpenClosedType.CLOSED : OpenClosedType.OPEN);
|
||||
|
||||
// Thermostat operation status
|
||||
BigInteger thermostatStatus = BigInteger.valueOf(status.getExtendedStatus());
|
||||
if (thermostatStatus.testBit(ThermostatStatus.HEATING.bit)) {
|
||||
updateState(CHANNEL_THERMO_STATUS, new DecimalType(ThermostatStatus.HEATING.modeValue));
|
||||
} else if (thermostatStatus.testBit(ThermostatStatus.COOLING.bit)) {
|
||||
updateState(CHANNEL_THERMO_STATUS, new DecimalType(ThermostatStatus.COOLING.modeValue));
|
||||
} else if (thermostatStatus.testBit(ThermostatStatus.HUMIDIFYING.bit)) {
|
||||
updateState(CHANNEL_THERMO_STATUS, new DecimalType(ThermostatStatus.HUMIDIFYING.modeValue));
|
||||
} else if (thermostatStatus.testBit(ThermostatStatus.DEHUMIDIFYING.bit)) {
|
||||
updateState(CHANNEL_THERMO_STATUS, new DecimalType(ThermostatStatus.DEHUMIDIFYING.modeValue));
|
||||
} else {
|
||||
updateState(CHANNEL_THERMO_STATUS, new DecimalType(0));
|
||||
}
|
||||
|
||||
// Thermostat temperature status
|
||||
if (bridgeHandler != null) {
|
||||
Optional<TemperatureFormat> temperatureFormat = bridgeHandler.getTemperatureFormat();
|
||||
if (temperatureFormat.isPresent()) {
|
||||
updateState(CHANNEL_THERMO_CURRENT_TEMP, new QuantityType<>(
|
||||
temperatureFormat.get().omniToFormat(status.getCurrentTemperature()),
|
||||
temperatureFormat.get().getFormatNumber() == 1 ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS));
|
||||
updateState(CHANNEL_THERMO_OUTDOOR_TEMP, new QuantityType<>(
|
||||
temperatureFormat.get().omniToFormat(status.getOutdoorTemperature()),
|
||||
temperatureFormat.get().getFormatNumber() == 1 ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS));
|
||||
updateState(CHANNEL_THERMO_COOL_SETPOINT, new QuantityType<>(
|
||||
temperatureFormat.get().omniToFormat(status.getCoolSetpoint()),
|
||||
temperatureFormat.get().getFormatNumber() == 1 ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS));
|
||||
updateState(CHANNEL_THERMO_HEAT_SETPOINT, new QuantityType<>(
|
||||
temperatureFormat.get().omniToFormat(status.getHeatSetpoint()),
|
||||
temperatureFormat.get().getFormatNumber() == 1 ? ImperialUnits.FAHRENHEIT : SIUnits.CELSIUS));
|
||||
} else {
|
||||
logger.warn("Receieved null temperature format, could not update Thermostat channels!");
|
||||
}
|
||||
} else {
|
||||
logger.warn("Could not connect to Bridge, failed to get temperature format!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Thermostat humidity status
|
||||
updateState(CHANNEL_THERMO_HUMIDITY, new QuantityType<>(
|
||||
TemperatureFormat.FAHRENHEIT.omniToFormat(status.getCurrentHumidity()), Units.PERCENT));
|
||||
updateState(CHANNEL_THERMO_HUMIDIFY_SETPOINT, new QuantityType<>(
|
||||
TemperatureFormat.FAHRENHEIT.omniToFormat(status.getHumidifySetpoint()), Units.PERCENT));
|
||||
updateState(CHANNEL_THERMO_DEHUMIDIFY_SETPOINT, new QuantityType<>(
|
||||
TemperatureFormat.FAHRENHEIT.omniToFormat(status.getDehumidifySetpoint()), Units.PERCENT));
|
||||
|
||||
// Thermostat mode, fan, and hold status
|
||||
updateState(CHANNEL_THERMO_SYSTEM_MODE, new DecimalType(status.getSystemMode()));
|
||||
updateState(CHANNEL_THERMO_FAN_MODE, new DecimalType(status.getFanMode()));
|
||||
updateState(CHANNEL_THERMO_HOLD_STATUS,
|
||||
new DecimalType(status.getHoldStatus() > 2 ? 1 : status.getHoldStatus()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedThermostatStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
ObjectStatus objStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_THERMO, thingID, thingID,
|
||||
true);
|
||||
return Optional.of((ExtendedThermostatStatus) objStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Thermostat status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Thermostat status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.UnitProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedUnitStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.systemevents.SwitchPressEvent;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link AbstractOmnilinkHandler} defines some methods that can be used across
|
||||
* the many different Units exposed by the OmniLink protocol
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UnitHandler extends AbstractOmnilinkStatusHandler<ExtendedUnitStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(UnitHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public UnitHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateUnitProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Unit!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUnitProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
final List<AreaProperties> areas = getAreaProperties();
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<UnitProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.UNIT, thingID, 0).selectNamed()
|
||||
.areaFilter(areaFilter).selectAnyLoad().build();
|
||||
|
||||
for (UnitProperties unitProperties : objectPropertyRequest) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, unitProperties.getName());
|
||||
properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_UNIT_LEVEL:
|
||||
case CHANNEL_UNIT_SWITCH:
|
||||
if (command instanceof OnOffType) {
|
||||
handleOnOff(channelUID, (OnOffType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_UNIT_ON_FOR_SECONDS:
|
||||
case CHANNEL_UNIT_OFF_FOR_SECONDS:
|
||||
case CHANNEL_UNIT_ON_FOR_MINUTES:
|
||||
case CHANNEL_UNIT_OFF_FOR_MINUTES:
|
||||
case CHANNEL_UNIT_ON_FOR_HOURS:
|
||||
case CHANNEL_UNIT_OFF_FOR_HOURS:
|
||||
if (command instanceof DecimalType) {
|
||||
handleUnitDuration(channelUID, (DecimalType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DecimalType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unknown channel for Unit thing: {}", channelUID);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnitDuration(ChannelUID channelUID, DecimalType command) {
|
||||
logger.debug("handleUnitDuration called for channel: {}, command: {}", channelUID, command);
|
||||
final String channelID = channelUID.getId();
|
||||
|
||||
int duration;
|
||||
if (channelID.endsWith("seconds")) {
|
||||
duration = command.intValue();
|
||||
} else if (channelID.endsWith("minutes")) {
|
||||
duration = command.intValue() + 100;
|
||||
} else if (channelID.endsWith("hours")) {
|
||||
duration = command.intValue() + 200;
|
||||
} else {
|
||||
logger.warn("Unknown channel for Unit duration: {}", channelUID);
|
||||
return;
|
||||
}
|
||||
|
||||
sendOmnilinkCommand(
|
||||
channelID.startsWith("on") ? OmniLinkCmd.CMD_UNIT_ON.getNumber() : OmniLinkCmd.CMD_UNIT_OFF.getNumber(),
|
||||
duration, thingID);
|
||||
}
|
||||
|
||||
protected void handleOnOff(ChannelUID channelUID, OnOffType command) {
|
||||
logger.debug("handleOnOff called for channel: {}, command: {}", channelUID, command);
|
||||
sendOmnilinkCommand(OnOffType.ON.equals(command) ? OmniLinkCmd.CMD_UNIT_ON.getNumber()
|
||||
: OmniLinkCmd.CMD_UNIT_OFF.getNumber(), 0, thingID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedUnitStatus status) {
|
||||
logger.debug("updateChannels called for Unit status: {}", status);
|
||||
int unitStatus = status.getStatus();
|
||||
int level = 0;
|
||||
|
||||
if (unitStatus == Status.UNIT_OFF) {
|
||||
level = 0;
|
||||
} else if (unitStatus == Status.UNIT_ON) {
|
||||
level = 100;
|
||||
} else if ((unitStatus >= Status.UNIT_SCENE_A) && (unitStatus <= Status.UNIT_SCENE_L)) {
|
||||
level = 100;
|
||||
} else if ((unitStatus >= Status.UNIT_LEVEL_0) && (unitStatus <= Status.UNIT_LEVEL_100)) {
|
||||
level = unitStatus - Status.UNIT_LEVEL_0;
|
||||
}
|
||||
|
||||
updateState(CHANNEL_UNIT_LEVEL, PercentType.valueOf(Integer.toString(level)));
|
||||
updateState(CHANNEL_UNIT_SWITCH, OnOffType.from(level != 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedUnitStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
ObjectStatus objectStatus = bridgeHandler.requestObjectStatus(Message.OBJ_TYPE_UNIT, thingID, thingID,
|
||||
true);
|
||||
return Optional.of((ExtendedUnitStatus) objectStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Unit status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Unit status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private static class Status {
|
||||
private static final int UNIT_OFF = 0;
|
||||
private static final int UNIT_ON = 1;
|
||||
private static final int UNIT_SCENE_A = 2;
|
||||
private static final int UNIT_SCENE_L = 13;
|
||||
private static final int UNIT_LEVEL_0 = 100;
|
||||
private static final int UNIT_LEVEL_100 = 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a switch press event by triggering the appropriate channel.
|
||||
*
|
||||
* @param switchPressEvent
|
||||
*/
|
||||
public void handleSwitchPressEvent(SwitchPressEvent switchPressEvent) {
|
||||
ChannelUID activateChannel = new ChannelUID(getThing().getUID(), TRIGGER_CHANNEL_SWITCH_PRESS_EVENT);
|
||||
triggerChannel(activateChannel, Integer.toString(switchPressEvent.getSwitchValue()));
|
||||
}
|
||||
}
|
@ -0,0 +1,201 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler;
|
||||
|
||||
import static com.digitaldan.jomnilinkII.MessageTypes.properties.AuxSensorProperties.SENSOR_TYPE_PROGRAMMABLE_ENERGY_SAVER_MODULE;
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequest;
|
||||
import org.openhab.binding.omnilink.internal.discovery.ObjectPropertyRequests;
|
||||
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.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.Message;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.ObjectStatus;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.SecurityCodeValidation;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.AreaProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.properties.ZoneProperties;
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedZoneStatus;
|
||||
import com.digitaldan.jomnilinkII.OmniInvalidResponseException;
|
||||
import com.digitaldan.jomnilinkII.OmniUnknownMessageTypeException;
|
||||
|
||||
/**
|
||||
* The {@link ZoneHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Zone. This by extension also defines the
|
||||
* OmniPro Zone thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ZoneHandler extends AbstractOmnilinkStatusHandler<ExtendedZoneStatus> {
|
||||
private final Logger logger = LoggerFactory.getLogger(ZoneHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public ZoneHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
final OmnilinkBridgeHandler bridgeHandler = getOmnilinkBridgeHandler();
|
||||
if (bridgeHandler != null) {
|
||||
updateZoneProperties(bridgeHandler);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR,
|
||||
"Received null bridge while initializing Zone!");
|
||||
}
|
||||
}
|
||||
|
||||
private void updateZoneProperties(OmnilinkBridgeHandler bridgeHandler) {
|
||||
final List<AreaProperties> areas = super.getAreaProperties();
|
||||
if (areas != null) {
|
||||
for (AreaProperties areaProperties : areas) {
|
||||
int areaFilter = super.bitFilterForArea(areaProperties);
|
||||
|
||||
ObjectPropertyRequest<ZoneProperties> objectPropertyRequest = ObjectPropertyRequest
|
||||
.builder(bridgeHandler, ObjectPropertyRequests.ZONE, getThingNumber(), 0).selectNamed()
|
||||
.areaFilter(areaFilter).build();
|
||||
|
||||
for (ZoneProperties zoneProperties : objectPropertyRequest) {
|
||||
if (zoneProperties.getZoneType() <= SENSOR_TYPE_PROGRAMMABLE_ENERGY_SAVER_MODULE) {
|
||||
Map<String, String> properties = editProperties();
|
||||
properties.put(THING_PROPERTIES_NAME, zoneProperties.getName());
|
||||
properties.put(THING_PROPERTIES_AREA, Integer.toString(areaProperties.getNumber()));
|
||||
updateProperties(properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
int mode;
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(command instanceof StringType)) {
|
||||
logger.debug("Invalid command: {}, must be StringType", command);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_ZONE_BYPASS:
|
||||
mode = OmniLinkCmd.CMD_SECURITY_BYPASS_ZONE.getNumber();
|
||||
break;
|
||||
case CHANNEL_ZONE_RESTORE:
|
||||
mode = OmniLinkCmd.CMD_SECURITY_RESTORE_ZONE.getNumber();
|
||||
break;
|
||||
default:
|
||||
mode = -1;
|
||||
}
|
||||
int areaNumber = getAreaNumber();
|
||||
logger.debug("mode {} on zone {} with code {}", mode, thingID, command.toFullString());
|
||||
char[] code = command.toFullString().toCharArray();
|
||||
if (code.length != 4) {
|
||||
logger.warn("Invalid code length, code must be 4 digits");
|
||||
} else {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridge = getOmnilinkBridgeHandler();
|
||||
if (bridge != null) {
|
||||
SecurityCodeValidation codeValidation = bridge.reqSecurityCodeValidation(areaNumber,
|
||||
Character.getNumericValue(code[0]), Character.getNumericValue(code[1]),
|
||||
Character.getNumericValue(code[2]), Character.getNumericValue(code[3]));
|
||||
/*
|
||||
* 0 Invalid code
|
||||
* 1 Master
|
||||
* 2 Manager
|
||||
* 3 User
|
||||
*/
|
||||
logger.debug("User code number: {} level: {}", codeValidation.getCodeNumber(),
|
||||
codeValidation.getAuthorityLevel());
|
||||
/*
|
||||
* Valid user code number are 1-99, 251 is duress code, 0 means code does not exist
|
||||
*/
|
||||
if ((codeValidation.getCodeNumber() > 0 && codeValidation.getCodeNumber() <= 99)
|
||||
&& codeValidation.getAuthorityLevel() > 0) {
|
||||
sendOmnilinkCommand(mode, codeValidation.getCodeNumber(), thingID);
|
||||
} else {
|
||||
logger.warn("System reported an invalid code");
|
||||
}
|
||||
} else {
|
||||
logger.debug("Received null bridge while sending zone command!");
|
||||
}
|
||||
} catch (OmniInvalidResponseException e) {
|
||||
logger.debug("Zone command failed: {}", e.getMessage());
|
||||
} catch (OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Could not send zone command: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
// This is a send only channel, so don't store the user code
|
||||
updateState(channelUID, UnDefType.UNDEF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChannels(ExtendedZoneStatus zoneStatus) {
|
||||
// 0 Secure. 1 Not ready, 3 Trouble
|
||||
int current = ((zoneStatus.getStatus() >> 0) & 0x03);
|
||||
// 0 Secure, 1 Tripped, 2 Reset, but previously tripped
|
||||
int latched = ((zoneStatus.getStatus() >> 2) & 0x03);
|
||||
// 0 Disarmed, 1 Armed, 2 Bypass user, 3 Bypass system
|
||||
int arming = ((zoneStatus.getStatus() >> 4) & 0x03);
|
||||
State contactState = Integer.valueOf(current).equals(0) ? OpenClosedType.CLOSED : OpenClosedType.OPEN;
|
||||
logger.debug("handling Zone Status change to state: {}, current: {}, latched: {}, arming: {}", contactState,
|
||||
current, latched, arming);
|
||||
updateState(CHANNEL_ZONE_CONTACT, contactState);
|
||||
updateState(CHANNEL_ZONE_CURRENT_CONDITION, new DecimalType(current));
|
||||
updateState(CHANNEL_ZONE_LATCHED_ALARM_STATUS, new DecimalType(latched));
|
||||
updateState(CHANNEL_ZONE_ARMING_STATUS, new DecimalType(arming));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Optional<ExtendedZoneStatus> retrieveStatus() {
|
||||
try {
|
||||
final OmnilinkBridgeHandler bridge = getOmnilinkBridgeHandler();
|
||||
if (bridge != null) {
|
||||
ObjectStatus objStatus = bridge.requestObjectStatus(Message.OBJ_TYPE_ZONE, thingID, thingID, true);
|
||||
return Optional.of((ExtendedZoneStatus) objStatus.getStatuses()[0]);
|
||||
} else {
|
||||
logger.debug("Received null bridge while updating Zone status!");
|
||||
return Optional.empty();
|
||||
}
|
||||
} catch (OmniInvalidResponseException | OmniUnknownMessageTypeException | BridgeOfflineException e) {
|
||||
logger.debug("Received exception while refreshing Zone status: {}", e.getMessage());
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler.units;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.CHANNEL_UNIT_LEVEL;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmniLinkCmd;
|
||||
import org.openhab.binding.omnilink.internal.handler.UnitHandler;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link DimmableUnitHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Dimmable Unit. This by extension also defines the
|
||||
* Dimmable Unit things that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Brian O'Connell - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DimmableUnitHandler extends UnitHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(DimmableUnitHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public DimmableUnitHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_UNIT_LEVEL:
|
||||
handleUnitLevel(channelUID, command);
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown channel for Dimmable Unit thing: {}", channelUID);
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleUnitLevel(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleUnitLevel called for channel: {}, command: {}", channelUID, command);
|
||||
if (command instanceof PercentType) {
|
||||
handlePercent(channelUID, (PercentType) command);
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
handleIncreaseDecrease(channelUID, (IncreaseDecreaseType) command);
|
||||
} else {
|
||||
// Only handle percent or increase/decrease.
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handlePercent(ChannelUID channelUID, PercentType command) {
|
||||
logger.debug("handlePercent called for channel: {}, command: {}", channelUID, command);
|
||||
int lightLevel = command.intValue();
|
||||
|
||||
if (lightLevel == 0) {
|
||||
super.handleOnOff(channelUID, OnOffType.OFF);
|
||||
} else if (lightLevel == 100) {
|
||||
super.handleOnOff(channelUID, OnOffType.ON);
|
||||
} else {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_UNIT_PERCENT.getNumber(), lightLevel, thingID);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleIncreaseDecrease(ChannelUID channelUID, IncreaseDecreaseType command) {
|
||||
logger.debug("handleIncreaseDecrease called for channel: {}, command: {}", channelUID, command);
|
||||
sendOmnilinkCommand(
|
||||
IncreaseDecreaseType.INCREASE.equals(command) ? OmniLinkCmd.CMD_UNIT_UNIT_BRIGHTEN_STEP_1.getNumber()
|
||||
: OmniLinkCmd.CMD_UNIT_UNIT_DIM_STEP_1.getNumber(),
|
||||
0, thingID);
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler.units;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmniLinkCmd;
|
||||
import org.openhab.binding.omnilink.internal.handler.UnitHandler;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedUnitStatus;
|
||||
|
||||
/**
|
||||
* The {@link FlagHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Flag. This by extension also defines the
|
||||
* Flag thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FlagHandler extends UnitHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(FlagHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public FlagHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_FLAG_VALUE:
|
||||
if (command instanceof DecimalType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_UNIT_SET_COUNTER.getNumber(),
|
||||
((DecimalType) command).intValue(), thingID);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DecimalType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_FLAG_SWITCH:
|
||||
if (command instanceof OnOffType) {
|
||||
handleOnOff(channelUID, (OnOffType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown channel for Flag thing: {}", channelUID);
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedUnitStatus status) {
|
||||
logger.debug("updateChannels called for Flag status: {}", status);
|
||||
updateState(CHANNEL_FLAG_VALUE, DecimalType.valueOf(Integer.toString(status.getStatus())));
|
||||
updateState(CHANNEL_FLAG_SWITCH, OnOffType.from(status.getStatus() == 1));
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler.units;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.handler.UnitHandler;
|
||||
import org.openhab.core.thing.Thing;
|
||||
|
||||
/**
|
||||
* The {@link OutputHandler} defines some methods that are used to
|
||||
* interface with an OmniLink Output. This by extension also defines the
|
||||
* Output thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Brian O'Connell - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class OutputHandler extends UnitHandler {
|
||||
public @Nullable String number;
|
||||
|
||||
public OutputHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler.units;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.*;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmniLinkCmd;
|
||||
import org.openhab.binding.omnilink.internal.handler.UnitHandler;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
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.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.digitaldan.jomnilinkII.MessageTypes.statuses.ExtendedUnitStatus;
|
||||
|
||||
/**
|
||||
* The {@link UpbRoomHandler} defines some methods that are used to
|
||||
* interface with an OmniLink UPB Room. This by extension also defines the
|
||||
* OmniPro UPB Room thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UpbRoomHandler extends UnitHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(UpbRoomHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public UpbRoomHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
retrieveStatus().ifPresentOrElse(this::updateChannels, () -> updateStatus(ThingStatus.OFFLINE,
|
||||
ThingStatusDetail.OFFLINE.COMMUNICATION_ERROR, "Received null staus update!"));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_ROOM_SCENE_A:
|
||||
case CHANNEL_ROOM_SCENE_B:
|
||||
case CHANNEL_ROOM_SCENE_C:
|
||||
case CHANNEL_ROOM_SCENE_D:
|
||||
if (command instanceof OnOffType) {
|
||||
handleRoomScene(channelUID, (OnOffType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ROOM_SWITCH:
|
||||
if (command instanceof OnOffType) {
|
||||
super.handleOnOff(channelUID, (OnOffType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be OnOffType", command);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ROOM_STATE:
|
||||
if (command instanceof DecimalType) {
|
||||
handleRoomState(channelUID, (DecimalType) command);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be DecimalType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown channel for UPB Room thing: {}", channelUID);
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRoomScene(ChannelUID channelUID, OnOffType command) {
|
||||
logger.debug("handleRoomScene called for channel: {}, command: {}", channelUID, command);
|
||||
int linkNum;
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case "scene_a":
|
||||
linkNum = 0;
|
||||
break;
|
||||
case "scene_b":
|
||||
linkNum = 1;
|
||||
break;
|
||||
case "scene_c":
|
||||
linkNum = 2;
|
||||
break;
|
||||
case "scene_d":
|
||||
linkNum = 3;
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unexpected UPB Room scene: {}", channelUID);
|
||||
return;
|
||||
}
|
||||
int roomNum = (thingID + 7) / 8;
|
||||
int param2 = ((roomNum * 6) - 3) + linkNum;
|
||||
sendOmnilinkCommand(OnOffType.ON.equals(command) ? OmniLinkCmd.CMD_UNIT_UPB_LINK_ON.getNumber()
|
||||
: OmniLinkCmd.CMD_UNIT_UPB_LINK_OFF.getNumber(), 0, param2);
|
||||
}
|
||||
|
||||
private void handleRoomState(ChannelUID channelUID, DecimalType command) {
|
||||
logger.debug("handleRoomState called for channel: {}, command: {}", channelUID, command);
|
||||
final int cmdValue = command.intValue();
|
||||
int cmd;
|
||||
int param2;
|
||||
|
||||
switch (cmdValue) {
|
||||
case 0:
|
||||
cmd = OmniLinkCmd.CMD_UNIT_OFF.getNumber();
|
||||
param2 = thingID;
|
||||
break;
|
||||
case 1:
|
||||
cmd = OmniLinkCmd.CMD_UNIT_ON.getNumber();
|
||||
param2 = thingID;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
cmd = OmniLinkCmd.CMD_UNIT_UPB_LINK_ON.getNumber();
|
||||
/*
|
||||
* A little magic with the link #'s: 0 and 1 are off and on, respectively.
|
||||
* So A ends up being 2, but OmniLink Protocol expects an offset of 0. That
|
||||
* is why we subtract the 2.
|
||||
*/
|
||||
int roomNum = (thingID + 7) / 8;
|
||||
param2 = ((roomNum * 6) - 3) + cmdValue - 2;
|
||||
break;
|
||||
default:
|
||||
logger.warn("Unexpected UPB Room state: {}", Integer.toString(cmdValue));
|
||||
return;
|
||||
}
|
||||
|
||||
sendOmnilinkCommand(cmd, 0, param2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateChannels(ExtendedUnitStatus status) {
|
||||
logger.debug("updateChannels called for UPB Room status: {}", status);
|
||||
int unitStatus = status.getStatus();
|
||||
|
||||
updateState(CHANNEL_ROOM_STATE, new DecimalType(unitStatus));
|
||||
updateState(CHANNEL_ROOM_SWITCH, OnOffType.from(unitStatus == 1));
|
||||
updateState(CHANNEL_ROOM_SCENE_A, OnOffType.from(unitStatus == 2));
|
||||
updateState(CHANNEL_ROOM_SCENE_B, OnOffType.from(unitStatus == 3));
|
||||
updateState(CHANNEL_ROOM_SCENE_C, OnOffType.from(unitStatus == 4));
|
||||
updateState(CHANNEL_ROOM_SCENE_D, OnOffType.from(unitStatus == 5));
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2021 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.omnilink.internal.handler.units.dimmable;
|
||||
|
||||
import static org.openhab.binding.omnilink.internal.OmnilinkBindingConstants.CHANNEL_UPB_STATUS;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.omnilink.internal.handler.OmniLinkCmd;
|
||||
import org.openhab.binding.omnilink.internal.handler.units.DimmableUnitHandler;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link UpbUnitHandler} defines some methods that are used to
|
||||
* interface with an OmniLink UPB Unit. This by extension also defines the
|
||||
* UPB Unit thing that openHAB will be able to pick up and interface with.
|
||||
*
|
||||
* @author Craig Hamilton - Initial contribution
|
||||
* @author Ethan Dye - openHAB3 rewrite
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class UpbUnitHandler extends DimmableUnitHandler {
|
||||
private final Logger logger = LoggerFactory.getLogger(UpbUnitHandler.class);
|
||||
private final int thingID = getThingNumber();
|
||||
public @Nullable String number;
|
||||
|
||||
public UpbUnitHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
logger.debug("handleCommand called for channel: {}, command: {}", channelUID, command);
|
||||
|
||||
if (command instanceof RefreshType) {
|
||||
updateState(CHANNEL_UPB_STATUS, UnDefType.UNDEF);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (channelUID.getId()) {
|
||||
case CHANNEL_UPB_STATUS:
|
||||
if (command instanceof StringType) {
|
||||
sendOmnilinkCommand(OmniLinkCmd.CMD_UNIT_UPB_REQ_STATUS.getNumber(), 0, thingID);
|
||||
updateState(CHANNEL_UPB_STATUS, UnDefType.UNDEF);
|
||||
} else {
|
||||
logger.debug("Invalid command: {}, must be StringType", command);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logger.debug("Unknown channel for UPB Unit thing: {}", channelUID);
|
||||
super.handleCommand(channelUID, command);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="omnilink" 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>OmniLink Binding</name>
|
||||
<description>This is the binding for OmniLink, a security system that interfaces with many devices.</description>
|
||||
|
||||
</binding:binding>
|
@ -0,0 +1,163 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Omni Area Thing -->
|
||||
<thing-type id="area">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Omni Area</label>
|
||||
<description>An Omni area configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="activate_keypad_emergency" typeId="omni_activate_keypad_emergency"/>
|
||||
<channel id="alarm_burglary" typeId="area_alarm"/>
|
||||
<channel id="alarm_fire" typeId="area_alarm"/>
|
||||
<channel id="alarm_gas" typeId="area_alarm"/>
|
||||
<channel id="alarm_auxiliary" typeId="area_alarm"/>
|
||||
<channel id="alarm_freeze" typeId="area_alarm"/>
|
||||
<channel id="alarm_water" typeId="area_alarm"/>
|
||||
<channel id="alarm_duress" typeId="area_alarm"/>
|
||||
<channel id="alarm_temperature" typeId="area_alarm"/>
|
||||
<channel id="mode" typeId="omni_area_mode"/>
|
||||
<channel id="disarm" typeId="area_command"/>
|
||||
<channel id="day" typeId="area_command"/>
|
||||
<channel id="night" typeId="area_command"/>
|
||||
<channel id="away" typeId="area_command"/>
|
||||
<channel id="vacation" typeId="area_command"/>
|
||||
<channel id="day_instant" typeId="area_command"/>
|
||||
<channel id="night_delayed" typeId="area_command"/>
|
||||
<channel id="all_on_off_event" typeId="all_on_off_event"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Area Number</label>
|
||||
<description>The area number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Lumina Area Thing -->
|
||||
<thing-type id="lumina_area">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Lumina Area</label>
|
||||
<description>An Lumina area configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="mode" typeId="lumina_area_mode"/>
|
||||
<channel id="home" typeId="area_command"/>
|
||||
<channel id="sleep" typeId="area_command"/>
|
||||
<channel id="away" typeId="area_command"/>
|
||||
<channel id="vacation" typeId="area_command"/>
|
||||
<channel id="party" typeId="area_command"/>
|
||||
<channel id="special" typeId="area_command"/>
|
||||
<channel id="all_on_off_event" typeId="all_on_off_event"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
</properties>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Area Number</label>
|
||||
<description>The area number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Area channels -->
|
||||
<channel-type id="area_alarm">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Area Alarm</label>
|
||||
<description>Indicates if an alarm is active.</description>
|
||||
<category>Alarm</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="omni_area_mode">
|
||||
<item-type>Number</item-type>
|
||||
<label>Security Mode</label>
|
||||
<description>Represents the area security mode.</description>
|
||||
<category>Alarm</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="0">Off</option>
|
||||
<option value="1">Day</option>
|
||||
<option value="2">Night</option>
|
||||
<option value="3">Away</option>
|
||||
<option value="4">Vacation</option>
|
||||
<option value="5">Day instant</option>
|
||||
<option value="6">Night delayed</option>
|
||||
<option value="9">Arming day</option>
|
||||
<option value="10">Arming night</option>
|
||||
<option value="11">Arming away</option>
|
||||
<option value="12">Arming vacation</option>
|
||||
<option value="13">Arming day instant</option>
|
||||
<option value="14">Arming night delayed</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="area_command">
|
||||
<item-type>String</item-type>
|
||||
<label>Security Command</label>
|
||||
<description>Sends a 4 digit user code to activate the area command.</description>
|
||||
<category>Alarm</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="omni_activate_keypad_emergency">
|
||||
<item-type>Number</item-type>
|
||||
<label>Activate Keypad Emergency</label>
|
||||
<description>Activate a burglary, fire, or auxiliary keypad emergency alarm on Omni based models.</description>
|
||||
<category>Alarm</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="1">Burglary</option>
|
||||
<option value="2">Fire</option>
|
||||
<option value="3">Auxiliary</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="lumina_area_mode">
|
||||
<item-type>Number</item-type>
|
||||
<label>Security Mode</label>
|
||||
<description>Represents the area security mode.</description>
|
||||
<category>Alarm</category>
|
||||
<state readOnly="true">
|
||||
<options>
|
||||
<option value="1">Home</option>
|
||||
<option value="2">Sleep</option>
|
||||
<option value="3">Away</option>
|
||||
<option value="4">Vacation</option>
|
||||
<option value="5">Party</option>
|
||||
<option value="6">Special</option>
|
||||
<option value="9">Setting home</option>
|
||||
<option value="10">Setting sleep</option>
|
||||
<option value="11">Setting away</option>
|
||||
<option value="12">Setting vacation</option>
|
||||
<option value="13">Setting party</option>
|
||||
<option value="14">Setting special</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="all_on_off_event">
|
||||
<kind>trigger</kind>
|
||||
<label>All On/Off Event</label>
|
||||
<description>Event sent when an all on/off event occurs.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="OFF">Off</option>
|
||||
<option value="ON">On</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Audio Source Thing -->
|
||||
<thing-type id="audio_source">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Audio Source</label>
|
||||
<description>An audio source configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="source_text_1" typeId="audio_source_text"/>
|
||||
<channel id="source_text_2" typeId="audio_source_text"/>
|
||||
<channel id="source_text_3" typeId="audio_source_text"/>
|
||||
<channel id="source_text_4" typeId="audio_source_text"/>
|
||||
<channel id="source_text_5" typeId="audio_source_text"/>
|
||||
<channel id="source_text_6" typeId="audio_source_text"/>
|
||||
<channel id="polling" typeId="audio_source_polling"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Audio Source Number</label>
|
||||
<description>The audio source number.</description>
|
||||
</parameter>
|
||||
<parameter name="autostart" type="boolean" required="false">
|
||||
<label>Autostart Polling</label>
|
||||
<description>Autostart polling of audio source on creation of thing.</description>
|
||||
<default>true</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Audio Source Channels -->
|
||||
<channel-type id="audio_source_text">
|
||||
<item-type>String</item-type>
|
||||
<label>Source Data</label>
|
||||
<description>A line of metadata from this audio source.</description>
|
||||
<category>Text</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="audio_source_polling">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Audio Source Polling</label>
|
||||
<description>Enable or disable polling of this audio source.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Audio Zone Thing -->
|
||||
<thing-type id="audio_zone">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Audio Zone</label>
|
||||
<description>An audio zone configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="zone_power" typeId="audio_zone_power"/>
|
||||
<channel id="zone_mute" typeId="audio_zone_mute"/>
|
||||
<channel id="zone_volume" typeId="audio_zone_volume"/>
|
||||
<channel id="zone_source" typeId="audio_zone_source"/>
|
||||
<channel id="zone_control" typeId="audio_zone_control"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Audio Zone Number</label>
|
||||
<description>The audio zone number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
|
||||
<!-- Audio Zone Channels -->
|
||||
<channel-type id="audio_zone_power">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Audio Zone Power</label>
|
||||
<description>Power status of this audio zone.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="audio_zone_mute">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Audio Zone Mute</label>
|
||||
<description>Mute status of this audio zone.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="audio_zone_volume">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Audio Zone Volume</label>
|
||||
<description>Volume level of this audio zone.</description>
|
||||
<category>Slider</category>
|
||||
<state min="0" max="100"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="audio_zone_source">
|
||||
<item-type>Number</item-type>
|
||||
<label>Source</label>
|
||||
<description>Source for this audio zone.</description>
|
||||
<category>MediaControl</category>
|
||||
<state min="1" max="100"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="audio_zone_control">
|
||||
<item-type>Player</item-type>
|
||||
<label>Control</label>
|
||||
<description>Control the audio zone, e.g. start/stop/next/previous.</description>
|
||||
<category>MediaControl</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,172 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- OmniLink Controller Bridge -->
|
||||
<bridge-type id="controller">
|
||||
<label>OmniLink Controller</label>
|
||||
<description>An OmniLink controller.</description>
|
||||
<channels>
|
||||
<channel id="sysdate" typeId="sysDate"/>
|
||||
<channel id="enable_disable_beeper" typeId="console_enable_disable_beeper">
|
||||
<label>Console Beepers</label>
|
||||
</channel>
|
||||
<channel id="beep" typeId="console_beep">
|
||||
<label>Beep Consoles</label>
|
||||
</channel>
|
||||
<channel id="last_log" typeId="last_log"/>
|
||||
<channel id="phone_line_event" typeId="phone_line_event"/>
|
||||
<channel id="ac_power_event" typeId="ac_power_event"/>
|
||||
<channel id="battery_event" typeId="battery_event"/>
|
||||
<channel id="dcm_event" typeId="dcm_event"/>
|
||||
<channel id="energy_cost_event" typeId="energy_cost_event"/>
|
||||
<channel id="camera_trigger_event" typeId="camera_trigger_event"/>
|
||||
<channel id="upb_link_activated_event" typeId="upb_link_activated_event"/>
|
||||
<channel id="upb_link_deactivated_event" typeId="upb_link_deactivated_event"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="model number"/>
|
||||
<property name="major version"/>
|
||||
<property name="minor version"/>
|
||||
<property name="revision"/>
|
||||
<property name="phone number"/>
|
||||
</properties>
|
||||
<config-description>
|
||||
<parameter name="ipAddress" type="text" required="true">
|
||||
<context>network-address</context>
|
||||
<label>IP or Host Name</label>
|
||||
<description>The IP or host name of the controller.</description>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" required="true">
|
||||
<label>Port</label>
|
||||
<description>The port of the controller.</description>
|
||||
<default>4369</default>
|
||||
</parameter>
|
||||
<parameter name="key1" type="text" required="true">
|
||||
<label>Key 1</label>
|
||||
<description>The first network encription key.</description>
|
||||
</parameter>
|
||||
<parameter name="key2" type="text" required="true">
|
||||
<label>Key 2</label>
|
||||
<description>The second network encription key.</description>
|
||||
</parameter>
|
||||
<parameter name="logPollingInterval" type="integer" required="true">
|
||||
<label>Log Polling Interval</label>
|
||||
<description>The interval to poll for new log messages on the controller.</description>
|
||||
<default>1</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
|
||||
<!-- Controller Channels -->
|
||||
<channel-type id="sysDate">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Date/Time</label>
|
||||
<description>Set controller date/time.</description>
|
||||
<category>Time</category>
|
||||
<state pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="last_log">
|
||||
<item-type>String</item-type>
|
||||
<label>Last Log Entry</label>
|
||||
<description>Last log message on the controller, represented in JSON.</description>
|
||||
<category>Text</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="upb_link_activated_event">
|
||||
<kind>trigger</kind>
|
||||
<label>UPB Link</label>
|
||||
<description>Event sent when a UPB link is activated.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="upb_link_deactivated_event">
|
||||
<kind>trigger</kind>
|
||||
<label>UPB Link</label>
|
||||
<description>Event sent when a UPB link is deactivated.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="phone_line_event">
|
||||
<kind>trigger</kind>
|
||||
<label>Phone Line Event</label>
|
||||
<description>Event sent when the phone line changes state.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="ON_HOOK">On Hook</option>
|
||||
<option value="OFF_HOOK">Off Hook</option>
|
||||
<option value="DEAD">Dead</option>
|
||||
<option value="RING">Ring</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="ac_power_event">
|
||||
<kind>trigger</kind>
|
||||
<label>AC Power Event</label>
|
||||
<description>Event sent when AC trouble conditions are detected.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="OFF">Off</option>
|
||||
<option value="RESTORED">Restored</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="battery_event">
|
||||
<kind>trigger</kind>
|
||||
<label>Battery Event</label>
|
||||
<description>Event sent when battery trouble conditions are detected.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="LOW">Low</option>
|
||||
<option value="OK">OK</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dcm_event">
|
||||
<kind>trigger</kind>
|
||||
<label>DCM Event</label>
|
||||
<description>Event sent when digital communicator trouble conditions are detected.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="TROUBLE">Trouble</option>
|
||||
<option value="OK">OK</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="energy_cost_event">
|
||||
<kind>trigger</kind>
|
||||
<label>Energy Cost Event</label>
|
||||
<description>Event sent when the cost of energy changes.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="LOW">Trouble</option>
|
||||
<option value="MID">Mid</option>
|
||||
<option value="HIGH">High</option>
|
||||
<option value="CRITCAL">Critical</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="camera_trigger_event">
|
||||
<kind>trigger</kind>
|
||||
<label>Camera Trigger Event</label>
|
||||
<description>Event sent when a camera trigger is detected.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="1">Camera 1</option>
|
||||
<option value="2">Camera 2</option>
|
||||
<option value="3">Camera 3</option>
|
||||
<option value="4">Camera 4</option>
|
||||
<option value="5">Camera 5</option>
|
||||
<option value="6">Camera 6</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Button Thing -->
|
||||
<thing-type id="button">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Button</label>
|
||||
<description>A button configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="press" typeId="button_press"/>
|
||||
<channel id="activated_event" typeId="button_activated"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Button Number</label>
|
||||
<description>The button number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Button Channels -->
|
||||
<channel-type id="button_press">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Button Press</label>
|
||||
<description>Sends a button event to the controller.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="button_activated">
|
||||
<kind>trigger</kind>
|
||||
<label>Button Activated</label>
|
||||
<description>Event sent when a button is activated.</description>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Console Thing -->
|
||||
<thing-type id="console">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Console</label>
|
||||
<description>A console configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="enable_disable_beeper" typeId="console_enable_disable_beeper"/>
|
||||
<channel id="beep" typeId="console_beep"/>
|
||||
</channels>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Console Number</label>
|
||||
<description>The console number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Console Channels -->
|
||||
<channel-type id="console_enable_disable_beeper">
|
||||
<item-type>String</item-type>
|
||||
<label>Enable/Disable Console Beeper</label>
|
||||
<description>Enable/Disable the beeper for this/all console(s).</description>
|
||||
<category>Switch</category>
|
||||
<command>
|
||||
<options>
|
||||
<option value="OFF">Off</option>
|
||||
<option value="ON">On</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="console_beep">
|
||||
<item-type>Number</item-type>
|
||||
<label>Beep Console</label>
|
||||
<description>Send a beep command to this/all console(s).</description>
|
||||
<category>SoundVolume</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="0">Off</option>
|
||||
<option value="1">Indefinitely</option>
|
||||
<option value="2">1 time</option>
|
||||
<option value="3">2 times</option>
|
||||
<option value="4">3 times</option>
|
||||
<option value="5">4 times</option>
|
||||
<option value="6">5 times</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Humidity Thing -->
|
||||
<thing-type id="humidity_sensor">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Humidity Sensor</label>
|
||||
<description>A humidity sensor configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="humidity" typeId="sensor_humidity"/>
|
||||
<channel id="low_setpoint" typeId="sensor_humidity_low_setpoint"/>
|
||||
<channel id="high_setpoint" typeId="sensor_humidity_high_setpoint"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Humidity Sensor Number</label>
|
||||
<description>The humidity sensor number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Humidity Channels -->
|
||||
<channel-type id="sensor_humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>The current relative humidity at this humidity sensor.</description>
|
||||
<category>Humidity</category>
|
||||
<state readOnly="true" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sensor_humidity_low_setpoint">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Low SetPoint</label>
|
||||
<description>The current low setpoint for this humidity sensor.</description>
|
||||
<category>Humidity</category>
|
||||
<state min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sensor_humidity_high_setpoint">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>High SetPoint</label>
|
||||
<description>The current high setpoint for this humidity sensor.</description>
|
||||
<category>Humidity</category>
|
||||
<state min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Lock Thing -->
|
||||
<thing-type id="lock">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Lock</label>
|
||||
<description>An access control reader lock configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="switch" typeId="lock_switch"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Lock Number</label>
|
||||
<description>The lock number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Lock Channels -->
|
||||
<channel-type id="lock_switch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Lock/Unlock</label>
|
||||
<description>Lock or unlock this lock.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Temperature Sensor Thing -->
|
||||
<thing-type id="temp_sensor">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Temperature Sensor</label>
|
||||
<description>A temperature sensor configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="temperature" typeId="sensor_temperature"/>
|
||||
<channel id="low_setpoint" typeId="sensor_temp_low_setpoint"/>
|
||||
<channel id="high_setpoint" typeId="sensor_temp_high_setpoint"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Temperature Sensor Number</label>
|
||||
<description>The temperature sensor number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Temperature Sensor Channels -->
|
||||
<channel-type id="sensor_temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>The current temperature at this temperature sensor.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sensor_temp_low_setpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Low SetPoint</label>
|
||||
<description>The current low setpoint of this temperature sensor.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="sensor_temp_high_setpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>High SetPoint</label>
|
||||
<description>The current high setpoint of this temperature sensor.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Thermostat Thing -->
|
||||
<thing-type id="thermostat">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Thermostat</label>
|
||||
<description>A thermostat configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="freeze_alarm" typeId="thermostat_freeze_alarm"/>
|
||||
<channel id="comm_failure" typeId="thermostat_comm_failure"/>
|
||||
<channel id="status" typeId="thermostat_status"/>
|
||||
<channel id="temperature" typeId="thermostat_temperature"/>
|
||||
<channel id="outdoor_temperature" typeId="thermostat_outdoor_temperature"/>
|
||||
<channel id="heat_setpoint" typeId="thermostat_heat_setpoint"/>
|
||||
<channel id="cool_setpoint" typeId="thermostat_cool_setpoint"/>
|
||||
<channel id="humidity" typeId="thermostat_humidity"/>
|
||||
<channel id="humidify_setpoint" typeId="thermostat_humidify_setpoint"/>
|
||||
<channel id="dehumidify_setpoint" typeId="thermostat_dehumidify_setpoint"/>
|
||||
<channel id="system_mode" typeId="thermostat_system_mode"/>
|
||||
<channel id="fan_mode" typeId="thermostat_fan_mode"/>
|
||||
<channel id="hold_status" typeId="thermostat_hold_status"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Thermostat Number</label>
|
||||
<description>The thermostat number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Thermostat Channels -->
|
||||
<channel-type id="thermostat_freeze_alarm">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Thermostat Freeze Alarm</label>
|
||||
<description>Closed when freeze alarm is triggered by this thermostat.</description>
|
||||
<category>Alarm</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_comm_failure">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Thermostat Communications Failure</label>
|
||||
<description>Closed during a communications failure with this thermostat.</description>
|
||||
<category>Contact</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_status">
|
||||
<item-type>Number</item-type>
|
||||
<label>Thermostat Status</label>
|
||||
<description>The current status of this thermostat.</description>
|
||||
<category>Heating</category>
|
||||
<state readOnly="true" pattern="%d">
|
||||
<options>
|
||||
<option value="0">Idle</option>
|
||||
<option value="1">Heating</option>
|
||||
<option value="2">Cooling</option>
|
||||
<option value="3">Humidifying</option>
|
||||
<option value="4">Dehumidifying</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>The current temperature at this thermostat.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_outdoor_temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Outdoor Temperature</label>
|
||||
<description>The current outdoor temperature detected by this thermostat.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_heat_setpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Heat SetPoint</label>
|
||||
<description>The current low/heating setpoint of this thermostat.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_cool_setpoint">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Cool SetPoint</label>
|
||||
<description>The current high/cooling setpoint of this thermostat.</description>
|
||||
<category>Temperature</category>
|
||||
<state pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_humidity">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidity</label>
|
||||
<description>The relative humidity at this thermostat.</description>
|
||||
<category>Humidity</category>
|
||||
<state readOnly="true" min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_humidify_setpoint">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Humidify SetPoint</label>
|
||||
<description>The current low/humidify setpoint for this thermostat.</description>
|
||||
<category>Humidity</category>
|
||||
<state min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_dehumidify_setpoint">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Dehumidify SetPoint</label>
|
||||
<description>The current high/dehumidify setpoint for this thermostat.</description>
|
||||
<category>Humidity</category>
|
||||
<state min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_system_mode">
|
||||
<item-type>Number</item-type>
|
||||
<label>System Mode</label>
|
||||
<description>The current system mode of this thermostat.</description>
|
||||
<category>Heating</category>
|
||||
<state pattern="%d">
|
||||
<options>
|
||||
<option value="0">Off</option>
|
||||
<option value="1">Heat</option>
|
||||
<option value="2">Cool</option>
|
||||
<option value="3">Auto</option>
|
||||
<option value="4">Emergency heat</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_fan_mode">
|
||||
<item-type>Number</item-type>
|
||||
<label>Fan Mode</label>
|
||||
<description>The current fan mode of this thermostat.</description>
|
||||
<category>Flow</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="0">Auto</option>
|
||||
<option value="1">On</option>
|
||||
<option value="2">Cycle</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="thermostat_hold_status">
|
||||
<item-type>Number</item-type>
|
||||
<label>Hold Status</label>
|
||||
<description>The current hold status of this thermostat.</description>
|
||||
<category>Heating</category>
|
||||
<state>
|
||||
<options>
|
||||
<option value="0">Off</option>
|
||||
<option value="1">Hold</option>
|
||||
<option value="2">Vacation hold</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,323 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Unit Thing -->
|
||||
<thing-type id="unit">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Unit</label>
|
||||
<description>A basic unit configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="level" typeId="unit_level"/>
|
||||
<channel id="switch" typeId="unit_switch"/>
|
||||
<channel id="on_for_seconds" typeId="on_for_seconds"/>
|
||||
<channel id="off_for_seconds" typeId="off_for_seconds"/>
|
||||
<channel id="on_for_minutes" typeId="on_for_minutes"/>
|
||||
<channel id="off_for_minutes" typeId="off_for_minutes"/>
|
||||
<channel id="on_for_hours" typeId="on_for_hours"/>
|
||||
<channel id="off_for_hours" typeId="off_for_hours"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Unit Number</label>
|
||||
<description>The unit number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Dimmable Thing -->
|
||||
<thing-type id="dimmable">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Dimmable Unit</label>
|
||||
<description>A dimmable unit configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="level" typeId="unit_level"/>
|
||||
<channel id="switch" typeId="unit_switch"/>
|
||||
<channel id="on_for_seconds" typeId="on_for_seconds"/>
|
||||
<channel id="off_for_seconds" typeId="off_for_seconds"/>
|
||||
<channel id="on_for_minutes" typeId="on_for_minutes"/>
|
||||
<channel id="off_for_minutes" typeId="off_for_minutes"/>
|
||||
<channel id="on_for_hours" typeId="on_for_hours"/>
|
||||
<channel id="off_for_hours" typeId="off_for_hours"/>
|
||||
<channel id="switch_press_event" typeId="switch_press_event"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Dimmable Unit Number</label>
|
||||
<description>The dimmable unit number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- UPB Thing -->
|
||||
<thing-type id="upb">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>UPB Unit</label>
|
||||
<description>A UPB unit configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="level" typeId="unit_level"/>
|
||||
<channel id="switch" typeId="unit_switch"/>
|
||||
<channel id="on_for_seconds" typeId="on_for_seconds"/>
|
||||
<channel id="off_for_seconds" typeId="off_for_seconds"/>
|
||||
<channel id="on_for_minutes" typeId="on_for_minutes"/>
|
||||
<channel id="off_for_minutes" typeId="off_for_minutes"/>
|
||||
<channel id="on_for_hours" typeId="on_for_hours"/>
|
||||
<channel id="off_for_hours" typeId="off_for_hours"/>
|
||||
<channel id="upb_status" typeId="upb_status"/>
|
||||
<channel id="switch_press_event" typeId="switch_press_event"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>UPB Unit Number</label>
|
||||
<description>The UPB unit number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Flag Thing -->
|
||||
<thing-type id="flag">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Flag</label>
|
||||
<description>A flag configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="value" typeId="flag_value"/>
|
||||
<channel id="switch" typeId="flag_switch"/>
|
||||
<channel id="on_for_seconds" typeId="on_for_seconds"/>
|
||||
<channel id="off_for_seconds" typeId="off_for_seconds"/>
|
||||
<channel id="on_for_minutes" typeId="on_for_minutes"/>
|
||||
<channel id="off_for_minutes" typeId="off_for_minutes"/>
|
||||
<channel id="on_for_hours" typeId="on_for_hours"/>
|
||||
<channel id="off_for_hours" typeId="off_for_hours"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Flag Number</label>
|
||||
<description>The flag number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Output Thing -->
|
||||
<thing-type id="output">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Voltage Output</label>
|
||||
<description>A voltage output configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="switch" typeId="unit_switch"/>
|
||||
<channel id="on_for_seconds" typeId="on_for_seconds"/>
|
||||
<channel id="off_for_seconds" typeId="off_for_seconds"/>
|
||||
<channel id="on_for_minutes" typeId="on_for_minutes"/>
|
||||
<channel id="off_for_minutes" typeId="off_for_minutes"/>
|
||||
<channel id="on_for_hours" typeId="on_for_hours"/>
|
||||
<channel id="off_for_hours" typeId="off_for_hours"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Voltage Output Number</label>
|
||||
<description>The voltage output number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Room Thing -->
|
||||
<thing-type id="room">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Room</label>
|
||||
<description>A room configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="switch" typeId="room_switch"/>
|
||||
<channel id="scene_a" typeId="scene_toggle">
|
||||
<label>Scene A</label>
|
||||
</channel>
|
||||
<channel id="scene_b" typeId="scene_toggle">
|
||||
<label>Scene B</label>
|
||||
</channel>
|
||||
<channel id="scene_c" typeId="scene_toggle">
|
||||
<label>Scene C</label>
|
||||
</channel>
|
||||
<channel id="scene_d" typeId="scene_toggle">
|
||||
<label>Scene D</label>
|
||||
</channel>
|
||||
<channel id="state" typeId="room_state"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Room Number</label>
|
||||
<description>The room number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Unit channels -->
|
||||
<channel-type id="unit_level">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Unit Level</label>
|
||||
<description>Increase/Decrease the level of this unit.</description>
|
||||
<category>Slider</category>
|
||||
<state min="0" max="100" pattern="%d %%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="unit_switch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch</label>
|
||||
<description>Turn this unit on/off.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="on_for_seconds">
|
||||
<item-type>Number</item-type>
|
||||
<label>On for Seconds</label>
|
||||
<description>Turn on this unit for a specified number of seconds.</description>
|
||||
<category>Switch</category>
|
||||
<state min="1" max="99"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="off_for_seconds">
|
||||
<item-type>Number</item-type>
|
||||
<label>Off for Seconds</label>
|
||||
<description>Turn off this unit for a specified number of seconds.</description>
|
||||
<category>Switch</category>
|
||||
<state min="1" max="99"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="on_for_minutes">
|
||||
<item-type>Number</item-type>
|
||||
<label>On for Minutes</label>
|
||||
<description>Turn on this unit for a specified number of minutes.</description>
|
||||
<category>Switch</category>
|
||||
<state min="1" max="99"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="off_for_minutes">
|
||||
<item-type>Number</item-type>
|
||||
<label>Off for Minutes</label>
|
||||
<description>Turn off this unit for a specified number of minutes.</description>
|
||||
<category>Switch</category>
|
||||
<state min="1" max="99"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="on_for_hours">
|
||||
<item-type>Number</item-type>
|
||||
<label>On for Hours</label>
|
||||
<description>Turn on this unit for a specified number of hours.</description>
|
||||
<category>Switch</category>
|
||||
<state min="1" max="18"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="off_for_hours">
|
||||
<item-type>Number</item-type>
|
||||
<label>Off for Hours</label>
|
||||
<description>Turn off this unit for a specified number of hours.</description>
|
||||
<category>Switch</category>
|
||||
<state min="1" max="18"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="upb_status">
|
||||
<item-type>String</item-type>
|
||||
<label>UPB Status</label>
|
||||
<description>Send a UPB status request message for this unit to the controller.</description>
|
||||
<category>Status</category>
|
||||
<command>
|
||||
<options>
|
||||
<option value="GET STATUS">Get Status</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="room_switch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch</label>
|
||||
<description>Turn this room on/off.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="scene_toggle">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Scene Toggle</label>
|
||||
<description>Turn this scene on/off.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="room_state">
|
||||
<item-type>Number</item-type>
|
||||
<label>State</label>
|
||||
<description>The current state of this room.</description>
|
||||
<category>Switch</category>
|
||||
<state pattern="%d">
|
||||
<options>
|
||||
<option value="0">Off</option>
|
||||
<option value="1">On</option>
|
||||
<option value="2">Scene A</option>
|
||||
<option value="3">Scene B</option>
|
||||
<option value="4">Scene C</option>
|
||||
<option value="5">Scene D</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="flag_value">
|
||||
<item-type>Number</item-type>
|
||||
<label>Flag Value</label>
|
||||
<description>Numeric value of this flag.</description>
|
||||
<category>Number</category>
|
||||
<state min="0" max="255" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="flag_switch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Flag Switch</label>
|
||||
<description>Turn this flag on/off.</description>
|
||||
<category>Switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="switch_press_event">
|
||||
<kind>trigger</kind>
|
||||
<label>Switch Press Event</label>
|
||||
<description>Event sent when an ALC, UPB, Radio RA, or Starlite switch is pressed.</description>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="omnilink"
|
||||
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">
|
||||
|
||||
<!-- Zone Thing -->
|
||||
<thing-type id="zone">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="controller"/>
|
||||
</supported-bridge-type-refs>
|
||||
<label>Zone</label>
|
||||
<description>A zone configured in the controller.</description>
|
||||
<channels>
|
||||
<channel id="contact" typeId="zone_contact"/>
|
||||
<channel id="current_condition" typeId="zone_current_condition"/>
|
||||
<channel id="latched_alarm_status" typeId="zone_latched_alarm_status"/>
|
||||
<channel id="arming_status" typeId="zone_arming_status"/>
|
||||
<channel id="bypass" typeId="zone_bypass"/>
|
||||
<channel id="restore" typeId="zone_restore"/>
|
||||
</channels>
|
||||
<properties>
|
||||
<property name="name"/>
|
||||
<property name="area"/>
|
||||
</properties>
|
||||
<representation-property>number</representation-property>
|
||||
<config-description>
|
||||
<parameter name="number" type="integer" required="true">
|
||||
<label>Zone Number</label>
|
||||
<description>The zone number.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
|
||||
<!-- Zone Channels -->
|
||||
<channel-type id="zone_contact">
|
||||
<item-type>Contact</item-type>
|
||||
<label>Contact State</label>
|
||||
<description>Contact state information of this zone.</description>
|
||||
<category>Contact</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="zone_current_condition">
|
||||
<item-type>Number</item-type>
|
||||
<label>Current Condition</label>
|
||||
<description>Current condition of this zone.</description>
|
||||
<category>Contact</category>
|
||||
<state readOnly="true" pattern="%d">
|
||||
<options>
|
||||
<option value="0">Secure</option>
|
||||
<option value="1">Not Ready</option>
|
||||
<option value="2">Trouble</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="zone_latched_alarm_status">
|
||||
<item-type>Number</item-type>
|
||||
<label>Latched Alarm Status</label>
|
||||
<description>Latched alarm status of this zone.</description>
|
||||
<category>Contact</category>
|
||||
<state readOnly="true" pattern="%d">
|
||||
<options>
|
||||
<option value="0">Secure</option>
|
||||
<option value="1">Tripped</option>
|
||||
<option value="2">Reset, but previously tripped</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="zone_arming_status">
|
||||
<item-type>Number</item-type>
|
||||
<label>Arming Status</label>
|
||||
<description>Arming status of this zone.</description>
|
||||
<category>Contact</category>
|
||||
<state readOnly="true" pattern="%d">
|
||||
<options>
|
||||
<option value="0">Disarmed</option>
|
||||
<option value="1">Armed</option>
|
||||
<option value="2">Bypassed by user</option>
|
||||
<option value="3">Bypassed by system</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="zone_bypass">
|
||||
<item-type>String</item-type>
|
||||
<label>Bypass Zone</label>
|
||||
<description>Send a 4 digit user code to bypass this zone.</description>
|
||||
<category>Alarm</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="zone_restore">
|
||||
<item-type>String</item-type>
|
||||
<label>Restore Zone</label>
|
||||
<description>Send a 4 digit user code to restore this zone.</description>
|
||||
<category>Alarm</category>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -216,6 +216,7 @@
|
||||
<module>org.openhab.binding.oceanic</module>
|
||||
<module>org.openhab.binding.ojelectronics</module>
|
||||
<module>org.openhab.binding.omnikinverter</module>
|
||||
<module>org.openhab.binding.omnilink</module>
|
||||
<module>org.openhab.binding.onebusaway</module>
|
||||
<module>org.openhab.binding.onewiregpio</module>
|
||||
<module>org.openhab.binding.onewire</module>
|
||||
|
Loading…
Reference in New Issue
Block a user