added migrated 2.x add-ons
Signed-off-by: Kai Kreuzer <kai@openhab.org>
This commit is contained in:
43
bundles/org.openhab.binding.hue/.classpath
Normal file
43
bundles/org.openhab.binding.hue/.classpath
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" path="target/generated-sources/annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="target/generated-test-sources/test-annotations">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="test" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
23
bundles/org.openhab.binding.hue/.project
Normal file
23
bundles/org.openhab.binding.hue/.project
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openhab.binding.hue</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
13
bundles/org.openhab.binding.hue/NOTICE
Normal file
13
bundles/org.openhab.binding.hue/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
||||
This content is produced and maintained by the openHAB project.
|
||||
|
||||
* Project home: https://www.openhab.org
|
||||
|
||||
== Declared Project Licenses
|
||||
|
||||
This program and the accompanying materials are made available under the terms
|
||||
of the Eclipse Public License 2.0 which is available at
|
||||
https://www.eclipse.org/legal/epl-2.0/.
|
||||
|
||||
== Source Code
|
||||
|
||||
https://github.com/openhab/openhab-addons
|
||||
373
bundles/org.openhab.binding.hue/README.md
Normal file
373
bundles/org.openhab.binding.hue/README.md
Normal file
@@ -0,0 +1,373 @@
|
||||
# Philips Hue Binding
|
||||
|
||||
This binding integrates the [Philips Hue Lighting system](https://www.meethue.com).
|
||||
The integration happens through the Hue bridge, which acts as an IP gateway to the ZigBee devices.
|
||||
|
||||

|
||||
|
||||
## Supported Things
|
||||
|
||||
The Hue bridge is required as a "bridge" for accessing any other Hue device.
|
||||
It supports the ZigBee LightLink protocol as well as the upwards compatible ZigBee 3.0 protocol.
|
||||
There are two types of Hue bridges, generally refered to as v1 (the rounded version) and v2 (the squared version).
|
||||
Only noticable difference between the two generation of bridges is the added support for Apple HomeKit in v2.
|
||||
Both bridges are fully supported by this binding.
|
||||
|
||||
Almost all available Hue devices are supported by this binding.
|
||||
This includes not only the "Friends of Hue", but also products like the LivingWhites adapter.
|
||||
Additionally, it is possible to use OSRAM Lightify devices as well as other ZigBee LightLink compatible products, including the IKEA TRÅDFRI lights (when updated).
|
||||
Beside bulbs and luminaires the Hue binding also supports some ZigBee sensors. Currently only Hue specific sensors are tested successfully (Hue Motion Sensor and Hue Dimmer Switch).
|
||||
Please note that the devices need to be registered with the Hue bridge before it is possible for this binding to use them.
|
||||
|
||||
The Hue binding supports all seven types of lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/documents/user_manual/JN-UG-3091.pdf).
|
||||
These are:
|
||||
|
||||
| Device type | ZigBee Device ID | Thing type |
|
||||
|--------------------------|------------------|------------|
|
||||
| On/Off Light | 0x0000 | 0000 |
|
||||
| On/Off Plug-in Unit | 0x0010 | 0010 |
|
||||
| Dimmable Light | 0x0100 | 0100 |
|
||||
| Dimmable Plug-in Unit | 0x0110 | 0110 |
|
||||
| Colour Light | 0x0200 | 0200 |
|
||||
| Extended Colour Light | 0x0210 | 0210 |
|
||||
| Colour Temperature Light | 0x0220 | 0220 |
|
||||
|
||||
All different models of Hue, OSRAM, or other bulbs nicely fit into one of these seven types.
|
||||
This type also determines the capability of a device and with that the possible ways of interacting with it.
|
||||
The following matrix lists the capabilities (channels) for each type:
|
||||
|
||||
| Thing type | On/Off | Brightness | Color | Color Temperature |
|
||||
|-------------|:------:|:----------:|:-----:|:-----------------:|
|
||||
| 0000 | X | | | |
|
||||
| 0010 | X | | | |
|
||||
| 0100 | X | X | | |
|
||||
| 0110 | X | X | | |
|
||||
| 0200 | X | | X | |
|
||||
| 0210 | X | | X | X |
|
||||
| 0220 | X | X | | X |
|
||||
|
||||
Beside bulbs and luminaires the Hue binding supports some ZigBee sensors.
|
||||
Currently only Hue specific sensors are tested successfully (e.g. Hue Motion Sensor, Hue Dimmer Switch, Hue Tap, CLIP Sensor).
|
||||
The Hue Motion Sensor registers a `ZLLLightLevel` sensor (0106), a `ZLLPresence` sensor (0107) and a `ZLLTemperature` sensor (0302) in one device.
|
||||
The Hue CLIP Sensor saves scene states with status or flag for HUE rules.
|
||||
They are presented by the following ZigBee Device ID and _Thing type_:
|
||||
|
||||
| Device type | ZigBee Device ID | Thing type |
|
||||
|-----------------------------|------------------|------------|
|
||||
| Light Sensor | 0x0106 | 0106 |
|
||||
| Occupancy Sensor | 0x0107 | 0107 |
|
||||
| Temperature Sensor | 0x0302 | 0302 |
|
||||
| Non-Colour Controller | 0x0820 | 0820 |
|
||||
| Non-Colour Scene Controller | 0x0830 | 0830 |
|
||||
| CLIP Generic Status Sensor | 0x0840 | 0840 |
|
||||
| CLIP Generic Flag Sensor | 0x0850 | 0850 |
|
||||
|
||||
The Hue Dimmer Switch has 4 buttons and registers as a Non-Colour Controller switch, while the Hue Tap (also 4 buttons) registers as a Non-Colour Scene Controller in accordance with the ZLL standard.
|
||||
|
||||
Also, Hue bridge support CLIP Generic Status Sensor and CLIP Generic Flag Sensor. These sensors save state for rules and calculate what actions to do. CLIP Sensor set or get by json through IP.
|
||||
|
||||
The type of a specific device can be found in the configuration section for things in the PaperUI.
|
||||
It is part of the unique thing id which could look like:
|
||||
|
||||
```
|
||||
hue:0210:00178810d0dc:1
|
||||
```
|
||||
|
||||
The thing type is the second string behind the first colon and in this example it is **0210**.
|
||||
|
||||
Finally, the Hue binding also supports the groups of lights and rooms set up on the Hue bridge.
|
||||
|
||||
## Discovery
|
||||
|
||||
The Hue bridge is discovered through UPnP in the local network.
|
||||
Once it is added as a Thing, its authentication button (in the middle) needs to be pressed in order to authorize the binding to access it.
|
||||
Once the binding is authorized, it automatically reads all devices and groups that are set up on the Hue bridge and puts them into the Inbox.
|
||||
|
||||
## Thing Configuration
|
||||
|
||||
The Hue bridge requires the IP address as a configuration value in order for the binding to know where to access it.
|
||||
In the thing file, this looks e.g. like
|
||||
|
||||
```
|
||||
Bridge hue:bridge:1 [ ipAddress="192.168.0.64" ]
|
||||
```
|
||||
|
||||
A user to authenticate against the Hue bridge is automatically generated.
|
||||
Please note that the generated user name cannot be written automatically to the `.thing` file, and has to be set manually.
|
||||
The generated user name can be found, after pressing the authentication button on the bridge, with the following console command: `hue <bridgeUID> username`.
|
||||
The user name can be set using the `userName` configuration value, e.g.:
|
||||
|
||||
```
|
||||
Bridge hue:bridge:1 [ ipAddress="192.168.0.64", userName="qwertzuiopasdfghjklyxcvbnm1234" ]
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ipAddress | Network address of the Hue bridge. **Mandatory** |
|
||||
| port | Port of the Hue bridge. Optional, default value is 80 or 443, derived from protocol, otherwise user-defined. |
|
||||
| userName | Name of a registered Hue bridge user, that allows to access the API. **Mandatory** |
|
||||
| pollingInterval | Seconds between fetching light values from the Hue bridge. Optional, the default value is 10 (min="1", step="1"). |
|
||||
| sensorPollingInterval | Milliseconds between fetching sensor-values from the Hue bridge. A higher value means more delay for the sensor values, but a too low value can cause congestion on the bridge. Optional, the default value is 500. Default value will be considered if the value is lower than 50. Use 0 to disable the polling for sensors. |
|
||||
|
||||
### Devices
|
||||
|
||||
The devices are identified by the number that the Hue bridge assigns to them (also shown in the Hue App as an identifier).
|
||||
Thus, all it needs for manual configuration is this single value like
|
||||
|
||||
```
|
||||
0210 bulb1 "Lamp 1" @ "Office" [ lightId="1" ]
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
0107 motion-sensor "Motion Sensor" @ "Entrance" [ sensorId="4" ]
|
||||
```
|
||||
|
||||
You can freely choose the thing identifier (such as motion-sensor), its name (such as "Motion Sensor") and the location (such as "Entrance"). The name will then be used e.g. by Paper UI to show the item.
|
||||
|
||||
The following device types also have an optional configuration value to specify the fade time in milliseconds for the transition to a new state:
|
||||
|
||||
* Dimmable Light
|
||||
* Dimmable Plug-in Unit
|
||||
* Colour Light
|
||||
* Extended Colour Light
|
||||
* Colour Temperature Light
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------------------------------------------------------------------------|
|
||||
| lightId | Number of the device provided by the Hue bridge. **Mandatory** |
|
||||
| fadetime | Fade time in Milliseconds to a new state (min="0", step="100", default="400") |
|
||||
|
||||
|
||||
### Groups
|
||||
|
||||
The groups are identified by the number that the Hue bridge assigns to them.
|
||||
Thus, all it needs for manual configuration is this single value like
|
||||
|
||||
```
|
||||
group kitchen-bulbs "Kitchen Lamps" @ "Kitchen" [ groupId="1" ]
|
||||
```
|
||||
|
||||
You can freely choose the thing identifier (such as kitchen-bulbs), its name (such as "Kitchen Lamps") and the location (such as "Kitchen").
|
||||
The name will then be used e.g. by Paper UI to show the item.
|
||||
|
||||
The group type also have an optional configuration value to specify the fade time in milliseconds for the transition to a new state.
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------------------------------------------------------------------------|
|
||||
| groupId | Number of the group provided by the Hue bridge. **Mandatory** |
|
||||
| fadetime | Fade time in Milliseconds to a new state (min="0", step="100", default="400") |
|
||||
|
||||
|
||||
## Channels
|
||||
|
||||
The devices support some of the following channels:
|
||||
|
||||
| Channel Type ID | Item Type | Description | Thing types supporting this channel |
|
||||
|-------------------|--------------------|-----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------|
|
||||
| switch | Switch | This channel supports switching the device on and off. | 0000, 0010, group |
|
||||
| color | Color | This channel supports full color control with hue, saturation and brightness values. | 0200, 0210, group |
|
||||
| brightness | Dimmer | This channel supports adjusting the brightness value. Note that this is not available, if the color channel is supported. | 0100, 0110, 0220, group |
|
||||
| color_temperature | Dimmer | This channel supports adjusting the color temperature from cold (0%) to warm (100%). | 0210, 0220, group |
|
||||
| alert | String | This channel supports displaying alerts by flashing the bulb either once or multiple times. Valid values are: NONE, SELECT and LSELECT. | 0000, 0100, 0200, 0210, 0220, group |
|
||||
| effect | Switch | This channel supports color looping. | 0200, 0210, 0220 |
|
||||
| dimmer_switch | Number | This channel shows which button was last pressed on the dimmer switch. | 0820 |
|
||||
| illuminance | Number:Illuminance | This channel shows the current illuminance measured by the sensor. | 0106 |
|
||||
| light_level | Number | This channel shows the current light level measured by the sensor. **Advanced** | 0106 |
|
||||
| dark | Switch | This channel indicates whether the light level is below the darkness threshold or not. | 0106 |
|
||||
| daylight | Switch | This channel indicates whether the light level is below the daylight threshold or not. | 0106 |
|
||||
| presence | Switch | This channel indicates whether a motion is detected by the sensor or not. | 0107 |
|
||||
| temperature | Number:Temperature | This channel shows the current temperature measured by the sensor. | 0302 |
|
||||
| flag | Switch | This channel save flag state for a CLIP sensor. | 0850 |
|
||||
| status | Number | This channel save status state for a CLIP sensor. | 0840 |
|
||||
| last_updated | DateTime | This channel the date and time when the sensor was last updated. | 0820, 0830, 0840, 0850, 0106, 0107, 0302|
|
||||
| battery_level | Number | This channel shows the battery level. | 0820, 0106, 0107, 0302 |
|
||||
| battery_low | Switch | This channel indicates whether the battery is low or not. | 0820, 0106, 0107, 0302 |
|
||||
| scene | String | This channel activates the scene with the given ID String. The ID String of each scene is assigned by the Hue bridge. | bridge, group |
|
||||
|
||||
To load a hue scene inside a rule for example, the ID of the scene will be required.
|
||||
You can list all the scene IDs with the following console commands: `hue <bridgeUID> scenes` and `hue <groupThingUID> scenes`.
|
||||
|
||||
### Trigger Channels
|
||||
|
||||
The dimmer switch additionally supports a trigger channel.
|
||||
|
||||
| Channel ID | Description | Thing types supporting this channel |
|
||||
|---------------------|----------------------------------|-------------------------------------|
|
||||
| dimmer_switch_event | Event for dimmer switch pressed. | 0820 |
|
||||
| tap_switch_event | Event for tap switch pressed. | 0830 |
|
||||
|
||||
The `dimmer_switch_event` can trigger one of the following events:
|
||||
|
||||
| Button | State | Event |
|
||||
|---------------------|-----------------|-------|
|
||||
| Button 1 (ON) | INITIAL_PRESSED | 1000 |
|
||||
| | HOLD | 1001 |
|
||||
| | SHORT RELEASED | 1002 |
|
||||
| | LONG RELEASED | 1003 |
|
||||
| Button 2 (DIM UP) | INITIAL_PRESSED | 2000 |
|
||||
| | HOLD | 2001 |
|
||||
| | SHORT RELEASED | 2002 |
|
||||
| | LONG RELEASED | 2003 |
|
||||
| Button 3 (DIM DOWN) | INITIAL_PRESSED | 3000 |
|
||||
| | HOLD | 3001 |
|
||||
| | SHORT RELEASED | 3002 |
|
||||
| | LONG RELEASED | 3003 |
|
||||
| Button 4 (OFF) | INITIAL_PRESSED | 4000 |
|
||||
| | HOLD | 4001 |
|
||||
| | SHORT RELEASED | 4002 |
|
||||
| | LONG RELEASED | 4003 |
|
||||
|
||||
The `tap_switch_event` can trigger one of the following events:
|
||||
|
||||
| Button | State | Event |
|
||||
|----------|----------|-------|
|
||||
| Button 1 | Button 1 | 34 |
|
||||
| Button 2 | Button 2 | 16 |
|
||||
| Button 3 | Button 3 | 17 |
|
||||
| Button 4 | Button 4 | 18 |
|
||||
|
||||
|
||||
## Rule Actions
|
||||
|
||||
This binding includes a rule action, which allows to change a light channel with a specific fading time from within rules.
|
||||
There is a separate instance for each light, which can be retrieved e.g. through
|
||||
|
||||
```
|
||||
val hueActions = getActions("hue","hue:0210:00178810d0dc:1")
|
||||
```
|
||||
|
||||
where the first parameter always has to be `hue` and the second is the full Thing UID of the light that should be used.
|
||||
Once this action instance is retrieved, you can invoke the `fadingLightCommand(String channel, Command command, DecimalType fadeTime)` method on it:
|
||||
|
||||
```
|
||||
hueActions.fadingLightCommand("color", new PercentType(100), new DecimalType(1000))
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|--------------------------------------------------------------------------------------------------|
|
||||
| channel | The following channels have fade time support: **brightness, color, color_temperature, switch** |
|
||||
| command | All commands supported by the channel can be used |
|
||||
| fadeTime | Fade time in Milliseconds to a new light value (min="0", step="100") |
|
||||
|
||||
## Full Example
|
||||
|
||||
In this example **bulb1** is a standard Philips Hue bulb (LCT001) which supports `color` and `color_temperature`.
|
||||
Therefore it is a thing of type **0210**.
|
||||
**bulb2** is an OSRAM tunable white bulb (PAR16 50 TW) supporting `color_temperature` and so the type is **0220**.
|
||||
And there is one Hue Motion Sensor (represented by three devices) and a Hue Dimmer Switch **dimmer-switch** with a Rule to trigger an action when a key has been pressed.
|
||||
|
||||
### demo.things:
|
||||
|
||||
```
|
||||
Bridge hue:bridge:1 "Hue Bridge" [ ipAddress="192.168.0.64" ] {
|
||||
0210 bulb1 "Lamp 1" @ "Kitchen" [ lightId="1" ]
|
||||
0220 bulb2 "Lamp 2" @ "Kitchen" [ lightId="2" ]
|
||||
group kitchen-bulbs "Kitchen Lamps" @ "Kitchen" [ groupId="1" ]
|
||||
0106 light-level-sensor "Light-Sensor" @ "Entrance" [ sensorId="3" ]
|
||||
0107 motion-sensor "Motion-Sensor" @ "Entrance" [ sensorId="4" ]
|
||||
0302 temperature-sensor "Temp-Sensor" @ "Entrance" [ sensorId="5" ]
|
||||
0820 dimmer-switch "Dimmer-Switch" @ "Entrance" [ sensorId="6" ]
|
||||
}
|
||||
```
|
||||
|
||||
### demo.items:
|
||||
|
||||
```
|
||||
// Bulb1
|
||||
Switch Light1_Toggle { channel="hue:0210:1:bulb1:color" }
|
||||
Dimmer Light1_Dimmer { channel="hue:0210:1:bulb1:color" }
|
||||
Color Light1_Color { channel="hue:0210:1:bulb1:color" }
|
||||
Dimmer Light1_ColorTemp { channel="hue:0210:1:bulb1:color_temperature" }
|
||||
String Light1_Alert { channel="hue:0210:1:bulb1:alert" }
|
||||
Switch Light1_Effect { channel="hue:0210:1:bulb1:effect" }
|
||||
|
||||
// Bulb2
|
||||
Switch Light2_Toggle { channel="hue:0220:1:bulb2:brightness" }
|
||||
Dimmer Light2_Dimmer { channel="hue:0220:1:bulb2:brightness" }
|
||||
Dimmer Light2_ColorTemp { channel="hue:0220:1:bulb2:color_temperature" }
|
||||
|
||||
// Kitchen
|
||||
Switch Kitchen_Switch { channel="hue:group:1:kitchen-bulbs:switch" }
|
||||
Dimmer Kitchen_Dimmer { channel="hue:group:1:kitchen-bulbs:brightness" }
|
||||
Color Kitchen_Color { channel="hue:group:1:kitchen-bulbs:color" }
|
||||
Dimmer Kitchen_ColorTemp { channel="hue:group:1:kitchen-bulbs:color_temperature" }
|
||||
|
||||
// Light Level Sensor
|
||||
Number:Illuminance LightLevelSensorIlluminance { channel="hue:0106:1:light-level-sensor:illuminance" }
|
||||
|
||||
// Motion Sensor
|
||||
Switch MotionSensorPresence { channel="hue:0107:1:motion-sensor:presence" }
|
||||
DateTime MotionSensorLastUpdate { channel="hue:0107:1:motion-sensor:last_updated" }
|
||||
Number MotionSensorBatteryLevel { channel="hue:0107:1:motion-sensor:battery_level" }
|
||||
Switch MotionSensorLowBattery { channel="hue:0107:1:motion-sensor:battery_low" }
|
||||
|
||||
// Temperature Sensor
|
||||
Number:Temperature TemperatureSensorTemperature { channel="hue:0302:1:temperature-sensor:temperature" }
|
||||
|
||||
// Scenes
|
||||
String LightScene { channel="hue:bridge:1:scene"}
|
||||
```
|
||||
|
||||
Note: The bridge ID is in this example **1** but can be different in each system.
|
||||
Also, if you are doing all your configuration through files and do not use Paper UI and the Inbox, you may add the full bridge id to the channel definitions (e.g. `channel="hue:0210:00178810d0dc:bulb1:color`) instead of the short version (e.g. `channel="hue:0210:1:bulb1:color`) to prevent frequent discovery messages in the log file.
|
||||
|
||||
### demo.sitemap:
|
||||
|
||||
```
|
||||
sitemap demo label="Main Menu"
|
||||
{
|
||||
Frame {
|
||||
// Bulb1
|
||||
Switch item= Light1_Toggle
|
||||
Slider item= Light1_Dimmer
|
||||
Colorpicker item= Light1_Color
|
||||
Slider item= Light1_ColorTemp
|
||||
Switch item= Light1_Alert mappings=[NONE="None", SELECT="Alert", LSELECT="Long Alert"]
|
||||
Switch item= Light1_Effect
|
||||
|
||||
// Bulb2
|
||||
Switch item= Light2_Toggle
|
||||
Slider item= Light2_Dimmer
|
||||
Slider item= Light2_ColorTemp
|
||||
|
||||
// Kitchen
|
||||
Switch item= Kitchen_Switch
|
||||
Slider item= Kitchen_Dimmer
|
||||
Colorpicker item= Kitchen_Color
|
||||
Slider item= Kitchen_ColorTemp
|
||||
|
||||
// Motion Sensor
|
||||
Switch item=MotionSensorPresence
|
||||
Text item=MotionSensorLastUpdate
|
||||
Text item=MotionSensorBatteryLevel
|
||||
Switch item=MotionSensorLowBattery
|
||||
|
||||
// Light Scenes
|
||||
Default item=LightScene label="Scene []"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
```php
|
||||
rule "example trigger rule"
|
||||
when
|
||||
Channel "hue:0820:1:dimmer-switch:dimmer_switch_event" triggered <EVENT>
|
||||
then
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
The optional `<EVENT>` represents one of the button events that are generated by the Hue Dimmer Switch.
|
||||
If ommited the rule gets triggered by any key action and you can determine the event that triggered it with the `receivedEvent.getEvent()` method.
|
||||
Be aware that the events have a '.0' attached to them, like `2001.0` or `34.0`.
|
||||
So, testing for specific events looks like this:
|
||||
|
||||
```
|
||||
if (receivedEvent.getEvent() == "1000.0")) {
|
||||
//do stuff
|
||||
}
|
||||
```
|
||||
BIN
bundles/org.openhab.binding.hue/doc/hue.jpg
Normal file
BIN
bundles/org.openhab.binding.hue/doc/hue.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
17
bundles/org.openhab.binding.hue/pom.xml
Normal file
17
bundles/org.openhab.binding.hue/pom.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.hue</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: hue Binding</name>
|
||||
|
||||
</project>
|
||||
10
bundles/org.openhab.binding.hue/src/main/feature/feature.xml
Normal file
10
bundles/org.openhab.binding.hue/src/main/feature/feature.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.hue-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.4.0">
|
||||
<repository>mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features</repository>
|
||||
|
||||
<feature name="openhab-binding-hue" description="Hue Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-upnp</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.hue/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Represents the version of the API of the form 1.0 or 1.2.1
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
*/
|
||||
public class ApiVersion {
|
||||
private final int major;
|
||||
private final int minor;
|
||||
private final int micro;
|
||||
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile("^([0-9]+)\\.([0-9]+)(\\.([0-9]+))?$");
|
||||
|
||||
public ApiVersion(int major, int minor, int micro) {
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.micro = micro;
|
||||
}
|
||||
|
||||
public static ApiVersion of(String version) {
|
||||
Matcher matcher = VERSION_PATTERN.matcher(version);
|
||||
if (matcher.matches()) {
|
||||
int major = Integer.parseInt(matcher.group(1));
|
||||
int minor = Integer.parseInt(matcher.group(2));
|
||||
String microString = matcher.group(4);
|
||||
int micro = Integer.parseInt(microString == null ? "0" : microString);
|
||||
|
||||
ApiVersion apiVersion = new ApiVersion(major, minor, micro);
|
||||
return apiVersion;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Version \"" + version + "\" is not valid");
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the major version part of the version
|
||||
*
|
||||
* @return the major part of the version
|
||||
*/
|
||||
public int getMajor() {
|
||||
return major;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the minor version part of the version
|
||||
*
|
||||
* @return the minor part of the version
|
||||
*/
|
||||
public int getMinor() {
|
||||
return minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the micro version part of the version
|
||||
*
|
||||
* @return the micro part of the version
|
||||
*/
|
||||
public int getMicro() {
|
||||
return micro;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare API versions according to {@link Comparator#compare(Object, Object)}
|
||||
*
|
||||
* @param other
|
||||
* @return
|
||||
*/
|
||||
public int compare(ApiVersion other) {
|
||||
int c = Integer.compare(major, other.major);
|
||||
if (c == 0) {
|
||||
c = Integer.compare(minor, other.minor);
|
||||
if (c == 0) {
|
||||
c = Integer.compare(micro, other.micro);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + major;
|
||||
result = prime * result + micro;
|
||||
result = prime * result + minor;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ApiVersion other = (ApiVersion) obj;
|
||||
if (major != other.major) {
|
||||
return false;
|
||||
}
|
||||
if (micro != other.micro) {
|
||||
return false;
|
||||
}
|
||||
if (minor != other.minor) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return major + "." + minor + "." + micro;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ApiVersionUtils {
|
||||
|
||||
private static ApiVersion fullLights = new ApiVersion(1, 11, 0);
|
||||
|
||||
/**
|
||||
* Starting from version 1.11, <code>GET</code>ing the Lights always returns {@link FullLight}s instead of
|
||||
* {@link HueObject}s.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean supportsFullLights(ApiVersion version) {
|
||||
return fullLights.compare(version) <= 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
/**
|
||||
* Collection of updates to the bridge configuration.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding, minor code cleanup
|
||||
* @author Samuel Leisering - added Sensor support
|
||||
*/
|
||||
public class BridgeConfigUpdate extends ConfigUpdate {
|
||||
/**
|
||||
* Set the port of the proxy or null if there is no proxy.
|
||||
*
|
||||
* @param port port for proxy
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setProxyPort(Integer port) {
|
||||
if (port != null && port < 0) {
|
||||
throw new IllegalArgumentException("Invalid value for port");
|
||||
}
|
||||
|
||||
commands.add(new Command("proxyport", port == null ? 0 : port));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the bridge, which also functions as the UPnP name.
|
||||
*
|
||||
* @param name new name [4..16]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setName(String name) {
|
||||
if (Util.stringSize(name) < 4 || Util.stringSize(name) > 16) {
|
||||
throw new IllegalArgumentException("Bridge name must be between 4 and 16 characters long");
|
||||
}
|
||||
|
||||
commands.add(new Command("name", name));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address of the proxy or null if there is no proxy.
|
||||
*
|
||||
* @param ip ip of proxy
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setProxyAddress(String ip) {
|
||||
if (ip != null && Util.stringSize(ip) > 40) {
|
||||
throw new IllegalArgumentException("Bridge proxy address can be at most 40 characters long");
|
||||
}
|
||||
|
||||
commands.add(new Command("proxyaddress", ip == null ? "none" : ip));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the link button has been pressed within the last 30 seconds or not.
|
||||
*
|
||||
* @param pressed true for pressed, false for not pressed
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setLinkButton(boolean pressed) {
|
||||
commands.add(new Command("linkbutton", pressed));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IP address of the bridge.
|
||||
*
|
||||
* @param ip ip address of bridge
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setIPAddress(String ip) {
|
||||
commands.add(new Command("ipaddress", ip));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the network mask of the bridge.
|
||||
*
|
||||
* @param netmask network mask
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setNetworkMask(String netmask) {
|
||||
commands.add(new Command("netmask", netmask));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the gateway address of the bridge.
|
||||
*
|
||||
* @param ip gateway address
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setGateway(String ip) {
|
||||
commands.add(new Command("gateway", ip));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the bridge uses DHCP to get an ip address or not.
|
||||
*
|
||||
* @param enabled dhcp enabled
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public BridgeConfigUpdate setDHCP(boolean enabled) {
|
||||
commands.add(new Command("dhcp", enabled));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
* @author Samuel Leisering - changed Command visibility to public
|
||||
*/
|
||||
public class Command {
|
||||
String key;
|
||||
Object value;
|
||||
|
||||
public Command(String key, Object value) {
|
||||
this.key = key;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
String toJson() {
|
||||
return "\"" + key + "\":" + new Gson().toJson(value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Detailed bridge info available if authenticated.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding, minor code cleanup
|
||||
* @author Samuel Leisering - added API-Version
|
||||
*/
|
||||
public class Config {
|
||||
private String name;
|
||||
private String swversion;
|
||||
private String apiversion;
|
||||
private String bridgeid;
|
||||
private String mac;
|
||||
private String modelid;
|
||||
private boolean dhcp;
|
||||
private String ipaddress;
|
||||
private String netmask;
|
||||
private String gateway;
|
||||
private String proxyaddress;
|
||||
private int proxyport;
|
||||
private Date UTC;
|
||||
private boolean linkbutton;
|
||||
private Map<String, User> whitelist;
|
||||
private SoftwareUpdate swupdate;
|
||||
|
||||
Config() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name.
|
||||
*
|
||||
* @return name of the bridge
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of the software.
|
||||
*
|
||||
* @return version of software on the bridge
|
||||
*/
|
||||
public String getSoftwareVersion() {
|
||||
return swversion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bridge id
|
||||
*
|
||||
* @return bridge id
|
||||
*/
|
||||
public String getBridgeId() {
|
||||
return bridgeid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MAC address.
|
||||
*
|
||||
* @return mac address of bridge
|
||||
*/
|
||||
public String getMACAddress() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the model id
|
||||
*
|
||||
* @return model id
|
||||
*/
|
||||
public String getModelId() {
|
||||
return modelid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the current IP address was obtained with DHCP.
|
||||
*
|
||||
* @return true if the current IP address was obtained with DHCP, false otherwise.
|
||||
*/
|
||||
public boolean isDHCPEnabled() {
|
||||
return dhcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IP address.
|
||||
*
|
||||
* @return ip address of bridge
|
||||
*/
|
||||
public String getIPAddress() {
|
||||
return ipaddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the network mask.
|
||||
*
|
||||
* @return network mask
|
||||
*/
|
||||
public String getNetworkMask() {
|
||||
return netmask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IP address of the gateway.
|
||||
*
|
||||
* @return ip address of gateway
|
||||
*/
|
||||
public String getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IP address of the proxy or null if there is none.
|
||||
*
|
||||
* @return ip address of proxy or null
|
||||
*/
|
||||
public String getProxyAddress() {
|
||||
return proxyaddress.equals("none") ? null : proxyaddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port of the proxy or null if there is none.
|
||||
*
|
||||
* @return port of proxy or null
|
||||
*/
|
||||
public Integer getProxyPort() {
|
||||
return proxyaddress.equals("none") ? null : proxyport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time on the bridge.
|
||||
*
|
||||
* @return time on the bridge
|
||||
*/
|
||||
public Date getUTCTime() {
|
||||
return UTC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the link button has been pressed within the last 30 seconds.
|
||||
*
|
||||
* @return true if the link button has been pressed within the last 30 seconds, false otherwise
|
||||
*/
|
||||
public boolean isLinkButtonPressed() {
|
||||
return linkbutton;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of whitelisted users.
|
||||
*
|
||||
* @return list of whitelisted users
|
||||
*/
|
||||
public List<User> getWhitelist() {
|
||||
ArrayList<User> usersList = new ArrayList<>();
|
||||
|
||||
usersList.addAll(whitelist.values());
|
||||
|
||||
return usersList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about a bridge firmware update.
|
||||
*
|
||||
* @return bridge firmware update info
|
||||
*/
|
||||
public SoftwareUpdate getSoftwareUpdate() {
|
||||
return swupdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current API-Version of the Bridge. This always returns <code>1.0</code>
|
||||
* for bridges with version less than <code>1.2.1</code>, which introduces this call.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getApiVersion() {
|
||||
if (apiversion == null) {
|
||||
return "1.0";
|
||||
}
|
||||
return apiversion;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static java.util.stream.Collectors.joining;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Collection of updates
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding, minor code cleanup
|
||||
* @author Samuel Leisering - Added support for sensor API
|
||||
* @author Christoph Weitkamp - Added support for sensor API
|
||||
*/
|
||||
public class ConfigUpdate {
|
||||
|
||||
protected final ArrayList<Command> commands = new ArrayList<>();
|
||||
|
||||
public ConfigUpdate() {
|
||||
super();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return commands.isEmpty();
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
return commands.stream().map(c -> c.toJson()).collect(joining(",", "{", "}"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message delay recommended by Philips
|
||||
* Regarding to this article: https://developers.meethue.com/documentation/hue-system-performance
|
||||
*/
|
||||
public long getMessageDelay() {
|
||||
return commands.size() * 40L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
class CreateScheduleRequest {
|
||||
private String name;
|
||||
private String description;
|
||||
private ScheduleCommand command;
|
||||
private Date time;
|
||||
|
||||
public CreateScheduleRequest(String name, String description, ScheduleCommand command, Date time) {
|
||||
if (name != null && Util.stringSize(name) > 32) {
|
||||
throw new IllegalArgumentException("Schedule name can be at most 32 characters long");
|
||||
}
|
||||
|
||||
if (description != null && Util.stringSize(description) > 64) {
|
||||
throw new IllegalArgumentException("Schedule description can be at most 64 characters long");
|
||||
}
|
||||
|
||||
if (command == null) {
|
||||
throw new IllegalArgumentException("No schedule command specified");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
this.command = command;
|
||||
this.time = time;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
class CreateUserRequest {
|
||||
private String username;
|
||||
private String devicetype;
|
||||
|
||||
public CreateUserRequest(String username, String devicetype) {
|
||||
if (Util.stringSize(devicetype) > 40) {
|
||||
throw new IllegalArgumentException("Device type can be at most 40 characters long");
|
||||
}
|
||||
|
||||
if (Util.stringSize(username) < 10 || Util.stringSize(username) > 40) {
|
||||
throw new IllegalArgumentException("Username must be between 10 and 40 characters long");
|
||||
}
|
||||
|
||||
this.username = username;
|
||||
this.devicetype = devicetype;
|
||||
}
|
||||
|
||||
public CreateUserRequest(String devicetype) {
|
||||
if (Util.stringSize(devicetype) > 40) {
|
||||
throw new IllegalArgumentException("Device type can be at most 40 characters long");
|
||||
}
|
||||
|
||||
this.devicetype = devicetype;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
class ErrorResponse {
|
||||
public static final Type GSON_TYPE = new TypeToken<List<ErrorResponse>>() {
|
||||
}.getType();
|
||||
|
||||
public class Error {
|
||||
private Integer type;
|
||||
private String address;
|
||||
private String description;
|
||||
}
|
||||
|
||||
private Error error;
|
||||
|
||||
public Integer getType() {
|
||||
if (error == null) {
|
||||
return null;
|
||||
}
|
||||
return error.type;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
if (error == null) {
|
||||
return null;
|
||||
}
|
||||
return error.address;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
if (error == null) {
|
||||
return null;
|
||||
}
|
||||
return error.description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Container for all data on a bridge.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
public class FullConfig {
|
||||
private Map<String, FullLight> lights;
|
||||
private Map<String, FullGroup> groups;
|
||||
private Config config;
|
||||
|
||||
/**
|
||||
* Returns detailed information about all lights known to the bridge.
|
||||
*
|
||||
* @return detailed lights list
|
||||
*/
|
||||
public List<FullLight> getLights() {
|
||||
ArrayList<FullLight> lightsList = new ArrayList<>();
|
||||
|
||||
for (String id : lights.keySet()) {
|
||||
FullLight light = lights.get(id);
|
||||
light.setId(id);
|
||||
lightsList.add(light);
|
||||
}
|
||||
|
||||
return lightsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns detailed information about all groups on the bridge.
|
||||
*
|
||||
* @return detailed groups list
|
||||
*/
|
||||
public List<FullGroup> getGroups() {
|
||||
ArrayList<FullGroup> groupsList = new ArrayList<>();
|
||||
|
||||
for (String id : groups.keySet()) {
|
||||
FullGroup group = groups.get(id);
|
||||
group.setId(id);
|
||||
groupsList.add(group);
|
||||
}
|
||||
|
||||
return groupsList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns bridge configuration.
|
||||
* Use HueBridge.getConfig() if you only need this.
|
||||
*
|
||||
* @return bridge configuration
|
||||
*/
|
||||
public Config getConfig() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Detailed group information.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
* @author Laurent Garnier - field state added
|
||||
*/
|
||||
public class FullGroup extends Group {
|
||||
public static final Type GSON_TYPE = new TypeToken<Map<String, FullGroup>>() {
|
||||
}.getType();
|
||||
|
||||
private State action;
|
||||
private List<String> lights;
|
||||
private State groupState; // Will not be set by hue API
|
||||
|
||||
FullGroup() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test constructor
|
||||
*/
|
||||
FullGroup(String id, String name, String type, State action, List<String> lights, State state) {
|
||||
super(id, name, type);
|
||||
this.action = action;
|
||||
this.lights = lights;
|
||||
this.groupState = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last sent state update to the group.
|
||||
* This does not have to reflect the current state of the group.
|
||||
*
|
||||
* @return last state update
|
||||
*/
|
||||
public State getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of the lights in the group.
|
||||
*
|
||||
* @return lights in the group
|
||||
*/
|
||||
public List<String> getLightIds() {
|
||||
return lights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current state of the group.
|
||||
*
|
||||
* @return current state
|
||||
*/
|
||||
public State getState() {
|
||||
return groupState;
|
||||
}
|
||||
|
||||
public void setState(State state) {
|
||||
this.groupState = state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.NORMALIZE_ID_REGEX;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Detailed information about an object on the hue bridge
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class FullHueObject extends HueObject {
|
||||
|
||||
private @NonNullByDefault({}) String type;
|
||||
private @Nullable String modelid;
|
||||
@SerializedName("manufacturername")
|
||||
private @NonNullByDefault({}) String manufacturerName;
|
||||
@SerializedName("productname")
|
||||
private @NonNullByDefault({}) String productName;
|
||||
private @Nullable String swversion;
|
||||
private @Nullable String uniqueid;
|
||||
|
||||
public FullHueObject() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the object.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of the object.
|
||||
*/
|
||||
protected void setType(final String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the model ID of the object.
|
||||
*
|
||||
* @return model id
|
||||
*/
|
||||
public @Nullable String getModelID() {
|
||||
return modelid;
|
||||
}
|
||||
|
||||
public @Nullable String getNormalizedModelID() {
|
||||
return modelid != null ? modelid.replaceAll(NORMALIZE_ID_REGEX, "_") : modelid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the model ID of the object.
|
||||
*/
|
||||
protected void setModelID(final String modelId) {
|
||||
this.modelid = modelId;
|
||||
}
|
||||
|
||||
public String getManufacturerName() {
|
||||
return manufacturerName;
|
||||
}
|
||||
|
||||
public void setManufacturerName(String manufacturerName) {
|
||||
this.manufacturerName = manufacturerName;
|
||||
}
|
||||
|
||||
public String getProductName() {
|
||||
return productName;
|
||||
}
|
||||
|
||||
public void setProductName(String productName) {
|
||||
this.productName = productName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the software version of the object.
|
||||
*
|
||||
* @return software version
|
||||
*/
|
||||
public @Nullable String getSoftwareVersion() {
|
||||
return swversion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique id of the object. The unique is the MAC address of the device with a unique endpoint id in the
|
||||
* form: AA:BB:CC:DD:EE:FF:00:11-XX
|
||||
*
|
||||
* @return the unique id, can be null for some virtual types like the daylight sensor
|
||||
*/
|
||||
|
||||
public @Nullable String getUniqueID() {
|
||||
return uniqueid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Detailed light information.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Thomas Höfer - added unique id and changed range check for brightness and saturation
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
* @author Samuel Leisering - added GSon Type to FullLight, refactored content to {@link FullHueObject}
|
||||
*/
|
||||
public class FullLight extends FullHueObject {
|
||||
public static final Type GSON_TYPE = new TypeToken<Map<String, FullLight>>() {
|
||||
}.getType();
|
||||
|
||||
private State state;
|
||||
private final long fadetime = 400; // milliseconds
|
||||
|
||||
FullLight() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current state of the light.
|
||||
*
|
||||
* @return current state
|
||||
*/
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public Duration getFadeTime() {
|
||||
return Duration.ofMillis(fadetime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Detailed schedule information.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
public class FullSchedule extends Schedule {
|
||||
private String description;
|
||||
private ScheduleCommand command; // Not really appropriate for exposure
|
||||
private Date time;
|
||||
|
||||
/**
|
||||
* Returns the description of the schedule.
|
||||
*
|
||||
* @return description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scheduled command.
|
||||
*
|
||||
* @return command
|
||||
*/
|
||||
public ScheduleCommand getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time for which the command is scheduled to be ran.
|
||||
*
|
||||
* @return scheduled time
|
||||
*/
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Detailed sensor information
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class FullSensor extends FullHueObject {
|
||||
|
||||
public static final String STATE_LAST_UPDATED = "lastupdated";
|
||||
public static final String STATE_BUTTON_EVENT = "buttonevent";
|
||||
public static final String STATE_PRESENCE = "presence";
|
||||
public static final String STATE_TEMPERATURE = "temperature";
|
||||
public static final String STATE_LIGHT_LEVEL = "lightlevel";
|
||||
public static final String STATE_DARK = "dark";
|
||||
public static final String STATE_DAYLIGHT = "daylight";
|
||||
public static final String STATE_STATUS = "status";
|
||||
public static final String STATE_FLAG = "flag";
|
||||
|
||||
public static final String CONFIG_REACHABLE = "reachable";
|
||||
public static final String CONFIG_BATTERY = "battery";
|
||||
public static final String CONFIG_ON = "on";
|
||||
public static final String CONFIG_LED_INDICATION = "ledindication";
|
||||
|
||||
public static final String CONFIG_PRESENCE_SENSITIVITY = "sensitivity";
|
||||
public static final String CONFIG_PRESENCE_SENSITIVITY_MAX = "sensitivitymax";
|
||||
|
||||
public static final String CONFIG_LIGHT_LEVEL_THRESHOLD_DARK = "tholddark";
|
||||
public static final String CONFIG_LIGHT_LEVEL_THRESHOLD_OFFSET = "tholdoffset";
|
||||
|
||||
public static final Type GSON_TYPE = new TypeToken<Map<String, FullSensor>>() {
|
||||
}.getType();
|
||||
|
||||
private Map<String, Object> state;
|
||||
private Map<String, Object> config;
|
||||
|
||||
public Map<String, Object> getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public Map<String, Object> getConfig() {
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
/**
|
||||
* Basic group information.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
* @author Laurent Garnier - field type added
|
||||
*/
|
||||
public class Group {
|
||||
private String id;
|
||||
private String name;
|
||||
private String type;
|
||||
|
||||
Group() {
|
||||
this.id = "0";
|
||||
this.name = "Lightset 0";
|
||||
this.type = "LightGroup";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test constructor
|
||||
*/
|
||||
Group(String id, String name, String type) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the group can be modified.
|
||||
* Currently only returns false for the all lights pseudo group.
|
||||
*
|
||||
* @return modifiability of group
|
||||
*/
|
||||
public boolean isModifiable() {
|
||||
return !id.equals("0");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the group.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the group.
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tyoe of the group.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HttpClient {
|
||||
private int timeout = 1000;
|
||||
private final Logger logger = LoggerFactory.getLogger(HttpClient.class);
|
||||
private final LinkedList<AsyncPutParameters> commandsQueue = new LinkedList<>();
|
||||
private @Nullable Future<?> job;
|
||||
|
||||
@SuppressWarnings({ "null", "unused" })
|
||||
private void executeCommands() {
|
||||
while (true) {
|
||||
try {
|
||||
long delayTime = 0;
|
||||
synchronized (commandsQueue) {
|
||||
AsyncPutParameters payloadCallbackPair = commandsQueue.poll();
|
||||
if (payloadCallbackPair != null) {
|
||||
logger.debug("Async sending put to address: {} delay: {} body: {}", payloadCallbackPair.address,
|
||||
payloadCallbackPair.delay, payloadCallbackPair.body);
|
||||
try {
|
||||
Result result = put(payloadCallbackPair.address, payloadCallbackPair.body);
|
||||
payloadCallbackPair.future.complete(result);
|
||||
} catch (IOException e) {
|
||||
payloadCallbackPair.future.completeExceptionally(e);
|
||||
}
|
||||
delayTime = payloadCallbackPair.delay;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Thread.sleep(delayTime);
|
||||
} catch (InterruptedException e) {
|
||||
logger.debug("commandExecutorThread was interrupted", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setTimeout(int timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public Result get(String address) throws IOException {
|
||||
return doNetwork(address, "GET");
|
||||
}
|
||||
|
||||
public Result post(String address, String body) throws IOException {
|
||||
return doNetwork(address, "POST", body);
|
||||
}
|
||||
|
||||
public Result put(String address, String body) throws IOException {
|
||||
return doNetwork(address, "PUT", body);
|
||||
}
|
||||
|
||||
public CompletableFuture<Result> putAsync(String address, String body, long delay,
|
||||
ScheduledExecutorService scheduler) {
|
||||
AsyncPutParameters asyncPutParameters = new AsyncPutParameters(address, body, delay);
|
||||
|
||||
synchronized (commandsQueue) {
|
||||
if (commandsQueue.isEmpty()) {
|
||||
commandsQueue.offer(asyncPutParameters);
|
||||
if (job == null || job.isDone()) {
|
||||
job = scheduler.submit(this::executeCommands);
|
||||
}
|
||||
} else {
|
||||
commandsQueue.offer(asyncPutParameters);
|
||||
}
|
||||
}
|
||||
|
||||
return asyncPutParameters.future;
|
||||
}
|
||||
|
||||
public Result delete(String address) throws IOException {
|
||||
return doNetwork(address, "DELETE");
|
||||
}
|
||||
|
||||
protected Result doNetwork(String address, String requestMethod) throws IOException {
|
||||
return doNetwork(address, requestMethod, null);
|
||||
}
|
||||
|
||||
protected Result doNetwork(String address, String requestMethod, @Nullable String body) throws IOException {
|
||||
HttpURLConnection conn = (HttpURLConnection) new URL(address).openConnection();
|
||||
try {
|
||||
conn.setRequestMethod(requestMethod);
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setConnectTimeout(timeout);
|
||||
conn.setReadTimeout(timeout);
|
||||
|
||||
if (body != null && !"".equals(body)) {
|
||||
conn.setDoOutput(true);
|
||||
try (Writer out = new OutputStreamWriter(conn.getOutputStream())) {
|
||||
out.write(body);
|
||||
}
|
||||
}
|
||||
|
||||
try (InputStream in = conn.getInputStream(); ByteArrayOutputStream result = new ByteArrayOutputStream()) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = in.read(buffer)) != -1) {
|
||||
result.write(buffer, 0, length);
|
||||
}
|
||||
return new Result(result.toString(StandardCharsets.UTF_8.name()), conn.getResponseCode());
|
||||
}
|
||||
} finally {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
private final String body;
|
||||
private final int responseCode;
|
||||
|
||||
public Result(String body, int responseCode) {
|
||||
this.body = body;
|
||||
this.responseCode = responseCode;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public int getResponseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
}
|
||||
|
||||
public final class AsyncPutParameters {
|
||||
public final String address;
|
||||
public final String body;
|
||||
public final CompletableFuture<Result> future;
|
||||
public final long delay;
|
||||
|
||||
public AsyncPutParameters(String address, String body, long delay) {
|
||||
this.address = address;
|
||||
this.body = body;
|
||||
this.future = new CompletableFuture<>();
|
||||
this.delay = delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link HueBindingConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
* @author Jochen Hiller - Added OSRAM Classic A60 RGBW
|
||||
* @author Markus Mazurczak - Added OSRAM PAR16 50
|
||||
* @author Andre Fuechsel - changed to generic thing types
|
||||
* @author Samuel Leisering - Added support for sensor API
|
||||
* @author Christoph Weitkamp - Added support for sensor API
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueBindingConstants {
|
||||
|
||||
public static final String BINDING_ID = "hue";
|
||||
|
||||
// List all Thing Type UIDs, related to the Hue Binding
|
||||
|
||||
// bridge
|
||||
public static final ThingTypeUID THING_TYPE_BRIDGE = new ThingTypeUID(BINDING_ID, "bridge");
|
||||
|
||||
// generic thing types
|
||||
public static final ThingTypeUID THING_TYPE_ON_OFF_LIGHT = new ThingTypeUID(BINDING_ID, "0000");
|
||||
public static final ThingTypeUID THING_TYPE_ON_OFF_PLUG = new ThingTypeUID(BINDING_ID, "0010");
|
||||
public static final ThingTypeUID THING_TYPE_COLOR_LIGHT = new ThingTypeUID(BINDING_ID, "0200");
|
||||
public static final ThingTypeUID THING_TYPE_COLOR_TEMPERATURE_LIGHT = new ThingTypeUID(BINDING_ID, "0220");
|
||||
public static final ThingTypeUID THING_TYPE_EXTENDED_COLOR_LIGHT = new ThingTypeUID(BINDING_ID, "0210");
|
||||
public static final ThingTypeUID THING_TYPE_DIMMABLE_LIGHT = new ThingTypeUID(BINDING_ID, "0100");
|
||||
public static final ThingTypeUID THING_TYPE_DIMMABLE_PLUG = new ThingTypeUID(BINDING_ID, "0110");
|
||||
|
||||
public static final ThingTypeUID THING_TYPE_DIMMER_SWITCH = new ThingTypeUID(BINDING_ID, "0820");
|
||||
public static final ThingTypeUID THING_TYPE_TAP_SWITCH = new ThingTypeUID(BINDING_ID, "0830");
|
||||
public static final ThingTypeUID THING_TYPE_CLIP_GENERIC_STATUS = new ThingTypeUID(BINDING_ID, "0840");
|
||||
public static final ThingTypeUID THING_TYPE_CLIP_GENERIC_FLAG = new ThingTypeUID(BINDING_ID, "0850");
|
||||
public static final ThingTypeUID THING_TYPE_PRESENCE_SENSOR = new ThingTypeUID(BINDING_ID, "0107");
|
||||
public static final ThingTypeUID THING_TYPE_TEMPERATURE_SENSOR = new ThingTypeUID(BINDING_ID, "0302");
|
||||
public static final ThingTypeUID THING_TYPE_LIGHT_LEVEL_SENSOR = new ThingTypeUID(BINDING_ID, "0106");
|
||||
|
||||
public static final ThingTypeUID THING_TYPE_GROUP = new ThingTypeUID(BINDING_ID, "group");
|
||||
|
||||
// List all channels
|
||||
public static final String CHANNEL_COLORTEMPERATURE = "color_temperature";
|
||||
public static final String CHANNEL_COLOR = "color";
|
||||
public static final String CHANNEL_BRIGHTNESS = "brightness";
|
||||
public static final String CHANNEL_ALERT = "alert";
|
||||
public static final String CHANNEL_EFFECT = "effect";
|
||||
public static final String CHANNEL_SWITCH = "switch";
|
||||
public static final String CHANNEL_DIMMER_SWITCH = "dimmer_switch";
|
||||
public static final String CHANNEL_TAP_SWITCH = "tap_switch";
|
||||
public static final String CHANNEL_PRESENCE = "presence";
|
||||
public static final String CHANNEL_TEMPERATURE = "temperature";
|
||||
public static final String CHANNEL_LAST_UPDATED = "last_updated";
|
||||
public static final String CHANNEL_BATTERY_LEVEL = "battery_level";
|
||||
public static final String CHANNEL_BATTERY_LOW = "battery_low";
|
||||
public static final String CHANNEL_ILLUMINANCE = "illuminance";
|
||||
public static final String CHANNEL_LIGHT_LEVEL = "light_level";
|
||||
public static final String CHANNEL_DARK = "dark";
|
||||
public static final String CHANNEL_DAYLIGHT = "daylight";
|
||||
public static final String CHANNEL_STATUS = "status";
|
||||
public static final String CHANNEL_FLAG = "flag";
|
||||
public static final String CHANNEL_SCENE = "scene";
|
||||
|
||||
// List all triggers
|
||||
public static final String EVENT_DIMMER_SWITCH = "dimmer_switch_event";
|
||||
public static final String EVENT_TAP_SWITCH = "tap_switch_event";
|
||||
|
||||
// Bridge config properties
|
||||
public static final String HOST = "ipAddress";
|
||||
public static final String PORT = "port";
|
||||
public static final String PROTOCOL = "protocol";
|
||||
public static final String USER_NAME = "userName";
|
||||
|
||||
// Thing configuration properties
|
||||
public static final String LIGHT_ID = "lightId";
|
||||
public static final String SENSOR_ID = "sensorId";
|
||||
public static final String PRODUCT_NAME = "productName";
|
||||
public static final String UNIQUE_ID = "uniqueId";
|
||||
public static final String FADETIME = "fadetime";
|
||||
public static final String GROUP_ID = "groupId";
|
||||
|
||||
public static final String NORMALIZE_ID_REGEX = "[^a-zA-Z0-9_]";
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import org.openhab.core.config.core.status.ConfigStatusMessage;
|
||||
|
||||
/**
|
||||
* The {@link HueConfigStatusMessage} defines
|
||||
* the keys to be used for {@link ConfigStatusMessage}s.
|
||||
*
|
||||
* @author Alexander Kostadinov - Initial contribution
|
||||
* @author Kai Kreuzer - Changed from enum to interface
|
||||
*
|
||||
*/
|
||||
public interface HueConfigStatusMessage {
|
||||
|
||||
static final String IP_ADDRESS_MISSING = "missing-ip-address-configuration";
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Basic hue object information.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
* @author Samuel Leisering - introduced Sensor support, renamed supertype to HueObject
|
||||
*/
|
||||
public class HueObject {
|
||||
public static final Type GSON_TYPE = new TypeToken<Map<String, HueObject>>() {
|
||||
}.getType();
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
|
||||
HueObject() {
|
||||
}
|
||||
|
||||
void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the light.
|
||||
*
|
||||
* @return id
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the light.
|
||||
*
|
||||
* @return name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.discovery.HueLightDiscoveryService;
|
||||
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
|
||||
import org.openhab.binding.hue.internal.handler.HueLightHandler;
|
||||
import org.openhab.binding.hue.internal.handler.HueStateDescriptionOptionProvider;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.ClipHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.DimmerSwitchHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.LightLevelHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.PresenceHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.TapSwitchHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* {@link HueThingHandlerFactory} is a factory for {@link HueBridgeHandler}s.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution of hue binding
|
||||
* @author Kai Kreuzer - added supportsThingType method
|
||||
* @author Andre Fuechsel - implemented to use one discovery service per bridge
|
||||
* @author Samuel Leisering - Added support for sensor API
|
||||
* @author Christoph Weitkamp - Added support for sensor API
|
||||
* @author Laurent Garnier - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.hue")
|
||||
public class HueThingHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.unmodifiableSet(
|
||||
Stream.of(HueBridgeHandler.SUPPORTED_THING_TYPES.stream(), HueLightHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(), TapSwitchHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
PresenceHandler.SUPPORTED_THING_TYPES.stream(), TemperatureHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
LightLevelHandler.SUPPORTED_THING_TYPES.stream(), ClipHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
HueGroupHandler.SUPPORTED_THING_TYPES.stream()).flatMap(i -> i).collect(Collectors.toSet()));
|
||||
|
||||
private final HueStateDescriptionOptionProvider stateOptionProvider;
|
||||
|
||||
private final Map<ThingUID, @Nullable ServiceRegistration<?>> discoveryServiceRegs = new HashMap<>();
|
||||
|
||||
@Activate
|
||||
public HueThingHandlerFactory(final @Reference HueStateDescriptionOptionProvider stateOptionProvider) {
|
||||
this.stateOptionProvider = stateOptionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Thing createThing(ThingTypeUID thingTypeUID, Configuration configuration,
|
||||
@Nullable ThingUID thingUID, @Nullable ThingUID bridgeUID) {
|
||||
if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
return super.createThing(thingTypeUID, configuration, thingUID, null);
|
||||
} else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
ThingUID hueLightUID = getLightUID(thingTypeUID, thingUID, configuration, bridgeUID);
|
||||
return super.createThing(thingTypeUID, configuration, hueLightUID, bridgeUID);
|
||||
} else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|
||||
|| TapSwitchHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|
||||
|| PresenceHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|
||||
|| TemperatureHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|
||||
|| LightLevelHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)
|
||||
|| ClipHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
ThingUID hueSensorUID = getSensorUID(thingTypeUID, thingUID, configuration, bridgeUID);
|
||||
return super.createThing(thingTypeUID, configuration, hueSensorUID, bridgeUID);
|
||||
} else if (HueGroupHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||
ThingUID hueGroupUID = getGroupUID(thingTypeUID, thingUID, configuration, bridgeUID);
|
||||
return super.createThing(thingTypeUID, configuration, hueGroupUID, bridgeUID);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("The thing type " + thingTypeUID + " is not supported by the hue binding.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
private ThingUID getLightUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, Configuration configuration,
|
||||
@Nullable ThingUID bridgeUID) {
|
||||
if (thingUID != null) {
|
||||
return thingUID;
|
||||
} else {
|
||||
return getThingUID(thingTypeUID, configuration.get(LIGHT_ID).toString(), bridgeUID);
|
||||
}
|
||||
}
|
||||
|
||||
private ThingUID getSensorUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, Configuration configuration,
|
||||
@Nullable ThingUID bridgeUID) {
|
||||
if (thingUID != null) {
|
||||
return thingUID;
|
||||
} else {
|
||||
return getThingUID(thingTypeUID, configuration.get(SENSOR_ID).toString(), bridgeUID);
|
||||
}
|
||||
}
|
||||
|
||||
private ThingUID getGroupUID(ThingTypeUID thingTypeUID, @Nullable ThingUID thingUID, Configuration configuration,
|
||||
@Nullable ThingUID bridgeUID) {
|
||||
if (thingUID != null) {
|
||||
return thingUID;
|
||||
} else {
|
||||
return getThingUID(thingTypeUID, configuration.get(GROUP_ID).toString(), bridgeUID);
|
||||
}
|
||||
}
|
||||
|
||||
private ThingUID getThingUID(ThingTypeUID thingTypeUID, String id, @Nullable ThingUID bridgeUID) {
|
||||
if (bridgeUID != null) {
|
||||
return new ThingUID(thingTypeUID, id, bridgeUID.getId());
|
||||
} else {
|
||||
return new ThingUID(thingTypeUID, id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
HueBridgeHandler handler = new HueBridgeHandler((Bridge) thing, stateOptionProvider);
|
||||
registerLightDiscoveryService(handler);
|
||||
return handler;
|
||||
} else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new HueLightHandler(thing);
|
||||
} else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new DimmerSwitchHandler(thing);
|
||||
} else if (TapSwitchHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new TapSwitchHandler(thing);
|
||||
} else if (PresenceHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new PresenceHandler(thing);
|
||||
} else if (TemperatureHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new TemperatureHandler(thing);
|
||||
} else if (LightLevelHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new LightLevelHandler(thing);
|
||||
} else if (ClipHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new ClipHandler(thing);
|
||||
} else if (HueGroupHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||
return new HueGroupHandler(thing, stateOptionProvider);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void registerLightDiscoveryService(HueBridgeHandler bridgeHandler) {
|
||||
HueLightDiscoveryService discoveryService = new HueLightDiscoveryService(bridgeHandler);
|
||||
discoveryService.activate();
|
||||
this.discoveryServiceRegs.put(bridgeHandler.getThing().getUID(),
|
||||
bundleContext.registerService(DiscoveryService.class.getName(), discoveryService, new Hashtable<>()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void removeHandler(ThingHandler thingHandler) {
|
||||
if (thingHandler instanceof HueBridgeHandler) {
|
||||
ServiceRegistration<?> serviceReg = this.discoveryServiceRegs.remove(thingHandler.getThing().getUID());
|
||||
if (serviceReg != null) {
|
||||
// remove discovery service, if bridge handler is removed
|
||||
HueLightDiscoveryService service = (HueLightDiscoveryService) bundleContext
|
||||
.getService(serviceReg.getReference());
|
||||
serviceReg.unregister();
|
||||
if (service != null) {
|
||||
service.deactivate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
||||
|
||||
/**
|
||||
* Updates the configuration of a light level sensor
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class LightLevelConfigUpdate extends SensorConfigUpdate {
|
||||
/**
|
||||
*
|
||||
* @param onOff
|
||||
*/
|
||||
public void setLedIndication(boolean onOff) {
|
||||
commands.add(new Command(CONFIG_LED_INDICATION, onOff));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param threshold
|
||||
*/
|
||||
public void setThresholdDark(int threshold) {
|
||||
commands.add(new Command(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK, threshold));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param offset
|
||||
*/
|
||||
public void setThresholdOffset(int offset) {
|
||||
commands.add(new Command(CONFIG_LIGHT_LEVEL_THRESHOLD_OFFSET, offset));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
class NewLightsResponse {
|
||||
public String lastscan;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
class PortalDiscoveryResult {
|
||||
public static final Type GSON_TYPE = new TypeToken<List<PortalDiscoveryResult>>() {
|
||||
}.getType();
|
||||
|
||||
private String internalipaddress;
|
||||
|
||||
public String getIPAddress() {
|
||||
return internalipaddress;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
||||
|
||||
/**
|
||||
* Updates the configuration of a presence sensor
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class PresenceConfigUpdate extends SensorConfigUpdate {
|
||||
/**
|
||||
*
|
||||
* @param onOff
|
||||
*/
|
||||
public void setLedIndication(boolean onOff) {
|
||||
commands.add(new Command(CONFIG_LED_INDICATION, onOff));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param sensitivity
|
||||
*/
|
||||
public void setSensitivity(int sensitivity) {
|
||||
commands.add(new Command(CONFIG_PRESENCE_SENSITIVITY, sensitivity));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.types.StateOption;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Basic scene information.
|
||||
*
|
||||
* @author Hengrui Jiang - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class Scene {
|
||||
public static final Type GSON_TYPE = new TypeToken<Map<String, Scene>>() {
|
||||
}.getType();
|
||||
|
||||
private @NonNullByDefault({}) String id;
|
||||
private @NonNullByDefault({}) String name;
|
||||
@SerializedName("lights")
|
||||
private @NonNullByDefault({}) List<String> lightIds;
|
||||
@SerializedName("group")
|
||||
private @Nullable String groupId;
|
||||
private boolean recycle;
|
||||
|
||||
/**
|
||||
* Default constructor for GSon.
|
||||
*/
|
||||
public Scene() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test constructor
|
||||
*/
|
||||
Scene(String id, String name, @Nullable String groupId, List<String> lightIds, boolean recycle) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.groupId = groupId;
|
||||
this.lightIds = lightIds;
|
||||
this.recycle = recycle;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the human readable name of the scene. If the name is omitted upon creation, this
|
||||
* defaults to the ID.
|
||||
*
|
||||
* @return human readable name of the scene
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of lights that the scene applies to. For group scenes, this list should be identical to the list
|
||||
* of all lights that are in the group.
|
||||
*
|
||||
* @return list of lights that the scene applies to
|
||||
*/
|
||||
public List<String> getLightIds() {
|
||||
return lightIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the group that the scene belongs to. This field is optional for scenes that applies to a specific list of
|
||||
* lights instead of a group.
|
||||
*
|
||||
* @return the group that the scene belongs to
|
||||
*/
|
||||
public @Nullable String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the scene can be recycled by the bridge. A recyclable scene is not able to be activated.
|
||||
*
|
||||
* @return whether the scene can be recycled
|
||||
*/
|
||||
public boolean isRecycle() {
|
||||
return recycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link StateOption} to display this scene, including the group that it belongs to.
|
||||
* <p>
|
||||
* The display name is built with the following pattern:
|
||||
* <ol>
|
||||
* <li>Human readable name of the scene if set. Otherwise, the ID is displayed</li>
|
||||
* <li>Group for which the scene is defined</li>
|
||||
* </ol>
|
||||
*/
|
||||
public StateOption toStateOption(Map<String, String> groupNames) {
|
||||
StringBuilder stateOptionLabel = new StringBuilder(name);
|
||||
if (groupId != null && groupNames.containsKey(groupId)) {
|
||||
stateOptionLabel.append(" (").append(groupNames.get(groupId)).append(")");
|
||||
}
|
||||
|
||||
return new StateOption(id, stateOptionLabel.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link StateOption} to display this scene.
|
||||
*/
|
||||
public StateOption toStateOption() {
|
||||
return new StateOption(id, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the scene is applicable to the given group.
|
||||
* <p>
|
||||
* According to the hue API, a scene is applicable to a group if either
|
||||
* <ol>
|
||||
* <li>The scene is defined for the group</li>
|
||||
* <li>All lights of the scene also belong to the group</li>
|
||||
* </ol>
|
||||
*/
|
||||
public boolean isApplicableTo(FullGroup group) {
|
||||
if (getGroupId() == null) {
|
||||
return getLightIds().stream().allMatch(id -> group.getLightIds().contains(id));
|
||||
} else {
|
||||
return group.getId().contentEquals(getGroupId());
|
||||
}
|
||||
}
|
||||
|
||||
public String extractKeyForComparator() {
|
||||
return (groupId != null ? groupId : "") + "#" + name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("{Scene name: %s; id: %s; lightIds: %s; groupId: %s; recycle: %s}", name, id, lightIds,
|
||||
groupId, recycle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* Basic schedule information.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
public class Schedule {
|
||||
public static final Type GSON_TYPE = new TypeToken<Map<String, Schedule>>() {
|
||||
}.getType();
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
|
||||
void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Information about a scheduled command.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
public class ScheduleCommand {
|
||||
private String address;
|
||||
private String method;
|
||||
private JsonElement body;
|
||||
|
||||
ScheduleCommand(String address, String method, JsonElement body) {
|
||||
this.address = address;
|
||||
this.method = method;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative request url.
|
||||
*
|
||||
* @return request url
|
||||
*/
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request method.
|
||||
* Can be GET, PUT, POST or DELETE.
|
||||
*
|
||||
* @return request method
|
||||
*/
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request body.
|
||||
*
|
||||
* @return request body
|
||||
*/
|
||||
public String getBody() {
|
||||
return body.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Collection of updates to a schedule.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding, minor code cleanup
|
||||
* @author Samuel Leisering - refactor configuration updates
|
||||
*/
|
||||
public class ScheduleUpdate extends ConfigUpdate {
|
||||
|
||||
/**
|
||||
* Set the name of the schedule.
|
||||
*
|
||||
* @param name new name
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public ScheduleUpdate setName(String name) {
|
||||
if (Util.stringSize(name) > 32) {
|
||||
throw new IllegalArgumentException("Schedule name can be at most 32 characters long");
|
||||
}
|
||||
|
||||
commands.add(new Command("name", name));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the description of the schedule.
|
||||
*
|
||||
* @param description new description
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public ScheduleUpdate setDescription(String description) {
|
||||
if (Util.stringSize(description) > 64) {
|
||||
throw new IllegalArgumentException("Schedule description can be at most 64 characters long");
|
||||
}
|
||||
|
||||
commands.add(new Command("description", description));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time of the schedule.
|
||||
*
|
||||
* @param time new time
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public ScheduleUpdate setTime(Date time) {
|
||||
commands.add(new Command("time", time));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Andre Fuechsel - search for lights with given serial number added
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
class SearchForLightsRequest {
|
||||
private List<String> deviceid;
|
||||
|
||||
public SearchForLightsRequest(List<String> deviceid) {
|
||||
if (deviceid != null && (deviceid.isEmpty() || deviceid.size() > 16)) {
|
||||
throw new IllegalArgumentException("Group cannot be empty and cannot have more than 16 lights");
|
||||
}
|
||||
if (deviceid != null) {
|
||||
this.deviceid = deviceid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.CONFIG_ON;
|
||||
|
||||
/**
|
||||
* Collection of updates to the sensor configuration.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class SensorConfigUpdate extends ConfigUpdate {
|
||||
/**
|
||||
*
|
||||
* @param onOff
|
||||
*/
|
||||
public void setOn(boolean onOff) {
|
||||
commands.add(new Command(CONFIG_ON, onOff));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
class SetAttributesRequest {
|
||||
private String name;
|
||||
private List<String> lights;
|
||||
|
||||
public SetAttributesRequest(String name) {
|
||||
this(name, null);
|
||||
}
|
||||
|
||||
public SetAttributesRequest(List<HueObject> lights) {
|
||||
this(null, lights);
|
||||
}
|
||||
|
||||
public SetAttributesRequest(String name, List<HueObject> lights) {
|
||||
if (name != null && Util.stringSize(name) > 32) {
|
||||
throw new IllegalArgumentException("Name can be at most 32 characters long");
|
||||
} else if (lights != null && (lights.isEmpty() || lights.size() > 16)) {
|
||||
throw new IllegalArgumentException("Group cannot be empty and cannot have more than 16 lights");
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
if (lights != null) {
|
||||
this.lights = Util.lightsToIds(lights);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
/**
|
||||
* Details of a bridge firmware update.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
public class SoftwareUpdate {
|
||||
private int updatestate;
|
||||
private String url;
|
||||
private String text;
|
||||
private boolean notify;
|
||||
|
||||
/**
|
||||
* Returns the state of the update.
|
||||
*
|
||||
* <p>
|
||||
* Actual meaning currently undocumented
|
||||
*
|
||||
* @return state of update
|
||||
*/
|
||||
public int getUpdateState() {
|
||||
return updatestate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the url of the changelog.
|
||||
*
|
||||
* @return changelog url
|
||||
*/
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description of the update.
|
||||
*
|
||||
* @return update description
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if there will be a notification about this update.
|
||||
*
|
||||
* @return true for notification, false otherwise
|
||||
*/
|
||||
public boolean isNotified() {
|
||||
return notify;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Current state of light.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
* @author Laurent Garnier - add few methods to update the object
|
||||
*/
|
||||
public class State {
|
||||
private boolean on;
|
||||
int bri;
|
||||
int hue;
|
||||
int sat;
|
||||
private float[] xy;
|
||||
private int ct;
|
||||
private String alert;
|
||||
private String effect;
|
||||
String colormode;
|
||||
private boolean reachable;
|
||||
|
||||
public State() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Color modes of a light.
|
||||
*/
|
||||
public enum ColorMode {
|
||||
/**
|
||||
* CIE color space coordinates
|
||||
*/
|
||||
XY,
|
||||
|
||||
/**
|
||||
* Hue and saturation
|
||||
*/
|
||||
HS,
|
||||
|
||||
/**
|
||||
* Color temperature in mirek
|
||||
*/
|
||||
CT
|
||||
}
|
||||
|
||||
/**
|
||||
* Alert modes of a light.
|
||||
*/
|
||||
public enum AlertMode {
|
||||
/**
|
||||
* Light is not performing alert effect
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Light is performing one breathe cycle
|
||||
*/
|
||||
SELECT,
|
||||
|
||||
/**
|
||||
* Light is performing breathe cycles for 30 seconds (unless cancelled)
|
||||
*/
|
||||
LSELECT
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects possible for a light.
|
||||
*/
|
||||
public enum Effect {
|
||||
/**
|
||||
* No effect
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Cycle through all hues with current saturation and brightness
|
||||
*/
|
||||
COLORLOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the on state.
|
||||
*
|
||||
* @return true if the light is on, false if it isn't
|
||||
*/
|
||||
public boolean isOn() {
|
||||
return on;
|
||||
}
|
||||
|
||||
public void setOn(boolean on) {
|
||||
this.on = on;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the brightness.
|
||||
*
|
||||
* @return brightness
|
||||
*/
|
||||
public int getBrightness() {
|
||||
return bri;
|
||||
}
|
||||
|
||||
public void setBri(int bri) {
|
||||
this.bri = bri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hue.
|
||||
*
|
||||
* @return hue
|
||||
*/
|
||||
public int getHue() {
|
||||
return hue;
|
||||
}
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the saturation.
|
||||
*
|
||||
* @return saturation
|
||||
*/
|
||||
public int getSaturation() {
|
||||
return sat;
|
||||
}
|
||||
|
||||
public void setSaturation(int sat) {
|
||||
this.sat = sat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the coordinates in CIE color space.
|
||||
*
|
||||
* @return cie color spaces coordinates
|
||||
*/
|
||||
public float[] getXY() {
|
||||
return xy;
|
||||
}
|
||||
|
||||
public void setXY(float[] xy) {
|
||||
this.xy = xy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the color temperature.
|
||||
*
|
||||
* @return color temperature
|
||||
*/
|
||||
public int getColorTemperature() {
|
||||
return ct;
|
||||
}
|
||||
|
||||
public void setColorTemperature(int ct) {
|
||||
this.ct = ct;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last alert mode set.
|
||||
* Future firmware updates may change this to actually report the current alert mode.
|
||||
*
|
||||
* @return last alert mode
|
||||
*/
|
||||
public AlertMode getAlertMode() {
|
||||
if (alert == null) {
|
||||
return null;
|
||||
}
|
||||
return AlertMode.valueOf(alert.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current color mode.
|
||||
*
|
||||
* @return current color mode
|
||||
*/
|
||||
public ColorMode getColorMode() {
|
||||
if (colormode == null) {
|
||||
return null;
|
||||
}
|
||||
return ColorMode.valueOf(colormode.toUpperCase());
|
||||
}
|
||||
|
||||
public void setColormode(ColorMode colormode) {
|
||||
this.colormode = colormode.name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current active effect.
|
||||
*
|
||||
* @return current active effect
|
||||
*/
|
||||
public Effect getEffect() {
|
||||
if (effect == null) {
|
||||
return null;
|
||||
}
|
||||
return Effect.valueOf(effect.toUpperCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns reachability.
|
||||
*
|
||||
* @return true if reachable, false if it isn't
|
||||
*/
|
||||
public boolean isReachable() {
|
||||
return reachable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((alert == null) ? 0 : alert.hashCode());
|
||||
result = prime * result + bri;
|
||||
result = prime * result + ((colormode == null) ? 0 : colormode.hashCode());
|
||||
result = prime * result + ct;
|
||||
result = prime * result + ((effect == null) ? 0 : effect.hashCode());
|
||||
result = prime * result + hue;
|
||||
result = prime * result + (on ? 1231 : 1237);
|
||||
result = prime * result + (reachable ? 1231 : 1237);
|
||||
result = prime * result + sat;
|
||||
result = prime * result + Arrays.hashCode(xy);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
State other = (State) obj;
|
||||
if (alert == null) {
|
||||
if (other.alert != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!alert.equals(other.alert)) {
|
||||
return false;
|
||||
}
|
||||
if (bri != other.bri) {
|
||||
return false;
|
||||
}
|
||||
if (colormode == null) {
|
||||
if (other.colormode != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!colormode.equals(other.colormode)) {
|
||||
return false;
|
||||
}
|
||||
if (ct != other.ct) {
|
||||
return false;
|
||||
}
|
||||
if (effect == null) {
|
||||
if (other.effect != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!effect.equals(other.effect)) {
|
||||
return false;
|
||||
}
|
||||
if (hue != other.hue) {
|
||||
return false;
|
||||
}
|
||||
if (on != other.on) {
|
||||
return false;
|
||||
}
|
||||
if (reachable != other.reachable) {
|
||||
return false;
|
||||
}
|
||||
if (sat != other.sat) {
|
||||
return false;
|
||||
}
|
||||
if (!Arrays.equals(xy, other.xy)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import org.openhab.binding.hue.internal.State.AlertMode;
|
||||
import org.openhab.binding.hue.internal.State.Effect;
|
||||
|
||||
/**
|
||||
* Collection of updates to the state of a light.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Thomas Höfer - added unique id and changed range check for brightness and saturation
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding, minor code cleanup
|
||||
* @author Samuel Leisering - refactor configuration updates
|
||||
*/
|
||||
public class StateUpdate extends ConfigUpdate {
|
||||
|
||||
private Integer colorTemperature;
|
||||
private Integer brightness;
|
||||
|
||||
/**
|
||||
* Turn light on.
|
||||
*
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate turnOn() {
|
||||
return setOn(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn light off.
|
||||
*
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate turnOff() {
|
||||
return setOn(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn light on or off.
|
||||
*
|
||||
* @param on on if true, off otherwise
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setOn(boolean on) {
|
||||
commands.add(new Command("on", on));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set brightness of light.
|
||||
* Brightness 0 is not the same as off.
|
||||
*
|
||||
* @param brightness brightness [1..254]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setBrightness(int brightness) {
|
||||
if (brightness < 1 || brightness > 254) {
|
||||
throw new IllegalArgumentException("Brightness out of range");
|
||||
}
|
||||
|
||||
commands.add(new Command("bri", brightness));
|
||||
this.brightness = brightness;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getBrightness() {
|
||||
return this.brightness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to HS color mode and set hue.
|
||||
*
|
||||
* @param hue hue [0..65535]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setHue(int hue) {
|
||||
if (hue < 0 || hue > 65535) {
|
||||
throw new IllegalArgumentException("Hue out of range");
|
||||
}
|
||||
|
||||
commands.add(new Command("hue", hue));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to HS color mode and set saturation.
|
||||
*
|
||||
* @param saturation saturation [0..254]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setSat(int saturation) {
|
||||
if (saturation < 0 || saturation > 254) {
|
||||
throw new IllegalArgumentException("Saturation out of range");
|
||||
}
|
||||
|
||||
commands.add(new Command("sat", saturation));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to XY color mode and set CIE color space coordinates.
|
||||
*
|
||||
* @param x x coordinate [0..1]
|
||||
* @param y y coordinate [0..1]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setXY(float x, float y) {
|
||||
return setXY(new float[] { x, y });
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to XY color mode and set CIE color space coordinates.
|
||||
*
|
||||
* @param xy x and y coordinates [0..1, 0..1]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setXY(float[] xy) {
|
||||
if (xy.length != 2) {
|
||||
throw new IllegalArgumentException("Invalid coordinate array given");
|
||||
} else if (xy[0] < 0.0f || xy[0] > 1.0f || xy[1] < 0.0f || xy[1] > 1.0f) {
|
||||
throw new IllegalArgumentException("X and/or Y coordinate(s) out of bounds");
|
||||
}
|
||||
|
||||
commands.add(new Command("xy", xy));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to CT color mode and set color temperature in mired.
|
||||
*
|
||||
* @param colorTemperature color temperature [153..500]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setColorTemperature(int colorTemperature) {
|
||||
if (colorTemperature < 153 || colorTemperature > 500) {
|
||||
throw new IllegalArgumentException("Color temperature out of range");
|
||||
}
|
||||
|
||||
commands.add(new Command("ct", colorTemperature));
|
||||
this.colorTemperature = colorTemperature;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Integer getColorTemperature() {
|
||||
return this.colorTemperature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the alert mode.
|
||||
*
|
||||
* @see AlertMode
|
||||
* @param mode alert mode
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setAlert(AlertMode mode) {
|
||||
commands.add(new Command("alert", mode.toString().toLowerCase()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current effect.
|
||||
*
|
||||
* @see Effect
|
||||
* @param effect effect
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setEffect(Effect effect) {
|
||||
commands.add(new Command("effect", effect.toString().toLowerCase()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transition time from the current state to the new state.
|
||||
* Time is accurate to 100 milliseconds.
|
||||
*
|
||||
* @param timeMillis time in milliseconds [0..6553600]
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setTransitionTime(long timeMillis) {
|
||||
if (timeMillis < 0 || timeMillis > 6553600) {
|
||||
throw new IllegalArgumentException("Transition time out of range");
|
||||
}
|
||||
|
||||
commands.add(new Command("transitiontime", timeMillis / 100));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn sensor flag on or off.
|
||||
*
|
||||
* @param flag on if true, off otherwise
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
|
||||
public StateUpdate setFlag(boolean flag) {
|
||||
commands.add(new Command("flag", flag));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set status of sensor.
|
||||
*
|
||||
* @param status status
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setStatus(int status) {
|
||||
commands.add(new Command("status", status));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recall the given scene.
|
||||
*
|
||||
* @param sceneId Identifier of the scene
|
||||
* @return this object for chaining calls
|
||||
*/
|
||||
public StateUpdate setScene(String sceneId) {
|
||||
commands.add(new Command("scene", sceneId));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
class SuccessResponse {
|
||||
public static final Type GSON_TYPE = new TypeToken<List<SuccessResponse>>() {
|
||||
}.getType();
|
||||
|
||||
public Map<String, Object> success;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.CONFIG_LED_INDICATION;
|
||||
|
||||
/**
|
||||
* Updates the configuration of a temperature sensor
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
public class TemperatureConfigUpdate extends SensorConfigUpdate {
|
||||
/**
|
||||
*
|
||||
* @param onOff
|
||||
*/
|
||||
public void setLedIndication(boolean onOff) {
|
||||
commands.add(new Command(CONFIG_LED_INDICATION, onOff));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* A whitelisted user.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
public class User {
|
||||
@SerializedName("last use date")
|
||||
private Date lastUseDate;
|
||||
|
||||
@SerializedName("create date")
|
||||
private Date createDate;
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Returns the last time a command was issued as this user.
|
||||
*
|
||||
* @return time of last command by this user
|
||||
*/
|
||||
public Date getLastUseDate() {
|
||||
return lastUseDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date this user was created.
|
||||
*
|
||||
* @return creation date of user
|
||||
*/
|
||||
public Date getCreationDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the username of this user.
|
||||
*
|
||||
* @return username
|
||||
*/
|
||||
public String getUsername() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@NonNullByDefault
|
||||
class Util {
|
||||
private Util() {
|
||||
}
|
||||
|
||||
// This is used to check what byte size strings have, because the bridge doesn't natively support UTF-8
|
||||
public static int stringSize(String str) {
|
||||
return str.getBytes(StandardCharsets.UTF_8).length;
|
||||
}
|
||||
|
||||
public static List<HueObject> idsToLights(List<String> ids) {
|
||||
List<HueObject> lights = new ArrayList<>();
|
||||
|
||||
for (String id : ids) {
|
||||
HueObject light = new HueObject();
|
||||
light.setId(id);
|
||||
lights.add(light);
|
||||
}
|
||||
|
||||
return lights;
|
||||
}
|
||||
|
||||
public static List<String> lightsToIds(List<HueObject> lights) {
|
||||
List<String> ids = new ArrayList<>();
|
||||
|
||||
for (HueObject light : lights) {
|
||||
ids.add(light.getId());
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
public static @Nullable String quickMatch(String needle, String haystack) {
|
||||
Matcher m = Pattern.compile(needle).matcher(haystack);
|
||||
m.find();
|
||||
return m.group(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.action;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.types.Command;
|
||||
|
||||
/**
|
||||
* The {@link ILightActions} defines the interface for all thing actions supported by the binding.
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ILightActions {
|
||||
|
||||
public void fadingLightCommand(@Nullable String channel, @Nullable Command command, @Nullable DecimalType fadeTime);
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.action;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.handler.HueLightHandler;
|
||||
import org.openhab.core.automation.annotation.ActionInput;
|
||||
import org.openhab.core.automation.annotation.RuleAction;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.thing.binding.ThingActions;
|
||||
import org.openhab.core.thing.binding.ThingActionsScope;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link LightActions} defines the thing actions for the hue binding.
|
||||
* <p>
|
||||
* <b>Note:</b>The static method <b>invokeMethodOf</b> handles the case where
|
||||
* the test <i>actions instanceof LightActions</i> fails. This test can fail
|
||||
* due to an issue in openHAB core v2.5.0 where the {@link LightActions} class
|
||||
* can be loaded by a different classloader than the <i>actions</i> instance.
|
||||
*
|
||||
* @author Jochen Leopold - Initial contribution
|
||||
* @author Laurent Garnier - new method invokeMethodOf + interface ILightActions
|
||||
*/
|
||||
@ThingActionsScope(name = "hue")
|
||||
@NonNullByDefault
|
||||
public class LightActions implements ThingActions, ILightActions {
|
||||
private final Logger logger = LoggerFactory.getLogger(LightActions.class);
|
||||
private @Nullable HueLightHandler handler;
|
||||
|
||||
@Override
|
||||
public void setThingHandler(@Nullable ThingHandler handler) {
|
||||
this.handler = (HueLightHandler) handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingHandler getThingHandler() {
|
||||
return this.handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
@RuleAction(label = "@text/actionLabel", description = "@text/actionDesc")
|
||||
public void fadingLightCommand(
|
||||
@ActionInput(name = "channel", label = "@text/actionInputChannelLabel", description = "@text/actionInputChannelDesc") @Nullable String channel,
|
||||
@ActionInput(name = "command", label = "@text/actionInputCommandLabel", description = "@text/actionInputCommandDesc") @Nullable Command command,
|
||||
@ActionInput(name = "fadeTime", label = "@text/actionInputFadeTimeLabel", description = "@text/actionInputFadeTimeDesc") @Nullable DecimalType fadeTime) {
|
||||
HueLightHandler lightHandler = handler;
|
||||
if (lightHandler == null) {
|
||||
logger.warn("Hue Action service ThingHandler is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (channel == null) {
|
||||
logger.debug("skipping Hue fadingLightCommand to channel '{}' due to null value.", channel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (command == null) {
|
||||
logger.debug("skipping Hue fadingLightCommand to command '{}' due to null value.", command);
|
||||
return;
|
||||
}
|
||||
if (fadeTime == null) {
|
||||
logger.debug("skipping Hue fadingLightCommand to fadeTime '{}' due to null value.", fadeTime);
|
||||
return;
|
||||
}
|
||||
|
||||
lightHandler.handleCommand(channel, command, fadeTime.longValue());
|
||||
logger.debug("send LightAction to {} with {}ms of fadeTime", channel, fadeTime);
|
||||
}
|
||||
|
||||
private static ILightActions invokeMethodOf(@Nullable ThingActions actions) {
|
||||
if (actions == null) {
|
||||
throw new IllegalArgumentException("actions cannot be null");
|
||||
}
|
||||
if (actions.getClass().getName().equals(LightActions.class.getName())) {
|
||||
if (actions instanceof ILightActions) {
|
||||
return (ILightActions) actions;
|
||||
} else {
|
||||
return (ILightActions) Proxy.newProxyInstance(ILightActions.class.getClassLoader(),
|
||||
new Class[] { ILightActions.class }, (Object proxy, Method method, Object[] args) -> {
|
||||
Method m = actions.getClass().getDeclaredMethod(method.getName(),
|
||||
method.getParameterTypes());
|
||||
return m.invoke(actions, args);
|
||||
});
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Actions is not an instance of LightActions");
|
||||
}
|
||||
|
||||
public static void fadingLightCommand(@Nullable ThingActions actions, @Nullable String channel,
|
||||
@Nullable Command command, @Nullable DecimalType fadeTime) {
|
||||
invokeMethodOf(actions).fadingLightCommand(channel, command, fadeTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||
|
||||
/**
|
||||
* Configuration for the {@link HueBridgeHandler}.
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueBridgeConfig {
|
||||
public static final String HTTP = "http";
|
||||
public static final String HTTPS = "https";
|
||||
|
||||
private @Nullable String ipAddress;
|
||||
private @Nullable Integer port;
|
||||
private String protocol = HTTP;
|
||||
private @Nullable String userName;
|
||||
private int pollingInterval = 10;
|
||||
private int sensorPollingInterval = 500;
|
||||
|
||||
public @Nullable String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
Integer thePort = this.port;
|
||||
return (thePort != null) ? thePort.intValue() : HTTPS.equals(protocol) ? 443 : 80;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
public void setProtocol(String protocol) {
|
||||
this.protocol = protocol;
|
||||
}
|
||||
|
||||
public @Nullable String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
}
|
||||
|
||||
public int getPollingInterval() {
|
||||
return pollingInterval;
|
||||
}
|
||||
|
||||
public void setPollingInterval(int pollingInterval) {
|
||||
this.pollingInterval = pollingInterval;
|
||||
}
|
||||
|
||||
public int getSensorPollingInterval() {
|
||||
return sensorPollingInterval;
|
||||
}
|
||||
|
||||
public void setSensorPollingInterval(int sensorPollingInterval) {
|
||||
this.sensorPollingInterval = sensorPollingInterval;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.console;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
|
||||
import org.openhab.core.io.console.Console;
|
||||
import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
|
||||
import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* The {@link HueCommandExtension} is responsible for handling console commands
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
|
||||
@NonNullByDefault
|
||||
@Component(service = ConsoleCommandExtension.class)
|
||||
public class HueCommandExtension extends AbstractConsoleCommandExtension {
|
||||
|
||||
private static final String USER_NAME = "username";
|
||||
private static final String SCENES = "scenes";
|
||||
|
||||
private final ThingRegistry thingRegistry;
|
||||
|
||||
@Activate
|
||||
public HueCommandExtension(final @Reference ThingRegistry thingRegistry) {
|
||||
super("hue", "Interact with the hue binding.");
|
||||
this.thingRegistry = thingRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String[] args, Console console) {
|
||||
if (args.length == 2) {
|
||||
Thing thing = null;
|
||||
try {
|
||||
ThingUID thingUID = new ThingUID(args[0]);
|
||||
thing = thingRegistry.get(thingUID);
|
||||
} catch (IllegalArgumentException e) {
|
||||
thing = null;
|
||||
}
|
||||
ThingHandler thingHandler = null;
|
||||
HueBridgeHandler bridgeHandler = null;
|
||||
HueGroupHandler groupHandler = null;
|
||||
if (thing != null) {
|
||||
thingHandler = thing.getHandler();
|
||||
if (thingHandler instanceof HueBridgeHandler) {
|
||||
bridgeHandler = (HueBridgeHandler) thingHandler;
|
||||
} else if (thingHandler instanceof HueGroupHandler) {
|
||||
groupHandler = (HueGroupHandler) thingHandler;
|
||||
}
|
||||
}
|
||||
if (thing == null) {
|
||||
console.println("Bad thing id '" + args[0] + "'");
|
||||
printUsage(console);
|
||||
} else if (thingHandler == null) {
|
||||
console.println("No handler initialized for the thing id '" + args[0] + "'");
|
||||
printUsage(console);
|
||||
} else if (bridgeHandler == null && groupHandler == null) {
|
||||
console.println("'" + args[0] + "' is neither a hue bridge id nor a hue group thing id");
|
||||
printUsage(console);
|
||||
} else {
|
||||
switch (args[1]) {
|
||||
case USER_NAME:
|
||||
if (bridgeHandler != null) {
|
||||
String userName = bridgeHandler.getUserName();
|
||||
console.println("Your user name is " + (userName != null ? userName : "undefined"));
|
||||
} else {
|
||||
console.println("'" + args[0] + "' is not a hue bridge id");
|
||||
printUsage(console);
|
||||
}
|
||||
break;
|
||||
case SCENES:
|
||||
if (bridgeHandler != null) {
|
||||
bridgeHandler.listScenesForConsole().forEach(console::println);
|
||||
} else if (groupHandler != null) {
|
||||
groupHandler.listScenesForConsole().forEach(console::println);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printUsage(console);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printUsage(console);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUsages() {
|
||||
return Arrays.asList(new String[] { buildCommandUsage("<bridgeUID> " + USER_NAME, "show the user name"),
|
||||
buildCommandUsage("<bridgeUID> " + SCENES, "list all the scenes with their id"),
|
||||
buildCommandUsage("<groupThingUID> " + SCENES, "list all the scenes from this group with their id") });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.discovery;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* The {@link BridgeJsonParameters} class defines JSON object, which
|
||||
* contains bridge attributes like IP address. It is used for bridge
|
||||
* N-UPNP Discovery.
|
||||
*
|
||||
* @author Awelkiyar Wehabrebi - Initial contribution and API
|
||||
* @author Christoph Knauf - Refactorings
|
||||
*/
|
||||
public class BridgeJsonParameters {
|
||||
|
||||
private String id;
|
||||
@SerializedName("internalipaddress")
|
||||
private String internalIpAddress;
|
||||
@SerializedName("macaddress")
|
||||
private String macAddress;
|
||||
private String name;
|
||||
|
||||
private BridgeJsonParameters() {
|
||||
// This no arguments constructor is required for Gson deserialization
|
||||
}
|
||||
|
||||
public BridgeJsonParameters(String id, String internalIpAddress, String macAdress, String name) {
|
||||
this.id = id;
|
||||
this.internalIpAddress = internalIpAddress;
|
||||
this.macAddress = macAdress;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getInternalIpAddress() {
|
||||
return internalIpAddress;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getMacAddress() {
|
||||
return macAddress;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.jupnp.model.meta.DeviceDetails;
|
||||
import org.jupnp.model.meta.ModelDetails;
|
||||
import org.jupnp.model.meta.RemoteDevice;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
|
||||
import org.openhab.core.config.discovery.upnp.internal.UpnpDiscoveryService;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
|
||||
/**
|
||||
* The {@link HueBridgeDiscoveryParticipant} is responsible for discovering new and
|
||||
* removed hue bridges. It uses the central {@link UpnpDiscoveryService}.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
* @author Thomas Höfer - Added representation
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = UpnpDiscoveryParticipant.class, immediate = true)
|
||||
public class HueBridgeDiscoveryParticipant implements UpnpDiscoveryParticipant {
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return Collections.singleton(THING_TYPE_BRIDGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
|
||||
ThingUID uid = getThingUID(device);
|
||||
if (uid != null) {
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(HOST, device.getDetails().getBaseURL().getHost());
|
||||
properties.put(PORT, device.getDetails().getBaseURL().getPort());
|
||||
properties.put(PROTOCOL, device.getDetails().getBaseURL().getProtocol());
|
||||
properties.put(PROPERTY_SERIAL_NUMBER, device.getDetails().getSerialNumber());
|
||||
|
||||
DiscoveryResult result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
||||
.withLabel(device.getDetails().getFriendlyName()).withRepresentationProperty(PROPERTY_SERIAL_NUMBER)
|
||||
.build();
|
||||
return result;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
||||
DeviceDetails details = device.getDetails();
|
||||
if (details != null) {
|
||||
ModelDetails modelDetails = details.getModelDetails();
|
||||
if (modelDetails != null) {
|
||||
String modelName = modelDetails.getModelName();
|
||||
if (modelName != null) {
|
||||
if (modelName.startsWith("Philips hue bridge")) {
|
||||
return new ThingUID(THING_TYPE_BRIDGE, details.getSerialNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.config.discovery.DiscoveryService;
|
||||
import org.openhab.core.io.net.http.HttpUtil;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* The {@link HueBridgeNupnpDiscovery} is responsible for discovering new hue bridges. It uses the 'NUPnP service
|
||||
* provided by Philips'.
|
||||
*
|
||||
* @author Awelkiyar Wehabrebi - Initial contribution
|
||||
* @author Christoph Knauf - Refactorings
|
||||
* @author Andre Fuechsel - make {@link #startScan()} asynchronous
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = DiscoveryService.class, immediate = true, configurationPid = "discovery.hue")
|
||||
public class HueBridgeNupnpDiscovery extends AbstractDiscoveryService {
|
||||
|
||||
private static final String MODEL_NAME_PHILIPS_HUE = "<modelName>Philips hue";
|
||||
|
||||
protected static final String BRIDGE_INDICATOR = "fffe";
|
||||
|
||||
private static final String DISCOVERY_URL = "https://discovery.meethue.com/";
|
||||
|
||||
protected static final String LABEL_PATTERN = "Philips hue (IP)";
|
||||
|
||||
private static final String DESC_URL_PATTERN = "http://HOST/description.xml";
|
||||
|
||||
private static final int REQUEST_TIMEOUT = 5000;
|
||||
|
||||
private static final int DISCOVERY_TIMEOUT = 10;
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BRIDGE);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HueBridgeNupnpDiscovery.class);
|
||||
|
||||
public HueBridgeNupnpDiscovery() {
|
||||
super(SUPPORTED_THING_TYPES, DISCOVERY_TIMEOUT, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startScan() {
|
||||
scheduler.schedule(this::discoverHueBridges, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Discover available Hue Bridges and then add them in the discovery inbox
|
||||
*/
|
||||
private void discoverHueBridges() {
|
||||
for (BridgeJsonParameters bridge : getBridgeList()) {
|
||||
if (isReachableAndValidHueBridge(bridge)) {
|
||||
String host = bridge.getInternalIpAddress();
|
||||
String serialNumber = bridge.getId().substring(0, 6) + bridge.getId().substring(10);
|
||||
ThingUID uid = new ThingUID(THING_TYPE_BRIDGE, serialNumber);
|
||||
DiscoveryResult result = DiscoveryResultBuilder.create(uid)
|
||||
.withProperties(buildProperties(host, serialNumber))
|
||||
.withLabel(LABEL_PATTERN.replace("IP", host)).withRepresentationProperty(PROPERTY_SERIAL_NUMBER)
|
||||
.build();
|
||||
thingDiscovered(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the bridge properties.
|
||||
*
|
||||
* @param host the ip of the bridge
|
||||
* @param serialNumber the id of the bridge
|
||||
* @return the bridge properties
|
||||
*/
|
||||
private Map<String, Object> buildProperties(String host, String serialNumber) {
|
||||
Map<String, Object> properties = new HashMap<>(2);
|
||||
properties.put(HOST, host);
|
||||
properties.put(PROPERTY_SERIAL_NUMBER, serialNumber);
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the Bridge is a reachable Hue Bridge with a valid id.
|
||||
*
|
||||
* @param bridge the {@link BridgeJsonParameters}s
|
||||
* @return true if Bridge is a reachable Hue Bridge with a id containing
|
||||
* BRIDGE_INDICATOR longer then 10
|
||||
*/
|
||||
private boolean isReachableAndValidHueBridge(BridgeJsonParameters bridge) {
|
||||
String host = bridge.getInternalIpAddress();
|
||||
String id = bridge.getId();
|
||||
String description;
|
||||
if (host == null) {
|
||||
logger.debug("Bridge not discovered: ip is null");
|
||||
return false;
|
||||
}
|
||||
if (id == null) {
|
||||
logger.debug("Bridge not discovered: id is null");
|
||||
return false;
|
||||
}
|
||||
if (id.length() < 10) {
|
||||
logger.debug("Bridge not discovered: id {} is shorter then 10.", id);
|
||||
return false;
|
||||
}
|
||||
if (!id.substring(6, 10).equals(BRIDGE_INDICATOR)) {
|
||||
logger.debug(
|
||||
"Bridge not discovered: id {} does not contain bridge indicator {} or its at the wrong position.",
|
||||
id, BRIDGE_INDICATOR);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
description = doGetRequest(DESC_URL_PATTERN.replace("HOST", host));
|
||||
} catch (IOException e) {
|
||||
logger.debug("Bridge not discovered: Failure accessing description file for ip: {}", host);
|
||||
return false;
|
||||
}
|
||||
if (!description.contains(MODEL_NAME_PHILIPS_HUE)) {
|
||||
logger.debug("Bridge not discovered: Description does not containing the model name: {}", description);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the Philips Hue NUPnP service to find Hue Bridges in local Network.
|
||||
*
|
||||
* @return a list of available Hue Bridges
|
||||
*/
|
||||
private List<BridgeJsonParameters> getBridgeList() {
|
||||
try {
|
||||
Gson gson = new Gson();
|
||||
String json = doGetRequest(DISCOVERY_URL);
|
||||
return gson.fromJson(json, new TypeToken<List<BridgeJsonParameters>>() {
|
||||
}.getType());
|
||||
} catch (IOException e) {
|
||||
logger.debug("Philips Hue NUPnP service not reachable. Can't discover bridges");
|
||||
} catch (JsonParseException je) {
|
||||
logger.debug("Invalid json respone from Hue NUPnP service. Can't discover bridges");
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Introduced in order to enable testing.
|
||||
*
|
||||
* @param url the url
|
||||
* @return the http request result as String
|
||||
* @throws IOException if request failed
|
||||
*/
|
||||
protected String doGetRequest(String url) throws IOException {
|
||||
return HttpUtil.executeUrl("GET", url, REQUEST_TIMEOUT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.discovery;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.FullGroup;
|
||||
import org.openhab.binding.hue.internal.FullHueObject;
|
||||
import org.openhab.binding.hue.internal.FullLight;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
|
||||
import org.openhab.binding.hue.internal.handler.HueLightHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.ClipHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.DimmerSwitchHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.LightLevelHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.PresenceHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.TapSwitchHandler;
|
||||
import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler;
|
||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HueBridgeServiceTracker} tracks for hue lights, sensors and groups which are connected
|
||||
* to a paired hue bridge. The default search time for hue is 60 seconds.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
* @author Andre Fuechsel - changed search timeout, changed discovery result creation to support generic thing types;
|
||||
* added representationProperty to discovery result
|
||||
* @author Thomas Höfer - Added representation
|
||||
* @author Denis Dudnik - switched to internally integrated source of Jue library
|
||||
* @author Samuel Leisering - Added support for sensor API
|
||||
* @author Christoph Weitkamp - Added support for sensor API
|
||||
* @author Meng Yiqi - Added support for CLIP sensor
|
||||
* @author Laurent Garnier - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueLightDiscoveryService extends AbstractDiscoveryService {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.unmodifiableSet(Stream
|
||||
.of(HueLightHandler.SUPPORTED_THING_TYPES.stream(), DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
TapSwitchHandler.SUPPORTED_THING_TYPES.stream(), PresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
TemperatureHandler.SUPPORTED_THING_TYPES.stream(), LightLevelHandler.SUPPORTED_THING_TYPES.stream(),
|
||||
ClipHandler.SUPPORTED_THING_TYPES.stream(), HueGroupHandler.SUPPORTED_THING_TYPES.stream())
|
||||
.flatMap(i -> i).collect(Collectors.toSet()));
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HueLightDiscoveryService.class);
|
||||
|
||||
private static final int SEARCH_TIME = 10;
|
||||
|
||||
// @formatter:off
|
||||
private static final Map<String, @Nullable String> TYPE_TO_ZIGBEE_ID_MAP = Stream.of(
|
||||
new SimpleEntry<>("on_off_light", "0000"),
|
||||
new SimpleEntry<>("on_off_plug_in_unit", "0010"),
|
||||
new SimpleEntry<>("dimmable_light", "0100"),
|
||||
new SimpleEntry<>("dimmable_plug_in_unit", "0110"),
|
||||
new SimpleEntry<>("color_light", "0200"),
|
||||
new SimpleEntry<>("extended_color_light", "0210"),
|
||||
new SimpleEntry<>("color_temperature_light", "0220"),
|
||||
new SimpleEntry<>("zllswitch", "0820"),
|
||||
new SimpleEntry<>("zgpswitch", "0830"),
|
||||
new SimpleEntry<>("clipgenericstatus", "0840"),
|
||||
new SimpleEntry<>("clipgenericflag", "0850"),
|
||||
new SimpleEntry<>("zllpresence", "0107"),
|
||||
new SimpleEntry<>("zlltemperature", "0302"),
|
||||
new SimpleEntry<>("zlllightlevel", "0106")
|
||||
).collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()));
|
||||
// @formatter:on
|
||||
|
||||
private final HueBridgeHandler hueBridgeHandler;
|
||||
|
||||
public HueLightDiscoveryService(HueBridgeHandler hueBridgeHandler) {
|
||||
super(SEARCH_TIME);
|
||||
this.hueBridgeHandler = hueBridgeHandler;
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
hueBridgeHandler.registerDiscoveryListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deactivate() {
|
||||
removeOlderResults(new Date().getTime(), hueBridgeHandler.getThing().getUID());
|
||||
hueBridgeHandler.unregisterDiscoveryListener();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypes() {
|
||||
return SUPPORTED_THING_TYPES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startScan() {
|
||||
List<FullLight> lights = hueBridgeHandler.getFullLights();
|
||||
for (FullLight l : lights) {
|
||||
addLightDiscovery(l);
|
||||
}
|
||||
List<FullSensor> sensors = hueBridgeHandler.getFullSensors();
|
||||
for (FullSensor s : sensors) {
|
||||
addSensorDiscovery(s);
|
||||
}
|
||||
List<FullGroup> groups = hueBridgeHandler.getFullGroups();
|
||||
for (FullGroup g : groups) {
|
||||
addGroupDiscovery(g);
|
||||
}
|
||||
// search for unpaired lights
|
||||
hueBridgeHandler.startSearch();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stopScan() {
|
||||
super.stopScan();
|
||||
removeOlderResults(getTimestampOfLastScan(), hueBridgeHandler.getThing().getUID());
|
||||
}
|
||||
|
||||
public void addLightDiscovery(FullLight light) {
|
||||
ThingUID thingUID = getThingUID(light);
|
||||
ThingTypeUID thingTypeUID = getThingTypeUID(light);
|
||||
|
||||
String modelId = light.getNormalizedModelID();
|
||||
|
||||
if (thingUID != null && thingTypeUID != null) {
|
||||
ThingUID bridgeUID = hueBridgeHandler.getThing().getUID();
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(LIGHT_ID, light.getId());
|
||||
if (modelId != null) {
|
||||
properties.put(Thing.PROPERTY_MODEL_ID, modelId);
|
||||
}
|
||||
String uniqueID = light.getUniqueID();
|
||||
if (uniqueID != null) {
|
||||
properties.put(UNIQUE_ID, uniqueID);
|
||||
}
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID)
|
||||
.withProperties(properties).withBridge(bridgeUID).withRepresentationProperty(UNIQUE_ID)
|
||||
.withLabel(light.getName()).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
} else {
|
||||
logger.debug("discovered unsupported light of type '{}' and model '{}' with id {}", light.getType(),
|
||||
modelId, light.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeLightDiscovery(FullLight light) {
|
||||
ThingUID thingUID = getThingUID(light);
|
||||
|
||||
if (thingUID != null) {
|
||||
thingRemoved(thingUID);
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable ThingUID getThingUID(FullHueObject hueObject) {
|
||||
ThingUID bridgeUID = hueBridgeHandler.getThing().getUID();
|
||||
ThingTypeUID thingTypeUID = getThingTypeUID(hueObject);
|
||||
|
||||
if (thingTypeUID != null && getSupportedThingTypes().contains(thingTypeUID)) {
|
||||
return new ThingUID(thingTypeUID, bridgeUID, hueObject.getId());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable ThingTypeUID getThingTypeUID(FullHueObject hueObject) {
|
||||
String thingTypeId = TYPE_TO_ZIGBEE_ID_MAP
|
||||
.get(hueObject.getType().replaceAll(NORMALIZE_ID_REGEX, "_").toLowerCase());
|
||||
return thingTypeId != null ? new ThingTypeUID(BINDING_ID, thingTypeId) : null;
|
||||
}
|
||||
|
||||
public void addSensorDiscovery(FullSensor sensor) {
|
||||
ThingUID thingUID = getThingUID(sensor);
|
||||
ThingTypeUID thingTypeUID = getThingTypeUID(sensor);
|
||||
|
||||
String modelId = sensor.getNormalizedModelID();
|
||||
if (thingUID != null && thingTypeUID != null) {
|
||||
ThingUID bridgeUID = hueBridgeHandler.getThing().getUID();
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(SENSOR_ID, sensor.getId());
|
||||
if (modelId != null) {
|
||||
properties.put(Thing.PROPERTY_MODEL_ID, modelId);
|
||||
}
|
||||
String uniqueID = sensor.getUniqueID();
|
||||
if (uniqueID != null) {
|
||||
properties.put(UNIQUE_ID, uniqueID);
|
||||
}
|
||||
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID)
|
||||
.withProperties(properties).withBridge(bridgeUID).withRepresentationProperty(UNIQUE_ID)
|
||||
.withLabel(sensor.getName()).build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
} else {
|
||||
logger.debug("discovered unsupported sensor of type '{}' and model '{}' with id {}", sensor.getType(),
|
||||
modelId, sensor.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSensorDiscovery(FullSensor sensor) {
|
||||
ThingUID thingUID = getThingUID(sensor);
|
||||
|
||||
if (thingUID != null) {
|
||||
thingRemoved(thingUID);
|
||||
}
|
||||
}
|
||||
|
||||
public void addGroupDiscovery(FullGroup group) {
|
||||
// Ignore the Hue Entertainment Areas
|
||||
if ("Entertainment".equalsIgnoreCase(group.getType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThingUID bridgeUID = hueBridgeHandler.getThing().getUID();
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_GROUP, bridgeUID, group.getId());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put(GROUP_ID, group.getId());
|
||||
|
||||
String name = String.format("%s (%s)", "0".equals(group.getId()) ? "All lights" : group.getName(),
|
||||
group.getType());
|
||||
DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withThingType(THING_TYPE_GROUP)
|
||||
.withProperties(properties).withBridge(bridgeUID).withRepresentationProperty(GROUP_ID).withLabel(name)
|
||||
.build();
|
||||
|
||||
thingDiscovered(discoveryResult);
|
||||
}
|
||||
|
||||
public void removeGroupDiscovery(FullGroup group) {
|
||||
ThingUID bridgeUID = hueBridgeHandler.getThing().getUID();
|
||||
ThingUID thingUID = new ThingUID(THING_TYPE_GROUP, bridgeUID, group.getId());
|
||||
thingRemoved(thingUID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when the API returns an unknown error.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ApiException extends Exception {
|
||||
public ApiException() {
|
||||
}
|
||||
|
||||
public ApiException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when trying to change the state of a light that is off.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class DeviceOffException extends ApiException {
|
||||
public DeviceOffException() {
|
||||
}
|
||||
|
||||
public DeviceOffException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when operating on a group, light or user that doesn't exist.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class EntityNotAvailableException extends ApiException {
|
||||
public EntityNotAvailableException() {
|
||||
}
|
||||
|
||||
public EntityNotAvailableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when adding more than 16 groups (excluding all lights group) to a bridge.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class GroupTableFullException extends ApiException {
|
||||
public GroupTableFullException() {
|
||||
}
|
||||
|
||||
public GroupTableFullException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when scheduling an invalid command.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class InvalidCommandException extends ApiException {
|
||||
public InvalidCommandException() {
|
||||
}
|
||||
|
||||
public InvalidCommandException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown if the link button hasn't been pressed in the last 30 seconds.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class LinkButtonException extends ApiException {
|
||||
public LinkButtonException() {
|
||||
}
|
||||
|
||||
public LinkButtonException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.exceptions;
|
||||
|
||||
/**
|
||||
* Thrown when the specified user is no longer whitelisted on the bridge.
|
||||
*
|
||||
* @author Q42 - Initial contribution
|
||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class UnauthorizedException extends ApiException {
|
||||
public UnauthorizedException() {
|
||||
}
|
||||
|
||||
public UnauthorizedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullGroup;
|
||||
import org.openhab.binding.hue.internal.Scene;
|
||||
|
||||
/**
|
||||
* The {@link GroupStatusListener} is notified when a group status has changed or a group has been removed or added.
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface GroupStatusListener {
|
||||
|
||||
/**
|
||||
* This method returns the group id of listener
|
||||
*
|
||||
* @return groupId String
|
||||
*/
|
||||
String getGroupId();
|
||||
|
||||
/**
|
||||
* This method is called whenever the state of the given group has changed. The new state can be obtained by
|
||||
* {@link FullGroup#getState()}.
|
||||
*
|
||||
* @param group The group which received the state update.
|
||||
* @return
|
||||
*/
|
||||
boolean onGroupStateChanged(FullGroup group);
|
||||
|
||||
/**
|
||||
* This method is called whenever a group is removed.
|
||||
*/
|
||||
void onGroupRemoved();
|
||||
|
||||
/**
|
||||
* This method is called whenever a group is reported as gone.
|
||||
*/
|
||||
void onGroupGone();
|
||||
|
||||
/**
|
||||
* This method is called whenever a group is added.
|
||||
*
|
||||
* @param group The added group
|
||||
*/
|
||||
void onGroupAdded(FullGroup group);
|
||||
|
||||
/**
|
||||
* This method is called whenever the list of available scenes is updated.
|
||||
*
|
||||
* @param updatedScenes available scenes
|
||||
*/
|
||||
void onScenesUpdated(List<Scene> scenes);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.ConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.FullGroup;
|
||||
import org.openhab.binding.hue.internal.FullLight;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.StateUpdate;
|
||||
import org.openhab.binding.hue.internal.discovery.HueLightDiscoveryService;
|
||||
|
||||
/**
|
||||
* Access to the Hue system for light handlers.
|
||||
*
|
||||
* @author Simon Kaufmann - initial contribution and API
|
||||
* @author Samuel Leisering - Added support for sensor API
|
||||
* @author Christoph Weitkamp - Added support for sensor API
|
||||
* @author Laurent Garnier - Added support for groups
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface HueClient {
|
||||
|
||||
/**
|
||||
* Register {@link HueLightDiscoveryService} to bridge handler
|
||||
*
|
||||
* @param listener the discovery service
|
||||
* @return {@code true} if the new discovery service is accepted
|
||||
*/
|
||||
boolean registerDiscoveryListener(HueLightDiscoveryService listener);
|
||||
|
||||
/**
|
||||
* Unregister {@link HueLightDiscoveryService} from bridge handler
|
||||
*
|
||||
* @return {@code true} if the discovery service was removed
|
||||
*/
|
||||
boolean unregisterDiscoveryListener();
|
||||
|
||||
/**
|
||||
* Register a light status listener.
|
||||
*
|
||||
* @param lightStatusListener the light status listener
|
||||
* @return {@code true} if the collection of listeners has changed as a result of this call
|
||||
*/
|
||||
boolean registerLightStatusListener(LightStatusListener lightStatusListener);
|
||||
|
||||
/**
|
||||
* Unregister a light status listener.
|
||||
*
|
||||
* @param lightStatusListener the light status listener
|
||||
* @return {@code true} if the collection of listeners has changed as a result of this call
|
||||
*/
|
||||
boolean unregisterLightStatusListener(LightStatusListener lightStatusListener);
|
||||
|
||||
/**
|
||||
* Register a sensor status listener.
|
||||
*
|
||||
* @param sensorStatusListener the sensor status listener
|
||||
* @return {@code true} if the collection of listeners has changed as a result of this call
|
||||
*/
|
||||
boolean registerSensorStatusListener(SensorStatusListener sensorStatusListener);
|
||||
|
||||
/**
|
||||
* Unregister a sensor status listener.
|
||||
*
|
||||
* @param sensorStatusListener the sensor status listener
|
||||
* @return {@code true} if the collection of listeners has changed as a result of this call
|
||||
*/
|
||||
boolean unregisterSensorStatusListener(SensorStatusListener sensorStatusListener);
|
||||
|
||||
/**
|
||||
* Register a group status listener.
|
||||
*
|
||||
* @param groupStatusListener the group status listener
|
||||
* @return {@code true} if the collection of listeners has changed as a result of this call
|
||||
*/
|
||||
boolean registerGroupStatusListener(GroupStatusListener groupStatusListener);
|
||||
|
||||
/**
|
||||
* Unregister a group status listener.
|
||||
*
|
||||
* @param groupStatusListener the group status listener
|
||||
* @return {@code true} if the collection of listeners has changed as a result of this call
|
||||
*/
|
||||
boolean unregisterGroupStatusListener(GroupStatusListener groupStatusListener);
|
||||
|
||||
/**
|
||||
* Get the light by its ID.
|
||||
*
|
||||
* @param lightId the light ID
|
||||
* @return the full light representation or {@code null} if it could not be found
|
||||
*/
|
||||
@Nullable
|
||||
FullLight getLightById(String lightId);
|
||||
|
||||
/**
|
||||
* Get the sensor by its ID.
|
||||
*
|
||||
* @param sensorId the sensor ID
|
||||
* @return the full sensor representation or {@code null} if it could not be found
|
||||
*/
|
||||
@Nullable
|
||||
FullSensor getSensorById(String sensorId);
|
||||
|
||||
/**
|
||||
* Get the group by its ID.
|
||||
*
|
||||
* @param groupId the group ID
|
||||
* @return the full group representation or {@code null} if it could not be found
|
||||
*/
|
||||
@Nullable
|
||||
FullGroup getGroupById(String groupId);
|
||||
|
||||
/**
|
||||
* Updates the given light.
|
||||
*
|
||||
* @param listener the light status listener to block it for state updates
|
||||
* @param light the light to be updated
|
||||
* @param stateUpdate the state update
|
||||
* @param fadeTime the status listener will be blocked for this duration after command
|
||||
*/
|
||||
void updateLightState(LightStatusListener listener, FullLight light, StateUpdate stateUpdate, long fadeTime);
|
||||
|
||||
/**
|
||||
* Updates the given sensors config.
|
||||
*
|
||||
* @param sensor the light to be updated
|
||||
* @param configUpdate the config update
|
||||
*/
|
||||
void updateSensorConfig(FullSensor sensor, ConfigUpdate configUpdate);
|
||||
|
||||
/**
|
||||
* Updates the given sensor.
|
||||
*
|
||||
* @param sensor the sensor to be updated
|
||||
* @param stateUpdate the state update
|
||||
*/
|
||||
void updateSensorState(FullSensor sensor, StateUpdate stateUpdate);
|
||||
|
||||
/**
|
||||
* Updates the given group.
|
||||
*
|
||||
* @param group the group to be updated
|
||||
* @param stateUpdate the state update
|
||||
*/
|
||||
void updateGroupState(FullGroup group, StateUpdate stateUpdate, long fadeTime);
|
||||
|
||||
/**
|
||||
* Recall scene to all lights that belong to the scene.
|
||||
*
|
||||
* @param id the ID of the scene to be recalled
|
||||
*/
|
||||
void recallScene(String id);
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.FullGroup;
|
||||
import org.openhab.binding.hue.internal.Scene;
|
||||
import org.openhab.binding.hue.internal.State;
|
||||
import org.openhab.binding.hue.internal.State.ColorMode;
|
||||
import org.openhab.binding.hue.internal.StateUpdate;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.StateOption;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* {@link HueGroupHandler} is the handler for a hue group of lights. It uses the {@link HueClient} to execute the
|
||||
* actual command.
|
||||
*
|
||||
* @author Laurent Garnier - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueGroupHandler extends BaseThingHandler implements GroupStatusListener {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_GROUP);
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HueGroupHandler.class);
|
||||
private final HueStateDescriptionOptionProvider stateDescriptionOptionProvider;
|
||||
|
||||
private @NonNullByDefault({}) String groupId;
|
||||
|
||||
private @Nullable Integer lastSentColorTemp;
|
||||
private @Nullable Integer lastSentBrightness;
|
||||
|
||||
private long defaultFadeTime = 400;
|
||||
|
||||
private @Nullable HueClient hueClient;
|
||||
|
||||
private @Nullable ScheduledFuture<?> scheduledFuture;
|
||||
private @Nullable FullGroup lastFullGroup;
|
||||
|
||||
private List<String> consoleScenesList = new ArrayList<>();
|
||||
|
||||
public HueGroupHandler(Thing thing, HueStateDescriptionOptionProvider stateDescriptionOptionProvider) {
|
||||
super(thing);
|
||||
this.stateDescriptionOptionProvider = stateDescriptionOptionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing hue group handler.");
|
||||
Bridge bridge = getBridge();
|
||||
initializeThing((bridge == null) ? null : bridge.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
|
||||
logger.debug("bridgeStatusChanged {}", bridgeStatusInfo);
|
||||
initializeThing(bridgeStatusInfo.getStatus());
|
||||
}
|
||||
|
||||
private void initializeThing(@Nullable ThingStatus bridgeStatus) {
|
||||
logger.debug("initializeThing thing {} bridge status {}", getThing().getUID(), bridgeStatus);
|
||||
final String configGroupId = (String) getConfig().get(GROUP_ID);
|
||||
if (configGroupId != null) {
|
||||
BigDecimal time = (BigDecimal) getConfig().get(FADETIME);
|
||||
if (time != null) {
|
||||
defaultFadeTime = time.longValueExact();
|
||||
}
|
||||
|
||||
groupId = configGroupId;
|
||||
// note: this call implicitly registers our handler as a listener on the bridge
|
||||
if (getHueClient() != null) {
|
||||
if (bridgeStatus == ThingStatus.ONLINE) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-no-group-id");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Hue group handler disposes. Unregistering listener.");
|
||||
cancelScheduledFuture();
|
||||
if (groupId != null) {
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler != null) {
|
||||
bridgeHandler.unregisterGroupStatusListener(this);
|
||||
hueClient = null;
|
||||
}
|
||||
groupId = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized @Nullable HueClient getHueClient() {
|
||||
if (hueClient == null) {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
return null;
|
||||
}
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof HueBridgeHandler) {
|
||||
HueClient bridgeHandler = (HueClient) handler;
|
||||
hueClient = bridgeHandler;
|
||||
bridgeHandler.registerGroupStatusListener(this);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return hueClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
handleCommand(channelUID.getId(), command, defaultFadeTime);
|
||||
}
|
||||
|
||||
public void handleCommand(String channel, Command command, long fadeTime) {
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler == null) {
|
||||
logger.debug("hue bridge handler not found. Cannot handle command without bridge.");
|
||||
return;
|
||||
}
|
||||
|
||||
FullGroup group = bridgeHandler.getGroupById(groupId);
|
||||
if (group == null) {
|
||||
logger.debug("hue group not known on bridge. Cannot handle command.");
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-wrong-group-id");
|
||||
return;
|
||||
}
|
||||
|
||||
Integer lastColorTemp;
|
||||
StateUpdate newState = null;
|
||||
switch (channel) {
|
||||
case CHANNEL_COLOR:
|
||||
if (command instanceof HSBType) {
|
||||
HSBType hsbCommand = (HSBType) command;
|
||||
if (hsbCommand.getBrightness().intValue() == 0) {
|
||||
newState = LightStateConverter.toOnOffLightState(OnOffType.OFF);
|
||||
} else {
|
||||
newState = LightStateConverter.toColorLightState(hsbCommand, group.getState());
|
||||
newState.setOn(true);
|
||||
newState.setTransitionTime(fadeTime);
|
||||
}
|
||||
} else if (command instanceof PercentType) {
|
||||
newState = LightStateConverter.toBrightnessLightState((PercentType) command);
|
||||
newState.setTransitionTime(fadeTime);
|
||||
} else if (command instanceof OnOffType) {
|
||||
newState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
newState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, group);
|
||||
if (newState != null) {
|
||||
newState.setTransitionTime(fadeTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_COLORTEMPERATURE:
|
||||
if (command instanceof PercentType) {
|
||||
newState = LightStateConverter.toColorTemperatureLightState((PercentType) command);
|
||||
newState.setTransitionTime(fadeTime);
|
||||
} else if (command instanceof OnOffType) {
|
||||
newState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
newState = convertColorTempChangeToStateUpdate((IncreaseDecreaseType) command, group);
|
||||
if (newState != null) {
|
||||
newState.setTransitionTime(fadeTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_BRIGHTNESS:
|
||||
if (command instanceof PercentType) {
|
||||
newState = LightStateConverter.toBrightnessLightState((PercentType) command);
|
||||
newState.setTransitionTime(fadeTime);
|
||||
} else if (command instanceof OnOffType) {
|
||||
newState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
newState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, group);
|
||||
if (newState != null) {
|
||||
newState.setTransitionTime(fadeTime);
|
||||
}
|
||||
}
|
||||
lastColorTemp = lastSentColorTemp;
|
||||
if (newState != null && lastColorTemp != null) {
|
||||
// make sure that the light also has the latest color temp
|
||||
// this might not have been yet set in the light, if it was off
|
||||
newState.setColorTemperature(lastColorTemp);
|
||||
newState.setTransitionTime(fadeTime);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SWITCH:
|
||||
if (command instanceof OnOffType) {
|
||||
newState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
}
|
||||
lastColorTemp = lastSentColorTemp;
|
||||
if (newState != null && lastColorTemp != null) {
|
||||
// make sure that the light also has the latest color temp
|
||||
// this might not have been yet set in the light, if it was off
|
||||
newState.setColorTemperature(lastColorTemp);
|
||||
newState.setTransitionTime(fadeTime);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALERT:
|
||||
if (command instanceof StringType) {
|
||||
newState = LightStateConverter.toAlertState((StringType) command);
|
||||
if (newState == null) {
|
||||
// Unsupported StringType is passed. Log a warning
|
||||
// message and return.
|
||||
logger.warn("Unsupported String command: {}. Supported commands are: {}, {}, {} ", command,
|
||||
LightStateConverter.ALERT_MODE_NONE, LightStateConverter.ALERT_MODE_SELECT,
|
||||
LightStateConverter.ALERT_MODE_LONG_SELECT);
|
||||
return;
|
||||
} else {
|
||||
scheduleAlertStateRestore(command);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SCENE:
|
||||
if (command instanceof StringType) {
|
||||
newState = new StateUpdate().setScene(command.toString());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (newState != null) {
|
||||
cacheNewState(newState);
|
||||
bridgeHandler.updateGroupState(group, newState, fadeTime);
|
||||
} else {
|
||||
logger.debug("Command sent to an unknown channel id: {}:{}", getThing().getUID(), channel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches the new state that is sent to the bridge. This is necessary in case the lights are off when the values are
|
||||
* sent. In this case, the values are not yet set in the lights.
|
||||
*
|
||||
* @param newState the state to be cached
|
||||
*/
|
||||
private void cacheNewState(StateUpdate newState) {
|
||||
Integer tmpBrightness = newState.getBrightness();
|
||||
if (tmpBrightness != null) {
|
||||
lastSentBrightness = tmpBrightness;
|
||||
}
|
||||
Integer tmpColorTemp = newState.getColorTemperature();
|
||||
if (tmpColorTemp != null) {
|
||||
lastSentColorTemp = tmpColorTemp;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable StateUpdate convertColorTempChangeToStateUpdate(IncreaseDecreaseType command, FullGroup group) {
|
||||
StateUpdate stateUpdate = null;
|
||||
Integer currentColorTemp = getCurrentColorTemp(group.getState());
|
||||
if (currentColorTemp != null) {
|
||||
int newColorTemp = LightStateConverter.toAdjustedColorTemp(command, currentColorTemp);
|
||||
stateUpdate = new StateUpdate().setColorTemperature(newColorTemp);
|
||||
}
|
||||
return stateUpdate;
|
||||
}
|
||||
|
||||
private @Nullable Integer getCurrentColorTemp(@Nullable State groupState) {
|
||||
Integer colorTemp = lastSentColorTemp;
|
||||
if (colorTemp == null && groupState != null) {
|
||||
colorTemp = groupState.getColorTemperature();
|
||||
}
|
||||
return colorTemp;
|
||||
}
|
||||
|
||||
private @Nullable StateUpdate convertBrightnessChangeToStateUpdate(IncreaseDecreaseType command, FullGroup group) {
|
||||
Integer currentBrightness = getCurrentBrightness(group);
|
||||
if (currentBrightness == null) {
|
||||
return null;
|
||||
}
|
||||
int newBrightness = LightStateConverter.toAdjustedBrightness(command, currentBrightness);
|
||||
return createBrightnessStateUpdate(currentBrightness, newBrightness);
|
||||
}
|
||||
|
||||
private @Nullable Integer getCurrentBrightness(FullGroup group) {
|
||||
if (lastSentBrightness != null) {
|
||||
return lastSentBrightness;
|
||||
}
|
||||
State currentState = group.getState();
|
||||
if (currentState == null) {
|
||||
return null;
|
||||
}
|
||||
return currentState.isOn() ? currentState.getBrightness() : 0;
|
||||
}
|
||||
|
||||
private StateUpdate createBrightnessStateUpdate(int currentBrightness, int newBrightness) {
|
||||
StateUpdate lightUpdate = new StateUpdate();
|
||||
if (newBrightness == 0) {
|
||||
lightUpdate.turnOff();
|
||||
} else {
|
||||
lightUpdate.setBrightness(newBrightness);
|
||||
if (currentBrightness == 0) {
|
||||
lightUpdate.turnOn();
|
||||
}
|
||||
}
|
||||
return lightUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelLinked(ChannelUID channelUID) {
|
||||
HueClient handler = getHueClient();
|
||||
if (handler != null) {
|
||||
FullGroup group = handler.getGroupById(groupId);
|
||||
if (group != null) {
|
||||
onGroupStateChanged(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGroupStateChanged(FullGroup group) {
|
||||
logger.trace("onGroupStateChanged() was called for group {}", group.getId());
|
||||
|
||||
State state = group.getState();
|
||||
|
||||
final FullGroup lastState = lastFullGroup;
|
||||
if (lastState == null || !Objects.equals(lastState.getState(), state)) {
|
||||
lastFullGroup = group;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.trace("New state for group {}", groupId);
|
||||
|
||||
lastSentColorTemp = null;
|
||||
lastSentBrightness = null;
|
||||
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
logger.debug("onGroupStateChanged Group {}: on {} bri {} hue {} sat {} temp {} mode {} XY {}", group.getName(),
|
||||
state.isOn(), state.getBrightness(), state.getHue(), state.getSaturation(), state.getColorTemperature(),
|
||||
state.getColorMode(), state.getXY());
|
||||
|
||||
HSBType hsbType = LightStateConverter.toHSBType(state);
|
||||
if (!state.isOn()) {
|
||||
hsbType = new HSBType(hsbType.getHue(), hsbType.getSaturation(), new PercentType(0));
|
||||
}
|
||||
updateState(CHANNEL_COLOR, hsbType);
|
||||
|
||||
ColorMode colorMode = state.getColorMode();
|
||||
if (ColorMode.CT.equals(colorMode)) {
|
||||
PercentType colorTempPercentType = LightStateConverter.toColorTemperaturePercentType(state);
|
||||
updateState(CHANNEL_COLORTEMPERATURE, colorTempPercentType);
|
||||
} else {
|
||||
updateState(CHANNEL_COLORTEMPERATURE, UnDefType.NULL);
|
||||
}
|
||||
|
||||
PercentType brightnessPercentType = LightStateConverter.toBrightnessPercentType(state);
|
||||
if (!state.isOn()) {
|
||||
brightnessPercentType = new PercentType(0);
|
||||
}
|
||||
updateState(CHANNEL_BRIGHTNESS, brightnessPercentType);
|
||||
|
||||
updateState(CHANNEL_SWITCH, state.isOn() ? OnOffType.ON : OnOffType.OFF);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupAdded(FullGroup group) {
|
||||
onGroupStateChanged(group);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupRemoved() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.group-removed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupGone() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "@text/offline.group-removed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state options for applicable scenes.
|
||||
*/
|
||||
@Override
|
||||
public void onScenesUpdated(List<Scene> updatedScenes) {
|
||||
List<StateOption> stateOptions = Collections.emptyList();
|
||||
consoleScenesList = new ArrayList<>();
|
||||
HueClient handler = getHueClient();
|
||||
if (handler != null) {
|
||||
FullGroup group = handler.getGroupById(groupId);
|
||||
if (group != null) {
|
||||
stateOptions = updatedScenes.stream().filter(scene -> scene.isApplicableTo(group))
|
||||
.map(Scene::toStateOption).collect(Collectors.toList());
|
||||
consoleScenesList = updatedScenes
|
||||
.stream().filter(scene -> scene.isApplicableTo(group)).map(scene -> "Id is \"" + scene.getId()
|
||||
+ "\" for scene \"" + scene.toStateOption().getLabel() + "\"")
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
stateDescriptionOptionProvider.setStateOptions(new ChannelUID(getThing().getUID(), CHANNEL_SCENE),
|
||||
stateOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules restoration of the alert item state to {@link LightStateConverter#ALERT_MODE_NONE} after a given time.
|
||||
* <br>
|
||||
* Based on the initial command:
|
||||
* <ul>
|
||||
* <li>For {@link LightStateConverter#ALERT_MODE_SELECT} restoration will be triggered after <strong>2
|
||||
* seconds</strong>.
|
||||
* <li>For {@link LightStateConverter#ALERT_MODE_LONG_SELECT} restoration will be triggered after <strong>15
|
||||
* seconds</strong>.
|
||||
* </ul>
|
||||
* This method also cancels any previously scheduled restoration.
|
||||
*
|
||||
* @param command The {@link Command} sent to the item
|
||||
*/
|
||||
private void scheduleAlertStateRestore(Command command) {
|
||||
cancelScheduledFuture();
|
||||
int delay = getAlertDuration(command);
|
||||
|
||||
if (delay > 0) {
|
||||
scheduledFuture = scheduler.schedule(() -> {
|
||||
updateState(CHANNEL_ALERT, new StringType(LightStateConverter.ALERT_MODE_NONE));
|
||||
}, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will cancel previously scheduled alert item state
|
||||
* restoration.
|
||||
*/
|
||||
private void cancelScheduledFuture() {
|
||||
ScheduledFuture<?> scheduledJob = scheduledFuture;
|
||||
if (scheduledJob != null) {
|
||||
scheduledJob.cancel(true);
|
||||
scheduledFuture = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the time in <strong>milliseconds</strong> after
|
||||
* which, the state of the alert item has to be restored to {@link LightStateConverter#ALERT_MODE_NONE}.
|
||||
*
|
||||
* @param command The initial command sent to the alert item.
|
||||
* @return Based on the initial command will return:
|
||||
* <ul>
|
||||
* <li><strong>2000</strong> for {@link LightStateConverter#ALERT_MODE_SELECT}.
|
||||
* <li><strong>15000</strong> for {@link LightStateConverter#ALERT_MODE_LONG_SELECT}.
|
||||
* <li><strong>-1</strong> for any command different from the previous two.
|
||||
* </ul>
|
||||
*/
|
||||
private int getAlertDuration(Command command) {
|
||||
int delay;
|
||||
switch (command.toString()) {
|
||||
case LightStateConverter.ALERT_MODE_LONG_SELECT:
|
||||
delay = 15000;
|
||||
break;
|
||||
case LightStateConverter.ALERT_MODE_SELECT:
|
||||
delay = 2000;
|
||||
break;
|
||||
default:
|
||||
delay = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
public List<String> listScenesForConsole() {
|
||||
return consoleScenesList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupId() {
|
||||
return groupId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
import static org.openhab.core.thing.Thing.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.FullLight;
|
||||
import org.openhab.binding.hue.internal.State;
|
||||
import org.openhab.binding.hue.internal.State.ColorMode;
|
||||
import org.openhab.binding.hue.internal.StateUpdate;
|
||||
import org.openhab.binding.hue.internal.action.LightActions;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.UnDefType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* {@link HueLightHandler} is the handler for a hue light. It uses the {@link HueClient} to execute the actual
|
||||
* command.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
* @author Oliver Libutzki - Adjustments
|
||||
* @author Kai Kreuzer - stabilized code
|
||||
* @author Andre Fuechsel - implemented switch off when brightness == 0, changed to support generic thing types, changed
|
||||
* the initialization of properties
|
||||
* @author Thomas Höfer - added thing properties
|
||||
* @author Jochen Hiller - fixed status updates for reachable=true/false
|
||||
* @author Markus Mazurczak - added code for command handling of OSRAM PAR16 50
|
||||
* bulbs
|
||||
* @author Yordan Zhelev - added alert and effect functions
|
||||
* @author Denis Dudnik - switched to internally integrated source of Jue library
|
||||
* @author Christoph Weitkamp - Added support for bulbs using CIE XY colormode only
|
||||
* @author Jochen Leopold - Added support for custom fade times
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueLightHandler extends BaseThingHandler implements LightStatusListener {
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream.of(THING_TYPE_COLOR_LIGHT,
|
||||
THING_TYPE_COLOR_TEMPERATURE_LIGHT, THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_EXTENDED_COLOR_LIGHT,
|
||||
THING_TYPE_ON_OFF_LIGHT, THING_TYPE_ON_OFF_PLUG, THING_TYPE_DIMMABLE_PLUG).collect(Collectors.toSet());
|
||||
|
||||
// @formatter:off
|
||||
private static final Map<String, List<String>> VENDOR_MODEL_MAP = Stream.of(
|
||||
new SimpleEntry<>("Philips",
|
||||
Arrays.asList("LCT001", "LCT002", "LCT003", "LCT007", "LLC001", "LLC006", "LLC007", "LLC010",
|
||||
"LLC011", "LLC012", "LLC013", "LLC020", "LST001", "LST002", "LWB004", "LWB006", "LWB007",
|
||||
"LWL001")),
|
||||
new SimpleEntry<>("OSRAM",
|
||||
Arrays.asList("Classic_A60_RGBW", "PAR16_50_TW", "Surface_Light_TW", "Plug_01")))
|
||||
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()));
|
||||
// @formatter:on
|
||||
|
||||
private static final String OSRAM_PAR16_50_TW_MODEL_ID = "PAR16_50_TW";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HueLightHandler.class);
|
||||
|
||||
private @NonNullByDefault({}) String lightId;
|
||||
|
||||
private @Nullable FullLight lastFullLight;
|
||||
private long endBypassTime = 0L;
|
||||
|
||||
private @Nullable Integer lastSentColorTemp;
|
||||
private @Nullable Integer lastSentBrightness;
|
||||
|
||||
// Flag to indicate whether the bulb is of type Osram par16 50 TW or not
|
||||
private boolean isOsramPar16 = false;
|
||||
|
||||
private boolean propertiesInitializedSuccessfully = false;
|
||||
private long defaultFadeTime = 400;
|
||||
|
||||
private @Nullable HueClient hueClient;
|
||||
|
||||
private @Nullable ScheduledFuture<?> scheduledFuture;
|
||||
|
||||
public HueLightHandler(Thing hueLight) {
|
||||
super(hueLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing hue light handler.");
|
||||
Bridge bridge = getBridge();
|
||||
initializeThing((bridge == null) ? null : bridge.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
|
||||
logger.debug("bridgeStatusChanged {}", bridgeStatusInfo);
|
||||
initializeThing(bridgeStatusInfo.getStatus());
|
||||
}
|
||||
|
||||
private void initializeThing(@Nullable ThingStatus bridgeStatus) {
|
||||
logger.debug("initializeThing thing {} bridge status {}", getThing().getUID(), bridgeStatus);
|
||||
final String configLightId = (String) getConfig().get(LIGHT_ID);
|
||||
if (configLightId != null) {
|
||||
BigDecimal time = (BigDecimal) getConfig().get(FADETIME);
|
||||
if (time != null) {
|
||||
defaultFadeTime = time.longValueExact();
|
||||
}
|
||||
|
||||
lightId = configLightId;
|
||||
// note: this call implicitly registers our handler as a listener on the bridge
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler != null) {
|
||||
if (bridgeStatus == ThingStatus.ONLINE) {
|
||||
initializeProperties(bridgeHandler.getLightById(lightId));
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-no-light-id");
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void initializeProperties(@Nullable FullLight fullLight) {
|
||||
if (!propertiesInitializedSuccessfully && fullLight != null) {
|
||||
Map<String, String> properties = editProperties();
|
||||
String softwareVersion = fullLight.getSoftwareVersion();
|
||||
if (softwareVersion != null) {
|
||||
properties.put(PROPERTY_FIRMWARE_VERSION, softwareVersion);
|
||||
}
|
||||
String modelId = fullLight.getNormalizedModelID();
|
||||
if (modelId != null) {
|
||||
properties.put(PROPERTY_MODEL_ID, modelId);
|
||||
String vendor = getVendor(modelId);
|
||||
if (vendor != null) {
|
||||
properties.put(PROPERTY_VENDOR, vendor);
|
||||
}
|
||||
} else {
|
||||
properties.put(PROPERTY_VENDOR, fullLight.getManufacturerName());
|
||||
}
|
||||
properties.put(PRODUCT_NAME, fullLight.getProductName());
|
||||
String uniqueID = fullLight.getUniqueID();
|
||||
if (uniqueID != null) {
|
||||
properties.put(UNIQUE_ID, uniqueID);
|
||||
}
|
||||
updateProperties(properties);
|
||||
isOsramPar16 = OSRAM_PAR16_50_TW_MODEL_ID.equals(modelId);
|
||||
propertiesInitializedSuccessfully = true;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable String getVendor(String modelId) {
|
||||
for (String vendor : VENDOR_MODEL_MAP.keySet()) {
|
||||
if (VENDOR_MODEL_MAP.get(vendor).contains(modelId)) {
|
||||
return vendor;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Hue light handler disposes. Unregistering listener.");
|
||||
cancelScheduledFuture();
|
||||
if (lightId != null) {
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler != null) {
|
||||
bridgeHandler.unregisterLightStatusListener(this);
|
||||
hueClient = null;
|
||||
}
|
||||
lightId = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
handleCommand(channelUID.getId(), command, defaultFadeTime);
|
||||
}
|
||||
|
||||
public void handleCommand(String channel, Command command, long fadeTime) {
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler == null) {
|
||||
logger.warn("hue bridge handler not found. Cannot handle command without bridge.");
|
||||
return;
|
||||
}
|
||||
|
||||
final FullLight light = lastFullLight == null ? bridgeHandler.getLightById(lightId) : lastFullLight;
|
||||
if (light == null) {
|
||||
logger.debug("hue light not known on bridge. Cannot handle command.");
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-wrong-light-id");
|
||||
return;
|
||||
}
|
||||
|
||||
Integer lastColorTemp;
|
||||
StateUpdate lightState = null;
|
||||
switch (channel) {
|
||||
case CHANNEL_COLORTEMPERATURE:
|
||||
if (command instanceof PercentType) {
|
||||
lightState = LightStateConverter.toColorTemperatureLightState((PercentType) command);
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
} else if (command instanceof OnOffType) {
|
||||
lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
if (isOsramPar16) {
|
||||
lightState = addOsramSpecificCommands(lightState, (OnOffType) command);
|
||||
}
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
lightState = convertColorTempChangeToStateUpdate((IncreaseDecreaseType) command, light);
|
||||
if (lightState != null) {
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case CHANNEL_BRIGHTNESS:
|
||||
if (command instanceof PercentType) {
|
||||
lightState = LightStateConverter.toBrightnessLightState((PercentType) command);
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
} else if (command instanceof OnOffType) {
|
||||
lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
if (isOsramPar16) {
|
||||
lightState = addOsramSpecificCommands(lightState, (OnOffType) command);
|
||||
}
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
lightState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, light);
|
||||
if (lightState != null) {
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
}
|
||||
}
|
||||
lastColorTemp = lastSentColorTemp;
|
||||
if (lightState != null && lastColorTemp != null) {
|
||||
// make sure that the light also has the latest color temp
|
||||
// this might not have been yet set in the light, if it was off
|
||||
lightState.setColorTemperature(lastColorTemp);
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_SWITCH:
|
||||
logger.trace("CHANNEL_SWITCH handling command {}", command);
|
||||
if (command instanceof OnOffType) {
|
||||
lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
if (isOsramPar16) {
|
||||
lightState = addOsramSpecificCommands(lightState, (OnOffType) command);
|
||||
}
|
||||
}
|
||||
lastColorTemp = lastSentColorTemp;
|
||||
if (lightState != null && lastColorTemp != null) {
|
||||
// make sure that the light also has the latest color temp
|
||||
// this might not have been yet set in the light, if it was off
|
||||
lightState.setColorTemperature(lastColorTemp);
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_COLOR:
|
||||
if (command instanceof HSBType) {
|
||||
HSBType hsbCommand = (HSBType) command;
|
||||
if (hsbCommand.getBrightness().intValue() == 0) {
|
||||
lightState = LightStateConverter.toOnOffLightState(OnOffType.OFF);
|
||||
} else {
|
||||
lightState = LightStateConverter.toColorLightState(hsbCommand, light.getState());
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
}
|
||||
} else if (command instanceof PercentType) {
|
||||
lightState = LightStateConverter.toBrightnessLightState((PercentType) command);
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
} else if (command instanceof OnOffType) {
|
||||
lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
|
||||
} else if (command instanceof IncreaseDecreaseType) {
|
||||
lightState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, light);
|
||||
if (lightState != null) {
|
||||
lightState.setTransitionTime(fadeTime);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_ALERT:
|
||||
if (command instanceof StringType) {
|
||||
lightState = LightStateConverter.toAlertState((StringType) command);
|
||||
if (lightState == null) {
|
||||
// Unsupported StringType is passed. Log a warning
|
||||
// message and return.
|
||||
logger.warn("Unsupported String command: {}. Supported commands are: {}, {}, {} ", command,
|
||||
LightStateConverter.ALERT_MODE_NONE, LightStateConverter.ALERT_MODE_SELECT,
|
||||
LightStateConverter.ALERT_MODE_LONG_SELECT);
|
||||
return;
|
||||
} else {
|
||||
scheduleAlertStateRestore(command);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_EFFECT:
|
||||
if (command instanceof OnOffType) {
|
||||
lightState = LightStateConverter.toOnOffEffectState((OnOffType) command);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (lightState != null) {
|
||||
// Cache values which we have sent
|
||||
Integer tmpBrightness = lightState.getBrightness();
|
||||
if (tmpBrightness != null) {
|
||||
lastSentBrightness = tmpBrightness;
|
||||
}
|
||||
Integer tmpColorTemp = lightState.getColorTemperature();
|
||||
if (tmpColorTemp != null) {
|
||||
lastSentColorTemp = tmpColorTemp;
|
||||
}
|
||||
bridgeHandler.updateLightState(this, light, lightState, fadeTime);
|
||||
} else {
|
||||
logger.warn("Command sent to an unknown channel id: {}:{}", getThing().getUID(), channel);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Applies additional {@link StateUpdate} commands as a workaround for Osram
|
||||
* Lightify PAR16 TW firmware bug. Also see
|
||||
* http://www.everyhue.com/vanilla/discussion/1756/solved-lightify-turning-off
|
||||
*/
|
||||
private StateUpdate addOsramSpecificCommands(StateUpdate lightState, OnOffType actionType) {
|
||||
if (actionType.equals(OnOffType.ON)) {
|
||||
lightState.setBrightness(254);
|
||||
} else {
|
||||
lightState.setTransitionTime(0);
|
||||
}
|
||||
return lightState;
|
||||
}
|
||||
|
||||
private @Nullable StateUpdate convertColorTempChangeToStateUpdate(IncreaseDecreaseType command, FullLight light) {
|
||||
StateUpdate stateUpdate = null;
|
||||
Integer currentColorTemp = getCurrentColorTemp(light.getState());
|
||||
if (currentColorTemp != null) {
|
||||
int newColorTemp = LightStateConverter.toAdjustedColorTemp(command, currentColorTemp);
|
||||
stateUpdate = new StateUpdate().setColorTemperature(newColorTemp);
|
||||
}
|
||||
return stateUpdate;
|
||||
}
|
||||
|
||||
private @Nullable Integer getCurrentColorTemp(@Nullable State lightState) {
|
||||
Integer colorTemp = lastSentColorTemp;
|
||||
if (colorTemp == null && lightState != null) {
|
||||
colorTemp = lightState.getColorTemperature();
|
||||
}
|
||||
return colorTemp;
|
||||
}
|
||||
|
||||
private @Nullable StateUpdate convertBrightnessChangeToStateUpdate(IncreaseDecreaseType command, FullLight light) {
|
||||
StateUpdate stateUpdate = null;
|
||||
Integer currentBrightness = getCurrentBrightness(light.getState());
|
||||
if (currentBrightness != null) {
|
||||
int newBrightness = LightStateConverter.toAdjustedBrightness(command, currentBrightness);
|
||||
stateUpdate = createBrightnessStateUpdate(currentBrightness, newBrightness);
|
||||
}
|
||||
return stateUpdate;
|
||||
}
|
||||
|
||||
private @Nullable Integer getCurrentBrightness(@Nullable State lightState) {
|
||||
Integer brightness = lastSentBrightness;
|
||||
if (brightness == null && lightState != null) {
|
||||
if (!lightState.isOn()) {
|
||||
brightness = 0;
|
||||
} else {
|
||||
brightness = lightState.getBrightness();
|
||||
}
|
||||
}
|
||||
return brightness;
|
||||
}
|
||||
|
||||
private StateUpdate createBrightnessStateUpdate(int currentBrightness, int newBrightness) {
|
||||
StateUpdate lightUpdate = new StateUpdate();
|
||||
if (newBrightness == 0) {
|
||||
lightUpdate.turnOff();
|
||||
} else {
|
||||
lightUpdate.setBrightness(newBrightness);
|
||||
if (currentBrightness == 0) {
|
||||
lightUpdate.turnOn();
|
||||
}
|
||||
}
|
||||
return lightUpdate;
|
||||
}
|
||||
|
||||
protected synchronized @Nullable HueClient getHueClient() {
|
||||
if (hueClient == null) {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
return null;
|
||||
}
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof HueClient) {
|
||||
HueClient bridgeHandler = (HueClient) handler;
|
||||
hueClient = bridgeHandler;
|
||||
bridgeHandler.registerLightStatusListener(this);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return hueClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPollBypass(long bypassTime) {
|
||||
endBypassTime = System.currentTimeMillis() + bypassTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsetPollBypass() {
|
||||
endBypassTime = 0L;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLightStateChanged(FullLight fullLight) {
|
||||
logger.trace("onLightStateChanged() was called");
|
||||
|
||||
if (System.currentTimeMillis() <= endBypassTime) {
|
||||
logger.debug("Bypass light update after command ({}).", lightId);
|
||||
return false;
|
||||
}
|
||||
|
||||
State state = fullLight.getState();
|
||||
|
||||
final FullLight lastState = lastFullLight;
|
||||
if (lastState == null || !Objects.equals(lastState.getState(), state)) {
|
||||
lastFullLight = fullLight;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.trace("New state for light {}", lightId);
|
||||
|
||||
initializeProperties(fullLight);
|
||||
|
||||
lastSentColorTemp = null;
|
||||
lastSentBrightness = null;
|
||||
|
||||
// update status (ONLINE, OFFLINE)
|
||||
if (state.isReachable()) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
// we assume OFFLINE without any error (NONE), as this is an
|
||||
// expected state (when bulb powered off)
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.light-not-reachable");
|
||||
}
|
||||
|
||||
logger.debug("onLightStateChanged Light {}: on {} bri {} hue {} sat {} temp {} mode {} XY {}",
|
||||
fullLight.getName(), state.isOn(), state.getBrightness(), state.getHue(), state.getSaturation(),
|
||||
state.getColorTemperature(), state.getColorMode(), state.getXY());
|
||||
|
||||
HSBType hsbType = LightStateConverter.toHSBType(state);
|
||||
if (!state.isOn()) {
|
||||
hsbType = new HSBType(hsbType.getHue(), hsbType.getSaturation(), new PercentType(0));
|
||||
}
|
||||
updateState(CHANNEL_COLOR, hsbType);
|
||||
|
||||
ColorMode colorMode = state.getColorMode();
|
||||
if (ColorMode.CT.equals(colorMode)) {
|
||||
PercentType colorTempPercentType = LightStateConverter.toColorTemperaturePercentType(state);
|
||||
updateState(CHANNEL_COLORTEMPERATURE, colorTempPercentType);
|
||||
} else {
|
||||
updateState(CHANNEL_COLORTEMPERATURE, UnDefType.NULL);
|
||||
}
|
||||
|
||||
PercentType brightnessPercentType = LightStateConverter.toBrightnessPercentType(state);
|
||||
if (!state.isOn()) {
|
||||
brightnessPercentType = new PercentType(0);
|
||||
}
|
||||
updateState(CHANNEL_BRIGHTNESS, brightnessPercentType);
|
||||
|
||||
if (state.isOn()) {
|
||||
updateState(CHANNEL_SWITCH, OnOffType.ON);
|
||||
} else {
|
||||
updateState(CHANNEL_SWITCH, OnOffType.OFF);
|
||||
}
|
||||
|
||||
StringType stringType = LightStateConverter.toAlertStringType(state);
|
||||
if (!"NULL".equals(stringType.toString())) {
|
||||
updateState(CHANNEL_ALERT, stringType);
|
||||
scheduleAlertStateRestore(stringType);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelLinked(ChannelUID channelUID) {
|
||||
HueClient handler = getHueClient();
|
||||
if (handler != null) {
|
||||
FullLight light = handler.getLightById(lightId);
|
||||
if (light != null) {
|
||||
onLightStateChanged(light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLightRemoved() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.light-removed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLightGone() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "@text/offline.light-not-reachable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLightAdded(FullLight light) {
|
||||
onLightStateChanged(light);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedules restoration of the alert item state to {@link LightStateConverter#ALERT_MODE_NONE} after a given time.
|
||||
* <br>
|
||||
* Based on the initial command:
|
||||
* <ul>
|
||||
* <li>For {@link LightStateConverter#ALERT_MODE_SELECT} restoration will be triggered after <strong>2
|
||||
* seconds</strong>.
|
||||
* <li>For {@link LightStateConverter#ALERT_MODE_LONG_SELECT} restoration will be triggered after <strong>15
|
||||
* seconds</strong>.
|
||||
* </ul>
|
||||
* This method also cancels any previously scheduled restoration.
|
||||
*
|
||||
* @param command The {@link Command} sent to the item
|
||||
*/
|
||||
private void scheduleAlertStateRestore(Command command) {
|
||||
cancelScheduledFuture();
|
||||
int delay = getAlertDuration(command);
|
||||
|
||||
if (delay > 0) {
|
||||
scheduledFuture = scheduler.schedule(() -> {
|
||||
updateState(CHANNEL_ALERT, new StringType(LightStateConverter.ALERT_MODE_NONE));
|
||||
}, delay, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will cancel previously scheduled alert item state
|
||||
* restoration.
|
||||
*/
|
||||
private void cancelScheduledFuture() {
|
||||
ScheduledFuture<?> scheduledJob = scheduledFuture;
|
||||
if (scheduledJob != null) {
|
||||
scheduledJob.cancel(true);
|
||||
scheduledFuture = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the time in <strong>milliseconds</strong> after
|
||||
* which, the state of the alert item has to be restored to {@link LightStateConverter#ALERT_MODE_NONE}.
|
||||
*
|
||||
* @param command The initial command sent to the alert item.
|
||||
* @return Based on the initial command will return:
|
||||
* <ul>
|
||||
* <li><strong>2000</strong> for {@link LightStateConverter#ALERT_MODE_SELECT}.
|
||||
* <li><strong>15000</strong> for {@link LightStateConverter#ALERT_MODE_LONG_SELECT}.
|
||||
* <li><strong>-1</strong> for any command different from the previous two.
|
||||
* </ul>
|
||||
*/
|
||||
private int getAlertDuration(Command command) {
|
||||
int delay;
|
||||
switch (command.toString()) {
|
||||
case LightStateConverter.ALERT_MODE_LONG_SELECT:
|
||||
delay = 15000;
|
||||
break;
|
||||
case LightStateConverter.ALERT_MODE_SELECT:
|
||||
delay = 2000;
|
||||
break;
|
||||
default:
|
||||
delay = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||
return Collections.singletonList(LightActions.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLightId() {
|
||||
return lightId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
import static org.openhab.core.thing.Thing.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.StateUpdate;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DateTimeType;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Bridge;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.ThingStatusInfo;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract Sensor Handler
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class HueSensorHandler extends BaseThingHandler implements SensorStatusListener {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSensorHandler.class);
|
||||
|
||||
private @NonNullByDefault({}) String sensorId;
|
||||
|
||||
private boolean configInitializedSuccessfully;
|
||||
private boolean propertiesInitializedSuccessfully;
|
||||
|
||||
private @Nullable HueClient hueClient;
|
||||
|
||||
private @Nullable FullSensor lastFullSensor;
|
||||
|
||||
public HueSensorHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing hue sensor handler.");
|
||||
Bridge bridge = getBridge();
|
||||
initializeThing((bridge == null) ? null : bridge.getStatus());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
|
||||
logger.debug("bridgeStatusChanged {}", bridgeStatusInfo);
|
||||
initializeThing(bridgeStatusInfo.getStatus());
|
||||
}
|
||||
|
||||
private void initializeThing(@Nullable ThingStatus bridgeStatus) {
|
||||
logger.debug("initializeThing thing {} bridge status {}", getThing().getUID(), bridgeStatus);
|
||||
final String configSensorId = (String) getConfig().get(SENSOR_ID);
|
||||
if (configSensorId != null) {
|
||||
sensorId = configSensorId;
|
||||
// note: this call implicitly registers our handler as a listener on the bridge
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler != null) {
|
||||
if (bridgeStatus == ThingStatus.ONLINE) {
|
||||
initializeProperties(bridgeHandler.getSensorById(sensorId));
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_UNINITIALIZED);
|
||||
}
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-no-sensor-id");
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void initializeProperties(@Nullable FullSensor fullSensor) {
|
||||
if (!propertiesInitializedSuccessfully && fullSensor != null) {
|
||||
Map<String, String> properties = editProperties();
|
||||
String softwareVersion = fullSensor.getSoftwareVersion();
|
||||
if (softwareVersion != null) {
|
||||
properties.put(PROPERTY_FIRMWARE_VERSION, softwareVersion);
|
||||
}
|
||||
String modelId = fullSensor.getNormalizedModelID();
|
||||
if (modelId != null) {
|
||||
properties.put(PROPERTY_MODEL_ID, modelId);
|
||||
}
|
||||
properties.put(PROPERTY_VENDOR, fullSensor.getManufacturerName());
|
||||
properties.put(PRODUCT_NAME, fullSensor.getProductName());
|
||||
String uniqueID = fullSensor.getUniqueID();
|
||||
if (uniqueID != null) {
|
||||
properties.put(UNIQUE_ID, uniqueID);
|
||||
}
|
||||
updateProperties(properties);
|
||||
propertiesInitializedSuccessfully = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
logger.debug("Hue sensor handler disposes. Unregistering listener.");
|
||||
if (sensorId != null) {
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler != null) {
|
||||
bridgeHandler.unregisterSensorStatusListener(this);
|
||||
hueClient = null;
|
||||
}
|
||||
sensorId = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized @Nullable HueClient getHueClient() {
|
||||
if (hueClient == null) {
|
||||
Bridge bridge = getBridge();
|
||||
if (bridge == null) {
|
||||
return null;
|
||||
}
|
||||
ThingHandler handler = bridge.getHandler();
|
||||
if (handler instanceof HueBridgeHandler) {
|
||||
HueClient bridgeHandler = (HueClient) handler;
|
||||
hueClient = bridgeHandler;
|
||||
bridgeHandler.registerSensorStatusListener(this);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return hueClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
handleCommand(channelUID.getId(), command);
|
||||
}
|
||||
|
||||
public void handleCommand(String channel, Command command) {
|
||||
HueClient bridgeHandler = getHueClient();
|
||||
if (bridgeHandler == null) {
|
||||
logger.warn("hue bridge handler not found. Cannot handle command without bridge.");
|
||||
return;
|
||||
}
|
||||
|
||||
final FullSensor sensor = lastFullSensor;
|
||||
|
||||
if (sensor == null) {
|
||||
logger.debug("hue sensor not known on bridge. Cannot handle command.");
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-wrong-sensor-id");
|
||||
return;
|
||||
}
|
||||
|
||||
StateUpdate sensorState = new StateUpdate();
|
||||
switch (channel) {
|
||||
case STATE_STATUS:
|
||||
sensorState = sensorState.setStatus(((DecimalType) command).intValue());
|
||||
break;
|
||||
case STATE_FLAG:
|
||||
sensorState = sensorState.setFlag(OnOffType.ON.equals(command));
|
||||
break;
|
||||
}
|
||||
|
||||
if (sensorState != null) {
|
||||
bridgeHandler.updateSensorState(sensor, sensorState);
|
||||
} else {
|
||||
logger.warn("Command sent to an unknown channel id: {}:{}", getThing().getUID(), channel);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
SensorConfigUpdate configUpdate = doConfigurationUpdate(configurationParameters);
|
||||
if (configurationParameters.containsKey(CONFIG_ON)) {
|
||||
configUpdate.setOn(Boolean.TRUE.equals(configurationParameters.get(CONFIG_ON)));
|
||||
}
|
||||
|
||||
if (!configUpdate.isEmpty()) {
|
||||
HueClient hueBridge = getHueClient();
|
||||
if (hueBridge == null) {
|
||||
logger.warn("hue bridge handler not found. Cannot handle configuration update without bridge.");
|
||||
return;
|
||||
}
|
||||
|
||||
final FullSensor sensor = lastFullSensor;
|
||||
if (sensor == null) {
|
||||
logger.debug("hue sensor not known on bridge. Cannot handle command.");
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/offline.conf-error-wrong-sensor-id");
|
||||
return;
|
||||
}
|
||||
|
||||
hueBridge.updateSensorConfig(sensor, configUpdate);
|
||||
}
|
||||
|
||||
super.handleConfigurationUpdate(configurationParameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSensorStateChanged(FullSensor sensor) {
|
||||
logger.trace("onSensorStateChanged() was called");
|
||||
|
||||
final FullSensor lastSensor = lastFullSensor;
|
||||
if (lastSensor == null || !Objects.equals(lastSensor.getState(), sensor.getState())) {
|
||||
lastFullSensor = sensor;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
logger.trace("New state for sensor {}", sensorId);
|
||||
|
||||
initializeProperties(sensor);
|
||||
|
||||
if (Boolean.TRUE.equals(sensor.getConfig().get(CONFIG_REACHABLE))) {
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.sensor-not-reachable");
|
||||
}
|
||||
|
||||
// update generic sensor config
|
||||
final Configuration config = !configInitializedSuccessfully ? editConfiguration() : getConfig();
|
||||
if (sensor.getConfig().containsKey(CONFIG_ON)) {
|
||||
config.put(CONFIG_ON, sensor.getConfig().get(CONFIG_ON));
|
||||
}
|
||||
|
||||
// update specific sensor config
|
||||
doSensorStateChanged(sensor, config);
|
||||
|
||||
Object lastUpdated = sensor.getState().get(STATE_LAST_UPDATED);
|
||||
if (lastUpdated != null) {
|
||||
try {
|
||||
updateState(CHANNEL_LAST_UPDATED,
|
||||
new DateTimeType(ZonedDateTime.ofInstant(
|
||||
LocalDateTime.parse(String.valueOf(lastUpdated), DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||
ZoneOffset.UTC, ZoneId.systemDefault())));
|
||||
} catch (DateTimeParseException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
Object status = sensor.getState().get(STATE_STATUS);
|
||||
if (status != null) {
|
||||
try {
|
||||
DecimalType value = new DecimalType(String.valueOf(status));
|
||||
updateState(STATE_STATUS, value);
|
||||
} catch (DateTimeParseException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
Object flag = sensor.getState().get(STATE_FLAG);
|
||||
if (flag != null) {
|
||||
try {
|
||||
boolean value = Boolean.parseBoolean(String.valueOf(flag));
|
||||
updateState(CHANNEL_FLAG, value ? OnOffType.ON : OnOffType.OFF);
|
||||
} catch (DateTimeParseException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
Object battery = sensor.getConfig().get(CONFIG_BATTERY);
|
||||
if (battery != null) {
|
||||
DecimalType batteryLevel = DecimalType.valueOf(String.valueOf(battery));
|
||||
updateState(CHANNEL_BATTERY_LEVEL, batteryLevel);
|
||||
updateState(CHANNEL_BATTERY_LOW, batteryLevel.intValue() <= 10 ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
|
||||
if (!configInitializedSuccessfully) {
|
||||
updateConfiguration(config);
|
||||
configInitializedSuccessfully = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelLinked(ChannelUID channelUID) {
|
||||
final FullSensor sensor = lastFullSensor;
|
||||
if (sensor != null) {
|
||||
onSensorStateChanged(sensor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the sensors configuration change.
|
||||
*
|
||||
* @param configurationParameters
|
||||
* @return
|
||||
*/
|
||||
protected abstract SensorConfigUpdate doConfigurationUpdate(Map<String, Object> configurationParameters);
|
||||
|
||||
/**
|
||||
* Handles the sensor change. Implementation should also update sensor-specific configuration that changed since the
|
||||
* last update.
|
||||
*
|
||||
* @param bridge the bridge
|
||||
* @param sensor the sensor
|
||||
* @param config the configuration in which to update the config states of the sensor
|
||||
*/
|
||||
protected abstract void doSensorStateChanged(FullSensor sensor, Configuration config);
|
||||
|
||||
@Override
|
||||
public void onSensorRemoved() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE, "@text/offline.sensor-not-reachable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorGone() {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.GONE, "@text/offline.conf-error-wrong-sensor-id");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSensorAdded(FullSensor sensor) {
|
||||
onSensorStateChanged(sensor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSensorId() {
|
||||
return sensorId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
|
||||
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
|
||||
import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
|
||||
/**
|
||||
* Dynamic provider of state options for {@link HueBridgeHandler} while leaving other state description fields as
|
||||
* original.
|
||||
*
|
||||
* @author Hengrui Jiang - Initial contribution
|
||||
*/
|
||||
@Component(service = { DynamicStateDescriptionProvider.class, HueStateDescriptionOptionProvider.class })
|
||||
@NonNullByDefault
|
||||
public class HueStateDescriptionOptionProvider extends BaseDynamicStateDescriptionProvider {
|
||||
|
||||
@Reference
|
||||
protected void setChannelTypeI18nLocalizationService(
|
||||
final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
|
||||
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
|
||||
}
|
||||
|
||||
protected void unsetChannelTypeI18nLocalizationService(
|
||||
final ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
|
||||
this.channelTypeI18nLocalizationService = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.hue.internal.State;
|
||||
import org.openhab.binding.hue.internal.State.AlertMode;
|
||||
import org.openhab.binding.hue.internal.State.ColorMode;
|
||||
import org.openhab.binding.hue.internal.State.Effect;
|
||||
import org.openhab.binding.hue.internal.StateUpdate;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.PercentType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
|
||||
/**
|
||||
* The {@link LightStateConverter} is responsible for mapping Eclipse SmartHome
|
||||
* types to jue types and vice versa.
|
||||
*
|
||||
* @author Dennis Nobel - Initial contribution
|
||||
* @author Oliver Libutzki - Adjustments
|
||||
* @author Kai Kreuzer - made code static
|
||||
* @author Andre Fuechsel - added method for brightness
|
||||
* @author Yordan Zhelev - added method for alert
|
||||
* @author Denis Dudnik - switched to internally integrated source of Jue library, minor code cleanup
|
||||
* @author Christoph Weitkamp - Added support for bulbs using CIE XY colormode only
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LightStateConverter {
|
||||
|
||||
private static final double HUE_FACTOR = 65535 / 360.0;
|
||||
private static final double SATURATION_FACTOR = 2.54;
|
||||
private static final double BRIGHTNESS_FACTOR = 2.54;
|
||||
|
||||
private static final int MIN_COLOR_TEMPERATURE = 153;
|
||||
private static final int MAX_COLOR_TEMPERATURE = 500;
|
||||
private static final int COLOR_TEMPERATURE_RANGE = MAX_COLOR_TEMPERATURE - MIN_COLOR_TEMPERATURE;
|
||||
|
||||
/**
|
||||
* {@value #ALERT_MODE_NONE}. The light is not performing an alert effect.
|
||||
*/
|
||||
static final String ALERT_MODE_NONE = "NONE";
|
||||
/**
|
||||
* {@value #ALERT_MODE_SELECT}. The light is performing one breathe cycle.
|
||||
*/
|
||||
static final String ALERT_MODE_SELECT = "SELECT";
|
||||
/**
|
||||
* {@value #ALERT_MODE_LONG_SELECT}. The light is performing breathe cycles
|
||||
* for 15 seconds or until an "alert": "none" command is received.
|
||||
*/
|
||||
static final String ALERT_MODE_LONG_SELECT = "LSELECT";
|
||||
|
||||
private static final int DIM_STEPSIZE = 30;
|
||||
|
||||
/**
|
||||
* Transforms the given {@link HSBType} into a light state.
|
||||
*
|
||||
* @param hsbType HSB type
|
||||
* @return light state representing the {@link HSBType}.
|
||||
*/
|
||||
public static StateUpdate toColorLightState(HSBType hsbType, State lightState) {
|
||||
StateUpdate stateUpdate = ColorMode.XY.equals(lightState.getColorMode()) ? toXYColorLightState(hsbType)
|
||||
: toHSBColorLightState(hsbType);
|
||||
|
||||
int brightness = (int) Math.floor(hsbType.getBrightness().doubleValue() * BRIGHTNESS_FACTOR);
|
||||
if (brightness > 0) {
|
||||
stateUpdate.setBrightness(brightness);
|
||||
}
|
||||
return stateUpdate;
|
||||
}
|
||||
|
||||
private static StateUpdate toHSBColorLightState(HSBType hsbType) {
|
||||
int hue = (int) Math.round(hsbType.getHue().doubleValue() * HUE_FACTOR);
|
||||
int saturation = (int) Math.floor(hsbType.getSaturation().doubleValue() * SATURATION_FACTOR);
|
||||
|
||||
return new StateUpdate().setHue(hue).setSat(saturation);
|
||||
}
|
||||
|
||||
private static StateUpdate toXYColorLightState(HSBType hsbType) {
|
||||
PercentType[] xy = hsbType.toXY();
|
||||
float x = xy[0].floatValue() / 100.0f;
|
||||
float y = xy[1].floatValue() / 100.0f;
|
||||
|
||||
return new StateUpdate().setXY(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given {@link OnOffType} into a light state containing the
|
||||
* 'on' value.
|
||||
*
|
||||
* @param onOffType on or off state
|
||||
* @return light state containing the 'on' value
|
||||
*/
|
||||
public static StateUpdate toOnOffLightState(OnOffType onOffType) {
|
||||
return new StateUpdate().setOn(OnOffType.ON.equals(onOffType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given {@link PercentType} into a light state containing
|
||||
* the brightness and the 'on' value represented by {@link PercentType}.
|
||||
*
|
||||
* @param percentType brightness represented as {@link PercentType}
|
||||
* @return light state containing the brightness and the 'on' value
|
||||
*/
|
||||
public static StateUpdate toBrightnessLightState(PercentType percentType) {
|
||||
boolean on = !percentType.equals(PercentType.ZERO);
|
||||
final StateUpdate stateUpdate = new StateUpdate().setOn(on);
|
||||
|
||||
int brightness = (int) Math.floor(percentType.doubleValue() * BRIGHTNESS_FACTOR);
|
||||
if (brightness > 0) {
|
||||
stateUpdate.setBrightness(brightness);
|
||||
}
|
||||
return stateUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the given brightness using the {@link IncreaseDecreaseType} and
|
||||
* returns the updated value.
|
||||
*
|
||||
* @param command The {@link IncreaseDecreaseType} to be used
|
||||
* @param currentBrightness The current brightness
|
||||
* @return The adjusted brightness value
|
||||
*/
|
||||
public static int toAdjustedBrightness(IncreaseDecreaseType command, int currentBrightness) {
|
||||
int newBrightness;
|
||||
if (command == IncreaseDecreaseType.DECREASE) {
|
||||
newBrightness = Math.max(currentBrightness - DIM_STEPSIZE, 0);
|
||||
} else {
|
||||
newBrightness = Math.min(currentBrightness + DIM_STEPSIZE, (int) (BRIGHTNESS_FACTOR * 100));
|
||||
}
|
||||
return newBrightness;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given {@link PercentType} into a light state containing
|
||||
* the color temperature represented by {@link PercentType}.
|
||||
*
|
||||
* @param percentType color temperature represented as {@link PercentType}
|
||||
* @return light state containing the color temperature
|
||||
*/
|
||||
public static StateUpdate toColorTemperatureLightState(PercentType percentType) {
|
||||
int colorTemperature = MIN_COLOR_TEMPERATURE
|
||||
+ Math.round((COLOR_TEMPERATURE_RANGE * percentType.floatValue()) / 100);
|
||||
return new StateUpdate().setColorTemperature(colorTemperature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the given color temperature using the {@link IncreaseDecreaseType} and returns the updated value.
|
||||
*
|
||||
* @param type The {@link IncreaseDecreaseType} to be used
|
||||
* @param currentColorTemp The current color temperature
|
||||
* @return The adjusted color temperature value
|
||||
*/
|
||||
public static int toAdjustedColorTemp(IncreaseDecreaseType type, int currentColorTemp) {
|
||||
int newColorTemp;
|
||||
if (type == IncreaseDecreaseType.DECREASE) {
|
||||
newColorTemp = Math.max(currentColorTemp - DIM_STEPSIZE, MIN_COLOR_TEMPERATURE);
|
||||
} else {
|
||||
newColorTemp = Math.min(currentColorTemp + DIM_STEPSIZE, MAX_COLOR_TEMPERATURE);
|
||||
}
|
||||
return newColorTemp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms Hue Light {@link State} into {@link PercentType} representing
|
||||
* the color temperature.
|
||||
*
|
||||
* @param lightState light state
|
||||
* @return percent type representing the color temperature
|
||||
*/
|
||||
public static PercentType toColorTemperaturePercentType(State lightState) {
|
||||
int percent = (int) Math
|
||||
.round(((lightState.getColorTemperature() - MIN_COLOR_TEMPERATURE) * 100.0) / COLOR_TEMPERATURE_RANGE);
|
||||
return new PercentType(restrictToBounds(percent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms Hue Light {@link State} into {@link PercentType} representing
|
||||
* the brightness.
|
||||
*
|
||||
* @param lightState light state
|
||||
* @return percent type representing the brightness
|
||||
*/
|
||||
public static PercentType toBrightnessPercentType(State lightState) {
|
||||
int percent = (int) Math.ceil(lightState.getBrightness() / BRIGHTNESS_FACTOR);
|
||||
return new PercentType(restrictToBounds(percent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms {@link State} into {@link StringType} representing the {@link AlertMode}.
|
||||
*
|
||||
* @param lightState light state.
|
||||
* @return string type representing the alert mode.
|
||||
*/
|
||||
public static StringType toAlertStringType(State lightState) {
|
||||
AlertMode alertMode = lightState.getAlertMode();
|
||||
if (alertMode == null) {
|
||||
return new StringType("NULL");
|
||||
} else {
|
||||
return new StringType(alertMode.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms Hue Light {@link State} into {@link HSBType} representing the
|
||||
* color.
|
||||
*
|
||||
* @param lightState light state
|
||||
* @return HSB type representing the color
|
||||
*/
|
||||
public static HSBType toHSBType(State lightState) {
|
||||
// even if color mode is reported to be XY, xy field of lightState might be null, while hsb is available
|
||||
boolean isInXYMode = ColorMode.XY.equals(lightState.getColorMode()) && lightState.getXY() != null;
|
||||
return isInXYMode ? fromXYtoHSBType(lightState) : fromHSBtoHSBType(lightState);
|
||||
}
|
||||
|
||||
private static HSBType fromHSBtoHSBType(State lightState) {
|
||||
int hue = (int) Math.round(lightState.getHue() / HUE_FACTOR) % 360;
|
||||
|
||||
int saturationInPercent = (int) Math.ceil(lightState.getSaturation() / SATURATION_FACTOR);
|
||||
saturationInPercent = restrictToBounds(saturationInPercent);
|
||||
|
||||
int brightnessInPercent = (int) Math.ceil(lightState.getBrightness() / BRIGHTNESS_FACTOR);
|
||||
brightnessInPercent = restrictToBounds(brightnessInPercent);
|
||||
|
||||
return new HSBType(new DecimalType(hue), new PercentType(saturationInPercent),
|
||||
new PercentType(brightnessInPercent));
|
||||
}
|
||||
|
||||
private static HSBType fromXYtoHSBType(State lightState) {
|
||||
float[] xy = lightState.getXY();
|
||||
HSBType hsb = HSBType.fromXY(xy[0], xy[1]);
|
||||
|
||||
int brightnessInPercent = (int) Math.ceil(lightState.getBrightness() / BRIGHTNESS_FACTOR);
|
||||
brightnessInPercent = restrictToBounds(brightnessInPercent);
|
||||
|
||||
return new HSBType(hsb.getHue(), hsb.getSaturation(), new PercentType(brightnessInPercent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given {@link StringType} into a light state containing the {@link AlertMode} to be triggered.
|
||||
*
|
||||
* @param alertType {@link StringType} representing the required {@link AlertMode} . <br>
|
||||
* Supported values are:
|
||||
* <ul>
|
||||
* <li>{@value #ALERT_MODE_NONE}.
|
||||
* <li>{@value #ALERT_MODE_SELECT}.
|
||||
* <li>{@value #ALERT_MODE_LONG_SELECT}.
|
||||
* <ul>
|
||||
* @return light state containing the {@link AlertMode} or <b><code>null </code></b> if the provided
|
||||
* {@link StringType} represents unsupported mode.
|
||||
*/
|
||||
public static @Nullable StateUpdate toAlertState(StringType alertType) {
|
||||
AlertMode alertMode;
|
||||
|
||||
switch (alertType.toString()) {
|
||||
case ALERT_MODE_NONE:
|
||||
alertMode = State.AlertMode.NONE;
|
||||
break;
|
||||
case ALERT_MODE_SELECT:
|
||||
alertMode = State.AlertMode.SELECT;
|
||||
break;
|
||||
case ALERT_MODE_LONG_SELECT:
|
||||
alertMode = State.AlertMode.LSELECT;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return new StateUpdate().setAlert(alertMode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the given {@link OnOffType} into a light state containing the {@link Effect} value.
|
||||
* {@link OnOffType#ON} will result in {@link Effect#COLORLOOP}. {@link OnOffType#OFF} will result in
|
||||
* {@link Effect#NONE}.
|
||||
*
|
||||
* @param onOffType on or off state
|
||||
* @return light state containing the {@link Effect} value
|
||||
*/
|
||||
public static StateUpdate toOnOffEffectState(OnOffType onOffType) {
|
||||
StateUpdate stateUpdate;
|
||||
|
||||
if (OnOffType.ON.equals(onOffType)) {
|
||||
stateUpdate = new StateUpdate().setEffect(Effect.COLORLOOP);
|
||||
} else {
|
||||
stateUpdate = new StateUpdate().setEffect(Effect.NONE);
|
||||
}
|
||||
|
||||
return stateUpdate;
|
||||
}
|
||||
|
||||
private static int restrictToBounds(int percentValue) {
|
||||
if (percentValue < 0) {
|
||||
return 0;
|
||||
} else if (percentValue > 100) {
|
||||
return 100;
|
||||
}
|
||||
return percentValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullLight;
|
||||
|
||||
/**
|
||||
* The {@link LightStatusListener} is notified when a light status has changed or a light has been removed or added.
|
||||
*
|
||||
* @author Oliver Libutzki - Initial contribution
|
||||
* @author Denis Dudnik - switched to internally integrated source of Jue library, minor code cleanup
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface LightStatusListener {
|
||||
|
||||
/**
|
||||
* This method returns the light id of the listener
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
String getLightId();
|
||||
|
||||
/**
|
||||
* This method is called whenever the state of the given light has changed. The new state can be obtained by
|
||||
* {@link FullLight#getState()}.
|
||||
*
|
||||
* @param light The light which received the state update.
|
||||
* @return
|
||||
*/
|
||||
boolean onLightStateChanged(FullLight light);
|
||||
|
||||
/**
|
||||
* This method is called whenever a light is removed.
|
||||
*/
|
||||
void onLightRemoved();
|
||||
|
||||
/**
|
||||
* This method is called whenever a light is reported as gone.
|
||||
*/
|
||||
void onLightGone();
|
||||
|
||||
/**
|
||||
* This method is called whenever a light is added.
|
||||
*
|
||||
* @param light The light which is added.
|
||||
*/
|
||||
void onLightAdded(FullLight light);
|
||||
|
||||
/**
|
||||
* The thing will block state updates for set time.
|
||||
*
|
||||
* @param bypassTime
|
||||
*/
|
||||
void setPollBypass(long bypassTime);
|
||||
|
||||
/**
|
||||
* Unblock state updates.
|
||||
*/
|
||||
void unsetPollBypass();
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
|
||||
/**
|
||||
* The {@link SensorStatusListener} is notified when a sensor status has changed or a sensor has been removed or added.
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface SensorStatusListener {
|
||||
|
||||
/**
|
||||
* This method returns the sensor Id
|
||||
*
|
||||
* @return sensor id of thing or DISCOVERY for discovery service
|
||||
*/
|
||||
String getSensorId();
|
||||
|
||||
/**
|
||||
* This method is called whenever the state of the given sensor has changed. The new state can be obtained by
|
||||
* {@link FullSensor#getState()}.
|
||||
*
|
||||
* @param sensor The sensor which received the state update.
|
||||
* @return The sensor handler returns true if it accepts the new state.
|
||||
*/
|
||||
boolean onSensorStateChanged(FullSensor sensor);
|
||||
|
||||
/**
|
||||
* This method is called whenever a sensor is removed.
|
||||
*/
|
||||
void onSensorRemoved();
|
||||
|
||||
/**
|
||||
* This method is called whenever a sensor is reported as gone.
|
||||
*/
|
||||
void onSensorGone();
|
||||
|
||||
/**
|
||||
* This method is called whenever a sensor is added.
|
||||
*
|
||||
* @param sensor The added sensor
|
||||
*/
|
||||
void onSensorAdded(FullSensor sensor);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler.sensors;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* CLIP Sensor
|
||||
*
|
||||
* @author Meng Yiqi - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class ClipHandler extends HueSensorHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream
|
||||
.of(THING_TYPE_CLIP_GENERIC_STATUS, THING_TYPE_CLIP_GENERIC_FLAG).collect(Collectors.toSet());
|
||||
|
||||
public ClipHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorConfigUpdate doConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
return new SensorConfigUpdate();
|
||||
}
|
||||
|
||||
protected void doSensorStateChanged(FullSensor sensor, Configuration config) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler.sensors;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* Hue Dimmer Switch
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class DimmerSwitchHandler extends HueSensorHandler {
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DIMMER_SWITCH);
|
||||
|
||||
public DimmerSwitchHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorConfigUpdate doConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
return new SensorConfigUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSensorStateChanged(FullSensor sensor, Configuration config) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
ZonedDateTime now = ZonedDateTime.now(zoneId), timestamp = now;
|
||||
|
||||
Object lastUpdated = sensor.getState().get(FullSensor.STATE_LAST_UPDATED);
|
||||
if (lastUpdated != null) {
|
||||
try {
|
||||
timestamp = ZonedDateTime.ofInstant(
|
||||
LocalDateTime.parse(String.valueOf(lastUpdated), DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||
ZoneOffset.UTC, zoneId);
|
||||
} catch (DateTimeParseException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
Object buttonState = sensor.getState().get(FullSensor.STATE_BUTTON_EVENT);
|
||||
if (buttonState != null) {
|
||||
String value = String.valueOf(buttonState);
|
||||
updateState(CHANNEL_DIMMER_SWITCH, new DecimalType(value));
|
||||
// Avoid dispatching events if "lastupdated" is older than now minus 3 seconds (e.g. during restart)
|
||||
Instant then = timestamp.toInstant();
|
||||
Instant someSecondsEarlier = now.minusSeconds(3).toInstant();
|
||||
if (then.isAfter(someSecondsEarlier) && then.isBefore(now.toInstant())) {
|
||||
triggerChannel(EVENT_DIMMER_SWITCH, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler.sensors;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.LightLevelConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SmartHomeUnits;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* Light Level Sensor
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class LightLevelHandler extends HueSensorHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_LIGHT_LEVEL_SENSOR);
|
||||
|
||||
public LightLevelHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorConfigUpdate doConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
LightLevelConfigUpdate configUpdate = new LightLevelConfigUpdate();
|
||||
if (configurationParameters.containsKey(CONFIG_LED_INDICATION)) {
|
||||
configUpdate.setLedIndication(Boolean.TRUE.equals(configurationParameters.get(CONFIG_LED_INDICATION)));
|
||||
}
|
||||
if (configurationParameters.containsKey(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK)) {
|
||||
configUpdate.setThresholdDark(
|
||||
Integer.parseInt(String.valueOf(configurationParameters.get(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK))));
|
||||
}
|
||||
if (configurationParameters.containsKey(CONFIG_LIGHT_LEVEL_THRESHOLD_OFFSET)) {
|
||||
configUpdate.setThresholdOffset(
|
||||
Integer.parseInt(String.valueOf(configurationParameters.get(CONFIG_LIGHT_LEVEL_THRESHOLD_OFFSET))));
|
||||
}
|
||||
return configUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSensorStateChanged(FullSensor sensor, Configuration config) {
|
||||
Object lightLevel = sensor.getState().get(STATE_LIGHT_LEVEL);
|
||||
if (lightLevel != null) {
|
||||
BigDecimal value = new BigDecimal(String.valueOf(lightLevel));
|
||||
updateState(CHANNEL_LIGHT_LEVEL, new DecimalType(value));
|
||||
|
||||
// calculate lux, according to
|
||||
// https://developers.meethue.com/documentation/supported-sensors#clip_zll_lightlevel
|
||||
double lux = Math.pow(10, (value.subtract(BigDecimal.ONE).divide(new BigDecimal(10000))).doubleValue());
|
||||
updateState(CHANNEL_ILLUMINANCE, new QuantityType<>(lux, SmartHomeUnits.LUX));
|
||||
}
|
||||
|
||||
Object dark = sensor.getState().get(STATE_DARK);
|
||||
if (dark != null) {
|
||||
boolean value = Boolean.parseBoolean(String.valueOf(dark));
|
||||
updateState(CHANNEL_DARK, value ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
|
||||
Object daylight = sensor.getState().get(STATE_DAYLIGHT);
|
||||
if (daylight != null) {
|
||||
boolean value = Boolean.parseBoolean(String.valueOf(daylight));
|
||||
updateState(CHANNEL_DAYLIGHT, value ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
|
||||
if (sensor.getConfig().containsKey(CONFIG_LED_INDICATION)) {
|
||||
config.put(CONFIG_LED_INDICATION, sensor.getConfig().get(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK));
|
||||
}
|
||||
if (sensor.getConfig().containsKey(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK)) {
|
||||
config.put(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK, sensor.getConfig().get(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK));
|
||||
}
|
||||
if (sensor.getConfig().containsKey(CONFIG_LIGHT_LEVEL_THRESHOLD_OFFSET)) {
|
||||
config.put(CONFIG_LIGHT_LEVEL_THRESHOLD_OFFSET,
|
||||
sensor.getConfig().get(CONFIG_LIGHT_LEVEL_THRESHOLD_OFFSET));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler.sensors;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.PresenceConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* Presence Sensor
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class PresenceHandler extends HueSensorHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_PRESENCE_SENSOR);
|
||||
|
||||
public PresenceHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorConfigUpdate doConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
PresenceConfigUpdate configUpdate = new PresenceConfigUpdate();
|
||||
if (configurationParameters.containsKey(CONFIG_LED_INDICATION)) {
|
||||
configUpdate.setLedIndication(Boolean.TRUE.equals(configurationParameters.get(CONFIG_LED_INDICATION)));
|
||||
}
|
||||
if (configurationParameters.containsKey(CONFIG_PRESENCE_SENSITIVITY)) {
|
||||
configUpdate.setSensitivity(
|
||||
Integer.parseInt(String.valueOf(configurationParameters.get(CONFIG_PRESENCE_SENSITIVITY))));
|
||||
}
|
||||
return configUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSensorStateChanged(FullSensor sensor, Configuration config) {
|
||||
Object presence = sensor.getState().get(STATE_PRESENCE);
|
||||
if (presence != null) {
|
||||
boolean value = Boolean.parseBoolean(String.valueOf(presence));
|
||||
updateState(CHANNEL_PRESENCE, value ? OnOffType.ON : OnOffType.OFF);
|
||||
}
|
||||
|
||||
if (sensor.getConfig().containsKey(CONFIG_LED_INDICATION)) {
|
||||
config.put(CONFIG_LED_INDICATION, sensor.getConfig().get(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK));
|
||||
}
|
||||
if (sensor.getConfig().containsKey(CONFIG_PRESENCE_SENSITIVITY)) {
|
||||
config.put(CONFIG_PRESENCE_SENSITIVITY, sensor.getConfig().get(CONFIG_PRESENCE_SENSITIVITY));
|
||||
}
|
||||
if (sensor.getConfig().containsKey(CONFIG_PRESENCE_SENSITIVITY_MAX)) {
|
||||
config.put(CONFIG_PRESENCE_SENSITIVITY_MAX, sensor.getConfig().get(CONFIG_PRESENCE_SENSITIVITY_MAX));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler.sensors;
|
||||
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* Hue Tap Switch
|
||||
*
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TapSwitchHandler extends HueSensorHandler {
|
||||
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_TAP_SWITCH);
|
||||
|
||||
public TapSwitchHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorConfigUpdate doConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
return new SensorConfigUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSensorStateChanged(FullSensor sensor, Configuration config) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
ZonedDateTime now = ZonedDateTime.now(zoneId), timestamp = now;
|
||||
|
||||
Object lastUpdated = sensor.getState().get(FullSensor.STATE_LAST_UPDATED);
|
||||
if (lastUpdated != null) {
|
||||
try {
|
||||
timestamp = ZonedDateTime.ofInstant(
|
||||
LocalDateTime.parse(String.valueOf(lastUpdated), DateTimeFormatter.ISO_LOCAL_DATE_TIME),
|
||||
ZoneOffset.UTC, zoneId);
|
||||
} catch (DateTimeParseException e) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
Object buttonState = sensor.getState().get(FullSensor.STATE_BUTTON_EVENT);
|
||||
if (buttonState != null) {
|
||||
String value = String.valueOf(buttonState);
|
||||
updateState(CHANNEL_TAP_SWITCH, new DecimalType(value));
|
||||
// Avoid dispatching events if "lastupdated" is older than now minus 3 seconds (e.g. during restart)
|
||||
Instant then = timestamp.toInstant();
|
||||
Instant someSecondsEarlier = now.minusSeconds(3).toInstant();
|
||||
if (then.isAfter(someSecondsEarlier) && then.isBefore(now.toInstant())) {
|
||||
triggerChannel(EVENT_TAP_SWITCH, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal.handler.sensors;
|
||||
|
||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.hue.internal.FullSensor;
|
||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.TemperatureConfigUpdate;
|
||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.SIUnits;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* Temperature Sensor
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
* @author Christoph Weitkamp - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class TemperatureHandler extends HueSensorHandler {
|
||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_TEMPERATURE_SENSOR);
|
||||
|
||||
public TemperatureHandler(Thing thing) {
|
||||
super(thing);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SensorConfigUpdate doConfigurationUpdate(Map<String, Object> configurationParameters) {
|
||||
TemperatureConfigUpdate configUpdate = new TemperatureConfigUpdate();
|
||||
if (configurationParameters.containsKey(CONFIG_LED_INDICATION)) {
|
||||
configUpdate.setLedIndication(Boolean.TRUE.equals(configurationParameters.get(CONFIG_LED_INDICATION)));
|
||||
}
|
||||
return configUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doSensorStateChanged(FullSensor sensor, Configuration config) {
|
||||
Object temperature = sensor.getState().get(STATE_TEMPERATURE);
|
||||
if (temperature != null) {
|
||||
BigDecimal value = new BigDecimal(String.valueOf(temperature));
|
||||
updateState(CHANNEL_TEMPERATURE, new QuantityType<>(value.divide(new BigDecimal(100)), SIUnits.CELSIUS));
|
||||
}
|
||||
|
||||
if (sensor.getConfig().containsKey(CONFIG_LED_INDICATION)) {
|
||||
config.put(CONFIG_LED_INDICATION, sensor.getConfig().get(CONFIG_LIGHT_LEVEL_THRESHOLD_DARK));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<binding:binding id="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:binding="https://openhab.org/schemas/binding/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/binding/v1.0.0 https://openhab.org/schemas/binding-1.0.0.xsd">
|
||||
|
||||
<name>hue Binding</name>
|
||||
<description>The hue Binding integrates the Philips hue system. It
|
||||
allows to control hue bulbs.</description>
|
||||
<author>Deutsche Telekom AG</author>
|
||||
|
||||
</binding:binding>
|
||||
@@ -0,0 +1,32 @@
|
||||
# Config status messages
|
||||
config-status.error.missing-ip-address-configuration=No IP address for the Hue bridge has been provided.
|
||||
|
||||
# Thing status descriptions
|
||||
offline.conf-error-no-ip-address = Cannot connect to Hue bridge. IP address not available in configuration.
|
||||
offline.conf-error-no-username = Cannot connect to Hue bridge. User name for authentication not available in configuration.
|
||||
offline.conf-error-invalid-username = Authentication failed. Remove user name from configuration to generate a new one.
|
||||
offline.conf-error-press-pairing-button = Not authenticated. Press pairing button on the Hue bridge or set a valid user name in configuration.
|
||||
offline.conf-error-creation-username = Failed to create new user on Hue bridge.
|
||||
offline.bridge-connection-lost = Hue bridge connection lost.
|
||||
offline.conf-error-no-light-id = Light ID not available in configuration.
|
||||
offline.conf-error-no-sensor-id = Sensor ID not available in configuration.
|
||||
offline.conf-error-no-group-id = Group ID not available in configuration.
|
||||
offline.conf-error-wrong-light-id = No light with given ID available on Hue bridge.
|
||||
offline.conf-error-wrong-sensor-id = No sensor with given ID available on Hue bridge.
|
||||
offline.conf-error-wrong-group-id = No group with given ID available on Hue bridge.
|
||||
offline.light-not-reachable = Hue bridge reports light as not reachable.
|
||||
offline.sensor-not-reachable = Hue bridge reports sensor as not reachable.
|
||||
offline.light-removed = Hue bridge reports light as removed.
|
||||
offline.sensor-removed = Hue bridge reports sensor as removed.
|
||||
offline.group-removed = Hue bridge reports group as removed.
|
||||
|
||||
#LightActions
|
||||
actionLabel=send a light command with a custom fade time
|
||||
actionDesc=Send a light command with a custom fade time.
|
||||
|
||||
actionInputChannelLabel=Channel
|
||||
actionInputChannelDesc=The channel to send the command to.
|
||||
actionInputCommandLabel=Command
|
||||
actionInputCommandDesc=The Command for the light.
|
||||
actionInputFadeTimeLabel=FadeTime
|
||||
actionInputFadeTimeDesc=The fade time to use for the light command in ms.
|
||||
@@ -0,0 +1,168 @@
|
||||
# binding
|
||||
binding.hue.name = Hue Binding
|
||||
binding.hue.description = Dieses Binding integriert das Philips Hue System. Durch diese können die Hue Lampen und Leuchten gesteuert werden.
|
||||
|
||||
# thing types
|
||||
thing-type.hue.bridge.label = Hue Bridge
|
||||
thing-type.hue.bridge.description = Philips Hue Bridge.
|
||||
thing-type.hue.0000.label = Lampe (weiß)
|
||||
thing-type.hue.0000.description = Lampe zum Ein- und Ausschalten.
|
||||
thing-type.hue.0010.label = Schaltbare Steckdose
|
||||
thing-type.hue.0010.description = Steckdose zum Ein- und Ausschalten von herkömmlichen Lampen oder anderen elektronischen Geräten.
|
||||
thing-type.hue.0100.label = Dimmbare Lampe (weiß)
|
||||
thing-type.hue.0100.description = Dimmbare Lampe mit fester Farbtemperatur.
|
||||
thing-type.hue.0110.label = Dimmbare Steckdose
|
||||
thing-type.hue.0110.description = Steckdose zum Dimmen von herkömmlichen Lampen.
|
||||
thing-type.hue.0200.label = Farbige Lampe
|
||||
thing-type.hue.0200.description = Dimmbare Lampe mit einstellbarer Farbe.
|
||||
thing-type.hue.0210.label = Farbige Lampe
|
||||
thing-type.hue.0210.description = Dimmbare Lampe mit einstellbarer Farbe und Farbtemperatur.
|
||||
thing-type.hue.0220.label = Farbtemperatur Lampe (weiß)
|
||||
thing-type.hue.0220.description = Dimmbare Lampe mit einstellbarer Farbtemperatur.
|
||||
thing-type.hue.0820.label = Dimmschalter
|
||||
thing-type.hue.0820.description = Fernbedienung mit Dimmfunktion.
|
||||
thing-type.hue.0830.label = Tap Schalter
|
||||
thing-type.hue.0830.description = Fernbedienung mit konfigurierbaren Tasten.
|
||||
thing-type.hue.0106.label = Lichtstärkesensor
|
||||
thing-type.hue.0106.description = Lichtstärkesensor mit einstellbaren Schwellwerten.
|
||||
thing-type.hue.0107.label = Bewegungsmelder
|
||||
thing-type.hue.0107.description = Bewegungsmelder mit einstellbarer Sensitivität.
|
||||
thing-type.hue.0302.label = Temperatursensor
|
||||
thing-type.hue.0302.description = Temperatursensor
|
||||
|
||||
# thing type configuration
|
||||
thing-type.config.hue.bridge.ipAddress.label = IP-Adresse
|
||||
thing-type.config.hue.bridge.ipAddress.description = Lokale IP-Adresse oder Hostname der Hue Bridge.
|
||||
thing-type.config.hue.bridge.port.label = Port
|
||||
thing-type.config.hue.bridge.port.description = Port der Hue Bridge.
|
||||
thing-type.config.hue.bridge.userName.label = Benutzer
|
||||
thing-type.config.hue.bridge.userName.description = Benutzer zur Authentifizierung an der Hue Bridge.
|
||||
thing-type.config.hue.bridge.pollingInterval.label = Abfrageintervall
|
||||
thing-type.config.hue.bridge.pollingInterval.description = Intervall zur Abfrage der Hue Bridge (in Sekunden).
|
||||
thing-type.config.hue.bridge.sensorPollingInterval.label = Sensor-Abfrageintervall
|
||||
thing-type.config.hue.bridge.sensorPollingInterval.description = Intervall zur Abfrage der Sensoren der Hue Bridge (in Millisekunden).
|
||||
thing-type.config.hue.0000.lightId.label = ID der Lampe
|
||||
thing-type.config.hue.0000.lightId.description = ID zur Identifikation der Lampe.
|
||||
thing-type.config.hue.0010.lightId.label = ID der Steckdose
|
||||
thing-type.config.hue.0010.lightId.description = ID zur Identifikation der Steckdose.
|
||||
thing-type.config.hue.0100.lightId.label = ID der Lampe
|
||||
thing-type.config.hue.0100.lightId.description = ID zur Identifikation der Lampe.
|
||||
thing-type.config.hue.0110.lightId.label = ID der Steckdose
|
||||
thing-type.config.hue.0110.lightId.description = ID zur Identifikation der Steckdose.
|
||||
thing-type.config.hue.0200.lightId.label = ID der Lampe
|
||||
thing-type.config.hue.0200.lightId.description = ID zur Identifikation der Lampe.
|
||||
thing-type.config.hue.0210.lightId.label = ID der Lampe
|
||||
thing-type.config.hue.0210.lightId.description = ID zur Identifikation der Lampe.
|
||||
thing-type.config.hue.0220.lightId.label = ID der Lampe
|
||||
thing-type.config.hue.0220.lightId.description = ID zur Identifikation der Lampe.
|
||||
|
||||
thing-type.config.hue.0820.sensorId.label = ID des Sensors
|
||||
thing-type.config.hue.0820.sensorId.description = ID zur Identifikation des Sensors.
|
||||
thing-type.config.hue.0820.on.label = Sensor Status
|
||||
thing-type.config.hue.0820.on.description = Aktiviert oder deaktiviert den Sensor.
|
||||
thing-type.config.hue.0830.sensorId.label = ID des Sensors
|
||||
thing-type.config.hue.0830.sensorId.description = ID zur Identifikation des Sensors.
|
||||
thing-type.config.hue.0830.on.label = Sensor Status
|
||||
thing-type.config.hue.0830.on.description = Aktiviert oder deaktiviert den Sensor.
|
||||
thing-type.config.hue.0106.sensorId.label = ID des Sensors
|
||||
thing-type.config.hue.0106.sensorId.description = ID zur Identifikation des Sensors.
|
||||
thing-type.config.hue.0106.on.label = Sensor Status
|
||||
thing-type.config.hue.0106.on.description = Aktiviert oder deaktiviert den Sensor.
|
||||
thing-type.config.hue.0106.ledindication.label = LED-Anzeige
|
||||
thing-type.config.hue.0106.ledindication.description = Aktiviert oder deaktiviert die LED-Anzeige des Sensors.
|
||||
thing-type.config.hue.0106.tholddark.label = Dunkel-Schwellwert
|
||||
thing-type.config.hue.0106.tholddark.description = Zeigt den Dunkel-Schwellwert an.
|
||||
thing-type.config.hue.0106.tholdoffset.label = Hell-Schwellwert
|
||||
thing-type.config.hue.0106.tholdoffset.description = Zeigt den Hell-Schwellwert an.
|
||||
thing-type.config.hue.0107.sensorId.label = ID des Sensors
|
||||
thing-type.config.hue.0107.sensorId.description = ID zur Identifikation des Sensors.
|
||||
thing-type.config.hue.0107.on.label = Sensor Status
|
||||
thing-type.config.hue.0107.on.description = Aktiviert oder deaktiviert den Sensor.
|
||||
thing-type.config.hue.0107.ledindication.label = LED-Anzeige
|
||||
thing-type.config.hue.0107.ledindication.description = Aktiviert oder deaktiviert die LED-Anzeige des Sensors.
|
||||
thing-type.config.hue.0107.sensitivity.label = Empfindlichkeit
|
||||
thing-type.config.hue.0107.sensitivity.description = Zeigt die Empfindlichkeit an.
|
||||
thing-type.config.hue.0107.sensitivitymax.label = Maximale Empfindlichkeit
|
||||
thing-type.config.hue.0107.sensitivitymax.description = Zeigt die maximale Empfindlichkeit an.
|
||||
thing-type.config.hue.0302.sensorId.label = ID des Sensors
|
||||
thing-type.config.hue.0302.sensorId.description = ID zur Identifikation des Sensors.
|
||||
thing-type.config.hue.0302.on.label = Sensor Status
|
||||
thing-type.config.hue.0302.on.description = Aktiviert oder deaktiviert den Sensor.
|
||||
thing-type.config.hue.0302.ledindication.label = LED-Anzeige
|
||||
thing-type.config.hue.0302.ledindication.description = Aktiviert oder deaktiviert die LED-Anzeige des Sensors.
|
||||
|
||||
# channel types
|
||||
channel-type.hue.color.label = Farbe
|
||||
channel-type.hue.color.description = Ermöglicht die Steuerung der Farbe. Ermöglicht ebenfalls die Lampe zu dimmen oder ein- und auszuschalten.
|
||||
channel-type.hue.brightness.label = Helligkeit
|
||||
channel-type.hue.brightness.description = Ermöglicht die Steuerung der Helligkeit. Ermöglicht ebenfalls die Lampe ein- und auszuschalten.
|
||||
channel-type.hue.switch.label = Schalter
|
||||
channel-type.hue.switch.description = Ermöglicht das Ein- und Ausschalten.
|
||||
channel-type.hue.color_temperature.label = Farbtemperatur
|
||||
channel-type.hue.color_temperature.description = Ermöglicht die Steuerung der Farbtemperatur. Von Tageslichtweiß (0) bis Warmweiß (100).
|
||||
channel-type.hue.alert.label = Alarm
|
||||
channel-type.hue.alert.description = Ermöglicht ein temporäres Blinken.
|
||||
channel-type.hue.alert.state.option.NONE = Kein Blinken
|
||||
channel-type.hue.alert.state.option.SELECT = Einmaliges Blinken
|
||||
channel-type.hue.alert.state.option.LSELECT = Mehrfaches Blinken
|
||||
channel-type.hue.effect.label = Farbeffekt
|
||||
channel-type.hue.effect.description = Ermöglicht einen automatischen Farbwechsels.
|
||||
|
||||
channel-type.hue.last_updated.label = Letzte Aktualisierung
|
||||
channel-type.hue.last_updated.description = Zeit, zu der sich dieser Wert geändert hat.
|
||||
channel-type.hue.last_updated.options.pattern = %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS
|
||||
channel-type.hue.illuminance.label = Beleuchtungsstärke
|
||||
channel-type.hue.illuminance.description = Die aktuelle Beleuchtungsstärke.
|
||||
channel-type.hue.light_level.label = Licht Level
|
||||
channel-type.hue.light_level.description = Das aktuelle Licht Level.
|
||||
channel-type.hue.dark.label = Dunkel
|
||||
channel-type.hue.dark.description = Der Licht Level ist unter dem Dunkel-Schwellwert.
|
||||
channel-type.hue.daylight.label = Hell
|
||||
channel-type.hue.daylight.description = Der Licht Level ist über dem Hell-Schwellwert.
|
||||
channel-type.hue.dimmer_switch.label = Dimmer-Schalter
|
||||
channel-type.hue.dimmer_switch.description = Der zuletzt gedrückte Taster an dem Dimmer-Schalter.
|
||||
channel-type.hue.tap_switch.label = Tap Schalter
|
||||
channel-type.hue.tap_switch.description = Der zuletzt gedrückte Taster an dem Tap Schalter.
|
||||
channel-type.hue.temperature.label = Temperatur
|
||||
channel-type.hue.temperature.description = Die aktuelle Temperatur.
|
||||
|
||||
channel-type.hue.dimmer_switch.state.option.1000 = An (Initial)
|
||||
channel-type.hue.dimmer_switch.state.option.1001 = An (Gehalten)
|
||||
channel-type.hue.dimmer_switch.state.option.1002 = An (Kurz Gedrückt)
|
||||
channel-type.hue.dimmer_switch.state.option.1003 = An (Lang Gedrückt)
|
||||
channel-type.hue.dimmer_switch.state.option.2000 = Heller (Initial)
|
||||
channel-type.hue.dimmer_switch.state.option.2001 = Heller (Gehalten)
|
||||
channel-type.hue.dimmer_switch.state.option.2002 = Heller (Kurz Gedrückt)
|
||||
channel-type.hue.dimmer_switch.state.option.2003 = Heller (Lang Gedrückt)
|
||||
channel-type.hue.dimmer_switch.state.option.3000 = Dunkler (Initial)
|
||||
channel-type.hue.dimmer_switch.state.option.3001 = Dunkler (Gehalten)
|
||||
channel-type.hue.dimmer_switch.state.option.3002 = Dunkler (Kurz Gedrückt)
|
||||
channel-type.hue.dimmer_switch.state.option.3003 = Dunkler (Lang Gedrückt)
|
||||
channel-type.hue.dimmer_switch.state.option.4000 = Aus (Initial)
|
||||
channel-type.hue.dimmer_switch.state.option.4001 = Aus (Gehalten)
|
||||
channel-type.hue.dimmer_switch.state.option.4002 = Aus (Kurz Gedrückt)
|
||||
channel-type.hue.dimmer_switch.state.option.4003 = Aus (Lang Gedrückt)
|
||||
|
||||
channel-type.hue.tap_switch.state.option.34 = Taste 1
|
||||
channel-type.hue.tap_switch.state.option.16 = Taste 2
|
||||
channel-type.hue.tap_switch.state.option.17 = Taste 3
|
||||
channel-type.hue.tap_switch.state.option.18 = Taste 4
|
||||
|
||||
# Config status messages
|
||||
config-status.error.missing-ip-address-configuration = Es wurde keine IP-Adresse für die Hue Bridge angegeben.
|
||||
|
||||
# Thing status descriptions
|
||||
offline.conf-error-no-ip-address = Verbindung zur Hue Bridge kann nicht aufgebaut werden. Es wurde keine IP-Adresse angegeben.
|
||||
offline.conf-error-no-username = Verbindung zur Hue Bridge kann nicht aufgebaut werden. Es wurde kein Benutzer angegeben.
|
||||
offline.conf-error-invalid-username = Fehler bei der Authentifizierung. Entfernen Sie den Benutzer zur automatischen Generierung eines neuen Benutzers über die Hue Bridge.
|
||||
offline.conf-error-press-pairing-button = Bitte drücken Sie den Knopf an der Hue Bridge zur automatischen Generierung eines neuen Benutzers.
|
||||
offline.conf-error-creation-username = Fehler bei der automatischen Generierung eines neuen Benutzers.
|
||||
offline.bridge-connection-lost = Verbindung zur Hue Bridge unterbrochen.
|
||||
offline.conf-error-no-light-id = Es wurde keine ID der Lampe angegeben.
|
||||
offline.conf-error-no-sensor-id = Es wurde keine ID des Sensors angegeben.
|
||||
offline.conf-error-wrong-light-id = Es wurde keine Lampe mit der angegebenen ID an der Hue Bridge gefunden.
|
||||
offline.conf-error-wrong-sensor-id = Es wurde kein Sensor mit der angegebenen ID an der Hue Bridge gefunden.
|
||||
offline.light-not-reachable = Die Hue Bridge meldet, dass die Lampe nicht erreichbar ist.
|
||||
offline.sensor-not-reachable = Die Hue Bridge meldet, dass der Sensor nicht erreichbar ist.
|
||||
offline.light-removed = Die Hue Bridge meldet, dass die Lampe entfernt wurde.
|
||||
offline.sensor-removed = Die Hue Bridge meldet, dass der Sensor entfernt wurde.
|
||||
@@ -0,0 +1,82 @@
|
||||
# binding
|
||||
binding.hue.name = Extension hue
|
||||
binding.hue.description = L'extension hue intègre le système Philips hue et permet de contrôler des ampoules hue.
|
||||
|
||||
# thing types
|
||||
thing-type.hue.bridge.label = Pont de connexion hue
|
||||
thing-type.hue.bridge.description = Le pont de connexion Philips Hue.
|
||||
thing-type.hue.0000.label = Ampoule sans variation
|
||||
thing-type.hue.0000.description = Une ampoule sans réglage de l'intensité lumineuse.
|
||||
thing-type.hue.0010.label = Prise commandée sans variation
|
||||
thing-type.hue.0010.description = Une prise commandée sans réglage de l'intensité de sortie.
|
||||
thing-type.hue.0100.label = Ampoule à variation
|
||||
thing-type.hue.0100.description = Une ampoule avec réglage de l'intensité lumineuse.
|
||||
thing-type.hue.0110.label = Prise commandée à variation
|
||||
thing-type.hue.0110.description = Une prise commandée avec réglage de l'intensité de sortie.
|
||||
thing-type.hue.0200.label = Ampoule couleur
|
||||
thing-type.hue.0200.description = Une ampoule avec réglages de l'intensité lumineuse et de la couleur.
|
||||
thing-type.hue.0210.label = Ampoule couleur
|
||||
thing-type.hue.0210.description = Une ampoule avec réglages de l'intensité lumineuse, de la couleur et de la température de couleur
|
||||
thing-type.hue.0220.label = Ampoule couleur
|
||||
thing-type.hue.0220.description = Une ampoule avec réglages de l'intensité lumineuse et de la température de couleur.
|
||||
thing-type.hue.group.label = Groupe hue
|
||||
thing-type.hue.group.description = Un groupe d'ampoules ou une pièce pouvant être allumé et éteint.
|
||||
|
||||
# thing type configuration
|
||||
thing-type.config.hue.bridge.ipAddress.label = Adresse réseau
|
||||
thing-type.config.hue.bridge.ipAddress.description = L'adresse réseau du pont de connexion hue.
|
||||
thing-type.config.hue.bridge.userName.label = Nom d'utilisateur
|
||||
thing-type.config.hue.bridge.userName.description = Le nom d'un utilisateur enregistré sur le pont de connexion hue, autorisant un accès à l'API.
|
||||
thing-type.config.hue.bridge.pollingInterval.label = Intervalle d'interrogation
|
||||
thing-type.config.hue.bridge.pollingInterval.description = Le nombre de secondes entre chaque récupération des valeurs du pont.
|
||||
thing-type.config.hue.0000.lightId.label = ID ampoule
|
||||
thing-type.config.hue.0000.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue.
|
||||
thing-type.config.hue.0010.lightId.label = ID prise commandée
|
||||
thing-type.config.hue.0010.lightId.description = L'identifiant de prise commandée identifie l'une des prises commandées. hue
|
||||
thing-type.config.hue.0100.lightId.label = ID ampoule
|
||||
thing-type.config.hue.0100.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue.
|
||||
thing-type.config.hue.0110.lightId.label = ID prise commandée
|
||||
thing-type.config.hue.0110.lightId.description = L'identifiant de prise commandée identifie l'une des prises commandées. hue.
|
||||
thing-type.config.hue.0200.lightId.label = ID ampoule
|
||||
thing-type.config.hue.0200.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue.
|
||||
thing-type.config.hue.0210.lightId.label = ID ampoule
|
||||
thing-type.config.hue.0210.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue.
|
||||
thing-type.config.hue.0220.lightId.label = ID ampoule
|
||||
thing-type.config.hue.0220.lightId.description = L'identifiant d'ampoule identifie l'une des ampoules hue.
|
||||
thing-type.config.hue.group.groupId.label = ID groupe
|
||||
thing-type.config.hue.group.groupId.description = L'identifiant de groupe identifie l'un des groupes d'ampoules hue ou une pièce.
|
||||
|
||||
# channel types
|
||||
channel-type.hue.color.label = Couleur
|
||||
channel-type.hue.color.description = Permet de contrôler la couleur de l'ampoule. Il est également possible d'allumer ou d'éteindre l'ampoule ainsi que de faire varier son intensité lumineuse.
|
||||
channel-type.hue.brightness.label = Intensité lumineuse
|
||||
channel-type.hue.brightness.description = Permet de contrôler l'intensité lumineuse de l'ampoule. Il est également possible d'allumer ou d'éteindre l'ampoule.
|
||||
channel-type.hue.switch.label = Commutateur
|
||||
channel-type.hue.switch.description = Permet d'allumer ou d'éteindre l'ampoule.
|
||||
channel-type.hue.color_temperature.label = Température couleur
|
||||
channel-type.hue.color_temperature.description = Permet de choisir la température de couleur de l'ampoule entre 0 (froid) et 100 (chaud).
|
||||
channel-type.hue.alert.label = Mode alerte
|
||||
channel-type.hue.alert.description = Permet un changement temporaire de l'état de l'ampoule.
|
||||
channel-type.hue.alert.state.option.NONE = Sans alerte
|
||||
channel-type.hue.alert.state.option.SELECT = Alerte courte
|
||||
channel-type.hue.alert.state.option.LSELECT = Alerte longue
|
||||
channel-type.hue.effect.label = Mode boucle de couleur
|
||||
channel-type.hue.effect.description = Permet de passer l'ampoule dans un mode boucle de couleur.
|
||||
|
||||
# Config status messages
|
||||
config-status.error.missing-ip-address-configuration=Aucune adresse IP fournie pour le pont de connexion hue.
|
||||
|
||||
# Thing status descriptions
|
||||
offline.conf-error-no-ip-address = Echec de la connexion au pont hue. Adresse IP non renseignée dans la configuration.
|
||||
offline.conf-error-no-username = Echec de la connexion au pont hue. Nom d''utilisateur pour l''autentification non renseigné dans la configuration.
|
||||
offline.conf-error-invalid-username = Echec de l''autentification. Supprimer le nom d''utilisateur de la configuration pour en générer un nouveau.
|
||||
offline.conf-error-press-pairing-button = Non autentifié. Appuyer sur le bouton d'appairage du pont de connexion hue ou définir un nom valide d''utilisateur dans la configuration.
|
||||
offline.conf-error-creation-username = Echec de la créatiion du nouvel utilisateur sur le pont de connexion hue.
|
||||
offline.bridge-connection-lost = Perte de la connexion au pont hue.
|
||||
offline.conf-error-no-light-id = ID ampoule non renseigné dans la configuration.
|
||||
offline.conf-error-no-group-id = ID groupe non renseigné dans la configuration.
|
||||
offline.conf-error-wrong-light-id = Pas d''ampoule avec cet ID dans le pont de connexion hue.
|
||||
offline.conf-error-wrong-group-id = Pas de groupe avec cet ID dans le pont de connexion hue.
|
||||
offline.light-not-reachable = Le pont de connexion hue signale l''ampoule comme inaccessible.
|
||||
offline.light-removed = Le pont de connexion hue signale l''ampoule comme supprimée.
|
||||
offline.group-removed = Le pont de connexion hue signale le groupe comme supprimé.
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- CLIP Generic Flag Sensor -->
|
||||
<thing-type id="0850">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>CLIP Generic Flag Sensor</label>
|
||||
<description>A generic sensor object for IP sensor use.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="flag" typeId="flag"/>
|
||||
<channel id="last_updated" typeId="last_updated"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="on" type="boolean">
|
||||
<label>Sensor Status</label>
|
||||
<description>Enables or disables the sensor.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- CLIP Generic Status Sensor -->
|
||||
<thing-type id="0840">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>CLIP Generic Status Sensor</label>
|
||||
<description>A generic sensor object for IP sensor use.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="status" typeId="status"/>
|
||||
<channel id="last_updated" typeId="last_updated"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="on" type="boolean">
|
||||
<label>Sensor Status</label>
|
||||
<description>Enables or disables the sensor.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for color lights (ZigBee Device ID: 0x0200) -->
|
||||
<thing-type id="0200">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Color Light</label>
|
||||
<description>A dimmable light with changeable colors.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="color" typeId="color"/>
|
||||
<channel id="alert" typeId="alert"/>
|
||||
<channel id="effect" typeId="effect"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="lightId" type="text">
|
||||
<label>Light ID</label>
|
||||
<description>The light identifier identifies one certain hue light.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
||||
<label>Fade Time</label>
|
||||
<description>Fade time in milliseconds for changing values</description>
|
||||
<default>400</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for color temperature lights (ZigBee Device ID: 0x0220) -->
|
||||
<thing-type id="0220">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Color Temperature Light</label>
|
||||
<description>A dimmable light with tunable color temperature.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="color_temperature" typeId="color_temperature"/>
|
||||
<channel id="brightness" typeId="brightness"/>
|
||||
<channel id="alert" typeId="alert"/>
|
||||
<channel id="effect" typeId="effect"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="lightId" type="text">
|
||||
<label>Light ID</label>
|
||||
<description>The light identifier identifies one certain hue light.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
||||
<label>Fade Time</label>
|
||||
<description>Fade time in milliseconds for changing values</description>
|
||||
<default>400</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for dimmable lights (ZigBee Device ID: 0x0100) -->
|
||||
<thing-type id="0100">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Dimmable Light</label>
|
||||
<description>A dimmable light.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="brightness"/>
|
||||
<channel id="alert" typeId="alert"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="lightId" type="text">
|
||||
<label>Light ID</label>
|
||||
<description>The light identifier identifies one certain hue light.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
||||
<label>Fade Time</label>
|
||||
<description>Fade time in milliseconds for changing values</description>
|
||||
<default>400</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for dimmable plugs (ZigBee Device ID: 0x0110) -->
|
||||
<thing-type id="0110">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Dimmable Plug-in Unit</label>
|
||||
<description>An outlet that can be dimmed.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="brightness" typeId="brightness"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="lightId" type="text">
|
||||
<label>Light ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
||||
<label>Fade Time</label>
|
||||
<description>Fade time in milliseconds for changing values</description>
|
||||
<default>400</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Hue Dimmer Switch -->
|
||||
<thing-type id="0820">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Hue Dimmer Switch</label>
|
||||
<description>A dimmer switch.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="dimmer_switch_event" typeId="dimmer_switch_event"/>
|
||||
<channel id="dimmer_switch" typeId="dimmer_switch"/>
|
||||
<channel id="last_updated" typeId="last_updated"/>
|
||||
<channel id="battery_level" typeId="system.battery-level"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="on" type="boolean">
|
||||
<label>Sensor Status</label>
|
||||
<description>Enables or disables the sensor.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for extended color lights (ZigBee Device ID: 0x0210) -->
|
||||
<thing-type id="0210">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Extended Color Light</label>
|
||||
<description>A dimmable light with changeable colors and tunable color temperature.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="color" typeId="color"/>
|
||||
<channel id="color_temperature" typeId="color_temperature"/>
|
||||
<channel id="alert" typeId="alert"/>
|
||||
<channel id="effect" typeId="effect"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="lightId" type="text">
|
||||
<label>Light ID</label>
|
||||
<description>The light identifier identifies one certain hue light.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
||||
<label>Fade Time</label>
|
||||
<description>Fade time in milliseconds for changing values</description>
|
||||
<default>400</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for Groups/Rooms -->
|
||||
<thing-type id="group">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Hue Group</label>
|
||||
<description>A group of lights or a room that could be switched on and off.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="switch"/>
|
||||
<channel id="color_temperature" typeId="color_temperature"/>
|
||||
<channel id="brightness" typeId="brightness"/>
|
||||
<channel id="color" typeId="color"/>
|
||||
<channel id="alert" typeId="alert"/>
|
||||
<channel id="scene" typeId="scene"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>groupId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="groupId" type="text">
|
||||
<label>Group ID</label>
|
||||
<description>The group identifier identifies one certain hue group or room.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
||||
<label>Fade Time</label>
|
||||
<description>Fade time in milliseconds for changing values</description>
|
||||
<default>400</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Hue Light Level Sensor -->
|
||||
<thing-type id="0106">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Hue Light Level Sensor</label>
|
||||
<description>A sensor providing light level information.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="illuminance" typeId="illuminance"/>
|
||||
<channel id="light_level" typeId="light_level"/>
|
||||
<channel id="dark" typeId="dark"/>
|
||||
<channel id="daylight" typeId="daylight"/>
|
||||
<channel id="last_updated" typeId="last_updated"/>
|
||||
<channel id="battery_level" typeId="system.battery-level"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="on" type="boolean">
|
||||
<label>Sensor Status</label>
|
||||
<description>Enables or disables the sensor.</description>
|
||||
</parameter>
|
||||
<parameter name="ledindication" type="boolean">
|
||||
<label>LED Indication</label>
|
||||
<description>Turns device LED during normal operation on or off. Devices might still indicate exceptional operation
|
||||
(Reset, SW Update, Battery Low).</description>
|
||||
</parameter>
|
||||
<parameter name="tholddark" type="integer" min="0" step="1">
|
||||
<label>Threshold Dark</label>
|
||||
<description>Threshold the user configured to be used in rules to determine insufficient light level (ie below
|
||||
threshold). Default value 16000.</description>
|
||||
<default>16000</default>
|
||||
</parameter>
|
||||
<parameter name="tholdoffset" type="integer" min="1" step="1">
|
||||
<label>Threshold Offset</label>
|
||||
<description>Threshold the user configured to be used in rules to determine sufficient light level (ie above
|
||||
threshold). Specified as relative offset to the “dark” threshold. Shall be >=1. Default value 7000.</description>
|
||||
<default>7000</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for OnOff lights (ZigBee Device ID: 0x0000) -->
|
||||
<thing-type id="0000">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>On/Off Light</label>
|
||||
<description>A light that could be switched on and off.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="switch"/>
|
||||
<channel id="alert" typeId="alert"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="lightId" type="text">
|
||||
<label>Light ID</label>
|
||||
<description>The light identifier identifies one certain hue light.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Generic thing for OnOff plugs (ZigBee Device ID: 0x0010) -->
|
||||
<thing-type id="0010">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>On/Off Plug-in Unit</label>
|
||||
<description>An outlet that could be switched on and off.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="switch" typeId="switch"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="lightId" type="text">
|
||||
<label>Light ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Hue Presence Sensor -->
|
||||
<thing-type id="0107">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Hue Presence Sensor</label>
|
||||
<description>A motion sensor providing presence detection.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="presence" typeId="system.motion"/>
|
||||
<channel id="last_updated" typeId="last_updated"/>
|
||||
<channel id="battery_level" typeId="system.battery-level"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="on" type="boolean">
|
||||
<label>Sensor Status</label>
|
||||
<description>Enables or disables the sensor.</description>
|
||||
</parameter>
|
||||
<parameter name="ledindication" type="boolean">
|
||||
<label>LED Indication</label>
|
||||
<description>Turns device LED during normal operation on or off. Devices might still indicate exceptional operation
|
||||
(Reset, SW Update, Battery Low).</description>
|
||||
</parameter>
|
||||
<parameter name="sensitivity" type="integer" min="0" step="1">
|
||||
<label>Sensitivity</label>
|
||||
<description>The current sensitivity of the presence sensor. Cannot exceed maximum sensitivity.</description>
|
||||
</parameter>
|
||||
<parameter name="sensitivitymax" type="integer" readOnly="true">
|
||||
<label>Maximum Sensitivity</label>
|
||||
<description>The maximum sensitivity of the presence sensor.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Hue Tap Switch -->
|
||||
<thing-type id="0830">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Hue Tap Switch</label>
|
||||
<description>A customizable switch.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="tap_switch_event" typeId="tap_switch_event"/>
|
||||
<channel id="tap_switch" typeId="tap_switch"/>
|
||||
<channel id="last_updated" typeId="last_updated"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="on" type="boolean">
|
||||
<label>Sensor Status</label>
|
||||
<description>Enables or disables the sensor.</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Hue Temperature Sensor -->
|
||||
<thing-type id="0302">
|
||||
<supported-bridge-type-refs>
|
||||
<bridge-type-ref id="bridge"/>
|
||||
</supported-bridge-type-refs>
|
||||
|
||||
<label>Hue Temperature Sensor</label>
|
||||
<description>A sensor providing temperature values.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="temperature" typeId="temperature"/>
|
||||
<channel id="last_updated" typeId="last_updated"/>
|
||||
<channel id="battery_level" typeId="system.battery-level"/>
|
||||
<channel id="battery_low" typeId="system.low-battery"/>
|
||||
</channels>
|
||||
|
||||
<representation-property>uniqueId</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="sensorId" type="text">
|
||||
<label>Sensor ID</label>
|
||||
<description>The identifier that is used within the hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="on" type="boolean">
|
||||
<label>Sensor Status</label>
|
||||
<description>Enables or disables the sensor.</description>
|
||||
</parameter>
|
||||
<parameter name="ledindication" type="boolean">
|
||||
<label>LED Indication</label>
|
||||
<description>Turns device LED during normal operation on or off. Devices might still indicate exceptional operation
|
||||
(Reset, SW Update, Battery Low).</description>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</thing-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Hue Bridge -->
|
||||
<bridge-type id="bridge">
|
||||
<label>Hue Bridge</label>
|
||||
<description>The Hue bridge represents the Philips Hue bridge.</description>
|
||||
|
||||
<channels>
|
||||
<channel id="scene" typeId="scene"/>
|
||||
</channels>
|
||||
|
||||
<properties>
|
||||
<property name="vendor">Philips</property>
|
||||
</properties>
|
||||
<representation-property>serialNumber</representation-property>
|
||||
|
||||
<config-description>
|
||||
<parameter name="ipAddress" type="text">
|
||||
<context>network-address</context>
|
||||
<label>Network Address</label>
|
||||
<description>Network address of the Hue bridge.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" required="false" min="1" max="65535">
|
||||
<label>Port</label>
|
||||
<description>Port of the Hue bridge.</description>
|
||||
</parameter>
|
||||
<parameter name="userName" type="text">
|
||||
<context>password</context>
|
||||
<label>Username</label>
|
||||
<description>Name of a registered Hue bridge user, that allows to access the API.</description>
|
||||
<required>false</required>
|
||||
</parameter>
|
||||
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s">
|
||||
<label>Polling Interval</label>
|
||||
<description>Seconds between fetching values from the Hue bridge. Default is 10.</description>
|
||||
<required>true</required>
|
||||
<default>10</default>
|
||||
</parameter>
|
||||
<parameter name="sensorPollingInterval" type="integer" min="0" step="1" unit="ms">
|
||||
<label>Sensor Polling Interval</label>
|
||||
<description>Milliseconds between fetching sensor-values from the Hue bridge. A higher value means more delay for
|
||||
the sensor values, but a too low value can cause congestion on the Hue bridge. Use 0 to disable the polling for
|
||||
sensors. Default is 500.</description>
|
||||
<required>true</required>
|
||||
<default>500</default>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</bridge-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,222 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="hue" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<!-- Color Channel -->
|
||||
<channel-type id="color">
|
||||
<item-type>Color</item-type>
|
||||
<label>Color</label>
|
||||
<description>The color channel allows to control the color of a light.
|
||||
It is also possible to dim values and switch the
|
||||
light on and off.
|
||||
</description>
|
||||
<category>ColorLight</category>
|
||||
<tags>
|
||||
<tag>Lighting</tag>
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<!-- Brightness Channel -->
|
||||
<channel-type id="brightness">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Brightness</label>
|
||||
<description>The brightness channel allows to control the brightness of a light.
|
||||
It is also possible to switch the
|
||||
light on and off.
|
||||
</description>
|
||||
<category>DimmableLight</category>
|
||||
<tags>
|
||||
<tag>Lighting</tag>
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="last_updated">
|
||||
<item-type>DateTime</item-type>
|
||||
<label>Last Updated</label>
|
||||
<description>The date and time when the sensor was last updated.</description>
|
||||
<category>Time</category>
|
||||
<state readOnly="true" pattern="%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="illuminance">
|
||||
<item-type>Number:Illuminance</item-type>
|
||||
<label>Illuminance</label>
|
||||
<description>Current illuminance.</description>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="light_level" advanced="true">
|
||||
<item-type>Number</item-type>
|
||||
<label>Light Level</label>
|
||||
<description>Current light level.</description>
|
||||
<state readOnly="true" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dark">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Dark</label>
|
||||
<description>Light level is below the darkness threshold.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="daylight">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Daylight</label>
|
||||
<description>Light level is above the daylight threshold.</description>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dimmer_switch">
|
||||
<item-type>Number</item-type>
|
||||
<label>Dimmer Switch State</label>
|
||||
<description>The Button that was last pressed on the dimmer switch.</description>
|
||||
<state readOnly="true" pattern="%d">
|
||||
<options>
|
||||
<option value="1000">On (Initial Press)</option>
|
||||
<option value="1001">On (Hold)</option>
|
||||
<option value="1002">On (Short Released)</option>
|
||||
<option value="1003">On (Long Released)</option>
|
||||
<option value="2000">Dim Up (Initial Press)</option>
|
||||
<option value="2001">Dim Up (Hold)</option>
|
||||
<option value="2002">Dim Up (Short Released)</option>
|
||||
<option value="2003">Dim Up (Long Released)</option>
|
||||
<option value="3000">Dim Down (Initial Press)</option>
|
||||
<option value="3001">Dim Down (Hold)</option>
|
||||
<option value="3002">Dim Down (Short Released)</option>
|
||||
<option value="3003">Dim Down (Long Released)</option>
|
||||
<option value="4000">Off (Initial Press)</option>
|
||||
<option value="4001">Off (Hold)</option>
|
||||
<option value="4002">Off (Short Released)</option>
|
||||
<option value="4003">Off (Long Released)</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="dimmer_switch_event">
|
||||
<kind>trigger</kind>
|
||||
<label>Dimmer Switch Event</label>
|
||||
<description>Triggers when a button is pressed on the dimmer switch.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="1000">1000</option>
|
||||
<option value="1001">1001</option>
|
||||
<option value="1002">1002</option>
|
||||
<option value="1003">1003</option>
|
||||
<option value="2000">2000</option>
|
||||
<option value="2001">2001</option>
|
||||
<option value="2002">2002</option>
|
||||
<option value="2003">2003</option>
|
||||
<option value="3000">3000</option>
|
||||
<option value="3001">3001</option>
|
||||
<option value="3002">3002</option>
|
||||
<option value="3003">3003</option>
|
||||
<option value="4000">4000</option>
|
||||
<option value="4001">4001</option>
|
||||
<option value="4002">4002</option>
|
||||
<option value="4003">4003</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tap_switch">
|
||||
<item-type>Number</item-type>
|
||||
<label>Tap Switch State</label>
|
||||
<description>The Button that was last pressed on the tap switch.</description>
|
||||
<state readOnly="true" pattern="%d">
|
||||
<options>
|
||||
<option value="34">Button 1</option>
|
||||
<option value="16">Button 2</option>
|
||||
<option value="17">Button 3</option>
|
||||
<option value="18">Button 4</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="tap_switch_event">
|
||||
<kind>trigger</kind>
|
||||
<label>Tap Switch Event</label>
|
||||
<description>Triggers when a button is pressed on the tap switch.</description>
|
||||
<event>
|
||||
<options>
|
||||
<option value="34">34</option>
|
||||
<option value="16">16</option>
|
||||
<option value="17">17</option>
|
||||
<option value="18">18</option>
|
||||
</options>
|
||||
</event>
|
||||
</channel-type>
|
||||
|
||||
<!-- Switch Channel -->
|
||||
<channel-type id="switch">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Switch</label>
|
||||
<description>The switch channel allows to switch the light on and off.
|
||||
</description>
|
||||
<category>Light</category>
|
||||
<tags>
|
||||
<tag>Lighting</tag>
|
||||
</tags>
|
||||
</channel-type>
|
||||
|
||||
<!-- Temperature Channel -->
|
||||
<channel-type id="temperature">
|
||||
<item-type>Number:Temperature</item-type>
|
||||
<label>Temperature</label>
|
||||
<description>Current temperature.</description>
|
||||
<category>Temperature</category>
|
||||
<state readOnly="true" pattern="%.1f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<!-- Color Temperature Channel -->
|
||||
<channel-type id="color_temperature">
|
||||
<item-type>Dimmer</item-type>
|
||||
<label>Color Temperature</label>
|
||||
<description>The color temperature channel allows to set the color
|
||||
temperature of a light from 0 (cold) to 100 (warm).
|
||||
</description>
|
||||
<category>ColorLight</category>
|
||||
</channel-type>
|
||||
|
||||
<!-- Alert Channel -->
|
||||
<channel-type id="alert" advanced="true">
|
||||
<item-type>String</item-type>
|
||||
<label>Alert</label>
|
||||
<description>The alert channel allows a temporary change to the bulb’s state.</description>
|
||||
<state>
|
||||
<options>
|
||||
<option value="NONE">None</option>
|
||||
<option value="SELECT">Alert</option>
|
||||
<option value="LSELECT">Long Alert</option>
|
||||
</options>
|
||||
</state>
|
||||
</channel-type>
|
||||
|
||||
<!-- Effect Channel -->
|
||||
<channel-type id="effect" advanced="true">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Color Loop</label>
|
||||
<description>The effect channel allows putting the bulb in a color looping mode.</description>
|
||||
<category>ColorLight</category>
|
||||
</channel-type>
|
||||
|
||||
<!-- CLIP Sensor -->
|
||||
<channel-type id="status">
|
||||
<item-type>Number</item-type>
|
||||
<label>Status</label>
|
||||
<description>Status of CLIP sensor.</description>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="flag">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Flag</label>
|
||||
<description>Flag of CLIP sensor.</description>
|
||||
</channel-type>
|
||||
|
||||
<!-- Scene Channel -->
|
||||
<channel-type id="scene">
|
||||
<item-type>String</item-type>
|
||||
<label>Scene</label>
|
||||
<description>The scene channel allows recalling a scene to all lights that belong to the scene.</description>
|
||||
</channel-type>
|
||||
</thing:thing-descriptions>
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2020 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.hue.internal;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Samuel Leisering - Initial contribution
|
||||
*/
|
||||
public class ApiVersionTest {
|
||||
|
||||
@Test
|
||||
public void testKnownVersions() {
|
||||
String version = "1.0";
|
||||
assertTrue(ApiVersion.of(version).compare(new ApiVersion(1, 0, 0)) == 0);
|
||||
|
||||
version = "1.0.0";
|
||||
assertTrue(ApiVersion.of(version).compare(new ApiVersion(1, 0, 0)) == 0);
|
||||
|
||||
version = "1.10.0";
|
||||
assertTrue(ApiVersion.of(version).compare(new ApiVersion(1, 10, 0)) == 0);
|
||||
|
||||
version = "1.2.1";
|
||||
assertTrue(ApiVersion.of(version).compare(new ApiVersion(1, 2, 1)) == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompare() {
|
||||
ApiVersion v = new ApiVersion(1, 2, 3);
|
||||
|
||||
assertTrue(v.compare(new ApiVersion(1, 2, 3)) == 0);
|
||||
|
||||
assertTrue(v.compare(new ApiVersion(1, 2, 2)) > 0);
|
||||
assertTrue(v.compare(new ApiVersion(1, 2, 4)) < 0);
|
||||
|
||||
assertTrue(v.compare(new ApiVersion(1, 1, 3)) > 0);
|
||||
assertTrue(v.compare(new ApiVersion(1, 3, 3)) < 0);
|
||||
|
||||
assertTrue(v.compare(new ApiVersion(0, 2, 3)) > 0);
|
||||
assertTrue(v.compare(new ApiVersion(3, 2, 3)) < 0);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user