Signed-off-by: Andrew Fiddian-Green <software@whitebear.ch>
This commit is contained in:
parent
d5f6bd326c
commit
64a713e74a
|
@ -5,6 +5,8 @@ This binding integrates the <B>Velux</B> devices with help of a gateway, the <B>
|
||||||
The Velux Binding interacts via the Velux Bridge with any [io-homecontrol](http://www.io-homecontrol.com/)-based
|
The Velux Binding interacts via the Velux Bridge with any [io-homecontrol](http://www.io-homecontrol.com/)-based
|
||||||
devices like window openers, shutters and others.
|
devices like window openers, shutters and others.
|
||||||
|
|
||||||
|
![Velux](doc/veluxlogo.jpg)
|
||||||
|
|
||||||
Based on the VELUX API this binding integrates <B>Velux</B> and other io-homecontrol devices directly into the openHAB, avoiding the necessity of any cloud-based mediation infrastructures. The complete home-automation will work even without any Internet connectivity.
|
Based on the VELUX API this binding integrates <B>Velux</B> and other io-homecontrol devices directly into the openHAB, avoiding the necessity of any cloud-based mediation infrastructures. The complete home-automation will work even without any Internet connectivity.
|
||||||
|
|
||||||
For details about the features, see the following websites:
|
For details about the features, see the following websites:
|
||||||
|
@ -12,242 +14,242 @@ For details about the features, see the following websites:
|
||||||
- [Velux](http://www.velux.com)
|
- [Velux](http://www.velux.com)
|
||||||
- [Velux API](http://www.velux.com/api/klf200)
|
- [Velux API](http://www.velux.com/api/klf200)
|
||||||
|
|
||||||
## Overview
|
## Supported Things
|
||||||
|
|
||||||
As the API is widely open, there are several use cases which are supported by the Bridge:
|
The binding supports the following types of Thing.
|
||||||
From the complete configuration of a set of io-homecontrol devices including registration, naming, grouping, crypto key setup and exchange, the definition of intended settings, so called scenes, up to the control of single devices, i.e. ```open window of bathroom up to 45%```.
|
|
||||||
|
|
||||||
The following areas are covered:
|
| Thing Type | Description | Note |
|
||||||
|
|---------------|-----------------------------------------------------------------------------------|------|
|
||||||
|
| bridge | A Velux KLF200 which acts as a gateway to all Velux / IO-home controlled devices. | |
|
||||||
|
| window | A Velux / IO-home control window. | 1. |
|
||||||
|
| rollershutter | A Velux / IO-home control roller shutter. | 1. |
|
||||||
|
| actuator | Generic Velux / IO-home device. | 1. |
|
||||||
|
| scene | A Velux Scene which commands Velux / IO-home devices to specific positions. | |
|
||||||
|
| vshutter | A Velux virtual shutter. | 2. |
|
||||||
|
| information | A Thing that provides overall information about the binding itself. | |
|
||||||
|
|
||||||
| Topic | Details |
|
1. Only supported in hubs with firmware v0.2.x.x or above
|
||||||
|-------------------------|------------------------------------------------------------------------------------------------------------|
|
2. Only needed in hubs with firmware v0.1.x.x (due to note 1. above)
|
||||||
| General bridge commands | SW version(\*), Gateway state(\*), Learn state, Clock, Reboot, FactoryReset, Network Setup(+) |
|
|
||||||
| Configuration Services | Node Discovery, Node Removal, Controller Copy, Crypto Key Generation, Crypto Key Exchange, Actuator config |
|
|
||||||
| Information Services | House Monitoring Service(\*), Node information(+), Group information |
|
|
||||||
| Activation Logging | |
|
|
||||||
| Command Handling | Command activation(\*), Command interruption(\*), Status Request(\*), Actuator Identification(\*), Limitations |
|
|
||||||
| Scene Handling | Scene definition, Scene execution(\*), Scene deletion, Scene renaming, Scene Overview(\*) |
|
|
||||||
| Physical I/O Handling | I/O Port setup |
|
|
||||||
|
|
||||||
Items marked with (\*) are fully implemented. Items marked with (+) have only partial support.
|
## Discovery
|
||||||
|
|
||||||
## Binding Configuration
|
To simplify the initial provisioning, the binding provides one thing which can be found by autodiscovery.
|
||||||
|
Unfortunately there is no way to discover Velux bridges themselves within the local network.
|
||||||
|
But after configuring a Velux Bridge, it is possible to discover all scenes and actuators like windows and rollershutters in that hub.
|
||||||
|
|
||||||
To simplify the initial provisioning, the binding provides one thing which can be found by autodiscovery:
|
## Thing Configuration
|
||||||
This thing named <B>Velux Binding Information</B> establishes one channel named <B>information</B> describing
|
|
||||||
the current binding state in a (hopefully) human understandable fashion. Additionally it will give three
|
|
||||||
properties with the version number of the bundle, the number of registered bridges and number of overall
|
|
||||||
things attached to the bridge(s).
|
|
||||||
|
|
||||||
The <B>Velux KLF200</B> bridge has to be configured with some parameters, at least with the IP address of the bridge.
|
### Thing Configuration for "bridge"
|
||||||
|
|
||||||
| Property | Default | Required | Description |
|
The bridge Thing connects to the KLF-200 hub (bridge) to communicate with any respective connected Velux or IO-home device Things.
|
||||||
|------------------------|------------------|:--------:|--------------------------------------------------------------|
|
It signs on to the hub using the supplied connection parameters, and it polls the hub at regular intervals to read and write the data for each connected device.
|
||||||
|
The KLF-200 supports two Application Programming Interfaces "API" (a SLIP based one, and a JSON based one), and this binding can use either of them to communicate with it.
|
||||||
|
Before the binding can communicate with the hub, the Configuration Parameters `ipAddress` and `password` must be entered.
|
||||||
|
In addition there are some optional Configuration Parameters.
|
||||||
|
|
||||||
|
| Configuration Parameter | Default | Required | Description |
|
||||||
|
|-------------------------|------------------|:--------:|--------------------------------------------------------------|
|
||||||
| ipAddress | | Yes | Hostname or address for accessing the Velux Bridge. |
|
| ipAddress | | Yes | Hostname or address for accessing the Velux Bridge. |
|
||||||
|
| password | velux123 | Yes | Password for authentication against the Velux Bridge.(\*\*) |
|
||||||
|
| timeoutMsecs | 500 | No | Communication timeout in milliseconds. |
|
||||||
| protocol | slip | No | Underlying communication protocol (http/https/slip). |
|
| protocol | slip | No | Underlying communication protocol (http/https/slip). |
|
||||||
| tcpPort | 51200 | No | TCP port (80 or 51200) for accessing the Velux Bridge. |
|
| tcpPort | 51200 | No | TCP port (80 or 51200) for accessing the Velux Bridge. |
|
||||||
| password | velux123 | No | Password for authentication against the Velux Bridge.(\*\*) |
|
|
||||||
| timeoutMsecs | 1000 | No | Initial Connection timeout in milliseconds. |
|
|
||||||
| retries | 5 | No | Number of retries during I/O. |
|
| retries | 5 | No | Number of retries during I/O. |
|
||||||
| refreshMsecs | 10000 | No | Refresh interval in milliseconds. |
|
| refreshMsecs | 10000 | No | Refresh interval in milliseconds. |
|
||||||
| isBulkRetrievalEnabled | yes | No | Load all scenes and actuators in one step. |
|
| isBulkRetrievalEnabled | yes | No | Load all scenes and actuators in one step. |
|
||||||
| isSequentialEnforced | no | No | Enforce Sequential Actuator Control even for long operations.|
|
| isSequentialEnforced | no | No | Enforce Sequential Actuator Control even for long operations.|
|
||||||
| isProtocolTraceEnabled | no | No | Show any protocol interaction (loglevel INFO). |
|
| isProtocolTraceEnabled | no | No | Show any protocol interaction (loglevel INFO). |
|
||||||
|
|
||||||
(\*\*) Note: This password is the API password that is printed on the back of the unit. Normally it differs from the password of the web frontend.
|
(\*\*) Note: This password is the API password that is printed on the back of the unit.
|
||||||
|
Normally it differs from the password of the web frontend.
|
||||||
|
|
||||||
Advise: if you see a significant number of messages per day like
|
Advice: if you see a significant number of messages per day as follows, you should increase the parameters `retries` or/and `timeoutMsecs`...
|
||||||
|
|
||||||
```
|
```
|
||||||
communicate(): socket I/O failed continuously (x times).
|
communicate(): socket I/O failed continuously (x times).
|
||||||
```
|
```
|
||||||
|
|
||||||
please increase the parameters retries or/and timeoutMsecs.
|
|
||||||
|
|
||||||
For your convenience you'll see a log entry for the recognized configuration within the log file i.e.
|
For your convenience you'll see a log entry for the recognized configuration within the log file i.e.
|
||||||
|
|
||||||
```
|
```
|
||||||
2018-07-23 20:40:24.746 [INFO ] [.b.velux.internal.VeluxBinding] - veluxConfig[ipAddress=192.168.42.1,tcpPort=80,password=********,timeoutMsecs=2000,retries=10]
|
2018-07-23 20:40:24.746 [INFO ] [.b.velux.internal.VeluxBinding] - veluxConfig[ipAddress=192.168.42.1,tcpPort=80,password=********,timeoutMsecs=2000,retries=10]
|
||||||
```
|
```
|
||||||
|
|
||||||
The <B>Velux</B> Things (beside the mentioned bridge) are <B>Velux Window</B>, <B>Velux Rollershutter</B>, and a generic <B>Velux Actuator</B> and <B>Velux Scene</B>. The 1st three Things have to be configured with an identification by their serial number.
|
### Thing Configuration for "actuator", "window", "rollershutter"
|
||||||
|
|
||||||
| Property | Default | Required | Description |
|
These types of Thing only supported in the Velux Bridge in API version two or higher (firmware version > 0.2.*.*).
|
||||||
|----------------|------------------------|:--------:|-----------------------------------------------------------|
|
These types of Thing are configured by means of their serial number in the hub.
|
||||||
| serial | | Yes | Serial number of the io-homecontrol device. |
|
In addition there are some optional Configuration Parameters.
|
||||||
| name | | No | (Optional) name of the io-homecontrol device. |
|
|
||||||
| inverted | false | No | Inverts any device values. |
|
|
||||||
|
|
||||||
The fourth Thing, the <B>Velux Scene</B>, has to be configured with an identification by their scenename.
|
| Configuration Parameter | Default | Required | Description |
|
||||||
|
|-------------------------|------------------------|:--------:|-------------------------------------------------------------------|
|
||||||
|
| serial | | Yes | Serial number of the io-homecontrol device in the hub. |
|
||||||
|
| name | | No | (Optional) name of the io-homecontrol device in the hub. |
|
||||||
|
| inverted | false | No | (Optional) the position is inverted (i.e. 0% translates to 100%). |
|
||||||
|
|
||||||
| Property | Default | Required | Description |
|
Notes:
|
||||||
|----------------|------------------------|:--------:|-----------------------------------------------------------|
|
|
||||||
| sceneName | | Yes | Name of the io-homecontrol configuration. |
|
|
||||||
|
|
||||||
The fifth Thing, the <B>Velux Virtual Shutter</B>, has to be configured with pairs of level combined with the appropriate scenenames.
|
1. To enable a complete invertion of all parameter values (i.e. for Velux windows), use the property `inverted` or add a trailing star to the eight-byte serial number. For an example, see below at item `Velux DG Window Bathroom`.
|
||||||
|
|
||||||
| Property | Default | Required | Description |
|
2. Somfy devices do not provide a valid serial number to the Velux KLF200 gateway. The bridge reports a registration of the serial number 00:00:00:00:00:00:00:00. Therefore the binding implements a fallback to allow an item specification with a actuator `name` instead of actuator serial number whenever such an invalid serial number occurs. For an example, see below at item `Velux OG Somfy Shutter`.
|
||||||
|----------------|------------------------|:--------:|-----------------------------------------------------------|
|
|
||||||
|
### Thing Configuration for "scene"
|
||||||
|
|
||||||
|
The Velux Bridge in API version one (firmware version 0.1.1.*) allows activating a set of predefined actions, so called scenes.
|
||||||
|
So besides the bridge, only one real Thing type exists, namely "scene".
|
||||||
|
This type of Thing is configured by means of its scene name in the hub.
|
||||||
|
|
||||||
|
| Configuration Parameter | Default | Required | Description |
|
||||||
|
|-------------------------|------------------------|:--------:|-----------------------------------------------------------|
|
||||||
|
| sceneName | | Yes | Name of the scene in the hub. |
|
||||||
|
|
||||||
|
### Thing Configuration for "vshutter"
|
||||||
|
|
||||||
|
The Velux Bridge in API version one (firmware version 0.1.1.*) does not support a real rollershutter interaction.
|
||||||
|
So besides the bridge, this binding provides a virtual rollershutter Thing consisting of different scenes which set a specific shutter level.
|
||||||
|
Therefore the respective Item definition contains multiple pairs of rollershutter levels each followed by a scene name.
|
||||||
|
The virtual shutter Thing must be configured with pairs of level (0..10%) combined with the appropriate scene names (text) as follows.
|
||||||
|
|
||||||
|
| Configuration Parameter | Default | Required | Description |
|
||||||
|
|-------------------------|------------------------|:--------:|-----------------------------------------------------------|
|
||||||
| sceneLevels | | Yes | <Level1>,<Scene1>,<Level2>,<Scene2>,.... |
|
| sceneLevels | | Yes | <Level1>,<Scene1>,<Level2>,<Scene2>,.... |
|
||||||
| currentLevel | 0 | No | Inverts any device values. |
|
| currentLevel | 0 | No | Inverts any device values. |
|
||||||
|
|
||||||
|
## Supported Channels for Thing Types
|
||||||
|
|
||||||
## Discovery
|
### Channels for "bridge" Things
|
||||||
|
|
||||||
Unfortunately there is no way to discover the Velux bridge itself within the local network. But after configuring the Velux Bridge, it is possible to discover all scenes and actuators like windows and rollershutters by the binding.
|
The supported Channels and their associated channel types are shown below.
|
||||||
|
|
||||||
## Item Configuration
|
| Channel | Data Type | Description |
|
||||||
|
|-------------|-----------|---------------------------------------------------------------------------------|
|
||||||
|
| status | String | Description of current Bridge State. |
|
||||||
|
| reload | Switch | Command to force reload of the bridge information. |
|
||||||
|
| downtime | Number | Time interval (sec) between last successful and most recent device interaction. |
|
||||||
|
| doDetection | Switch | Command to activate bridge detection mode. |
|
||||||
|
|
||||||
The Items of a Velux Bridge consists in general of a pair of mastertype and subtype definition.
|
### Channels for "window", "rollershutter" Things
|
||||||
In the appropriate items file, i.e. velux.items, this looks like
|
|
||||||
|
|
||||||
```
|
The supported Channels and their associated channel types are shown below.
|
||||||
{ velux="thing=<Mastertype>;channel=<Subtype>" }
|
|
||||||
```
|
|
||||||
|
|
||||||
Optionally the subtype is enhanced with parameters like the appropriate name of the scene.
|
| Channel | Data Type | Description |
|
||||||
|
|--------------|---------------|-------------------------------------------------|
|
||||||
|
| position | Rollershutter | Actual position of the window or device. |
|
||||||
|
| limitMinimum | Rollershutter | Minimum limit position of the window or device. |
|
||||||
|
| limitMaximum | Rollershutter | Maximum limit position of the window or device. |
|
||||||
|
|
||||||
```
|
### Channels for "actuator" Things
|
||||||
{ velux="thing=<Mastertype>;channel=<Subtype>#<Parameter>" }
|
|
||||||
```
|
|
||||||
|
|
||||||
| Mastertype | Description |
|
The supported Channels and their associated channel types are shown below.
|
||||||
|---------------|----------------------------------------------------------------------------------|
|
|
||||||
| binding | Provides informations for easier configuration of this binding. |
|
|
||||||
| bridge | The Velux KLF200 represents a gateway to all Velux devices. |
|
|
||||||
| scene | Named ordered set of product states which can be activated for execution. |
|
|
||||||
| actuator | Generic IO-home controlled device which can be maintained by parameter settings. |
|
|
||||||
| window | IO-home controlled device of type window. |
|
|
||||||
| rollershutter | IO-home controlled device of type rollershutter. |
|
|
||||||
| vshutter | IO-home controlled device of type rollershutter. |
|
|
||||||
|
|
||||||
|
| Channel | Data Type | Description |
|
||||||
|
|--------------|---------------|-------------------------------------------------|
|
||||||
|
| position | Rollershutter | Actual position of the window or device. |
|
||||||
|
| state | Switch | Device control (ON, OFF). |
|
||||||
|
| limitMinimum | Rollershutter | Minimum limit position of the window or device. |
|
||||||
|
| limitMaximum | Rollershutter | Maximum limit position of the window or device. |
|
||||||
|
|
||||||
### Subtype
|
### Channels for "scene" Things
|
||||||
|
|
||||||
|
The supported Channels and their associated channel types are shown below.
|
||||||
|
|
||||||
| Subtype | Item Type | Description | Mastertype | Parameter |
|
| Channel | Data Type | Description |
|
||||||
|--------------|---------------|-----------------------------------------------------------------|--------------|-----------|
|
|------------|-----------|----------------------------------------------------------------|
|
||||||
| information | String | Describes the current state of the binding | binding | N/A |
|
| action | Switch | Activates the scene (moves devices to their preset positions). |
|
||||||
| status | String | Current Bridge State (\*\*\*) | bridge | N/A |
|
| silentMode | Switch | Enables silent mode. |
|
||||||
| reload | Switch | Reload information from bridge into binding | bridge | N/A |
|
|
||||||
| timestamp | Number | Timestamp of last successful device interaction | bridge | N/A |
|
|
||||||
| doDetection | Switch | Start of the product detection mode | bridge | N/A |
|
|
||||||
| firmware | String | Software version of the Bridge | bridge | N/A |
|
|
||||||
| ipAddress | String | IP address of the Bridge | bridge | N/A |
|
|
||||||
| subnetMask | String | IP subnetmask of the Bridge | bridge | N/A |
|
|
||||||
| defaultGW | String | IP address of the Default Gateway of the Bridge | bridge | N/A |
|
|
||||||
| DHCP | Switch | Flag whether automatic IP configuration is enabled | bridge | N/A |
|
|
||||||
| WLANSSID | String | Name of the wireless network | bridge | N/A |
|
|
||||||
| WLANPassword | String | WLAN Authentication Password | bridge | N/A |
|
|
||||||
| products | String | List of all recognized products | bridge | N/A |
|
|
||||||
| scenes | String | List of all defined scenes | bridge | N/A |
|
|
||||||
| check | String | Result of the check of current item configuration | bridge | N/A |
|
|
||||||
| shutter | Rollershutter | Virtual rollershutter as combination of different scenes | bridge | required |
|
|
||||||
|--------------|---------------|-----------------------------------------------------------------|--------------|-----------|
|
|
||||||
| serial | String | IO-Homecontrol'ed device (\*\*\*\*) (\*\*\*\*\*) | actuator | required |
|
|
||||||
| position | Rollershutter | Position of the IO-Homecontrol'ed device (\*\*\*\*) | actuator | optional |
|
|
||||||
| state | Switch | State of the IO-Homecontrol'ed device | actuator | optional |
|
|
||||||
| limitMinimum | Rollershutter | Minimum position of the IO-Homecontrol'ed device (\*\*\*\*) | actuator | optional |
|
|
||||||
| limitMaximum | Rollershutter | Maximum position of the IO-Homecontrol'ed device (\*\*\*\*) | actuator | optional |
|
|
||||||
|--------------|---------------|-----------------------------------------------------------------|--------------|-----------|
|
|
||||||
| serial | String | IO-Homecontrol'ed device (\*\*\*\*) (\*\*\*\*\*) | window | required |
|
|
||||||
| position | Rollershutter | Position of the IO-Homecontrol'ed device (\*\*\*\*) | window | optional |
|
|
||||||
| limitMinimum | Rollershutter | Minimum position of the IO-Homecontrol'ed device (\*\*\*\*) | window | optional |
|
|
||||||
| limitMaximum | Rollershutter | Maximum position of the IO-Homecontrol'ed device (\*\*\*\*) | window | optional |
|
|
||||||
|--------------|---------------|-----------------------------------------------------------------|--------------|-----------|
|
|
||||||
| serial | String | IO-Homecontrol'ed device (\*\*\*\*) (\*\*\*\*\*) | rollershutter| required |
|
|
||||||
| position | Rollershutter | Position of the IO-Homecontrol'ed device (\*\*\*\*) | rollershutter| optional |
|
|
||||||
| limitMinimum | Rollershutter | Minimum position of the IO-Homecontrol'ed device (\*\*\*\*) | rollershutter| optional |
|
|
||||||
| limitMaximum | Rollershutter | Maximum position of the IO-Homecontrol'ed device (\*\*\*\*) | rollershutter| optional |
|
|
||||||
|--------------|---------------|-----------------------------------------------------------------|--------------|-----------|
|
|
||||||
| sceneName | String | Defines the scene by name according to registration in KLF200 | scene | required |
|
|
||||||
| action | Switch | Activates a set of predefined product settings | scene | optional |
|
|
||||||
| silentMode | Switch | Modification of the silent mode of the defined product settings | scene | optional |
|
|
||||||
|
|
||||||
Notes:
|
### Channels for "vshutter" Things
|
||||||
(\*\*\*) The existence of this item triggers the continuous realtime status updates of any Velux item like shutters even if they are manually controlled by other controllers.
|
|
||||||
|
|
||||||
(\*\*\*\*) To enable a complete invertion of all parameter values (i.e. for Velux windows), use the property `inverted` or add a trailing star to the eight-byte serial number. For an example, see below at item `Velux DG Window Bathroom`.
|
The supported Channel and its associated channel type is shown below.
|
||||||
|
|
||||||
(\*\*\*\*\*) Somfy devices does not provides a valid serial number to the Velux KLF200 gateway: The bridge reports a registration of the serial number 00:00:00:00:00:00:00:00. Therefore the binding implements a fallback to allow an item specification with a actuator name instead of actuator serial number whenever such an invalid serial number occurs. For an example, see below at item `Velux OG Somfy Shutter`.
|
| Channel | Data Type | Description |
|
||||||
|
|--------------|---------------|-----------------------------------------|
|
||||||
|
| position | Rollershutter | Position of the virtual roller shutter. |
|
||||||
|
|
||||||
|
### Channels for "information" Thing
|
||||||
|
|
||||||
### Subtype Parameters
|
The supported Channel and its associated channel type is shown below.
|
||||||
|
|
||||||
In case of the scene-related subtypes, action and silentMode, the specification of the related scene as parameters is necessary;
|
| Channel | Data Type | Description |
|
||||||
|
|-------------|-----------|--------------------------------|
|
||||||
|
| information | String | Information about the binding. |
|
||||||
|
|
||||||
```
|
## Rain Sensor
|
||||||
{ velux="thing=scene;channel=<Subtype>#<Parameter>" }
|
|
||||||
```
|
|
||||||
|
|
||||||
The subtype shutter requires an even pair of parameters, each defining the shutter level and the related scene:
|
Unfortunately Velux has decided to closely integrate the rain sensor into the window device.
|
||||||
|
The rain sensor is therefore not displayed in the device list.
|
||||||
|
On the other hand, the 'limitMinimum' channel of a roof window provides information about rainy weather:
|
||||||
|
If it is set internally by the Velux control unit to a value other than zero, it rains. (Joke!!)
|
||||||
|
|
||||||
```
|
## Properties of the "bridge" Thing
|
||||||
{ velux="thing=brigde;channel=shutter#<Level1>,<Scene1>,<Level2>,<Scene2>" }
|
|
||||||
```
|
|
||||||
|
|
||||||
### Rain Sensor
|
The bridge Thing provides the following properties.
|
||||||
|
|
||||||
Unfortunately Velux has decided to closely integrate the rain sensor into the window device. The rain sensor is therefore not displayed in the device list. On the other hand, the 'limitMinimum' channel of a roof window now provides information about rainy weather: if it is set internally by the Velux control unit to a value other than zero, it rains.
|
| Property | Description |
|
||||||
|
|-------------------|-----------------------------------------------------------------|
|
||||||
|
| check | Result of the check of current item configuration |
|
||||||
|
| connectionAttempt | Date-Time of last connection attampt |
|
||||||
|
| connectionSuccess | Date-Time of last successful connection attampt |
|
||||||
|
| defaultGW | IP address of the Default Gateway of the Bridge |
|
||||||
|
| DHCP | Flag whether automatic IP configuration is enabled |
|
||||||
|
| firmware | Software version of the Bridge |
|
||||||
|
| ipAddress | IP address of the Bridge |
|
||||||
|
| products | List of all recognized products |
|
||||||
|
| scenes | List of all defined scenes |
|
||||||
|
| subnetMask | IP subnetmask of the Bridge |
|
||||||
|
| vendor | Vendow name |
|
||||||
|
| WLANSSID | Name of the wireless network (not suported any more) |
|
||||||
|
| WLANPassword | WLAN Authentication Password (not suported any more) |
|
||||||
|
|
||||||
### Virtual shutter
|
## Full Example
|
||||||
|
|
||||||
As the bridge with firmware version one does not support a real rollershutter interaction, this binding provides a virtual rollershutter consisting of different scenes which set a specific shutter level. Therefore the item definition contains multiple pairs of rollershutter levels each followed by a scene name, which leads to this setting.
|
|
||||||
|
|
||||||
|
|
||||||
### Items
|
|
||||||
|
|
||||||
[Sample items file for textual configuration](doc/conf/items/velux.items)
|
|
||||||
|
|
||||||
### Sitemap
|
|
||||||
|
|
||||||
[Sample sitemaps file for textual configuration](doc/conf/sitemaps/velux.sitemap)
|
|
||||||
|
|
||||||
### Rules
|
|
||||||
|
|
||||||
[Sample rules file for textual configuration](doc/conf/rules/velux.rules)
|
|
||||||
|
|
||||||
### Things
|
### Things
|
||||||
|
|
||||||
[Sample things file for textual configuration](doc/conf/things/velux.things)
|
```
|
||||||
|
Bridge velux:klf200:g24 "Velux KLF200 Hub" @ "Under Stairs" [ipAddress="192.168.1.xxx", password="secret"] {
|
||||||
|
Thing window w56-36-13-5A-11-2A-05-70 "Bathroom Roof Window" @ "Bathroom" [serial="56:36:13:5A:11:2A:05:70", inverted=true]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## More automation samples
|
[=> download sample things file for textual configuration](./doc/conf/things/velux.things)
|
||||||
|
|
||||||
At this point some interesting automation rules are included to demonstrate the power of this gateway to the io-homecontrol world.
|
### Items
|
||||||
|
|
||||||
|
```
|
||||||
|
Rollershutter Bathroom_Roof_Window_Position "Bathroom Roof Window Position [%.0f %%]" {channel="velux:window:g24:w56-36-13-5A-11-2A-05-70:position"}
|
||||||
|
```
|
||||||
|
|
||||||
### Closing windows after a period of time
|
[=> download sample items file for textual configuration](./doc/conf/items/velux.items)
|
||||||
|
|
||||||
|
### Sitemap
|
||||||
|
|
||||||
|
```
|
||||||
|
Frame label="Velux Windows" {
|
||||||
|
Slider item=Bathroom_Roof_Window_Position
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[=> download sample sitemaps file for textual configuration](./doc/conf/sitemaps/velux.sitemap)
|
||||||
|
|
||||||
|
### Rules
|
||||||
|
|
||||||
|
**Rule for closing windows after a period of time**:
|
||||||
Especially in the colder months, it is advisable to close the window after adequate ventilation. Therefore, automatic closing after one minute is good to save on heating costs.
|
Especially in the colder months, it is advisable to close the window after adequate ventilation. Therefore, automatic closing after one minute is good to save on heating costs.
|
||||||
However, to allow the case of intentional prolonged opening, an automatic closure is made only with the window fully open.
|
However, to allow the case of intentional prolonged opening, an automatic closure is made only with the window fully open.
|
||||||
|
|
||||||
```
|
```java
|
||||||
/*
|
|
||||||
* Start of imports
|
|
||||||
*/
|
|
||||||
|
|
||||||
import org.openhab.core.library.types.*
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start of rules
|
|
||||||
*/
|
|
||||||
|
|
||||||
rule "V_WINDOW_changed"
|
rule "V_WINDOW_changed"
|
||||||
when
|
when
|
||||||
Item V_WINDOW changed
|
Item V_WINDOW changed
|
||||||
then
|
then
|
||||||
logInfo("rules.V_WINDOW", "V_WINDOW_changes() called.")
|
logInfo("rules.V_WINDOW", "V_WINDOW_changes() called.")
|
||||||
//
|
|
||||||
// Get the sensor value
|
// Get the sensor value
|
||||||
//
|
|
||||||
val Number windowState = V_WINDOW.state as DecimalType
|
val Number windowState = V_WINDOW.state as DecimalType
|
||||||
logWarn("rules.V_WINDOW", "Window state is "+windowState+".")
|
logWarn("rules.V_WINDOW", "Window state is "+windowState+".")
|
||||||
if (windowState < 80) {
|
if (windowState < 80) {
|
||||||
if (windowState == 0) {
|
if (windowState == 0) {
|
||||||
logWarn("rules.V_WINDOW", "V-WINDOW changed to fully open.")
|
logWarn("rules.V_WINDOW", "V-WINDOW changed to fully open.")
|
||||||
|
|
||||||
var int interval = 1
|
var int interval = 1
|
||||||
|
|
||||||
createTimer(now.plusMinutes(interval)) [ |
|
createTimer(now.plusMinutes(interval)) [ |
|
||||||
logWarn("rules.V_WINDOW:event", "event-V_WINDOW(): setting V-WINDOW to 100.")
|
logWarn("rules.V_WINDOW:event", "event-V_WINDOW(): setting V-WINDOW to 100.")
|
||||||
sendCommand(V_WINDOW,100)
|
sendCommand(V_WINDOW,100)
|
||||||
|
@ -258,17 +260,13 @@ then
|
||||||
logWarn("rules.V_WINDOW", "V-WINDOW changed to partially open.")
|
logWarn("rules.V_WINDOW", "V-WINDOW changed to partially open.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// Check type of item
|
// Check type of item
|
||||||
//
|
|
||||||
logDebug("rules.V_WINDOW", "V_WINDOW_changes finished.")
|
logDebug("rules.V_WINDOW", "V_WINDOW_changes finished.")
|
||||||
end
|
end
|
||||||
|
|
||||||
/*
|
|
||||||
* end-of-rules/V_WINDOW.rules
|
|
||||||
*/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
[=> download sample rules file for textual configuration](./doc/conf/rules/velux.rules)
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
For those who are interested in more detailed insight of the processing of this binding, a deeper look can be achieved by increased loglevel.
|
For those who are interested in more detailed insight of the processing of this binding, a deeper look can be achieved by increased loglevel.
|
||||||
|
@ -352,46 +350,46 @@ However if you have set the configuration parameter isProtocolTraceEnabled to tr
|
||||||
[INFO ] [internal.bridge.slip.SlipVeluxBridge] - Received answer GW_GET_NODE_INFORMATION_CFM.
|
[INFO ] [internal.bridge.slip.SlipVeluxBridge] - Received answer GW_GET_NODE_INFORMATION_CFM.
|
||||||
[INFO ] [internal.bridge.slip.SlipVeluxBridge] - Received answer GW_GET_NODE_INFORMATION_NTF.
|
[INFO ] [internal.bridge.slip.SlipVeluxBridge] - Received answer GW_GET_NODE_INFORMATION_NTF.
|
||||||
[INFO ] [internal.bridge.slip.SlipVeluxBridge] - Sending command GW_GET_LIMITATION_STATUS_REQ.
|
[INFO ] [internal.bridge.slip.SlipVeluxBridge] - Sending command GW_GET_LIMITATION_STATUS_REQ.
|
||||||
...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Supported/Tested Firmware Revisions
|
## Supported/Tested Firmware Revisions
|
||||||
|
|
||||||
The Velux Bridge in API version one (firmware version 0.1.1.*) allows activating a set of predefined actions, so called scenes. Therefore beside the bridge, only one main thing exists, the scene element. The next-generation firmware version two is not backward compatible, and does not provide a public web frontend, but version two does provide full access to any IO-Home compatible devices not limited to Velux and includes many different features.
|
The Velux Bridge in API version one (firmware version 0.1.1.*) allows activating a set of predefined actions, so called scenes.
|
||||||
|
Therefore beside the bridge, only one main thing exists, the scene element.
|
||||||
|
|
||||||
|
The next-generation firmware version two is not backward compatible, and does not provide a public web frontend, but version two does provide full access to any IO-Home compatible devices not limited to Velux and includes many different features.
|
||||||
|
|
||||||
| Firmware revision | Release date | Description |
|
| Firmware revision | Release date | Description |
|
||||||
|:-----------------:|:------------:|-------------------------------------------------------------------------|
|
|:-----------------:|:------------:|-------------------------------------------------------------------------|
|
||||||
| 0.1.1.0.41.0 | 2016-06-01 | Default factory shipping revision. |
|
| 0.1.1.0.41.0 | 2016-06-01 | Default factory shipping revision. |
|
||||||
| 0.1.1.0.42.0 | 2017-07-01 | Public Web Frontend w/ JSON-API. |
|
| 0.1.1.0.42.0 | 2017-07-01 | Public Web Frontend w/ JSON-API. |
|
||||||
| 0.1.1.0.44.0 | 2017-12-14 | Public Web Frontend w/ JSON-API. |
|
| 0.1.1.0.44.0 | 2017-12-14 | Public Web Frontend w/ JSON-API. |
|
||||||
| 2.0.0.71 | 2018-09-27 | Public SLIP-API w/ private-only WLAN-based Web Frontend w/ JSON-API. |
|
| 0.2.0.0.71.0 | 2018-09-27 | Public SLIP-API w/ private-only WLAN-based Web Frontend w/ JSON-API. |
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- Velux bridges cannot be returned to version one of the firmware after being upgraded to version two.
|
- Velux bridges cannot be returned to version one of the firmware after being upgraded to version two.
|
||||||
- Firmware updates are currently provided at [Velux download area](https://updates2.velux.com/).
|
- Firmware updates are currently provided at [Velux download area](https://updates2.velux.com/).
|
||||||
|
|
||||||
|
|
||||||
## Is it possible to run the both communication methods in parallel?
|
## Is it possible to run the both communication methods in parallel?
|
||||||
|
|
||||||
For environments with the firmware version 0.1.* on the gateway, the interaction with the bridge is limited to the HTTP/JSON based communication, of course. On the other hand, after upgrading the gateway firmware to version 2, it is possible to run the binding either using HTTP/JSON if there is a permanent connectivity towards the WLAN interface of the KLF200 or using SLIP towards the LAN interface of the gateway. For example the Raspberry PI can directly be connected via WLAN to the Velux gateway and providing the other services via the LAN interface (but not vice versa).
|
For environments with the firmware version 0.1.* on the gateway, the interaction with the bridge is limited to the HTTP/JSON based communication, of course. On the other hand, after upgrading the gateway firmware to version 2, it is possible to run the binding either using HTTP/JSON if there is a permanent connectivity towards the WLAN interface of the KLF200 or using SLIP towards the LAN interface of the gateway. For example the Raspberry PI can directly be connected via WLAN to the Velux gateway and providing the other services via the LAN interface (but not vice versa).
|
||||||
|
|
||||||
|
|
||||||
## Known Limitations
|
## Known Limitations
|
||||||
|
|
||||||
The communication based on HTTP/JSON is limited to one connection: If the binding is operational, you won't get access to the Web Frontend in parallel.
|
The communication based on HTTP/JSON is limited to one connection: If the binding is operational, you won't get access to the Web Frontend in parallel.
|
||||||
|
|
||||||
The SLIP communication is limited to two connections in parallel, i.e. two different openHAB bindings - or - one openHAB binding and another platform connection.
|
The SLIP communication is limited to two connections in parallel, i.e. two different openHAB bindings - or - one openHAB binding and another platform connection.
|
||||||
|
|
||||||
Both interfacing methods, HTTP/JSON and SLIP, can be run in parallel. Therefore, on the one hand you can use the Web Frontend for manual control and on the other hand a binding can do all automatic jobs.
|
Both interfacing methods, HTTP/JSON and SLIP, can be run in parallel.
|
||||||
|
Therefore, on the one hand you can use the Web Frontend for manual control and on the other hand a binding can do all automatic jobs.
|
||||||
|
|
||||||
## Unknown Velux devices
|
## Unknown Velux devices
|
||||||
|
|
||||||
All known <B>Velux</B> devices can be handled by this binding. However, there might be some new ones which will be reported within the logfiles. Therefore, error messages like the one below should be reported to the maintainers so that the new Velux device type can be incorporated."
|
All known <B>Velux</B> devices can be handled by this binding.
|
||||||
|
However, there might be some new ones which will be reported within the logfiles.
|
||||||
|
Therefore, error messages like the one below should be reported to the maintainers so that the new Velux device type can be incorporated.
|
||||||
|
|
||||||
```
|
```
|
||||||
[ERROR] [g.velux.things.VeluxProductReference] - PLEASE REPORT THIS TO MAINTAINER: VeluxProductReference(3) has found an unregistered ProductTypeId.
|
[ERROR] [g.velux.things.VeluxProductReference] - PLEASE REPORT THIS TO MAINTAINER: VeluxProductReference(3) has found an unregistered ProductTypeId.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -145,4 +145,7 @@ public class VeluxBindingConstants {
|
||||||
|
|
||||||
// Critical issues to be reported will use the following message
|
// Critical issues to be reported will use the following message
|
||||||
public static final String LOGGING_CONTACT = "Please report to maintainer: ";
|
public static final String LOGGING_CONTACT = "Please report to maintainer: ";
|
||||||
|
|
||||||
|
public static final String UNKNOWN_THING_TYPE_ID = "FAILED";
|
||||||
|
public static final String UNKNOWN_IP_ADDRESS = "xxx.xxx.xxx.xxx";
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,8 @@ class JClogin extends Login implements JsonBridgeCommunicationProtocol {
|
||||||
private static final String URL = "/api/v1/auth";
|
private static final String URL = "/api/v1/auth";
|
||||||
private static final String DESCRIPTION = "authenticate / login";
|
private static final String DESCRIPTION = "authenticate / login";
|
||||||
|
|
||||||
private static Request request = new Request();
|
private Request request = new Request();
|
||||||
private static Response response = new Response();
|
private Response response = new Response();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Message Objects
|
* Message Objects
|
||||||
|
|
|
@ -83,19 +83,19 @@ import org.slf4j.LoggerFactory;
|
||||||
class JsonBridgeAPI implements BridgeAPI {
|
class JsonBridgeAPI implements BridgeAPI {
|
||||||
private final Logger logger = LoggerFactory.getLogger(JsonBridgeAPI.class);
|
private final Logger logger = LoggerFactory.getLogger(JsonBridgeAPI.class);
|
||||||
|
|
||||||
private static final GetDeviceStatus GETDEVICESTATUS = new JCgetDeviceStatus();
|
private final GetDeviceStatus jsonGetDeviceStatus = new JCgetDeviceStatus();
|
||||||
private static final GetFirmware GETFIRMWARE = new JCgetFirmware();
|
private final GetFirmware jsonGetFirmware = new JCgetFirmware();
|
||||||
private static final GetLANConfig GETLANCONFIG = new JCgetLANConfig();
|
private final GetLANConfig jsonGetLanConfig = new JCgetLANConfig();
|
||||||
private static final GetProducts GETPRODUCTS = new JCgetProducts();
|
private final GetProducts jsonGetProducts = new JCgetProducts();
|
||||||
private static final GetScenes GETSCENES = new JCgetScenes();
|
private final GetScenes jsonGetScenes = new JCgetScenes();
|
||||||
private static final GetWLANConfig GETWLANCONFIG = new JCgetWLANConfig();
|
private final GetWLANConfig jsonGetWLanConfig = new JCgetWLANConfig();
|
||||||
private static final Login LOGIN = new JClogin();
|
private final Login jsonLogin = new JClogin();
|
||||||
private static final Logout LOGOUT = new JClogout();
|
private final Logout jsonLogout = new JClogout();
|
||||||
private static final RunProductDiscovery RUNPRODUCTDISCOVERY = new JCrunProductDiscovery();
|
private final RunProductDiscovery jsonRunProductDiscovery = new JCrunProductDiscovery();
|
||||||
private static final RunProductIdentification RUNPRODUCTIDENTIFICATION = new JCrunProductIdentification();
|
private final RunProductIdentification jsonRunProductIdentification = new JCrunProductIdentification();
|
||||||
private static final RunProductSearch RUNPRODUCTSEARCH = new JCrunProductSearch();
|
private final RunProductSearch jsonRunProductSearch = new JCrunProductSearch();
|
||||||
private static final RunScene RUNSCENE = new JCrunScene();
|
private final RunScene jsonRunScene = new JCrunScene();
|
||||||
private static final SetSceneVelocity SETSCENEVELOCITY = new JCsetSceneVelocity();
|
private final SetSceneVelocity jsonSetSceneVelocity = new JCsetSceneVelocity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -113,12 +113,12 @@ class JsonBridgeAPI implements BridgeAPI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetDeviceStatus getDeviceStatus() {
|
public GetDeviceStatus getDeviceStatus() {
|
||||||
return GETDEVICESTATUS;
|
return jsonGetDeviceStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetFirmware getFirmware() {
|
public GetFirmware getFirmware() {
|
||||||
return GETFIRMWARE;
|
return jsonGetFirmware;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -128,7 +128,7 @@ class JsonBridgeAPI implements BridgeAPI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetLANConfig getLANConfig() {
|
public GetLANConfig getLANConfig() {
|
||||||
return GETLANCONFIG;
|
return jsonGetLanConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -148,27 +148,27 @@ class JsonBridgeAPI implements BridgeAPI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetProducts getProducts() {
|
public GetProducts getProducts() {
|
||||||
return GETPRODUCTS;
|
return jsonGetProducts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetScenes getScenes() {
|
public GetScenes getScenes() {
|
||||||
return GETSCENES;
|
return jsonGetScenes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetWLANConfig getWLANConfig() {
|
public GetWLANConfig getWLANConfig() {
|
||||||
return GETWLANCONFIG;
|
return jsonGetWLanConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Login login() {
|
public Login login() {
|
||||||
return LOGIN;
|
return jsonLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Logout logout() {
|
public Logout logout() {
|
||||||
return LOGOUT;
|
return jsonLogout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -178,22 +178,22 @@ class JsonBridgeAPI implements BridgeAPI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunProductDiscovery runProductDiscovery() {
|
public RunProductDiscovery runProductDiscovery() {
|
||||||
return RUNPRODUCTDISCOVERY;
|
return jsonRunProductDiscovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunProductIdentification runProductIdentification() {
|
public RunProductIdentification runProductIdentification() {
|
||||||
return RUNPRODUCTIDENTIFICATION;
|
return jsonRunProductIdentification;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunProductSearch runProductSearch() {
|
public RunProductSearch runProductSearch() {
|
||||||
return RUNPRODUCTSEARCH;
|
return jsonRunProductSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunScene runScene() {
|
public RunScene runScene() {
|
||||||
return RUNSCENE;
|
return jsonRunScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -203,6 +203,6 @@ class JsonBridgeAPI implements BridgeAPI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SetSceneVelocity setSceneVelocity() {
|
public SetSceneVelocity setSceneVelocity() {
|
||||||
return SETSCENEVELOCITY;
|
return jsonSetSceneVelocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,25 +83,25 @@ import org.slf4j.LoggerFactory;
|
||||||
class SlipBridgeAPI implements BridgeAPI {
|
class SlipBridgeAPI implements BridgeAPI {
|
||||||
private final Logger logger = LoggerFactory.getLogger(SlipBridgeAPI.class);
|
private final Logger logger = LoggerFactory.getLogger(SlipBridgeAPI.class);
|
||||||
|
|
||||||
private static final GetDeviceStatus GETDEVICESTATUS = new SCgetDeviceStatus();
|
private final GetDeviceStatus slipGetDeviceStatus = new SCgetDeviceStatus();
|
||||||
private static final GetFirmware GETFIRMWARE = new SCgetFirmware();
|
private final GetFirmware slipGetFirmware = new SCgetFirmware();
|
||||||
private static final GetHouseStatus GETHOUSESTATUS = new SCgetHouseStatus();
|
private final GetHouseStatus slipGetHouseStatus = new SCgetHouseStatus();
|
||||||
private static final GetLANConfig GETLANCONFIG = new SCgetLANConfig();
|
private final GetLANConfig slipGetLanConfig = new SCgetLANConfig();
|
||||||
private static final GetProduct GETPRODUCT = new SCgetProduct();
|
private final GetProduct slipGetProduct = new SCgetProduct();
|
||||||
private static final GetProductLimitation GETPRODUCTLIMITATION = new SCgetLimitation();
|
private final GetProductLimitation slipGetProductLimitation = new SCgetLimitation();
|
||||||
private static final GetProducts GETPRODUCTS = new SCgetProducts();
|
private final GetProducts slipGetProducts = new SCgetProducts();
|
||||||
private static final GetScenes GETSCENES = new SCgetScenes();
|
private final GetScenes slipGetScenes = new SCgetScenes();
|
||||||
private static final GetWLANConfig GETWLANCONFIG = new SCgetWLANConfig();
|
private final GetWLANConfig slipGetWLanConfig = new SCgetWLANConfig();
|
||||||
private static final Login LOGIN = new SClogin();
|
private final Login slipLogin = new SClogin();
|
||||||
private static final Logout LOGOUT = new SClogout();
|
private final Logout slipLogout = new SClogout();
|
||||||
private static final RunProductCommand RUNPRODUCTCOMMAND = new SCrunProductCommand();
|
private final RunProductCommand slipRunProductCommand = new SCrunProductCommand();
|
||||||
private static final RunProductDiscovery RUNPRODUCTDISCOVERY = new SCrunProductDiscovery();
|
private final RunProductDiscovery slipRunProductDiscovery = new SCrunProductDiscovery();
|
||||||
private static final RunProductIdentification RUNPRODUCTIDENTIFICATION = new SCrunProductIdentification();
|
private final RunProductIdentification slipRunProductIdentification = new SCrunProductIdentification();
|
||||||
private static final RunProductSearch RUNPRODUCTSEARCH = new SCrunProductSearch();
|
private final RunProductSearch slipRunProductSearch = new SCrunProductSearch();
|
||||||
private static final RunScene RUNSCENE = new SCrunScene();
|
private final RunScene slipRunScene = new SCrunScene();
|
||||||
private static final SetHouseStatusMonitor SETHOUSESTATUSMONITOR = new SCsetHouseStatusMonitor();
|
private final SetHouseStatusMonitor slipSetHouseMonitor = new SCsetHouseStatusMonitor();
|
||||||
private static final SetProductLimitation SETPRODUCTLIMITATION = new SCsetLimitation();
|
private final SetProductLimitation slipSetProductLimitation = new SCsetLimitation();
|
||||||
private static final SetSceneVelocity SETSCENEVELOCITY = new SCsetSceneVelocity();
|
private final SetSceneVelocity slipSetSceneVelocity = new SCsetSceneVelocity();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -118,96 +118,96 @@ class SlipBridgeAPI implements BridgeAPI {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetDeviceStatus getDeviceStatus() {
|
public GetDeviceStatus getDeviceStatus() {
|
||||||
return GETDEVICESTATUS;
|
return slipGetDeviceStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetFirmware getFirmware() {
|
public GetFirmware getFirmware() {
|
||||||
return GETFIRMWARE;
|
return slipGetFirmware;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable GetHouseStatus getHouseStatus() {
|
public @Nullable GetHouseStatus getHouseStatus() {
|
||||||
return GETHOUSESTATUS;
|
return slipGetHouseStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetLANConfig getLANConfig() {
|
public GetLANConfig getLANConfig() {
|
||||||
return GETLANCONFIG;
|
return slipGetLanConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable GetProduct getProduct() {
|
public @Nullable GetProduct getProduct() {
|
||||||
return GETPRODUCT;
|
return slipGetProduct;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable GetProductLimitation getProductLimitation() {
|
public @Nullable GetProductLimitation getProductLimitation() {
|
||||||
return GETPRODUCTLIMITATION;
|
return slipGetProductLimitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable SetProductLimitation setProductLimitation() {
|
public @Nullable SetProductLimitation setProductLimitation() {
|
||||||
return SETPRODUCTLIMITATION;
|
return slipSetProductLimitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetProducts getProducts() {
|
public GetProducts getProducts() {
|
||||||
return GETPRODUCTS;
|
return slipGetProducts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetScenes getScenes() {
|
public GetScenes getScenes() {
|
||||||
return GETSCENES;
|
return slipGetScenes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GetWLANConfig getWLANConfig() {
|
public GetWLANConfig getWLANConfig() {
|
||||||
return GETWLANCONFIG;
|
return slipGetWLanConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Login login() {
|
public Login login() {
|
||||||
return LOGIN;
|
return slipLogin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Logout logout() {
|
public Logout logout() {
|
||||||
return LOGOUT;
|
return slipLogout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable RunProductCommand runProductCommand() {
|
public @Nullable RunProductCommand runProductCommand() {
|
||||||
return RUNPRODUCTCOMMAND;
|
return slipRunProductCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunProductDiscovery runProductDiscovery() {
|
public RunProductDiscovery runProductDiscovery() {
|
||||||
return RUNPRODUCTDISCOVERY;
|
return slipRunProductDiscovery;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunProductIdentification runProductIdentification() {
|
public RunProductIdentification runProductIdentification() {
|
||||||
return RUNPRODUCTIDENTIFICATION;
|
return slipRunProductIdentification;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunProductSearch runProductSearch() {
|
public RunProductSearch runProductSearch() {
|
||||||
return RUNPRODUCTSEARCH;
|
return slipRunProductSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RunScene runScene() {
|
public RunScene runScene() {
|
||||||
return RUNSCENE;
|
return slipRunScene;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable SetHouseStatusMonitor setHouseStatusMonitor() {
|
public @Nullable SetHouseStatusMonitor setHouseStatusMonitor() {
|
||||||
return SETHOUSESTATUSMONITOR;
|
return slipSetHouseMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SetSceneVelocity setSceneVelocity() {
|
public SetSceneVelocity setSceneVelocity() {
|
||||||
return SETSCENEVELOCITY;
|
return slipSetSceneVelocity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,8 @@ public class SlipVeluxBridge extends VeluxBridge {
|
||||||
*/
|
*/
|
||||||
private synchronized boolean bridgeDirectCommunicate(SlipBridgeCommunicationProtocol communication,
|
private synchronized boolean bridgeDirectCommunicate(SlipBridgeCommunicationProtocol communication,
|
||||||
boolean useAuthentication) {
|
boolean useAuthentication) {
|
||||||
logger.trace("bridgeDirectCommunicate({},{}authenticated) called.", communication.name(),
|
String host = this.bridgeInstance.veluxBridgeConfiguration().ipAddress;
|
||||||
|
logger.trace("bridgeDirectCommunicate({},{}authenticated) on {} called.", host, communication.name(),
|
||||||
useAuthentication ? "" : "un");
|
useAuthentication ? "" : "un");
|
||||||
|
|
||||||
assert this.bridgeInstance.veluxBridgeConfiguration().protocol.contentEquals("slip");
|
assert this.bridgeInstance.veluxBridgeConfiguration().protocol.contentEquals("slip");
|
||||||
|
@ -213,15 +214,15 @@ public class SlipVeluxBridge extends VeluxBridge {
|
||||||
Threads.findDeadlocked();
|
Threads.findDeadlocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("bridgeDirectCommunicate({},{}authenticated) initiated by {}.", commandString,
|
logger.debug("bridgeDirectCommunicate({},{}authenticated) on {} initiated by {}.", host, commandString,
|
||||||
useAuthentication ? "" : "un", Thread.currentThread());
|
useAuthentication ? "" : "un", Thread.currentThread());
|
||||||
boolean success = false;
|
boolean success = false;
|
||||||
|
|
||||||
communication: do {
|
communication: do {
|
||||||
if (communicationStartInMSecs + COMMUNICATION_TIMEOUT_MSECS < System.currentTimeMillis()) {
|
if (communicationStartInMSecs + COMMUNICATION_TIMEOUT_MSECS < System.currentTimeMillis()) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"{} bridgeDirectCommunicate({}): communication handshake failed (unexpected sequence of requests/responses).",
|
"{} bridgeDirectCommunicate({}) on {}: communication handshake failed (unexpected sequence of requests/responses).",
|
||||||
VeluxBindingConstants.BINDING_VALUES_SEPARATOR, communication.name());
|
VeluxBindingConstants.BINDING_VALUES_SEPARATOR, communication.name(), host);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,67 +235,71 @@ public class SlipVeluxBridge extends VeluxBridge {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal processing
|
// Normal processing
|
||||||
logger.trace("bridgeDirectCommunicate(): working on request {} with {} bytes of data.", commandString,
|
logger.trace("bridgeDirectCommunicate() on {}: working on request {} with {} bytes of data.", host,
|
||||||
data.length);
|
commandString, data.length);
|
||||||
byte[] sendBytes = emptyPacket;
|
byte[] sendBytes = emptyPacket;
|
||||||
if (Command.get(command) == Command.GW_OPENHAB_RECEIVEONLY) {
|
if (Command.get(command) == Command.GW_OPENHAB_RECEIVEONLY) {
|
||||||
logger.trace(
|
logger.trace(
|
||||||
"bridgeDirectCommunicate(): special command: determine whether there is any message waiting.");
|
"bridgeDirectCommunicate() on {}: special command: determine whether there is any message waiting.",
|
||||||
|
host);
|
||||||
logger.trace("bridgeDirectCommunicate(): check for a waiting message.");
|
logger.trace("bridgeDirectCommunicate(): check for a waiting message.");
|
||||||
if (!connection.isMessageAvailable()) {
|
if (!connection.isMessageAvailable()) {
|
||||||
logger.trace("bridgeDirectCommunicate(): no message waiting, aborting.");
|
logger.trace("bridgeDirectCommunicate() on {}: no message waiting, aborting.", host);
|
||||||
break communication;
|
break communication;
|
||||||
}
|
}
|
||||||
logger.trace("bridgeDirectCommunicate(): there is a message waiting.");
|
logger.trace("bridgeDirectCommunicate() on {}: there is a message waiting.", host);
|
||||||
} else {
|
} else {
|
||||||
SlipEncoding t = new SlipEncoding(command, data);
|
SlipEncoding t = new SlipEncoding(command, data);
|
||||||
if (!t.isValid()) {
|
if (!t.isValid()) {
|
||||||
logger.warn("bridgeDirectCommunicate(): SlipEncoding() failed, aborting.");
|
logger.warn("bridgeDirectCommunicate() on {}: SlipEncoding() failed, aborting.", host);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
logger.trace("bridgeDirectCommunicate(): transportEncoding={}.", t.toString());
|
logger.trace("bridgeDirectCommunicate() on {}: transportEncoding={}.", host, t.toString());
|
||||||
sendBytes = new SlipRFC1055().encode(t.toMessage());
|
sendBytes = new SlipRFC1055().encode(t.toMessage());
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
if (communicationStartInMSecs + COMMUNICATION_TIMEOUT_MSECS < System.currentTimeMillis()) {
|
if (communicationStartInMSecs + COMMUNICATION_TIMEOUT_MSECS < System.currentTimeMillis()) {
|
||||||
logger.warn("bridgeDirectCommunicate(): receive takes too long. Please report to maintainer.");
|
logger.warn("bridgeDirectCommunicate() on {}: receive takes too long. Please report to maintainer.",
|
||||||
|
host);
|
||||||
break communication;
|
break communication;
|
||||||
}
|
}
|
||||||
byte[] receivedPacket;
|
byte[] receivedPacket;
|
||||||
try {
|
try {
|
||||||
if (sendBytes.length > 0) {
|
if (sendBytes.length > 0) {
|
||||||
logger.trace("bridgeDirectCommunicate(): sending {} bytes.", sendBytes.length);
|
logger.trace("bridgeDirectCommunicate() on {}: sending {} bytes.", host, sendBytes.length);
|
||||||
if (isProtocolTraceEnabled) {
|
if (isProtocolTraceEnabled) {
|
||||||
logger.info("Sending command {}.", commandString);
|
logger.info("Sending command {}.", commandString);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.trace("bridgeDirectCommunicate(): initiating receive-only.");
|
logger.trace("bridgeDirectCommunicate() on {}: initiating receive-only.", host);
|
||||||
}
|
}
|
||||||
// (Optionally) Send and receive packet.
|
// (Optionally) Send and receive packet.
|
||||||
receivedPacket = connection.io(this.bridgeInstance, sendBytes);
|
receivedPacket = connection.io(this.bridgeInstance, sendBytes);
|
||||||
// Once being sent, it should never be sent again
|
// Once being sent, it should never be sent again
|
||||||
sendBytes = emptyPacket;
|
sendBytes = emptyPacket;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("bridgeDirectCommunicate(): connection.io returns {}", e.getMessage());
|
logger.warn("bridgeDirectCommunicate() on {}: connection.io returns {}", host, e.getMessage());
|
||||||
break communication;
|
break communication;
|
||||||
}
|
}
|
||||||
logger.trace("bridgeDirectCommunicate(): received packet {}.", new Packet(receivedPacket).toString());
|
logger.trace("bridgeDirectCommunicate() on {}: received packet {}.", host,
|
||||||
|
new Packet(receivedPacket).toString());
|
||||||
byte[] response;
|
byte[] response;
|
||||||
try {
|
try {
|
||||||
response = new SlipRFC1055().decode(receivedPacket);
|
response = new SlipRFC1055().decode(receivedPacket);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
logger.warn("bridgeDirectCommunicate(): method SlipRFC1055() raised a decoding error: {}.",
|
logger.warn("bridgeDirectCommunicate() on {}: method SlipRFC1055() raised a decoding error: {}.",
|
||||||
e.getMessage());
|
host, e.getMessage());
|
||||||
break communication;
|
break communication;
|
||||||
}
|
}
|
||||||
SlipEncoding tr = new SlipEncoding(response);
|
SlipEncoding tr = new SlipEncoding(response);
|
||||||
if (!tr.isValid()) {
|
if (!tr.isValid()) {
|
||||||
logger.warn("bridgeDirectCommunicate(): method SlipEncoding() raised a decoding error.");
|
logger.warn("bridgeDirectCommunicate() on {}: method SlipEncoding() raised a decoding error.",
|
||||||
|
host);
|
||||||
break communication;
|
break communication;
|
||||||
}
|
}
|
||||||
short responseCommand = tr.getCommand();
|
short responseCommand = tr.getCommand();
|
||||||
byte[] responseData = tr.getData();
|
byte[] responseData = tr.getData();
|
||||||
logger.debug("bridgeDirectCommunicate(): working on response {} with {} bytes of data.",
|
logger.debug("bridgeDirectCommunicate() on {}: working on response {} with {} bytes of data.", host,
|
||||||
Command.get(responseCommand).toString(), responseData.length);
|
Command.get(responseCommand).toString(), responseData.length);
|
||||||
if (isProtocolTraceEnabled) {
|
if (isProtocolTraceEnabled) {
|
||||||
logger.info("Received answer {}.", Command.get(responseCommand).toString());
|
logger.info("Received answer {}.", Command.get(responseCommand).toString());
|
||||||
|
@ -302,63 +307,66 @@ public class SlipVeluxBridge extends VeluxBridge {
|
||||||
// Handle some common (unexpected) answers
|
// Handle some common (unexpected) answers
|
||||||
switch (Command.get(responseCommand)) {
|
switch (Command.get(responseCommand)) {
|
||||||
case GW_NODE_INFORMATION_CHANGED_NTF:
|
case GW_NODE_INFORMATION_CHANGED_NTF:
|
||||||
logger.trace("bridgeDirectCommunicate(): received GW_NODE_INFORMATION_CHANGED_NTF.");
|
logger.trace("bridgeDirectCommunicate() on {}: received GW_NODE_INFORMATION_CHANGED_NTF.",
|
||||||
logger.trace("bridgeDirectCommunicate(): continue with receiving.");
|
host);
|
||||||
|
logger.trace("bridgeDirectCommunicate() on {}: continue with receiving.", host);
|
||||||
continue;
|
continue;
|
||||||
case GW_NODE_STATE_POSITION_CHANGED_NTF:
|
case GW_NODE_STATE_POSITION_CHANGED_NTF:
|
||||||
logger.trace(
|
logger.trace(
|
||||||
"bridgeDirectCommunicate(): received GW_NODE_STATE_POSITION_CHANGED_NTF, special processing of this packet.");
|
"bridgeDirectCommunicate() on {}: received GW_NODE_STATE_POSITION_CHANGED_NTF, special processing of this packet.",
|
||||||
|
host);
|
||||||
SCgetHouseStatus receiver = new SCgetHouseStatus();
|
SCgetHouseStatus receiver = new SCgetHouseStatus();
|
||||||
receiver.setResponse(responseCommand, responseData, isSequentialEnforced);
|
receiver.setResponse(responseCommand, responseData, isSequentialEnforced);
|
||||||
if (receiver.isCommunicationSuccessful()) {
|
if (receiver.isCommunicationSuccessful()) {
|
||||||
logger.trace("bridgeDirectCommunicate(): existingProducts().update() called.");
|
logger.trace("bridgeDirectCommunicate() on {}: existingProducts().update() called.", host);
|
||||||
bridgeInstance.existingProducts().update(new ProductBridgeIndex(receiver.getNtfNodeID()),
|
bridgeInstance.existingProducts().update(new ProductBridgeIndex(receiver.getNtfNodeID()),
|
||||||
receiver.getNtfState(), receiver.getNtfCurrentPosition(), receiver.getNtfTarget());
|
receiver.getNtfState(), receiver.getNtfCurrentPosition(), receiver.getNtfTarget());
|
||||||
}
|
}
|
||||||
logger.trace("bridgeDirectCommunicate(): continue with receiving.");
|
logger.trace("bridgeDirectCommunicate() on {}: continue with receiving.", host);
|
||||||
continue;
|
continue;
|
||||||
case GW_ERROR_NTF:
|
case GW_ERROR_NTF:
|
||||||
switch (responseData[0]) {
|
switch (responseData[0]) {
|
||||||
case 0:
|
case 0:
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF on {} (Not further defined error), aborting.",
|
"bridgeDirectCommunicate() on {}: received GW_ERROR_NTF on {} (Not further defined error), aborting.",
|
||||||
commandString);
|
host, commandString);
|
||||||
break communication;
|
break communication;
|
||||||
case 1:
|
case 1:
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Unknown Command or command is not accepted at this state) on {}, aborting.",
|
"bridgeDirectCommunicate() on {}: received GW_ERROR_NTF (Unknown Command or command is not accepted at this state) on {}, aborting.",
|
||||||
commandString);
|
host, commandString);
|
||||||
break communication;
|
break communication;
|
||||||
case 2:
|
case 2:
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (ERROR on Frame Structure) on {}, aborting.",
|
"bridgeDirectCommunicate() on {}: received GW_ERROR_NTF (ERROR on Frame Structure) on {}, aborting.",
|
||||||
commandString);
|
host, commandString);
|
||||||
break communication;
|
break communication;
|
||||||
case 7:
|
case 7:
|
||||||
logger.trace(
|
logger.trace(
|
||||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Busy. Try again later) on {}, retrying.",
|
"bridgeDirectCommunicate() on {}: received GW_ERROR_NTF (Busy. Try again later) on {}, retrying.",
|
||||||
commandString);
|
host, commandString);
|
||||||
sendBytes = emptyPacket;
|
sendBytes = emptyPacket;
|
||||||
continue;
|
continue;
|
||||||
case 8:
|
case 8:
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Bad system table index) on {}, aborting.",
|
"bridgeDirectCommunicate() on {}: received GW_ERROR_NTF (Bad system table index) on {}, aborting.",
|
||||||
commandString);
|
host, commandString);
|
||||||
break communication;
|
break communication;
|
||||||
case 12:
|
case 12:
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"bridgeDirectCommunicate(): received GW_ERROR_NTF (Not authenticated) on {}, aborting.",
|
"bridgeDirectCommunicate() on {}: received GW_ERROR_NTF (Not authenticated) on {}, aborting.",
|
||||||
commandString);
|
host, commandString);
|
||||||
resetAuthentication();
|
resetAuthentication();
|
||||||
break communication;
|
break communication;
|
||||||
default:
|
default:
|
||||||
logger.warn("bridgeDirectCommunicate(): received GW_ERROR_NTF ({}) on {}, aborting.",
|
logger.warn(
|
||||||
responseData[0], commandString);
|
"bridgeDirectCommunicate() on {}: received GW_ERROR_NTF ({}) on {}, aborting.",
|
||||||
|
host, responseData[0], commandString);
|
||||||
break communication;
|
break communication;
|
||||||
}
|
}
|
||||||
case GW_ACTIVATION_LOG_UPDATED_NTF:
|
case GW_ACTIVATION_LOG_UPDATED_NTF:
|
||||||
logger.info("bridgeDirectCommunicate(): received GW_ACTIVATION_LOG_UPDATED_NTF.");
|
logger.info("bridgeDirectCommunicate() on {}: received GW_ACTIVATION_LOG_UPDATED_NTF.", host);
|
||||||
logger.trace("bridgeDirectCommunicate(): continue with receiving.");
|
logger.trace("bridgeDirectCommunicate() on {}: continue with receiving.", host);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case GW_COMMAND_RUN_STATUS_NTF:
|
case GW_COMMAND_RUN_STATUS_NTF:
|
||||||
|
@ -366,19 +374,21 @@ public class SlipVeluxBridge extends VeluxBridge {
|
||||||
case GW_SESSION_FINISHED_NTF:
|
case GW_SESSION_FINISHED_NTF:
|
||||||
if (!isSequentialEnforced) {
|
if (!isSequentialEnforced) {
|
||||||
logger.trace(
|
logger.trace(
|
||||||
"bridgeDirectCommunicate(): response ignored due to activated parallelism, continue with receiving.");
|
"bridgeDirectCommunicate() on {}: response ignored due to activated parallelism, continue with receiving.",
|
||||||
|
host);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
logger.trace("bridgeDirectCommunicate(): passes back command {} and data {}.",
|
logger.trace("bridgeDirectCommunicate() on {}: passes back command {} and data {}.", host,
|
||||||
new CommandNumber(responseCommand).toString(), new Packet(responseData).toString());
|
new CommandNumber(responseCommand).toString(), new Packet(responseData).toString());
|
||||||
communication.setResponse(responseCommand, responseData, isSequentialEnforced);
|
communication.setResponse(responseCommand, responseData, isSequentialEnforced);
|
||||||
} while (!communication.isCommunicationFinished());
|
} while (!communication.isCommunicationFinished());
|
||||||
success = communication.isCommunicationSuccessful();
|
success = communication.isCommunicationSuccessful();
|
||||||
} while (false); // communication
|
} while (false); // communication
|
||||||
logger.debug("bridgeDirectCommunicate({}) returns {}.", commandString, success ? "success" : "failure");
|
logger.debug("bridgeDirectCommunicate({}) on {}: returns {}.", commandString, host,
|
||||||
|
success ? "success" : "failure");
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import java.io.IOException;
|
||||||
import java.net.ConnectException;
|
import java.net.ConnectException;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||||
import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
|
import org.openhab.binding.velux.internal.bridge.VeluxBridgeInstance;
|
||||||
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
import org.openhab.binding.velux.internal.bridge.slip.utils.Packet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -59,6 +60,8 @@ public class Connection {
|
||||||
*/
|
*/
|
||||||
private SSLconnection connectivity = SSLconnection.UNKNOWN;
|
private SSLconnection connectivity = SSLconnection.UNKNOWN;
|
||||||
|
|
||||||
|
private String host = VeluxBindingConstants.UNKNOWN_IP_ADDRESS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* **************************
|
* **************************
|
||||||
* ***** Public Methods *****
|
* ***** Public Methods *****
|
||||||
|
@ -75,7 +78,7 @@ public class Connection {
|
||||||
*/
|
*/
|
||||||
public synchronized byte[] io(VeluxBridgeInstance bridgeInstance, byte[] request)
|
public synchronized byte[] io(VeluxBridgeInstance bridgeInstance, byte[] request)
|
||||||
throws ConnectException, IOException {
|
throws ConnectException, IOException {
|
||||||
logger.trace("io() called.");
|
logger.trace("io() on {}: called.", host);
|
||||||
|
|
||||||
lastCommunicationInMSecs = System.currentTimeMillis();
|
lastCommunicationInMSecs = System.currentTimeMillis();
|
||||||
|
|
||||||
|
@ -88,18 +91,18 @@ public class Connection {
|
||||||
if (!connectivity.isReady()) {
|
if (!connectivity.isReady()) {
|
||||||
try {
|
try {
|
||||||
// From configuration
|
// From configuration
|
||||||
String host = bridgeInstance.veluxBridgeConfiguration().ipAddress;
|
host = bridgeInstance.veluxBridgeConfiguration().ipAddress;
|
||||||
int port = bridgeInstance.veluxBridgeConfiguration().tcpPort;
|
int port = bridgeInstance.veluxBridgeConfiguration().tcpPort;
|
||||||
int timeoutMsecs = bridgeInstance.veluxBridgeConfiguration().timeoutMsecs;
|
int timeoutMsecs = bridgeInstance.veluxBridgeConfiguration().timeoutMsecs;
|
||||||
|
|
||||||
logger.trace("io(): connecting to {}:{}.", host, port);
|
logger.trace("io() on {}: connecting to port {}", host, port);
|
||||||
connectivity = new SSLconnection(host, port);
|
connectivity = new SSLconnection(host, port);
|
||||||
connectivity.setTimeout(timeoutMsecs);
|
connectivity.setTimeout(timeoutMsecs);
|
||||||
} catch (ConnectException ce) {
|
} catch (ConnectException ce) {
|
||||||
throw new ConnectException(String
|
throw new ConnectException(String
|
||||||
.format("raised a non-recoverable error during connection setup: %s", ce.getMessage()));
|
.format("raised a non-recoverable error during connection setup: %s", ce.getMessage()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.warn("io(): raised an error during connection setup: {}.", e.getMessage());
|
logger.warn("io() on {}: raised an error during connection setup: {}.", host, e.getMessage());
|
||||||
lastIOE = new IOException(String.format("error during connection setup: %s.", e.getMessage()));
|
lastIOE = new IOException(String.format("error during connection setup: %s.", e.getMessage()));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -107,65 +110,68 @@ public class Connection {
|
||||||
if (request.length > 0) {
|
if (request.length > 0) {
|
||||||
try {
|
try {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("io(): sending packet with {} bytes: {}", request.length, new Packet(request));
|
logger.trace("io() on {}: sending packet with {} bytes: {}", host, request.length,
|
||||||
|
new Packet(request));
|
||||||
} else {
|
} else {
|
||||||
logger.debug("io(): sending packet of size {}.", request.length);
|
logger.debug("io() on {}: sending packet of size {}.", host, request.length);
|
||||||
}
|
}
|
||||||
if (connectivity.isReady()) {
|
if (connectivity.isReady()) {
|
||||||
connectivity.send(request);
|
connectivity.send(request);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.info("io(): raised an error during sending: {}.", e.getMessage());
|
logger.info("io() on {}: raised an error during sending: {}.", host, e.getMessage());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give the bridge some time to breathe
|
// Give the bridge some time to breathe
|
||||||
if (bridgeInstance.veluxBridgeConfiguration().timeoutMsecs > 0) {
|
if (bridgeInstance.veluxBridgeConfiguration().timeoutMsecs > 0) {
|
||||||
logger.trace("io(): wait time {} msecs.",
|
logger.trace("io() on {}: wait time {} msecs.", host,
|
||||||
bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||||
try {
|
try {
|
||||||
Thread.sleep(bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
Thread.sleep(bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
logger.trace("io() wait interrupted.");
|
logger.trace("io() on {}: wait interrupted.", host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byte[] packet = new byte[0];
|
byte[] packet = new byte[0];
|
||||||
logger.trace("io(): receiving bytes.");
|
logger.trace("io() on {}: receiving bytes.", host);
|
||||||
if (connectivity.isReady()) {
|
if (connectivity.isReady()) {
|
||||||
packet = connectivity.receive();
|
packet = connectivity.receive();
|
||||||
}
|
}
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("io(): received packet with {} bytes: {}", packet.length, new Packet(packet));
|
logger.trace("io() on {}: received packet with {} bytes: {}", host, packet.length,
|
||||||
|
new Packet(packet));
|
||||||
} else {
|
} else {
|
||||||
logger.debug("io(): received packet with {} bytes.", packet.length);
|
logger.debug("io() on {}: received packet with {} bytes.", host, packet.length);
|
||||||
}
|
}
|
||||||
lastSuccessfulCommunicationInMSecs = System.currentTimeMillis();
|
lastSuccessfulCommunicationInMSecs = System.currentTimeMillis();
|
||||||
lastCommunicationInMSecs = lastSuccessfulCommunicationInMSecs;
|
lastCommunicationInMSecs = lastSuccessfulCommunicationInMSecs;
|
||||||
logger.trace("io() finished.");
|
logger.trace("io() on {}: finished.", host);
|
||||||
return packet;
|
return packet;
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
logger.info("io(): Exception occurred during I/O: {}.", ioe.getMessage());
|
logger.info("io() on {}: Exception occurred during I/O: {}.", host, ioe.getMessage());
|
||||||
lastIOE = ioe;
|
lastIOE = ioe;
|
||||||
// Error Retries with Exponential Backoff
|
// Error Retries with Exponential Backoff
|
||||||
long waitTime = ((long) Math.pow(2, retryCount)
|
long waitTime = ((long) Math.pow(2, retryCount)
|
||||||
* bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
* bridgeInstance.veluxBridgeConfiguration().timeoutMsecs);
|
||||||
logger.trace("io(): wait time {} msecs.", waitTime);
|
logger.trace("io() on {}: wait time {} msecs.", host, waitTime);
|
||||||
try {
|
try {
|
||||||
Thread.sleep(waitTime);
|
Thread.sleep(waitTime);
|
||||||
} catch (InterruptedException ie) {
|
} catch (InterruptedException ie) {
|
||||||
logger.trace("io(): wait interrupted.");
|
logger.trace("io() on {}: wait interrupted.", host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (retryCount++ < bridgeInstance.veluxBridgeConfiguration().retries);
|
} while (retryCount++ < bridgeInstance.veluxBridgeConfiguration().retries);
|
||||||
if (retryCount >= bridgeInstance.veluxBridgeConfiguration().retries) {
|
if (retryCount >= bridgeInstance.veluxBridgeConfiguration().retries) {
|
||||||
logger.info("io(): socket I/O failed {} times.", bridgeInstance.veluxBridgeConfiguration().retries);
|
logger.info("io() on {}: socket I/O failed {} times.", host,
|
||||||
|
bridgeInstance.veluxBridgeConfiguration().retries);
|
||||||
}
|
}
|
||||||
logger.trace("io(): shutting down connection.");
|
logger.trace("io() on {}: shutting down connection.", host);
|
||||||
if (connectivity.isReady()) {
|
if (connectivity.isReady()) {
|
||||||
connectivity.close();
|
connectivity.close();
|
||||||
}
|
}
|
||||||
logger.trace("io() finishes with failure by throwing exception.");
|
logger.trace("io() on {}: finishes with failure by throwing exception.", host);
|
||||||
throw lastIOE;
|
throw lastIOE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,7 +181,7 @@ public class Connection {
|
||||||
* @return state as boolean.
|
* @return state as boolean.
|
||||||
*/
|
*/
|
||||||
public boolean isAlive() {
|
public boolean isAlive() {
|
||||||
logger.trace("isAlive(): called.");
|
logger.trace("isAlive() on {}: called.", host);
|
||||||
return connectivity.isReady();
|
return connectivity.isReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,17 +191,17 @@ public class Connection {
|
||||||
* @return state as boolean.
|
* @return state as boolean.
|
||||||
*/
|
*/
|
||||||
public synchronized boolean isMessageAvailable() {
|
public synchronized boolean isMessageAvailable() {
|
||||||
logger.trace("isMessageAvailable(): called.");
|
logger.trace("isMessageAvailable() on {}: called.", host);
|
||||||
try {
|
try {
|
||||||
if ((connectivity.isReady()) && (connectivity.available())) {
|
if ((connectivity.isReady()) && (connectivity.available())) {
|
||||||
logger.trace("isMessageAvailable(): there is a message waiting.");
|
logger.trace("isMessageAvailable() on {}: there is a message waiting.", host);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.trace("isMessageAvailable(): lost connection due to {}.", e.getMessage());
|
logger.trace("isMessageAvailable() on {}: lost connection due to {}.", host, e.getMessage());
|
||||||
resetConnection();
|
resetConnection();
|
||||||
}
|
}
|
||||||
logger.trace("isMessageAvailable(): no message waiting.");
|
logger.trace("isMessageAvailable() on {}: no message waiting.", host);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,18 +229,12 @@ public class Connection {
|
||||||
* Resets an open connectivity by closing the socket and resetting the authentication information.
|
* Resets an open connectivity by closing the socket and resetting the authentication information.
|
||||||
*/
|
*/
|
||||||
public synchronized void resetConnection() {
|
public synchronized void resetConnection() {
|
||||||
logger.trace("resetConnection() called.");
|
logger.trace("resetConnection() on {}: called.", host);
|
||||||
if (connectivity.isReady()) {
|
|
||||||
logger.trace("resetConnection(): shutting down connection.");
|
|
||||||
try {
|
try {
|
||||||
if (connectivity.isReady()) {
|
|
||||||
connectivity.close();
|
connectivity.close();
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.info("resetConnection(): raised an error during connection close: {}.", e.getMessage());
|
logger.info("resetConnection() on {}: raised an error during connection close: {}.", host, e.getMessage());
|
||||||
}
|
}
|
||||||
logger.trace("resetConnection(): clearing authentication token.");
|
logger.trace("resetConnection() on {}: done.", host);
|
||||||
}
|
|
||||||
logger.trace("resetConnection() done.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -155,17 +155,33 @@ class SSLconnection {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to pass a message towards the bridge.
|
* Method to pass a message towards the bridge.
|
||||||
|
* This method gets called when we are initiating a new SLIP transaction.
|
||||||
|
* <p>
|
||||||
|
* Note that DataOutputStream and DataInputStream are buffered I/O's. The SLIP protocol requires that prior requests
|
||||||
|
* should have been fully sent over the socket, and their responses should have been fully read from the buffer
|
||||||
|
* before the next request is initiated. i.e. Both read and write buffers should already be empty. Nevertheless,
|
||||||
|
* just in case, we do the following..
|
||||||
|
* <p>
|
||||||
|
* 1) Flush from the read buffer any orphan response data that may have been left over from prior transactions, and
|
||||||
|
* 2) Flush the write buffer directly to the socket to ensure that any exceptions are raised immediately, and the
|
||||||
|
* KLF starts work immediately
|
||||||
*
|
*
|
||||||
* @param packet as Array of bytes to be transmitted towards the bridge via the established connection.
|
* @param packet as Array of bytes to be transmitted towards the bridge via the established connection.
|
||||||
* @throws java.io.IOException in case of a communication I/O failure.
|
* @throws java.io.IOException in case of a communication I/O failure, and sets 'ready' = false
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
synchronized void send(byte[] packet) throws IOException {
|
synchronized void send(byte[] packet) throws IOException {
|
||||||
logger.trace("send() called, writing {} bytes.", packet.length);
|
logger.trace("send() called, writing {} bytes.", packet.length);
|
||||||
if (!ready || (dOut == null)) {
|
try {
|
||||||
|
if (!ready || (dOut == null) || (dIn == null)) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
|
// flush the read buffer if (exceptionally) there is orphan response data in it
|
||||||
|
flushReadBufffer();
|
||||||
|
// copy packet data to the write buffer
|
||||||
dOut.write(packet, 0, packet.length);
|
dOut.write(packet, 0, packet.length);
|
||||||
|
// force the write buffer data to be written to the socket
|
||||||
|
dOut.flush();
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (byte b : packet) {
|
for (byte b : packet) {
|
||||||
|
@ -173,6 +189,10 @@ class SSLconnection {
|
||||||
}
|
}
|
||||||
logger.trace("send() finished after having send {} bytes: {}", packet.length, sb.toString());
|
logger.trace("send() finished after having send {} bytes: {}", packet.length, sb.toString());
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ready = false;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,10 +216,11 @@ class SSLconnection {
|
||||||
* Method to get a message from the bridge.
|
* Method to get a message from the bridge.
|
||||||
*
|
*
|
||||||
* @return <b>packet</b> as Array of bytes as received from the bridge via the established connection.
|
* @return <b>packet</b> as Array of bytes as received from the bridge via the established connection.
|
||||||
* @throws java.io.IOException in case of a communication I/O failure.
|
* @throws java.io.IOException in case of a communication I/O failure, and sets 'ready' = false
|
||||||
*/
|
*/
|
||||||
synchronized byte[] receive() throws IOException {
|
synchronized byte[] receive() throws IOException {
|
||||||
logger.trace("receive() called.");
|
logger.trace("receive() called.");
|
||||||
|
try {
|
||||||
if (!ready || (dIn == null)) {
|
if (!ready || (dIn == null)) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
|
@ -216,6 +237,10 @@ class SSLconnection {
|
||||||
logger.trace("receive() finished after having read {} bytes: {}", messageLength, sb.toString());
|
logger.trace("receive() finished after having read {} bytes: {}", messageLength, sb.toString());
|
||||||
}
|
}
|
||||||
return packet;
|
return packet;
|
||||||
|
} catch (IOException e) {
|
||||||
|
ready = false;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -231,16 +256,19 @@ class SSLconnection {
|
||||||
DataInputStreamWithTimeout dInX = dIn;
|
DataInputStreamWithTimeout dInX = dIn;
|
||||||
if (dInX != null) {
|
if (dInX != null) {
|
||||||
dInX.close();
|
dInX.close();
|
||||||
|
dIn = null;
|
||||||
}
|
}
|
||||||
// Just for avoidance of Potential null pointer access
|
// Just for avoidance of Potential null pointer access
|
||||||
DataOutputStream dOutX = dOut;
|
DataOutputStream dOutX = dOut;
|
||||||
if (dOutX != null) {
|
if (dOutX != null) {
|
||||||
dOutX.close();
|
dOutX.close();
|
||||||
|
dOut = null;
|
||||||
}
|
}
|
||||||
// Just for avoidance of Potential null pointer access
|
// Just for avoidance of Potential null pointer access
|
||||||
SSLSocket socketX = socket;
|
SSLSocket socketX = socket;
|
||||||
if (socketX != null) {
|
if (socketX != null) {
|
||||||
socketX.close();
|
socketX.close();
|
||||||
|
socket = null;
|
||||||
}
|
}
|
||||||
logger.trace("close() finished.");
|
logger.trace("close() finished.");
|
||||||
}
|
}
|
||||||
|
@ -254,4 +282,32 @@ class SSLconnection {
|
||||||
logger.debug("setTimeout() set timeout to {} milliseconds.", timeoutMSecs);
|
logger.debug("setTimeout() set timeout to {} milliseconds.", timeoutMSecs);
|
||||||
ioTimeoutMSecs = timeoutMSecs;
|
ioTimeoutMSecs = timeoutMSecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to flush the input buffer.
|
||||||
|
*
|
||||||
|
* @throws java.io.IOException in case of a communication I/O failure.
|
||||||
|
*/
|
||||||
|
private void flushReadBufffer() throws IOException {
|
||||||
|
logger.trace("flushReadBuffer() called.");
|
||||||
|
DataInputStreamWithTimeout dInX = dIn;
|
||||||
|
if (!ready || (dInX == null)) {
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
int byteCount = dInX.available();
|
||||||
|
if (byteCount > 0) {
|
||||||
|
byte[] byteArray = new byte[byteCount];
|
||||||
|
dInX.readFully(byteArray);
|
||||||
|
if (logger.isTraceEnabled()) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for (byte currByte : byteArray) {
|
||||||
|
stringBuilder.append(String.format("%02X ", currByte));
|
||||||
|
}
|
||||||
|
logger.trace("flushReadBuffer(): discarded {} unexpected bytes in the input buffer: {}", byteCount,
|
||||||
|
stringBuilder.toString());
|
||||||
|
} else {
|
||||||
|
logger.warn("flushReadBuffer(): discarded {} unexpected bytes in the input buffer", byteCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,9 +64,9 @@ public class KLF200Response {
|
||||||
*/
|
*/
|
||||||
public static void errorLogging(Logger logger, short responseCommand) {
|
public static void errorLogging(Logger logger, short responseCommand) {
|
||||||
logger.trace("setResponse(): cannot handle response {} ({}).", Command.get(responseCommand).toString(),
|
logger.trace("setResponse(): cannot handle response {} ({}).", Command.get(responseCommand).toString(),
|
||||||
responseCommand);
|
new CommandNumber(responseCommand).toString());
|
||||||
logger.warn("Gateway response {} ({}) cannot be handled at this point of interaction.",
|
logger.warn("Gateway response {} ({}) cannot be handled at this point of interaction.",
|
||||||
Command.get(responseCommand).toString(), responseCommand);
|
Command.get(responseCommand).toString(), new CommandNumber(responseCommand).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -125,7 +125,7 @@ public class KLF200Response {
|
||||||
logger.trace("check4matchingAnyID() called for request {} {} and response {} {}.", idName, requestID, idName,
|
logger.trace("check4matchingAnyID() called for request {} {} and response {} {}.", idName, requestID, idName,
|
||||||
responseID);
|
responseID);
|
||||||
if (requestID != responseID) {
|
if (requestID != responseID) {
|
||||||
logger.warn("Gateway response with {} {} unexpected as query asked for {} {}.", idName, requestID, idName,
|
logger.warn("Gateway query for {} {} received unexpected response of {} {}.", idName, requestID, idName,
|
||||||
responseID);
|
responseID);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,8 @@ public class SlipEncoding {
|
||||||
private final Logger logger = LoggerFactory.getLogger(SlipEncoding.class);
|
private final Logger logger = LoggerFactory.getLogger(SlipEncoding.class);
|
||||||
|
|
||||||
private static final byte PROTOCOL_ID = 0;
|
private static final byte PROTOCOL_ID = 0;
|
||||||
private static boolean encodingValid = false;
|
private boolean encodingValid = false;
|
||||||
private static byte[] message = new byte[0];
|
private byte[] message = new byte[0];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a message based on command and parameters.
|
* Builds a message based on command and parameters.
|
||||||
|
|
|
@ -14,8 +14,10 @@ package org.openhab.binding.velux.internal.discovery;
|
||||||
|
|
||||||
import static org.openhab.binding.velux.internal.VeluxBindingConstants.*;
|
import static org.openhab.binding.velux.internal.VeluxBindingConstants.*;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||||
import org.openhab.binding.velux.internal.VeluxBindingProperties;
|
import org.openhab.binding.velux.internal.VeluxBindingProperties;
|
||||||
import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler;
|
import org.openhab.binding.velux.internal.handler.VeluxBridgeHandler;
|
||||||
|
@ -60,7 +62,7 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
private @NonNullByDefault({}) LocaleProvider localeProvider;
|
private @NonNullByDefault({}) LocaleProvider localeProvider;
|
||||||
private @NonNullByDefault({}) TranslationProvider i18nProvider;
|
private @NonNullByDefault({}) TranslationProvider i18nProvider;
|
||||||
private Localization localization = Localization.UNKNOWN;
|
private Localization localization = Localization.UNKNOWN;
|
||||||
private static @Nullable VeluxBridgeHandler bridgeHandler = null;
|
private final Set<VeluxBridgeHandler> bridgeHandlers = new HashSet<>();
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
|
@ -102,21 +104,11 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
* Initializes the {@link VeluxDiscoveryService} with a reference to the well-prepared environment with a
|
* Initializes the {@link VeluxDiscoveryService} with a reference to the well-prepared environment with a
|
||||||
* {@link VeluxBridgeHandler}.
|
* {@link VeluxBridgeHandler}.
|
||||||
*
|
*
|
||||||
* @param bridge Initialized Velux bridge handler.
|
|
||||||
* @param localizationHandler Initialized localization handler.
|
* @param localizationHandler Initialized localization handler.
|
||||||
*/
|
*/
|
||||||
public VeluxDiscoveryService(VeluxBridgeHandler bridge, Localization localizationHandler) {
|
public VeluxDiscoveryService(Localization localizationHandler) {
|
||||||
super(VeluxBindingConstants.SUPPORTED_THINGS_ITEMS, DISCOVER_TIMEOUT_SECONDS);
|
super(VeluxBindingConstants.SUPPORTED_THINGS_ITEMS, DISCOVER_TIMEOUT_SECONDS);
|
||||||
logger.trace("VeluxDiscoveryService(bridge={},locale={},i18n={}) just initialized.", bridge, localeProvider,
|
logger.trace("VeluxDiscoveryService(locale={},i18n={}) just initialized.", localeProvider, i18nProvider);
|
||||||
i18nProvider);
|
|
||||||
|
|
||||||
if (bridgeHandler == null) {
|
|
||||||
logger.trace("VeluxDiscoveryService(): registering bridge {} for lateron use for Discovery.", bridge);
|
|
||||||
} else if (!bridge.equals(bridgeHandler)) {
|
|
||||||
logger.trace("VeluxDiscoveryService(): replacing already registered bridge {} by {}.", bridgeHandler,
|
|
||||||
bridge);
|
|
||||||
}
|
|
||||||
bridgeHandler = bridge;
|
|
||||||
localization = localizationHandler;
|
localization = localizationHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,16 +118,14 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
* Initializes the {@link VeluxDiscoveryService} with a reference to the well-prepared environment with a
|
* Initializes the {@link VeluxDiscoveryService} with a reference to the well-prepared environment with a
|
||||||
* {@link VeluxBridgeHandler}.
|
* {@link VeluxBridgeHandler}.
|
||||||
*
|
*
|
||||||
* @param bridge Initialized Velux bridge handler.
|
|
||||||
* @param locationProvider Provider for a location.
|
* @param locationProvider Provider for a location.
|
||||||
* @param localeProvider Provider for a locale.
|
* @param localeProvider Provider for a locale.
|
||||||
* @param i18nProvider Provider for the internationalization.
|
* @param i18nProvider Provider for the internationalization.
|
||||||
*/
|
*/
|
||||||
public VeluxDiscoveryService(VeluxBridgeHandler bridge, LocationProvider locationProvider,
|
public VeluxDiscoveryService(LocationProvider locationProvider, LocaleProvider localeProvider,
|
||||||
LocaleProvider localeProvider, TranslationProvider i18nProvider) {
|
TranslationProvider i18nProvider) {
|
||||||
this(bridge, new Localization(localeProvider, i18nProvider));
|
this(new Localization(localeProvider, i18nProvider));
|
||||||
logger.trace("VeluxDiscoveryService(bridge={},locale={},i18n={}) finished.", bridge, localeProvider,
|
logger.trace("VeluxDiscoveryService(locale={},i18n={}) finished.", localeProvider, i18nProvider);
|
||||||
i18nProvider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -157,8 +147,8 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
logger.debug("startScan(): registering new thing {}.", discoveryResult);
|
logger.debug("startScan(): registering new thing {}.", discoveryResult);
|
||||||
thingDiscovered(discoveryResult);
|
thingDiscovered(discoveryResult);
|
||||||
|
|
||||||
if (bridgeHandler == null) {
|
if (bridgeHandlers.isEmpty()) {
|
||||||
logger.debug("startScan(): VeluxDiscoveryService cannot proceed due to missing Velux bridge.");
|
logger.debug("startScan(): VeluxDiscoveryService cannot proceed due to missing Velux bridge(s).");
|
||||||
} else {
|
} else {
|
||||||
logger.debug("startScan(): Starting Velux discovery scan for scenes and actuators.");
|
logger.debug("startScan(): Starting Velux discovery scan for scenes and actuators.");
|
||||||
discoverScenes();
|
discoverScenes();
|
||||||
|
@ -185,14 +175,9 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
*/
|
*/
|
||||||
private void discoverScenes() {
|
private void discoverScenes() {
|
||||||
logger.trace("discoverScenes() called.");
|
logger.trace("discoverScenes() called.");
|
||||||
// Just for avoidance of Potential null pointer access
|
for (VeluxBridgeHandler bridgeHandlerX : bridgeHandlers) {
|
||||||
VeluxBridgeHandler bridgeHandlerX = bridgeHandler;
|
|
||||||
if (bridgeHandlerX == null) {
|
|
||||||
logger.debug("discoverScenes(): VeluxDiscoveryService.bridgeHandler not initialized, aborting discovery.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ThingUID bridgeUID = bridgeHandlerX.getThing().getUID();
|
ThingUID bridgeUID = bridgeHandlerX.getThing().getUID();
|
||||||
logger.debug("discoverScenes(): discovering all scenes.");
|
logger.debug("discoverScenes(): discovering all scenes on bridge {}.", bridgeUID);
|
||||||
for (VeluxScene scene : bridgeHandlerX.existingScenes().values()) {
|
for (VeluxScene scene : bridgeHandlerX.existingScenes().values()) {
|
||||||
String sceneName = scene.getName().toString();
|
String sceneName = scene.getName().toString();
|
||||||
logger.trace("discoverScenes(): found scene {}.", sceneName);
|
logger.trace("discoverScenes(): found scene {}.", sceneName);
|
||||||
|
@ -209,6 +194,7 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
logger.debug("discoverScenes(): registering new thing {}.", discoveryResult);
|
logger.debug("discoverScenes(): registering new thing {}.", discoveryResult);
|
||||||
thingDiscovered(discoveryResult);
|
thingDiscovered(discoveryResult);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
logger.trace("discoverScenes() finished.");
|
logger.trace("discoverScenes() finished.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,14 +203,9 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
*/
|
*/
|
||||||
private void discoverProducts() {
|
private void discoverProducts() {
|
||||||
logger.trace("discoverProducts() called.");
|
logger.trace("discoverProducts() called.");
|
||||||
// Just for avoidance of Potential null pointer access
|
for (VeluxBridgeHandler bridgeHandlerX : bridgeHandlers) {
|
||||||
VeluxBridgeHandler bridgeHandlerX = bridgeHandler;
|
|
||||||
if (bridgeHandlerX == null) {
|
|
||||||
logger.debug("discoverScenes() VeluxDiscoveryService.bridgeHandlerR not initialized, aborting discovery.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ThingUID bridgeUID = bridgeHandlerX.getThing().getUID();
|
ThingUID bridgeUID = bridgeHandlerX.getThing().getUID();
|
||||||
logger.debug("discoverProducts(): discovering all actuators.");
|
logger.debug("discoverProducts(): discovering all actuators on bridge {}.", bridgeUID);
|
||||||
for (VeluxProduct product : bridgeHandlerX.existingProducts().values()) {
|
for (VeluxProduct product : bridgeHandlerX.existingProducts().values()) {
|
||||||
String serialNumber = product.getSerialNumber();
|
String serialNumber = product.getSerialNumber();
|
||||||
String actuatorName = product.getProductName().toString();
|
String actuatorName = product.getProductName().toString();
|
||||||
|
@ -267,6 +248,42 @@ public class VeluxDiscoveryService extends AbstractDiscoveryService implements R
|
||||||
logger.debug("discoverProducts(): registering new thing {}.", discoveryResult);
|
logger.debug("discoverProducts(): registering new thing {}.", discoveryResult);
|
||||||
thingDiscovered(discoveryResult);
|
thingDiscovered(discoveryResult);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
logger.trace("discoverProducts() finished.");
|
logger.trace("discoverProducts() finished.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a {@link VeluxBridgeHandler} to the {@link VeluxDiscoveryService}
|
||||||
|
*
|
||||||
|
* @param bridge Velux bridge handler.
|
||||||
|
* @return true if the bridge was added, or false if it was already present
|
||||||
|
*/
|
||||||
|
public boolean addBridge(VeluxBridgeHandler bridge) {
|
||||||
|
if (!bridgeHandlers.contains(bridge)) {
|
||||||
|
logger.trace("VeluxDiscoveryService(): registering bridge {} for discovery.", bridge);
|
||||||
|
bridgeHandlers.add(bridge);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
logger.trace("VeluxDiscoveryService(): bridge {} already registered for discovery.", bridge);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a {@link VeluxBridgeHandler} from the {@link VeluxDiscoveryService}
|
||||||
|
*
|
||||||
|
* @param bridge Velux bridge handler.
|
||||||
|
* @return true if the bridge was removed, or false if it was not present
|
||||||
|
*/
|
||||||
|
public boolean removeBridge(VeluxBridgeHandler bridge) {
|
||||||
|
return bridgeHandlers.remove(bridge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the {@link VeluxDiscoveryService} list of {@link VeluxBridgeHandler} is empty
|
||||||
|
*
|
||||||
|
* @return true if empty
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return bridgeHandlers.isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,8 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.velux.internal.factory;
|
package org.openhab.binding.velux.internal.factory;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
@ -32,7 +30,6 @@ import org.openhab.core.i18n.TranslationProvider;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
import org.openhab.core.thing.ThingUID;
|
|
||||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||||
import org.openhab.core.thing.binding.ThingHandler;
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||||
|
@ -56,7 +53,8 @@ public class VeluxHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
// Class internal
|
// Class internal
|
||||||
|
|
||||||
private final Map<ThingUID, ServiceRegistration<?>> discoveryServiceRegistrations = new HashMap<>();
|
private @Nullable ServiceRegistration<?> discoveryServiceRegistration = null;
|
||||||
|
private @Nullable VeluxDiscoveryService discoveryService = null;
|
||||||
|
|
||||||
private Set<VeluxBindingHandler> veluxBindingHandlers = new HashSet<>();
|
private Set<VeluxBindingHandler> veluxBindingHandlers = new HashSet<>();
|
||||||
private Set<VeluxBridgeHandler> veluxBridgeHandlers = new HashSet<>();
|
private Set<VeluxBridgeHandler> veluxBridgeHandlers = new HashSet<>();
|
||||||
|
@ -69,20 +67,25 @@ public class VeluxHandlerFactory extends BaseThingHandlerFactory {
|
||||||
// Private
|
// Private
|
||||||
|
|
||||||
private void registerDeviceDiscoveryService(VeluxBridgeHandler bridgeHandler) {
|
private void registerDeviceDiscoveryService(VeluxBridgeHandler bridgeHandler) {
|
||||||
VeluxDiscoveryService discoveryService = new VeluxDiscoveryService(bridgeHandler, localization);
|
logger.trace("registerDeviceDiscoveryService({}) called.", bridgeHandler);
|
||||||
ServiceRegistration<?> discoveryServiceReg = bundleContext.registerService(DiscoveryService.class.getName(),
|
boolean createNew = (discoveryService == null);
|
||||||
|
if (createNew) {
|
||||||
|
discoveryService = new VeluxDiscoveryService(localization);
|
||||||
|
}
|
||||||
|
discoveryService.addBridge(bridgeHandler);
|
||||||
|
if (createNew) {
|
||||||
|
discoveryServiceRegistration = bundleContext.registerService(DiscoveryService.class.getName(),
|
||||||
discoveryService, new Hashtable<>());
|
discoveryService, new Hashtable<>());
|
||||||
discoveryServiceRegistrations.put(bridgeHandler.getThing().getUID(), discoveryServiceReg);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even if the compiler tells, that the value of <remove> cannot be null, it is possible!
|
private synchronized void unregisterDeviceDiscoveryService(VeluxBridgeHandler bridgeHandler) {
|
||||||
// Therefore a @SuppressWarnings("null") is needed to suppress the warning
|
logger.trace("unregisterDeviceDiscoveryService({}) called.", bridgeHandler);
|
||||||
@SuppressWarnings("null")
|
if (discoveryService != null) {
|
||||||
private synchronized void unregisterDeviceDiscoveryService(ThingUID thingUID) {
|
discoveryService.removeBridge(bridgeHandler);
|
||||||
logger.trace("unregisterDeviceDiscoveryService({}) called.", thingUID);
|
if (discoveryService.isEmpty()) {
|
||||||
ServiceRegistration<?> remove = discoveryServiceRegistrations.remove(thingUID);
|
discoveryServiceRegistration.unregister();
|
||||||
if (remove != null) {
|
}
|
||||||
remove.unregister();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +194,7 @@ public class VeluxHandlerFactory extends BaseThingHandlerFactory {
|
||||||
if (thingHandler instanceof VeluxBridgeHandler) {
|
if (thingHandler instanceof VeluxBridgeHandler) {
|
||||||
logger.trace("removeHandler() removing bridge '{}'.", thingHandler.toString());
|
logger.trace("removeHandler() removing bridge '{}'.", thingHandler.toString());
|
||||||
veluxBridgeHandlers.remove(thingHandler);
|
veluxBridgeHandlers.remove(thingHandler);
|
||||||
unregisterDeviceDiscoveryService(thingHandler.getThing().getUID());
|
unregisterDeviceDiscoveryService((VeluxBridgeHandler) thingHandler);
|
||||||
} else
|
} else
|
||||||
// Handle removal of Things behind the Bridge
|
// Handle removal of Things behind the Bridge
|
||||||
if (thingHandler instanceof VeluxHandler) {
|
if (thingHandler instanceof VeluxHandler) {
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.openhab.binding.velux.internal.VeluxItemType;
|
||||||
import org.openhab.binding.velux.internal.bridge.VeluxBridgeWLANConfig;
|
import org.openhab.binding.velux.internal.bridge.VeluxBridgeWLANConfig;
|
||||||
import org.openhab.binding.velux.internal.handler.utils.StateUtils;
|
import org.openhab.binding.velux.internal.handler.utils.StateUtils;
|
||||||
import org.openhab.binding.velux.internal.handler.utils.ThingProperty;
|
import org.openhab.binding.velux.internal.handler.utils.ThingProperty;
|
||||||
|
import org.openhab.core.library.types.StringType;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -69,16 +70,15 @@ final class ChannelBridgeWLANconfig extends ChannelHandlerTemplate {
|
||||||
if (thisBridgeHandler.bridgeParameters.wlanConfig.isRetrieved) {
|
if (thisBridgeHandler.bridgeParameters.wlanConfig.isRetrieved) {
|
||||||
VeluxItemType itemType = VeluxItemType.getByThingAndChannel(thisBridgeHandler.thingTypeUIDOf(channelUID),
|
VeluxItemType itemType = VeluxItemType.getByThingAndChannel(thisBridgeHandler.thingTypeUIDOf(channelUID),
|
||||||
channelUID.getId());
|
channelUID.getId());
|
||||||
|
String msg = thisBridgeHandler.localization.getText("config.velux.bridge.unAvailable");
|
||||||
switch (itemType) {
|
switch (itemType) {
|
||||||
case BRIDGE_WLANSSID:
|
case BRIDGE_WLANSSID:
|
||||||
newState = StateUtils.createState(thisBridgeHandler.bridgeParameters.lanConfig.openHABipAddress);
|
newState = StateUtils.createState(new StringType(msg));
|
||||||
ThingProperty.setValue(thisBridgeHandler, VeluxBindingConstants.PROPERTY_BRIDGE_WLANSSID,
|
ThingProperty.setValue(thisBridgeHandler, VeluxBindingConstants.PROPERTY_BRIDGE_WLANSSID, msg);
|
||||||
thisBridgeHandler.bridgeParameters.wlanConfig.openHABwlanSSID.toString());
|
|
||||||
break;
|
break;
|
||||||
case BRIDGE_WLANPASSWORD:
|
case BRIDGE_WLANPASSWORD:
|
||||||
newState = StateUtils.createState(thisBridgeHandler.bridgeParameters.lanConfig.openHABsubnetMask);
|
newState = StateUtils.createState(new StringType(msg));
|
||||||
ThingProperty.setValue(thisBridgeHandler, VeluxBindingConstants.PROPERTY_BRIDGE_WLANPASSWORD,
|
ThingProperty.setValue(thisBridgeHandler, VeluxBindingConstants.PROPERTY_BRIDGE_WLANPASSWORD, msg);
|
||||||
thisBridgeHandler.bridgeParameters.wlanConfig.openHABwlanPassword.toString());
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
package org.openhab.binding.velux.internal.handler;
|
package org.openhab.binding.velux.internal.handler;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.velux.internal.VeluxBindingConstants;
|
||||||
import org.openhab.binding.velux.internal.VeluxBindingProperties;
|
import org.openhab.binding.velux.internal.VeluxBindingProperties;
|
||||||
import org.openhab.binding.velux.internal.VeluxItemType;
|
import org.openhab.binding.velux.internal.VeluxItemType;
|
||||||
import org.openhab.binding.velux.internal.handler.utils.ExtendedBaseThingHandler;
|
import org.openhab.binding.velux.internal.handler.utils.ExtendedBaseThingHandler;
|
||||||
|
@ -20,6 +21,7 @@ import org.openhab.binding.velux.internal.handler.utils.StateUtils;
|
||||||
import org.openhab.binding.velux.internal.handler.utils.ThingProperty;
|
import org.openhab.binding.velux.internal.handler.utils.ThingProperty;
|
||||||
import org.openhab.binding.velux.internal.utils.Localization;
|
import org.openhab.binding.velux.internal.utils.Localization;
|
||||||
import org.openhab.binding.velux.internal.utils.ManifestInformation;
|
import org.openhab.binding.velux.internal.utils.ManifestInformation;
|
||||||
|
import org.openhab.core.common.AbstractUID;
|
||||||
import org.openhab.core.thing.Channel;
|
import org.openhab.core.thing.Channel;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
|
@ -82,9 +84,13 @@ public class VeluxBindingHandler extends ExtendedBaseThingHandler {
|
||||||
* @param channelUID for type {@link ChannelUID}.
|
* @param channelUID for type {@link ChannelUID}.
|
||||||
* @return thingTypeUID of type {@link ThingTypeUID}.
|
* @return thingTypeUID of type {@link ThingTypeUID}.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private ThingTypeUID thingTypeUIDOf(ChannelUID channelUID) {
|
private ThingTypeUID thingTypeUIDOf(ChannelUID channelUID) {
|
||||||
return channelUID.getThingUID().getThingTypeUID();
|
String[] segments = channelUID.getAsString().split(AbstractUID.SEPARATOR);
|
||||||
|
if (segments.length > 1) {
|
||||||
|
return new ThingTypeUID(segments[0], segments[1]);
|
||||||
|
}
|
||||||
|
logger.warn("thingTypeUIDOf({}) failed.", channelUID);
|
||||||
|
return new ThingTypeUID(VeluxBindingConstants.BINDING_ID, VeluxBindingConstants.UNKNOWN_THING_TYPE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -49,6 +49,7 @@ import org.openhab.binding.velux.internal.things.VeluxProduct;
|
||||||
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
import org.openhab.binding.velux.internal.things.VeluxProduct.ProductBridgeIndex;
|
||||||
import org.openhab.binding.velux.internal.things.VeluxProductPosition;
|
import org.openhab.binding.velux.internal.things.VeluxProductPosition;
|
||||||
import org.openhab.binding.velux.internal.utils.Localization;
|
import org.openhab.binding.velux.internal.utils.Localization;
|
||||||
|
import org.openhab.core.common.AbstractUID;
|
||||||
import org.openhab.core.common.ThreadPoolManager;
|
import org.openhab.core.common.ThreadPoolManager;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
|
@ -187,9 +188,13 @@ public class VeluxBridgeHandler extends ExtendedBaseBridgeHandler implements Vel
|
||||||
* @param channelUID for type {@link ChannelUID}.
|
* @param channelUID for type {@link ChannelUID}.
|
||||||
* @return thingTypeUID of type {@link ThingTypeUID}.
|
* @return thingTypeUID of type {@link ThingTypeUID}.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
ThingTypeUID thingTypeUIDOf(ChannelUID channelUID) {
|
ThingTypeUID thingTypeUIDOf(ChannelUID channelUID) {
|
||||||
return channelUID.getThingUID().getThingTypeUID();
|
String[] segments = channelUID.getAsString().split(AbstractUID.SEPARATOR);
|
||||||
|
if (segments.length > 1) {
|
||||||
|
return new ThingTypeUID(segments[0], segments[1]);
|
||||||
|
}
|
||||||
|
logger.warn("thingTypeUIDOf({}) failed.", channelUID);
|
||||||
|
return new ThingTypeUID(VeluxBindingConstants.BINDING_ID, VeluxBindingConstants.UNKNOWN_THING_TYPE_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Objects and Methods for interface VeluxBridgeInstance
|
// Objects and Methods for interface VeluxBridgeInstance
|
||||||
|
|
|
@ -129,7 +129,7 @@ public class VeluxKLFAPI {
|
||||||
UNDEFTYPE((short) -1, "Unknown command."),
|
UNDEFTYPE((short) -1, "Unknown command."),
|
||||||
// Special item: Shutdown of the connection
|
// Special item: Shutdown of the connection
|
||||||
GW_OPENHAB_CLOSE((short) -2, "openHAB connection shutdown command."),
|
GW_OPENHAB_CLOSE((short) -2, "openHAB connection shutdown command."),
|
||||||
// Special item: Shutdown of the connection
|
// Special item: Empty Command (used to send nothing and process an incoming message only)
|
||||||
GW_OPENHAB_RECEIVEONLY((short) -3, "openHAB receive command."),
|
GW_OPENHAB_RECEIVEONLY((short) -3, "openHAB receive command."),
|
||||||
// Velux specific commands
|
// Velux specific commands
|
||||||
GW_ERROR_NTF((short) 0x0000, "Provides information on what triggered the error."),
|
GW_ERROR_NTF((short) 0x0000, "Provides information on what triggered the error."),
|
||||||
|
|
|
@ -68,6 +68,7 @@ config.velux.bridge.isSequentialEnforced.label = Enforce Sequential Mode
|
||||||
config.velux.bridge.isSequentialEnforced.description = Enforce Sequential Actuator Control. Determine the mode of operation for long-time actions like running commands or activation of scenes. However the parallelism disables the in-depth protocol handshake processing which does not affect or limit any functionalities.
|
config.velux.bridge.isSequentialEnforced.description = Enforce Sequential Actuator Control. Determine the mode of operation for long-time actions like running commands or activation of scenes. However the parallelism disables the in-depth protocol handshake processing which does not affect or limit any functionalities.
|
||||||
config.velux.bridge.isProtocolTraceEnabled.label = Enable Protocol Trace
|
config.velux.bridge.isProtocolTraceEnabled.label = Enable Protocol Trace
|
||||||
config.velux.bridge.isProtocolTraceEnabled.description = Provide KLF200 protocol details.
|
config.velux.bridge.isProtocolTraceEnabled.description = Provide KLF200 protocol details.
|
||||||
|
config.velux.bridge.unAvailable = Unavailable
|
||||||
#
|
#
|
||||||
config.velux.thing.scene.sceneName.label = Scene Name
|
config.velux.thing.scene.sceneName.label = Scene Name
|
||||||
config.velux.thing.scene.sceneName.description = Name of the scene to be handled.
|
config.velux.thing.scene.sceneName.description = Name of the scene to be handled.
|
||||||
|
|
|
@ -69,6 +69,7 @@ config.velux.bridge.isSequentialEnforced.label = Sequentielles Modus
|
||||||
config.velux.bridge.isSequentialEnforced.description = Erzwingt den sequentiellen Modus von Operationen, insbesondere von länger andauernden Aktionen, wie der Aktivierung von Szenen.
|
config.velux.bridge.isSequentialEnforced.description = Erzwingt den sequentiellen Modus von Operationen, insbesondere von länger andauernden Aktionen, wie der Aktivierung von Szenen.
|
||||||
config.velux.bridge.isProtocolTraceEnabled.label = Protokolleinblick
|
config.velux.bridge.isProtocolTraceEnabled.label = Protokolleinblick
|
||||||
config.velux.bridge.isProtocolTraceEnabled.description = Aktiviert KLF200 Protokolldetails.
|
config.velux.bridge.isProtocolTraceEnabled.description = Aktiviert KLF200 Protokolldetails.
|
||||||
|
config.velux.bridge.unAvailable = Nicht verfügbar
|
||||||
#
|
#
|
||||||
config.velux.thing.scene.sceneName.label = Scenenname
|
config.velux.thing.scene.sceneName.label = Scenenname
|
||||||
config.velux.thing.scene.sceneName.description = Name der Szene, wie sie auf dem Kopplungselements definiert wurde.
|
config.velux.thing.scene.sceneName.description = Name der Szene, wie sie auf dem Kopplungselements definiert wurde.
|
||||||
|
|
|
@ -65,6 +65,7 @@ config.velux.bridge.isSequentialEnforced.label = Håndhæv sekventiel tilstand
|
||||||
config.velux.bridge.isSequentialEnforced.description = Håndhæv sekventiel aktuatorstyring. Bestem driftsmåden for handlinger i lang tid som at køre kommandoer eller aktivering af scener. Paralleliteten deaktiverer imidlertid den dybdegående protokolhåndtryksbehandling, som ikke påvirker eller begrænser nogen funktionaliteter.
|
config.velux.bridge.isSequentialEnforced.description = Håndhæv sekventiel aktuatorstyring. Bestem driftsmåden for handlinger i lang tid som at køre kommandoer eller aktivering af scener. Paralleliteten deaktiverer imidlertid den dybdegående protokolhåndtryksbehandling, som ikke påvirker eller begrænser nogen funktionaliteter.
|
||||||
config.velux.bridge.isProtocolTraceEnabled.label = Protocol Insight
|
config.velux.bridge.isProtocolTraceEnabled.label = Protocol Insight
|
||||||
config.velux.bridge.isProtocolTraceEnabled.description = Aktiverer KLF200-protokoldetaljer.
|
config.velux.bridge.isProtocolTraceEnabled.description = Aktiverer KLF200-protokoldetaljer.
|
||||||
|
config.velux.bridge.unAvailable = Utilgængelig
|
||||||
#
|
#
|
||||||
config.velux.thing.scene.sceneName.label = Scenavn
|
config.velux.thing.scene.sceneName.label = Scenavn
|
||||||
config.velux.thing.scene.sceneName.description = Navn på den scene, der skal håndteres.
|
config.velux.thing.scene.sceneName.description = Navn på den scene, der skal håndteres.
|
||||||
|
|
|
@ -65,6 +65,7 @@ config.velux.bridge.isSequentialEnforced.label = Opeenvolgende modus afdwingen
|
||||||
config.velux.bridge.isSequentialEnforced.description = Handhaving van sequentiële actuatorcontrole. Bepaal de werkingsmodus voor langdurige acties zoals het uitvoeren van opdrachten of het activeren van scènes. Het parallellisme schakelt echter de diepgaande protocolhandshake-verwerking uit die geen enkele functionaliteit beïnvloedt of beperkt.
|
config.velux.bridge.isSequentialEnforced.description = Handhaving van sequentiële actuatorcontrole. Bepaal de werkingsmodus voor langdurige acties zoals het uitvoeren van opdrachten of het activeren van scènes. Het parallellisme schakelt echter de diepgaande protocolhandshake-verwerking uit die geen enkele functionaliteit beïnvloedt of beperkt.
|
||||||
config.velux.bridge.isProtocolTraceEnabled.label = Protocol Insight
|
config.velux.bridge.isProtocolTraceEnabled.label = Protocol Insight
|
||||||
config.velux.bridge.isProtocolTraceEnabled.description = Schakelt KLF200-protocoldetails in.
|
config.velux.bridge.isProtocolTraceEnabled.description = Schakelt KLF200-protocoldetails in.
|
||||||
|
config.velux.bridge.unAvailable = Niet beschikbaar
|
||||||
#
|
#
|
||||||
config.velux.thing.scene.sceneName.label = Scènenaam
|
config.velux.thing.scene.sceneName.label = Scènenaam
|
||||||
config.velux.thing.scene.sceneName.description = Naam van de te behandelen scène.
|
config.velux.thing.scene.sceneName.description = Naam van de te behandelen scène.
|
||||||
|
|
|
@ -280,6 +280,7 @@
|
||||||
<module>org.openhab.binding.valloxmv</module>
|
<module>org.openhab.binding.valloxmv</module>
|
||||||
<module>org.openhab.binding.vektiva</module>
|
<module>org.openhab.binding.vektiva</module>
|
||||||
<module>org.openhab.binding.velbus</module>
|
<module>org.openhab.binding.velbus</module>
|
||||||
|
<module>org.openhab.binding.velux</module>
|
||||||
<module>org.openhab.binding.venstarthermostat</module>
|
<module>org.openhab.binding.venstarthermostat</module>
|
||||||
<module>org.openhab.binding.verisure</module>
|
<module>org.openhab.binding.verisure</module>
|
||||||
<module>org.openhab.binding.vigicrues</module>
|
<module>org.openhab.binding.vigicrues</module>
|
||||||
|
|
|
@ -52,7 +52,6 @@
|
||||||
|
|
||||||
<!-- temporarily exclude add-ons, which are still excluded from the build -->
|
<!-- temporarily exclude add-ons, which are still excluded from the build -->
|
||||||
<exclude name="**/org.openhab.binding.netatmo/**/feature.xml"/>
|
<exclude name="**/org.openhab.binding.netatmo/**/feature.xml"/>
|
||||||
<exclude name="**/org.openhab.binding.velux/**/feature.xml"/>
|
|
||||||
<exclude name="**/org.openhab.io.hueemulation/**/feature.xml"/>
|
<exclude name="**/org.openhab.io.hueemulation/**/feature.xml"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
<filterchain>
|
<filterchain>
|
||||||
|
|
Loading…
Reference in New Issue