mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[huesync] Initial contribution (#16516)
* ☠️ Binding skeleton created for org.openhab.binding.huesync
Signed-off-by: Patrik Gfeller <patrik.gfeller@gmail.com>
Signed-off-by: Patrik Gfeller <patrik.gfeller@proton.me>
This commit is contained in:
parent
36bde0037f
commit
5a27b0e752
@ -159,6 +159,7 @@
|
||||
/bundles/org.openhab.binding.hpprinter/ @cossey
|
||||
/bundles/org.openhab.binding.http/ @J-N-K
|
||||
/bundles/org.openhab.binding.hue/ @cweitkamp @andrewfg
|
||||
/bundles/org.openhab.binding.huesync/ @pgfeller
|
||||
/bundles/org.openhab.binding.hydrawise/ @digitaldan
|
||||
/bundles/org.openhab.binding.hyperion/ @tavalin
|
||||
/bundles/org.openhab.binding.iammeter/ @lewei50
|
||||
|
@ -796,6 +796,11 @@
|
||||
<artifactId>org.openhab.binding.hue</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.huesync</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.binding.hydrawise</artifactId>
|
||||
|
13
bundles/org.openhab.binding.huesync/NOTICE
Normal file
13
bundles/org.openhab.binding.huesync/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
|
220
bundles/org.openhab.binding.huesync/README.md
Normal file
220
bundles/org.openhab.binding.huesync/README.md
Normal file
@ -0,0 +1,220 @@
|
||||
# hueSync Binding
|
||||
|
||||
<!-- markdownlint-disable MD033 -->
|
||||
This binding integrates the [Play HDMI Sync Box](https://www.philips-hue.com/en-us/p/hue-philips-hue-play-hdmi-sync-box/046677579753) into openHAB.
|
||||
The integration happens directly through the Hue [HDMI Sync Box API](https://developers.meethue.com/develop/hue-entertainment/hue-hdmi-sync-box-api/).
|
||||
|
||||
- [hueSync Binding](#huesync-binding)
|
||||
- [Supported Things](#supported-things)
|
||||
- [Discovery](#discovery)
|
||||
- [Configuration](#configuration)
|
||||
- [Thing(s)](#things)
|
||||
- [Channels](#channels)
|
||||
- [Firmware Information](#firmware-information)
|
||||
- [HDMI connections \[in|out\]](#hdmi-connections-inout)
|
||||
- [Commands](#commands)
|
||||
- [Example Configuration](#example-configuration)
|
||||
- [huesyncbox.things](#huesyncboxthings)
|
||||
- [huesyncbox.items](#huesyncboxitems)
|
||||
- [example.sitemap](#examplesitemap)
|
||||
|
||||
## Supported Things
|
||||
|
||||
This binding provides only one thing type: **`box`**.
|
||||
Each thing will represent a Hue Play HDMI sync box.
|
||||
|
||||
## Discovery
|
||||
|
||||
The binding supports auto discovery using [mDNS](https://en.wikipedia.org/wiki/Multicast_DNS) to find devices in the local network.
|
||||
|
||||
Make sure the device is connected to the network (the LED on the Sync Box is white or red).
|
||||
If the LED is blinking blue, you need to setup the device using the official [Hue Sync App](https://www.philips-hue.com/en-in/explore-hue/propositions/entertainment/hue-sync).
|
||||
|
||||
If the device is not discovered you can check if it is properly configured and discoverable:
|
||||
|
||||
<p>
|
||||
<details>
|
||||
<summary><b>Linux</b> (Ubuntu based distributions)</summary>
|
||||
|
||||
```bash
|
||||
$ avahi-browse --resolve _huesync._tcp
|
||||
+ wlp0s20f3 IPv4 HueSyncBox-XXXXXXXXXXX _huesync._tcp local
|
||||
= wlp0s20f3 IPv4 HueSyncBox-XXXXXXXXXXX _huesync._tcp local
|
||||
hostname = [XXXXXXXXXXX.local]
|
||||
address = [192.168.0.12]
|
||||
port = [443]
|
||||
txt = ["name=Sync Box" "devicetype=HSB1" "uniqueid=XXXXXXXXXXX" "path=/api"]
|
||||
```
|
||||
|
||||
</details>
|
||||
</p>
|
||||
|
||||
mDNS uses link-local multicast addresses; its scope is limited to a single physical or logical LAN ([Layer 3](https://en.wikipedia.org/wiki/OSI_model#Layer_3:_Network_layer")).
|
||||
If your device is not automatically discovered, create a thing and manually configure the "host" parameter.
|
||||
|
||||
To communicate with the sync box, you need to couple the thing with the hardware (registration).
|
||||
The thing will start this process automatically.
|
||||
To complete the registration you just press the "coupling" button on the sync box for 3 seconds.:
|
||||
|
||||
![Device Registration](doc/device_registration.png)
|
||||
|
||||
For special use cases it is possible to configure the id and token manually in the **advanced configuration** settings section.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Thing(s)
|
||||
|
||||
| Name | Type | Description | Default | Required | Advanced |
|
||||
| -------------------- | ------- | --------------------------------- | ------- | -------- | -------- |
|
||||
| host | text | IP address of the device | N/A | yes | no |
|
||||
| port | integer | Port of the HDMI Sync Box. | 443 | yes | yes |
|
||||
| registrationId | text | Application Registration Id | N/A | no | yes |
|
||||
| apiAccessToken | text | API Access Token | N/A | no | yes |
|
||||
| statusUpdateInterval | integer | Status Update Interval in seconds | 10 | yes | yes |
|
||||
|
||||
## Channels
|
||||
|
||||
### Firmware Information
|
||||
|
||||
Information about the installed device firmware and available updates.
|
||||
|
||||
| Channel | Type | Read/Write | Description |
|
||||
| ------------------ | ------ | ---------- | --------------------------------- |
|
||||
| firmware | String | R | Installed firmware version |
|
||||
| available-firmware | String | R | Latest available firmware version |
|
||||
|
||||
### HDMI connections [in\|out]
|
||||
|
||||
Information about a HDMI input connection.
|
||||
|
||||
| Channel | Type | Read/Write | Description |
|
||||
| ------- | ------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| type | String | R | <details><summary>Friendly Type</summary><ul><li>generic</li><li>video</li><li>game</li><li>music</li><li>xbox</li><li>playstation</li><li>nintendoswitch</li><li>phone</li><li>desktop</li><li>laptop</li><li>appletv</li><li>roku</li><li>shield</li><li>chromecast</li><li>firetv</li><li>diskplayer</li><li>settopbox</li><li>satellite</li><li>avreceiver</li><li>soundbar</li><li>hdmiswitch</li></ul></details> |
|
||||
| status | String | R | <details><summary>Device connection status</summary><ul><li>unplugged</li><li>plugged</li><li>linked</li><li>unknown</li></ul></details> |
|
||||
| name | String | R | Friendly Name |
|
||||
| mode | String | R | <details><summary>Mode</summary><ul><li>video</li><li>game</li><li>music</li><li>powersave</li><li>passthrough</li></ul></details> |
|
||||
|
||||
### Commands
|
||||
|
||||
| Channel | Type | Read/Write | Description |
|
||||
| ----------- | -------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| mode | String | R/W | <details><summary>Hue Sync operation mode</summary><ul><li>video</li><li>game</li><li>music</li><li>powersave</li><li>passthrough</li></ul></details> |
|
||||
| hdmi-source | Switch | R/W | <details><summary>Source</summary><ul><li>input1</li><li>input2</li><li>input3</li><li>input4</li></ul></details> |
|
||||
| sync-active | Switch | R/W | <details><summary>Synchronization</summary><p><b>OFF</b> in case of powersave or passthrough mode, and <b>ON</b> in case of video, game or music mode. When changed from OFF to ON, it will start syncing in last used mode for current source. When changed from ON to OFF, will set passthrough mode.</p></details> |
|
||||
| brightness | Number:Dimensionless | R/W | <details><summary>Brightness</summary><p><ul><li>0 = max reduction</li><li>100 = no brightness reduction/boost compared to input</li><li>200 = max boost</li></ul></p></details> |
|
||||
|
||||
## Example Configuration
|
||||
|
||||
### huesyncbox.things
|
||||
|
||||
```java
|
||||
Thing huesync:box:LivingRoom "Philips Hue HDMI Sync Box, LivingRoom" [
|
||||
host="192.168.2.115",
|
||||
httpPollingInterval=60,
|
||||
apiAccessToken="yourTokenGoesHere=",
|
||||
registrationId="8",
|
||||
port=443,
|
||||
statusUpdateInterval=10
|
||||
]
|
||||
```
|
||||
|
||||
### huesyncbox.items
|
||||
|
||||
Both item and sitemap configuration example use the `iconify` support for the `firmware` as well as `input1` and `input2`.
|
||||
Those icons loaded if needed from the internet and not suited for a pure offline setup.
|
||||
The other items use the `classic` icons.
|
||||
Read the documentation about the offline provider for `iconify` icons, or use the `classic` icons bundled with openHAB.
|
||||
|
||||
```java
|
||||
// Firmware
|
||||
Group firmware "Firmware Information" <iconify:mdi:info>
|
||||
String firmware_version "Current Firmware" <iconify:mdi:text> (firmware) {channel="huesync:box:LivingRoom:device-firmware#firmware"}
|
||||
String latest_firmware_version "Latest Firmware" <iconify:mdi:text> (firmware) {channel="huesync:box:LivingRoom:device-firmware#available-firmware"}
|
||||
|
||||
//HDMI Input 1
|
||||
Group hdmi_in1 "HDMI 1" <iconify:mdi:hdmi-port>
|
||||
String friendly_name_input1 "Friendly Name" <iconify:mdi:text> (hdmi_in1) {channel="huesync:box:LivingRoom:device-hdmi-in-1#name"}
|
||||
String friendly_type_input1 "Friendly Type" <iconify:mdi:devices> (hdmi_in1) {channel="huesync:box:LivingRoom:device-hdmi-in-1#type"}
|
||||
String hdmi_connection_status_input1 "Connection Status" <iconify:mdi:connection> (hdmi_in1) {channel="huesync:box:LivingRoom:device-hdmi-in-1#status"}
|
||||
String last_sync_mode_input1 "Last Sync Mode " <iconify:mdi:multimedia> (hdmi_in1) {channel="huesync:box:LivingRoom:device-hdmi-in-1#mode"}
|
||||
|
||||
//HDMI Input 2
|
||||
Group hdmi_in2
|
||||
String friendly_name_input2 "Friendly Name" {channel="huesync:box:LivingRoom:device-hdmi-in-2#name"}
|
||||
String friendly_type_input2 "Friendly Type" {channel="huesync:box:LivingRoom:device-hdmi-in-2#type"}
|
||||
String hdmi_connection_status_input2 "Connection Status" {channel="huesync:box:LivingRoom:device-hdmi-in-2#status"}
|
||||
String last_sync_mode_input2 "Last Sync Mode" {channel="huesync:box:LivingRoom:device-hdmi-in-2#mode"}
|
||||
|
||||
//HDMI Input 3
|
||||
String friendly_name_input3 "Friendly Name" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-3#name"}
|
||||
String friendly_type_input3 "Friendly Type" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-3#type"}
|
||||
String hdmi_connection_status_input3 "Connection Status" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-3#status"}
|
||||
String last_sync_mode_input3 "Last Sync Mode" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-3#mode"}
|
||||
|
||||
//HDMI Input 4
|
||||
String friendly_name_input4 "Friendly Name" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-4#name"}
|
||||
String friendly_type_input4 "Friendly Type" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-4#type"}
|
||||
String hdmi_connection_status_input4 "Connection Status" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-4#status"}
|
||||
String last_sync_mode_input4 "Last Sync Mode" <text> {channel="huesync:box:LivingRoom:device-hdmi-in-4#mode"}
|
||||
|
||||
|
||||
//HDMI output
|
||||
String friendly_name_output "Friendly Name" <text> {channel="huesync:box:LivingRoom:device-hdmi-out#name"}
|
||||
String friendly_type_output "Friendly Type" <text> {channel="huesync:box:LivingRoom:device-hdmi-out#type"}
|
||||
String hdmi_connection_status_output "Connection Status" <text> {channel="huesync:box:LivingRoom:device-hdmi-out#status"}
|
||||
String last_sync_mode_output "Last Sync Mode" <text> {channel="huesync:box:LivingRoom:device-hdmi-out#mode"}
|
||||
|
||||
//Commands
|
||||
String huesync_mode "Mode" <switch> {channel="huesync:box:LivingRoom:device-commands#mode"}
|
||||
Switch sync_active "Sync active" <switch> {channel="huesync:box:LivingRoom:device-commands#sync-active"}
|
||||
Switch hdmi_active "HDMI active" <switch> {channel="huesync:box:LivingRoom:device-commands#hdmi-active"}
|
||||
String hdmi_source "HDMI Source" <player> {channel="huesync:box:LivingRoom:device-commands#hdmi-source"}
|
||||
Dimmer huesync_brightness "Brightness" <slider> {channel="huesync:box:LivingRoom:device-commands#brightness"}
|
||||
|
||||
```
|
||||
|
||||
### example.sitemap
|
||||
|
||||
```java
|
||||
sitemap demo label="Hue Sync Box" {
|
||||
Frame {
|
||||
Group item=firmware
|
||||
}
|
||||
Frame label="Commands" icon=settings {
|
||||
Text item=huesync_mode
|
||||
Text item=hdmi_active
|
||||
Switch item=sync_active
|
||||
Text item=hdmi_source
|
||||
Buttongrid label="HDMI Source" staticIcon=player {
|
||||
Button row=1 column=1 item=hdmi_source label="Source 1" stateless click=input1
|
||||
Button row=2 column=1 item=hdmi_source label="Source 2" stateless click=input2
|
||||
Button row=3 column=1 item=hdmi_source label="Source 3" stateless click=input3
|
||||
Button row=4 column=1 item=hdmi_source label="Source 4" stateless click=input4
|
||||
}
|
||||
Selection item=hdmi_source mappings=[input1="Source 1", input2="Source 2", input3="Source 3", input3="Source 4"]
|
||||
|
||||
Slider item=huesync_brightness minValue=0 maxValue=200 step=10
|
||||
}
|
||||
Frame label="HDMI Inputs 1 & 2" icon="iconify:mdi:hdmi-port" {
|
||||
Default item=hdmi_in1
|
||||
|
||||
Group item=hdmi_in2 label="HDMI 2" icon="iconify:mdi:hdmi-port" {
|
||||
Default item=friendly_name_input2 icon="iconify:mdi:text"
|
||||
Default item=friendly_type_input2 icon="iconify:mdi:devices"
|
||||
Default item=hdmi_connection_status_input2 icon="iconify:mdi:connection"
|
||||
Default item=last_sync_mode_input2 icon="iconify:mdi:multimedia"
|
||||
}
|
||||
}
|
||||
Frame label="HDMI 3" icon=player {
|
||||
Default item=friendly_name_input3
|
||||
Default item=friendly_type_input3
|
||||
Default item=hdmi_connection_status_input3
|
||||
Default item=last_sync_mode_input3
|
||||
}
|
||||
Frame label="HDMI 4" icon=player {
|
||||
Text item=friendly_name_input4
|
||||
Text item=friendly_type_input4
|
||||
Text item=hdmi_connection_status_input4
|
||||
Text item=last_sync_mode_input4
|
||||
}
|
||||
```
|
BIN
bundles/org.openhab.binding.huesync/doc/device_registration.png
Normal file
BIN
bundles/org.openhab.binding.huesync/doc/device_registration.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
17
bundles/org.openhab.binding.huesync/pom.xml
Normal file
17
bundles/org.openhab.binding.huesync/pom.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.openhab.addons.bundles</groupId>
|
||||
<artifactId>org.openhab.addons.reactor.bundles</artifactId>
|
||||
<version>4.3.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>org.openhab.binding.huesync</artifactId>
|
||||
|
||||
<name>openHAB Add-ons :: Bundles :: Hue Sync Box Binding</name>
|
||||
|
||||
</project>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<features name="org.openhab.binding.huesync-${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-huesync" description="Hue Sync Box Binding" version="${project.version}">
|
||||
<feature>openhab-runtime-base</feature>
|
||||
<feature>openhab-transport-mdns</feature>
|
||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.huesync/${project.version}</bundle>
|
||||
</feature>
|
||||
</features>
|
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HdmiChannels {
|
||||
public String name;
|
||||
public String type;
|
||||
public String mode;
|
||||
public String status;
|
||||
|
||||
public HdmiChannels(String name, String type, String mode, String status) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
this.status = status;
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
|
||||
/**
|
||||
* The {@link HueSyncConstants} class defines common constants, which are
|
||||
* used across the whole binding.
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncConstants {
|
||||
public static class ENDPOINTS {
|
||||
public static final String DEVICE = "device";
|
||||
public static final String REGISTRATIONS = "registrations";
|
||||
public static final String HDMI = "hdmi";
|
||||
public static final String EXECUTION = "execution";
|
||||
|
||||
public static class COMMANDS {
|
||||
public static final String MODE = "mode";
|
||||
public static final String SYNC = "syncActive";
|
||||
public static final String HDMI = "hdmiActive";
|
||||
public static final String SOURCE = "hdmiSource";
|
||||
public static final String BRIGHTNESS = "brightness";
|
||||
}
|
||||
}
|
||||
|
||||
public static class CHANNELS {
|
||||
public static class DEVICE {
|
||||
public static class INFORMATION {
|
||||
public static final String FIRMWARE = "device-firmware#firmware";
|
||||
public static final String FIRMWARE_AVAILABLE = "device-firmware#available-firmware";
|
||||
}
|
||||
}
|
||||
|
||||
public static class COMMANDS {
|
||||
public static final String MODE = "device-commands#mode";
|
||||
public static final String SYNC = "device-commands#sync-active";
|
||||
public static final String HDMI = "device-commands#hdmi-active";
|
||||
public static final String SOURCE = "device-commands#hdmi-source";
|
||||
public static final String BRIGHTNESS = "device-commands#brightness";
|
||||
}
|
||||
|
||||
public static class HDMI {
|
||||
public static final HdmiChannels IN_1 = new HdmiChannels("device-hdmi-in-1#name", "device-hdmi-in-1#type",
|
||||
"device-hdmi-in-1#mode", "device-hdmi-in-1#status");
|
||||
public static final HdmiChannels IN_2 = new HdmiChannels("device-hdmi-in-2#name", "device-hdmi-in-2#type",
|
||||
"device-hdmi-in-2#mode", "device-hdmi-in-2#status");
|
||||
public static final HdmiChannels IN_3 = new HdmiChannels("device-hdmi-in-3#name", "device-hdmi-in-3#type",
|
||||
"device-hdmi-in-3#mode", "device-hdmi-in-3#status");
|
||||
public static final HdmiChannels IN_4 = new HdmiChannels("device-hdmi-in-4#name", "device-hdmi-in-4#type",
|
||||
"device-hdmi-in-4#mode", "device-hdmi-in-4#status");
|
||||
|
||||
public static final HdmiChannels OUT = new HdmiChannels("device-hdmi-out#name", "device-hdmi-out#type",
|
||||
"device-hdmi-out#mode", "device-hdmi-out#status");
|
||||
}
|
||||
}
|
||||
|
||||
public static final String APPLICATION_NAME = "openHAB";
|
||||
|
||||
/** Minimal API Version required. Only apiLevel >= 7 is supported. */
|
||||
public static final Integer MINIMAL_API_VERSION = 7;
|
||||
|
||||
public static final String BINDING_ID = "huesync";
|
||||
public static final String THING_TYPE_ID = "box";
|
||||
public static final ThingTypeUID THING_TYPE_UID = new ThingTypeUID(BINDING_ID, THING_TYPE_ID);
|
||||
|
||||
public static final String PARAMETER_HOST = "host";
|
||||
public static final String PARAMETER_PORT = "port";
|
||||
|
||||
public static final Integer REGISTRATION_INITIAL_DELAY = 3;
|
||||
public static final Integer REGISTRATION_INTERVAL = 1;
|
||||
|
||||
public static final String REGISTRATION_ID = "registrationId";
|
||||
public static final String API_TOKEN = "apiAccessToken";
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* HDMI Sync Box Device Information
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://developers.meethue.com/develop/hue-entertainment/hue-hdmi-sync-box-api/#Resource%20Table">Hue
|
||||
* HDMI Sync Box API</a>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncDevice {
|
||||
/** Friendly name of the device */
|
||||
public @Nullable String name;
|
||||
/** Device Type identifier */
|
||||
public @Nullable String deviceType;
|
||||
/**
|
||||
* Capitalized hex string of the 6 byte / 12 characters device id without
|
||||
* delimiters. Used as unique id on label, certificate common name, hostname
|
||||
* etc.
|
||||
*/
|
||||
public @Nullable String uniqueId;
|
||||
/**
|
||||
* Increased between firmware versions when api changes. Only apiLevel >= 7 is
|
||||
* supported.
|
||||
*/
|
||||
public int apiLevel = 0;
|
||||
/**
|
||||
* User readable version of the device firmware, starting with decimal major
|
||||
* .minor .maintenance format e.g. “1.12.3”
|
||||
*/
|
||||
public @Nullable String firmwareVersion;
|
||||
/**
|
||||
* Build number of the firmware. Unique for every build with newer builds
|
||||
* guaranteed a higher number than older.
|
||||
*/
|
||||
public int buildNumber = 0;
|
||||
|
||||
public boolean termsAgreed;
|
||||
|
||||
/** uninitialized, disconnected, lan, wan */
|
||||
public @Nullable String wifiState;
|
||||
public @Nullable String ipAddress;
|
||||
|
||||
public @Nullable HueSyncDeviceCapabilitiesInfo capabilities;
|
||||
|
||||
public boolean beta;
|
||||
public boolean overheating;
|
||||
public boolean bluetooth;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* HDMI Sync Box Device Information Capabilities
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://developers.meethue.com/develop/hue-entertainment/hue-hdmi-sync-box-api/#Resource%20Table">Hue
|
||||
* HDMI Sync Box API</a>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncDeviceCapabilitiesInfo {
|
||||
/** The total number of IR codes configurable */
|
||||
public int maxIrCodes;
|
||||
/** The total number of Presets configurable */
|
||||
public int maxPresets;
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.device;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* HDMI Sync Box Device Information - Extended information (only available
|
||||
* to registered clients)
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://developers.meethue.com/develop/hue-entertainment/hue-hdmi-sync-box-api/#Resource%20Table">Hue
|
||||
* HDMI Sync Box API</a>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncDeviceDetailed extends HueSyncDevice {
|
||||
public @Nullable HueSyncDeviceDetailedWifiInfo wifi;
|
||||
public @Nullable HueSyncDeviceDetailedUpdateInfo update;
|
||||
|
||||
/** UTC time when last check for update was performed. */
|
||||
public @Nullable Date lastCheckedUpdate;
|
||||
/**
|
||||
* Build number that is available to update to. Item is set to null when there
|
||||
* is no update available.
|
||||
*/
|
||||
public int updatableBuildNumber;
|
||||
/**
|
||||
* User readable version of the firmware the device can upgrade to. Item is set
|
||||
* to null when there is no update available.
|
||||
*/
|
||||
public @Nullable String updatableFirmwareVersion;
|
||||
/**
|
||||
* 1 = regular;
|
||||
* 0 = off in powersave, passthrough or sync mode;
|
||||
* 2 = dimmed in powersave or passthrough mode and off in sync mode
|
||||
*/
|
||||
public int ledMode = -1;
|
||||
|
||||
/** none, doSoftwareRestart, doFirmwareUpdate */
|
||||
public @Nullable String action;
|
||||
public @Nullable String pushlink;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* HDMI Sync Box Device Information - Automatic Firmware update
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://developers.meethue.com/develop/hue-entertainment/hue-hdmi-sync-box-api/#Resource%20Table">Hue
|
||||
* HDMI Sync Box API</a>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncDeviceDetailedUpdateInfo {
|
||||
/**
|
||||
* Sync Box checks daily for a firmware update. If true, an available update
|
||||
* will automatically be installed. This will be postponed if Sync Box is
|
||||
* passing through content to the TV and being used.
|
||||
*/
|
||||
public boolean autoUpdateEnabled;
|
||||
/**
|
||||
* TC hour when the automatic update will check and execute, values 0 – 23.
|
||||
* Default is 10. Ideally this value should be set to 3AM according to user’s
|
||||
* timezone.
|
||||
*/
|
||||
public int autoUpdateTime;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.device;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* HDMI Sync Box Device Information - Wifi connection information
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
* @see <a href=
|
||||
* "https://developers.meethue.com/develop/hue-entertainment/hue-hdmi-sync-box-api/#Resource%20Table">Hue
|
||||
* HDMI Sync Box API</a>
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncDeviceDetailedWifiInfo {
|
||||
/** Wifi SSID */
|
||||
public @Nullable String ssid;
|
||||
/**
|
||||
* 0 = not connected;
|
||||
* 1 = weak;
|
||||
* 2 = fair;
|
||||
* 3 = good;
|
||||
* 4 = excellent
|
||||
*/
|
||||
public int strength;
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.execution;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
/**
|
||||
* Root object for execution resource
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncExecution {
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncExecution.class);
|
||||
|
||||
public static final List<String> KNOWN_MODES = Collections
|
||||
.unmodifiableList(Arrays.asList("powersave", "passthrough", "video", "game", "music"));
|
||||
|
||||
private @Nullable String mode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return powersave, passthrough, video, game, music
|
||||
*/
|
||||
@JsonProperty("mode")
|
||||
public @Nullable String getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @apiNote More modes can be added in the future, so clients must gracefully
|
||||
* handle modes they don’t recognize. If an unknown mode is received, a
|
||||
* warning will be logged and mode will fallback to "unknown"
|
||||
*
|
||||
* @param mode powersave, passthrough, video, game, music
|
||||
*/
|
||||
public void setMode(String mode) {
|
||||
if (!HueSyncExecution.KNOWN_MODES.contains(mode)) {
|
||||
logger.warn(
|
||||
"device mode [{}] is not known by this version of the binding. Please open an issue to notify the maintainer(s). Fallback will be used. ",
|
||||
mode);
|
||||
}
|
||||
|
||||
this.mode = HueSyncExecution.KNOWN_MODES.contains(mode) ? mode : "unknown";
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports `false` in case of `powersave` or `passthrough` mode, and `true` in case of `video`, `game`, or `music`
|
||||
* mode.
|
||||
* When changed from false to true, it will start syncing in last used mode for current source.
|
||||
* When changed from true to false, will set passthrough mode.
|
||||
*/
|
||||
public boolean syncActive;
|
||||
/**
|
||||
* Reports `false` in case of `powersave mode`, and true in case of `passthrough`, `video`, `game`, `music` mode.
|
||||
* When changed from false to true, it will set passthrough mode. When changed from `true` to `false`, will set
|
||||
* powersave mode.
|
||||
*/
|
||||
public boolean hdmiActive;
|
||||
|
||||
/**
|
||||
* Currently selected hdmi input: `input1`, `input2`, `input3,` `input4`
|
||||
*/
|
||||
public @Nullable String hdmiSource;
|
||||
|
||||
public @Nullable String hueTarget;
|
||||
public @Nullable String lastSyncMode;
|
||||
public @Nullable String preset;
|
||||
|
||||
/**
|
||||
* brightness:
|
||||
* - Get, Put
|
||||
* - number, uint
|
||||
* - 0 ... 200 (100 = no brightness reduction/boost compared to input, 0 = max reduction, 200 = max boost)
|
||||
*/
|
||||
public int brightness;
|
||||
|
||||
public @Nullable HueSyncExecutionVideo video;
|
||||
public @Nullable HueSyncExecutionGame game;
|
||||
public @Nullable HueSyncExecutionMusic music;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.execution;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncExecutionGame {
|
||||
public @Nullable String intensity;
|
||||
|
||||
public boolean backgroundLighting;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.execution;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncExecutionMusic {
|
||||
public @Nullable String intensity;
|
||||
public @Nullable String palette;
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.execution;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncExecutionVideo {
|
||||
public @Nullable String intensity;
|
||||
|
||||
public boolean backgroundLighting;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.hdmi;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncHdmi {
|
||||
public @Nullable HueSyncHdmiConnectionInfo input1;
|
||||
public @Nullable HueSyncHdmiConnectionInfo input2;
|
||||
public @Nullable HueSyncHdmiConnectionInfo input3;
|
||||
public @Nullable HueSyncHdmiConnectionInfo input4;
|
||||
|
||||
public @Nullable HueSyncHdmiConnectionInfo output;
|
||||
|
||||
/** <horizontal pixels> x <vertical pixels> @ <framerate fps> – <HDR> */
|
||||
public @Nullable String contentSpecs;
|
||||
|
||||
/** Current content specs supported for video sync (video/game mode) */
|
||||
public boolean videoSyncSupported;
|
||||
/** Current content specs supported for audio sync (music mode) */
|
||||
public boolean audioSyncSupported;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.hdmi;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncHdmiConnectionInfo {
|
||||
/** Friendly name, not empty */
|
||||
public @Nullable String name;
|
||||
/**
|
||||
* Friendly type:
|
||||
* generic,
|
||||
* video,
|
||||
* game,
|
||||
* music,
|
||||
* xbox,
|
||||
* playstation,
|
||||
* nintendoswitch,
|
||||
* phone,
|
||||
* desktop,
|
||||
* laptop,
|
||||
* appletv,
|
||||
* roku,
|
||||
* shield,
|
||||
* chromecast,
|
||||
* firetv,
|
||||
* diskplayer,
|
||||
* settopbox,
|
||||
* satellite,
|
||||
* avreceiver,
|
||||
* soundbar,
|
||||
* hdmiswitch
|
||||
*/
|
||||
public @Nullable String type;
|
||||
/**
|
||||
* unplugged,
|
||||
* plugged,
|
||||
* linked,
|
||||
* unknown
|
||||
*/
|
||||
public @Nullable String status;
|
||||
/**
|
||||
* video,
|
||||
* game,
|
||||
* music
|
||||
*/
|
||||
public @Nullable String lastSyncMode;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.registration;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncRegistration {
|
||||
public String registrationId = "";
|
||||
public String accessToken = "";
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.api.dto.registration;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncRegistrationRequest {
|
||||
/** User recognizable name of registered application */
|
||||
public @Nullable String appName;
|
||||
/** User recognizable name of application instance. */
|
||||
public @Nullable String instanceName;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
* Binding configuration parameters,
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncConfiguration {
|
||||
public String registrationId = "";
|
||||
public String apiAccessToken = "";
|
||||
public String host = "";
|
||||
public Integer port = 443;
|
||||
public Integer statusUpdateInterval = 10;
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.connection;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.api.Authentication.Result;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncAuthenticationResult implements Result {
|
||||
private final String token;
|
||||
private final URI uri;
|
||||
|
||||
public HueSyncAuthenticationResult(URI uri, String token) {
|
||||
this.uri = uri;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getURI() {
|
||||
return this.uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(@Nullable Request request) {
|
||||
if (request != null && !request.getHeaders().contains(HttpHeader.AUTHORIZATION)) {
|
||||
request.header(HttpHeader.AUTHORIZATION, "Bearer " + this.token);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,248 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.connection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.client.api.AuthenticationStore;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.util.StringContentProvider;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.openhab.binding.huesync.internal.HueSyncConstants.ENDPOINTS;
|
||||
import org.openhab.binding.huesync.internal.exceptions.HueSyncConnectionException;
|
||||
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncConnection {
|
||||
public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper()
|
||||
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
/**
|
||||
* Request format: The Sync Box API can be accessed locally via HTTPS on root level (port 443,
|
||||
* /api/v1), resource level /api/v1/<resource> and in some cases sub-resource level
|
||||
* /api/v1/<resource>/<sub-resource>.
|
||||
*/
|
||||
private static final String REQUEST_FORMAT = "https://%s:%s/%s/%s";
|
||||
private static final String API = "api/v1";
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncConnection.class);
|
||||
|
||||
private final Integer port;
|
||||
private final String host;
|
||||
|
||||
private final ServiceRegistration<?> tlsProviderService;
|
||||
private final HttpClient httpClient;
|
||||
private final URI deviceUri;
|
||||
|
||||
private Optional<HueSyncAuthenticationResult> authentication = Optional.empty();
|
||||
|
||||
protected String registrationId = "";
|
||||
|
||||
public HueSyncConnection(HttpClient httpClient, String host, Integer port)
|
||||
throws CertificateException, IOException, URISyntaxException {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
|
||||
this.deviceUri = new URI(String.format("https://%s:%s", this.host, this.port));
|
||||
|
||||
HueSyncTrustManagerProvider trustManagerProvider = new HueSyncTrustManagerProvider(this.host, this.port);
|
||||
BundleContext context = FrameworkUtil.getBundle(getClass()).getBundleContext();
|
||||
|
||||
this.tlsProviderService = context.registerService(TlsTrustManagerProvider.class.getName(), trustManagerProvider,
|
||||
null);
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public void updateAuthentication(String id, String token) {
|
||||
this.removeAuthentication();
|
||||
|
||||
if (!id.isBlank() && !token.isBlank()) {
|
||||
this.registrationId = id;
|
||||
|
||||
this.authentication = Optional.of(new HueSyncAuthenticationResult(this.deviceUri, token));
|
||||
this.httpClient.getAuthenticationStore().addAuthenticationResult(this.authentication.get());
|
||||
}
|
||||
}
|
||||
|
||||
// #region protected
|
||||
protected @Nullable <T> T executeRequest(HttpMethod method, String endpoint, String payload,
|
||||
@Nullable Class<T> type) {
|
||||
try {
|
||||
return this.processedResponse(this.executeRequest(method, endpoint, payload), type);
|
||||
} catch (ExecutionException e) {
|
||||
this.handleExecutionException(e);
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected @Nullable <T> T executeGetRequest(String endpoint, Class<T> type) {
|
||||
try {
|
||||
return this.processedResponse(this.executeGetRequest(endpoint), type);
|
||||
} catch (ExecutionException e) {
|
||||
this.handleExecutionException(e);
|
||||
} catch (InterruptedException | TimeoutException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean isRegistered() {
|
||||
return this.authentication.isPresent();
|
||||
}
|
||||
|
||||
protected void unregisterDevice() {
|
||||
if (this.isRegistered()) {
|
||||
try {
|
||||
String endpoint = ENDPOINTS.REGISTRATIONS + "/" + this.registrationId;
|
||||
ContentResponse response = this.executeRequest(HttpMethod.DELETE, endpoint);
|
||||
|
||||
if (response.getStatus() == HttpStatus.OK_200) {
|
||||
this.removeAuthentication();
|
||||
}
|
||||
} catch (InterruptedException | TimeoutException | ExecutionException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void dispose() {
|
||||
this.tlsProviderService.unregister();
|
||||
}
|
||||
// #endregion
|
||||
|
||||
// #region private
|
||||
private @Nullable <T> T processedResponse(Response response, @Nullable Class<T> type) {
|
||||
int status = response.getStatus();
|
||||
try {
|
||||
/*
|
||||
* 400 Invalid State: Registration in progress
|
||||
*
|
||||
* 401 Authentication failed: If credentials are missing or invalid, errors out. If
|
||||
* credentials are missing, continues on to GET only the Configuration state when
|
||||
* unauthenticated, to allow for device identification.
|
||||
*
|
||||
* 404 Invalid URI Path: Accessing URI path which is not supported
|
||||
*
|
||||
* 500 Internal: Internal errors like out of memory
|
||||
*/
|
||||
switch (status) {
|
||||
case HttpStatus.OK_200 -> {
|
||||
return (type != null && (response instanceof ContentResponse))
|
||||
? this.deserialize(((ContentResponse) response).getContentAsString(), type)
|
||||
: null;
|
||||
}
|
||||
case HttpStatus.BAD_REQUEST_400 -> this.logger.debug("registration in progress: no token received yet");
|
||||
case HttpStatus.UNAUTHORIZED_401 -> {
|
||||
this.authentication = Optional.empty();
|
||||
throw new HueSyncConnectionException("@text/connection.invalid-login");
|
||||
}
|
||||
case HttpStatus.NOT_FOUND_404 -> this.logger.warn("invalid device URI or API endpoint");
|
||||
case HttpStatus.INTERNAL_SERVER_ERROR_500 -> this.logger.warn("hue sync box server problem");
|
||||
default -> this.logger.warn("unexpected HTTP status: {}", status);
|
||||
}
|
||||
} catch (HueSyncConnectionException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private @Nullable <T> T deserialize(String json, Class<T> type) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(json, type);
|
||||
} catch (JsonProcessingException | NoClassDefFoundError e) {
|
||||
this.logger.error("{}", e.getMessage());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private ContentResponse executeRequest(HttpMethod method, String endpoint)
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
return this.executeRequest(method, endpoint, "");
|
||||
}
|
||||
|
||||
private ContentResponse executeGetRequest(String endpoint)
|
||||
throws InterruptedException, ExecutionException, TimeoutException {
|
||||
String uri = String.format(REQUEST_FORMAT, this.host, this.port, API, endpoint);
|
||||
|
||||
return httpClient.GET(uri);
|
||||
}
|
||||
|
||||
private ContentResponse executeRequest(HttpMethod method, String endpoint, String payload)
|
||||
throws InterruptedException, TimeoutException, ExecutionException {
|
||||
String uri = String.format(REQUEST_FORMAT, this.host, this.port, API, endpoint);
|
||||
|
||||
Request request = this.httpClient.newRequest(uri).method(method);
|
||||
|
||||
this.logger.trace("uri: {}", uri);
|
||||
this.logger.trace("method: {}", method);
|
||||
this.logger.trace("payload: {}", payload);
|
||||
|
||||
if (!payload.isBlank()) {
|
||||
request.header(HttpHeader.CONTENT_TYPE, MimeTypes.Type.APPLICATION_JSON_UTF_8.toString())
|
||||
.content(new StringContentProvider(payload));
|
||||
}
|
||||
|
||||
return request.send();
|
||||
}
|
||||
|
||||
private void handleExecutionException(ExecutionException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
|
||||
Throwable cause = e.getCause();
|
||||
if (cause != null && cause instanceof HttpResponseException) {
|
||||
processedResponse(((HttpResponseException) cause).getResponse(), null);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeAuthentication() {
|
||||
AuthenticationStore store = this.httpClient.getAuthenticationStore();
|
||||
store.clearAuthenticationResults();
|
||||
this.httpClient.setAuthenticationStore(store);
|
||||
|
||||
this.registrationId = "";
|
||||
this.authentication = Optional.empty();
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.connection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.openhab.binding.huesync.internal.HueSyncConstants;
|
||||
import org.openhab.binding.huesync.internal.HueSyncConstants.ENDPOINTS;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDevice;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDeviceDetailed;
|
||||
import org.openhab.binding.huesync.internal.api.dto.execution.HueSyncExecution;
|
||||
import org.openhab.binding.huesync.internal.api.dto.hdmi.HueSyncHdmi;
|
||||
import org.openhab.binding.huesync.internal.api.dto.registration.HueSyncRegistration;
|
||||
import org.openhab.binding.huesync.internal.api.dto.registration.HueSyncRegistrationRequest;
|
||||
import org.openhab.binding.huesync.internal.config.HueSyncConfiguration;
|
||||
import org.openhab.binding.huesync.internal.exceptions.HueSyncConnectionException;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.RefreshType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
/**
|
||||
* Handles the connection to a Hue HDMI Sync Box using the official API.
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncDeviceConnection {
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncDeviceConnection.class);
|
||||
|
||||
private final HueSyncConnection connection;
|
||||
|
||||
private final Map<String, Consumer<Command>> deviceCommandExecutors = new HashMap<>();
|
||||
|
||||
public HueSyncDeviceConnection(HttpClient httpClient, HueSyncConfiguration configuration)
|
||||
throws CertificateException, IOException, URISyntaxException {
|
||||
this.connection = new HueSyncConnection(httpClient, configuration.host, configuration.port);
|
||||
|
||||
registerCommandHandlers();
|
||||
}
|
||||
|
||||
// #region private
|
||||
|
||||
private void registerCommandHandlers() {
|
||||
this.deviceCommandExecutors.put(HueSyncConstants.CHANNELS.COMMANDS.MODE,
|
||||
defaultHandler(HueSyncConstants.ENDPOINTS.COMMANDS.MODE));
|
||||
this.deviceCommandExecutors.put(HueSyncConstants.CHANNELS.COMMANDS.SOURCE,
|
||||
defaultHandler(HueSyncConstants.ENDPOINTS.COMMANDS.SOURCE));
|
||||
this.deviceCommandExecutors.put(HueSyncConstants.CHANNELS.COMMANDS.BRIGHTNESS,
|
||||
defaultHandler(HueSyncConstants.ENDPOINTS.COMMANDS.BRIGHTNESS));
|
||||
this.deviceCommandExecutors.put(HueSyncConstants.CHANNELS.COMMANDS.SYNC,
|
||||
defaultHandler(HueSyncConstants.ENDPOINTS.COMMANDS.SYNC));
|
||||
this.deviceCommandExecutors.put(HueSyncConstants.CHANNELS.COMMANDS.HDMI,
|
||||
defaultHandler(HueSyncConstants.ENDPOINTS.COMMANDS.HDMI));
|
||||
}
|
||||
|
||||
private Consumer<Command> defaultHandler(String endpoint) {
|
||||
return command -> {
|
||||
execute(endpoint, command);
|
||||
};
|
||||
}
|
||||
|
||||
private void execute(String key, Command command) {
|
||||
this.logger.debug("Command executor: {} - {}", key, command);
|
||||
|
||||
if (!this.connection.isRegistered()) {
|
||||
this.logger.warn("Device is not registered - ignoring command: {}", command);
|
||||
return;
|
||||
}
|
||||
|
||||
String value;
|
||||
|
||||
if (command instanceof QuantityType quantityCommand) {
|
||||
value = Integer.toString(quantityCommand.intValue());
|
||||
} else if (command instanceof OnOffType) {
|
||||
value = command == OnOffType.ON ? "true" : "false";
|
||||
} else if (command instanceof StringType) {
|
||||
value = '"' + command.toString() + '"';
|
||||
} else {
|
||||
this.logger.warn("Type [{}] not supported by this connection", command.getClass().getCanonicalName());
|
||||
return;
|
||||
}
|
||||
|
||||
String json = String.format("{ \"%s\": %s }", key, value);
|
||||
|
||||
this.connection.executeRequest(HttpMethod.PUT, ENDPOINTS.EXECUTION, json, null);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
public void executeCommand(Channel channel, Command command) {
|
||||
String uid = channel.getUID().getAsString();
|
||||
String commandId = channel.getUID().getId();
|
||||
|
||||
this.logger.debug("Channel UID: {} - Command: {}", uid, command.toFullString());
|
||||
|
||||
if (RefreshType.REFRESH.equals(command)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.deviceCommandExecutors.containsKey(commandId)) {
|
||||
Objects.requireNonNull(this.deviceCommandExecutors.get(commandId)).accept(command);
|
||||
} else {
|
||||
this.logger.error("No executor registered for command {} - please report this as an issue", commandId);
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable HueSyncDevice getDeviceInfo() {
|
||||
return this.connection.executeGetRequest(ENDPOINTS.DEVICE, HueSyncDevice.class);
|
||||
}
|
||||
|
||||
public @Nullable HueSyncDeviceDetailed getDetailedDeviceInfo() {
|
||||
return this.connection.isRegistered()
|
||||
? this.connection.executeRequest(HttpMethod.GET, ENDPOINTS.DEVICE, "", HueSyncDeviceDetailed.class)
|
||||
: null;
|
||||
}
|
||||
|
||||
public @Nullable HueSyncHdmi getHdmiInfo() {
|
||||
return this.connection.isRegistered()
|
||||
? this.connection.executeRequest(HttpMethod.GET, ENDPOINTS.HDMI, "", HueSyncHdmi.class)
|
||||
: null;
|
||||
}
|
||||
|
||||
public @Nullable HueSyncExecution getExecutionInfo() {
|
||||
return this.connection.isRegistered()
|
||||
? this.connection.executeRequest(HttpMethod.GET, ENDPOINTS.EXECUTION, "", HueSyncExecution.class)
|
||||
: null;
|
||||
}
|
||||
|
||||
public @Nullable HueSyncRegistration registerDevice(String id) throws HueSyncConnectionException {
|
||||
if (!id.isBlank()) {
|
||||
try {
|
||||
HueSyncRegistrationRequest dto = new HueSyncRegistrationRequest();
|
||||
dto.appName = HueSyncConstants.APPLICATION_NAME;
|
||||
dto.instanceName = id;
|
||||
|
||||
String payload = HueSyncConnection.OBJECT_MAPPER.writeValueAsString(dto);
|
||||
|
||||
HueSyncRegistration registration = this.connection.executeRequest(HttpMethod.POST,
|
||||
ENDPOINTS.REGISTRATIONS, payload, HueSyncRegistration.class);
|
||||
if (registration != null) {
|
||||
this.connection.updateAuthentication(id, registration.accessToken);
|
||||
|
||||
return registration;
|
||||
}
|
||||
} catch (JsonProcessingException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isRegistered() {
|
||||
return this.connection.isRegistered();
|
||||
}
|
||||
|
||||
public void unregisterDevice() {
|
||||
this.connection.unregisterDevice();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
this.connection.dispose();
|
||||
}
|
||||
|
||||
public void updateConfiguration(HueSyncConfiguration config) {
|
||||
this.logger.debug("Connection configuration update for device {}:{} - Registration Id [{}]", config.host,
|
||||
config.port, config.registrationId);
|
||||
|
||||
this.connection.updateAuthentication(config.registrationId, config.apiAccessToken);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.connection;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.net.ssl.X509ExtendedTrustManager;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.io.net.http.PEMTrustManager;
|
||||
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
|
||||
|
||||
/**
|
||||
* Provides a {@link PEMTrustManager} to allow secure connections to a Hue HDMI
|
||||
* Sync Box
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncTrustManagerProvider implements TlsTrustManagerProvider {
|
||||
private final String host;
|
||||
private final Integer port;
|
||||
|
||||
private final X509ExtendedTrustManager trustManager;
|
||||
|
||||
public HueSyncTrustManagerProvider(String host, Integer port) throws IOException, CertificateException {
|
||||
this.trustManager = PEMTrustManager.getInstanceFromServer("https://" + host);
|
||||
this.port = port;
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHostName() {
|
||||
return this.host + ":" + this.port;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509ExtendedTrustManager getTrustManager() {
|
||||
return this.trustManager;
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.discovery;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.jmdns.ServiceInfo;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.huesync.internal.HueSyncConstants;
|
||||
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.config.discovery.mdns.MDNSDiscoveryParticipant;
|
||||
import org.openhab.core.thing.ThingRegistry;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.ThingUID;
|
||||
import org.osgi.service.component.ComponentContext;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Modified;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HueSyncDiscoveryParticipant} is responsible for discovering
|
||||
* the remote huesync.boxes using mDNS discovery service.
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(service = MDNSDiscoveryParticipant.class, configurationPid = "mdnsdiscovery.huesync")
|
||||
public class HueSyncDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncDiscoveryParticipant.class);
|
||||
|
||||
/**
|
||||
*
|
||||
* Match the hostname + identifier of the discovered huesync-box.
|
||||
* Input is like "HueSyncBox-XXXXXXXXXXXX._huesync._tcp.local."
|
||||
*
|
||||
* @see·<a·href=
|
||||
* "https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=huesync">
|
||||
* Service·Name·and·Transport·Protocol·Port·Number·Registry</a>
|
||||
*/
|
||||
private static final String SERVICE_TYPE = "_huesync._tcp.local.";
|
||||
|
||||
private boolean autoDiscoveryEnabled = true;
|
||||
|
||||
protected final ThingRegistry thingRegistry;
|
||||
|
||||
@Activate
|
||||
public HueSyncDiscoveryParticipant(final @Reference ThingRegistry thingRegistry) {
|
||||
this.thingRegistry = thingRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||
return Collections.singleton(HueSyncConstants.THING_TYPE_UID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceType() {
|
||||
return SERVICE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable DiscoveryResult createResult(ServiceInfo service) {
|
||||
if (this.autoDiscoveryEnabled) {
|
||||
ThingUID uid = getThingUID(service);
|
||||
if (uid != null) {
|
||||
try {
|
||||
logger.debug("HDMI Sync Box {} discovered at {}:{}", service.getName(),
|
||||
service.getHostAddresses()[0], service.getPort());
|
||||
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
|
||||
properties.put(HueSyncConstants.PARAMETER_HOST, service.getHostAddresses()[0]);
|
||||
properties.put(HueSyncConstants.PARAMETER_PORT, service.getPort());
|
||||
|
||||
return DiscoveryResultBuilder.create(uid).withLabel(service.getName()).withProperties(properties)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
logger.debug("Unable to query device information for {}: {}", service.getQualifiedName(),
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ThingUID getThingUID(ServiceInfo service) {
|
||||
String id = service.getName();
|
||||
String[] addresses = service.getHostAddresses();
|
||||
|
||||
if (addresses.length == 0 || id == null || id.isBlank()) {
|
||||
logger.debug("Incomplete mDNS device discovery information - {} ignored.",
|
||||
id == null ? "[name: null]" : id);
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ThingUID(HueSyncConstants.THING_TYPE_UID, id);
|
||||
}
|
||||
|
||||
@Activate
|
||||
protected void activate(ComponentContext componentContext) {
|
||||
updateService(componentContext);
|
||||
}
|
||||
|
||||
@Modified
|
||||
protected void modified(ComponentContext componentContext) {
|
||||
updateService(componentContext);
|
||||
}
|
||||
|
||||
private void updateService(ComponentContext componentContext) {
|
||||
String autoDiscoveryPropertyValue = (String) componentContext.getProperties()
|
||||
.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY);
|
||||
|
||||
if (autoDiscoveryPropertyValue != null && !autoDiscoveryPropertyValue.isBlank()) {
|
||||
boolean value = Boolean.parseBoolean(autoDiscoveryPropertyValue);
|
||||
if (value != this.autoDiscoveryEnabled) {
|
||||
logger.debug("{} update: {} - {}", DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY,
|
||||
autoDiscoveryPropertyValue, value);
|
||||
this.autoDiscoveryEnabled = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.exceptions;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncApiException extends HueSyncException {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
public HueSyncApiException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.exceptions;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncConnectionException extends HueSyncException {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
public HueSyncConnectionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.exceptions;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.huesync.internal.i18n.HueSyncLocalizer;
|
||||
|
||||
/**
|
||||
* Base class for all HueSyncExceptions
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public abstract class HueSyncException extends Exception {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
public HueSyncException(String message) {
|
||||
super(message.startsWith("@text") ? HueSyncLocalizer.getResourceString(message) : message);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.exceptions;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncTaskException extends HueSyncException {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
public HueSyncTaskException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.factory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.huesync.internal.HueSyncConstants;
|
||||
import org.openhab.binding.huesync.internal.handler.HueSyncHandler;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingTypeUID;
|
||||
import org.openhab.core.thing.binding.BaseThingHandlerFactory;
|
||||
import org.openhab.core.thing.binding.ThingHandler;
|
||||
import org.openhab.core.thing.binding.ThingHandlerFactory;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Reference;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HueSyncHandlerFactory} is responsible for creating things and
|
||||
* thing
|
||||
* handlers.
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
@Component(configurationPid = "binding.huesync", service = ThingHandlerFactory.class)
|
||||
public class HueSyncHandlerFactory extends BaseThingHandlerFactory {
|
||||
|
||||
private final HttpClientFactory httpClientFactory;
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncHandlerFactory.class);
|
||||
|
||||
@Activate
|
||||
public HueSyncHandlerFactory(@Reference final HttpClientFactory httpClientFactory) throws Exception {
|
||||
this.httpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES_UIDS = Collections
|
||||
.singleton(HueSyncConstants.THING_TYPE_UID);
|
||||
|
||||
@Override
|
||||
public boolean supportsThingType(ThingTypeUID thingTypeUID) {
|
||||
return SUPPORTED_THING_TYPES_UIDS.contains(thingTypeUID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||
ThingTypeUID thingTypeUID = thing.getThingTypeUID();
|
||||
|
||||
if (HueSyncConstants.THING_TYPE_UID.equals(thingTypeUID)) {
|
||||
try {
|
||||
return new HueSyncHandler(thing, this.httpClientFactory);
|
||||
} catch (IOException | URISyntaxException | CertificateException e) {
|
||||
this.logger.warn("It was not possible to create a handler for {}: {}", thingTypeUID.getId(),
|
||||
e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,349 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.openhab.binding.huesync.internal.HdmiChannels;
|
||||
import org.openhab.binding.huesync.internal.HueSyncConstants;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDevice;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDeviceDetailed;
|
||||
import org.openhab.binding.huesync.internal.api.dto.execution.HueSyncExecution;
|
||||
import org.openhab.binding.huesync.internal.api.dto.hdmi.HueSyncHdmi;
|
||||
import org.openhab.binding.huesync.internal.api.dto.hdmi.HueSyncHdmiConnectionInfo;
|
||||
import org.openhab.binding.huesync.internal.api.dto.registration.HueSyncRegistration;
|
||||
import org.openhab.binding.huesync.internal.config.HueSyncConfiguration;
|
||||
import org.openhab.binding.huesync.internal.connection.HueSyncDeviceConnection;
|
||||
import org.openhab.binding.huesync.internal.exceptions.HueSyncApiException;
|
||||
import org.openhab.binding.huesync.internal.handler.tasks.HueSyncRegistrationTask;
|
||||
import org.openhab.binding.huesync.internal.handler.tasks.HueSyncUpdateTask;
|
||||
import org.openhab.binding.huesync.internal.handler.tasks.HueSyncUpdateTaskResult;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||
import org.openhab.core.library.types.DecimalType;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.StringType;
|
||||
import org.openhab.core.thing.Channel;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.thing.ThingStatusDetail;
|
||||
import org.openhab.core.thing.binding.BaseThingHandler;
|
||||
import org.openhab.core.types.Command;
|
||||
import org.openhab.core.types.State;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@link HueSyncHandler} is responsible for handling commands, which are sent to one of the
|
||||
* channels.
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncHandler extends BaseThingHandler {
|
||||
private static final String REGISTER = "Registration";
|
||||
private static final String POLL = "Update";
|
||||
|
||||
private static final String PROPERTY_API_VERSION = "apiVersion";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncHandler.class);
|
||||
|
||||
Map<String, @Nullable ScheduledFuture<?>> tasks = new HashMap<>();
|
||||
|
||||
private Optional<HueSyncDevice> deviceInfo = Optional.empty();
|
||||
|
||||
private final HueSyncDeviceConnection connection;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
public HueSyncHandler(Thing thing, HttpClientFactory httpClientFactory)
|
||||
throws CertificateException, IOException, URISyntaxException {
|
||||
super(thing);
|
||||
|
||||
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||
|
||||
this.connection = new HueSyncDeviceConnection(this.httpClient, this.getConfigAs(HueSyncConfiguration.class));
|
||||
}
|
||||
|
||||
// #region private
|
||||
private Runnable initializeConnection() {
|
||||
return () -> {
|
||||
this.deviceInfo = Optional.ofNullable(this.connection.getDeviceInfo());
|
||||
this.deviceInfo.ifPresent(info -> {
|
||||
setProperty(Thing.PROPERTY_SERIAL_NUMBER, info.uniqueId != null ? info.uniqueId : "");
|
||||
setProperty(Thing.PROPERTY_MODEL_ID, info.deviceType);
|
||||
setProperty(Thing.PROPERTY_FIRMWARE_VERSION, info.firmwareVersion);
|
||||
|
||||
setProperty(HueSyncHandler.PROPERTY_API_VERSION, String.format("%d", info.apiLevel));
|
||||
|
||||
try {
|
||||
this.checkCompatibility();
|
||||
} catch (HueSyncApiException e) {
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||
} finally {
|
||||
this.startTasks();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private void stopTask(@Nullable ScheduledFuture<?> task) {
|
||||
if (task == null || task.isCancelled() || task.isDone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
task.cancel(true);
|
||||
}
|
||||
|
||||
private @Nullable ScheduledFuture<?> executeTask(Runnable task, long initialDelay, long interval) {
|
||||
return scheduler.scheduleWithFixedDelay(task, initialDelay, interval, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void startTasks() {
|
||||
this.stopTasks();
|
||||
|
||||
this.connection.updateConfiguration(this.getConfigAs(HueSyncConfiguration.class));
|
||||
|
||||
Runnable task = null;
|
||||
String id = this.connection.isRegistered() ? POLL : REGISTER;
|
||||
|
||||
this.logger.debug("startTasks - [{}]", id);
|
||||
|
||||
long initialDelay = 0;
|
||||
long interval = 0;
|
||||
|
||||
switch (id) {
|
||||
case POLL -> {
|
||||
initialDelay = 0;
|
||||
interval = this.getConfigAs(HueSyncConfiguration.class).statusUpdateInterval;
|
||||
|
||||
this.updateStatus(ThingStatus.ONLINE);
|
||||
|
||||
task = new HueSyncUpdateTask(this.connection, this.deviceInfo.get(),
|
||||
deviceStatus -> this.handleUpdate(deviceStatus));
|
||||
}
|
||||
case REGISTER -> {
|
||||
initialDelay = HueSyncConstants.REGISTRATION_INITIAL_DELAY;
|
||||
interval = HueSyncConstants.REGISTRATION_INTERVAL;
|
||||
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
|
||||
"@text/thing.config.huesync.box.registration");
|
||||
|
||||
task = new HueSyncRegistrationTask(this.connection, this.deviceInfo.get(),
|
||||
registration -> this.handleRegistration(registration));
|
||||
}
|
||||
}
|
||||
|
||||
if (task != null) {
|
||||
logger.debug("Starting task [{}]", id);
|
||||
this.tasks.put(id, this.executeTask(task, initialDelay, interval));
|
||||
}
|
||||
}
|
||||
|
||||
private void stopTasks() {
|
||||
logger.debug("Stopping {} task(s): {}", this.tasks.values().size(), String.join(",", this.tasks.keySet()));
|
||||
|
||||
this.tasks.values().forEach(task -> this.stopTask(task));
|
||||
this.tasks.clear();
|
||||
|
||||
this.updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
|
||||
"@text/thing.config.huesync.box.registration");
|
||||
}
|
||||
|
||||
private void handleUpdate(@Nullable HueSyncUpdateTaskResult dto) {
|
||||
try {
|
||||
HueSyncUpdateTaskResult update = Optional.ofNullable(dto).get();
|
||||
|
||||
try {
|
||||
this.updateFirmwareInformation(Optional.ofNullable(update.deviceStatus).get());
|
||||
} catch (NoSuchElementException e) {
|
||||
this.logMissingUpdateInformation("device");
|
||||
}
|
||||
|
||||
this.updateHdmiInformation(Optional.ofNullable(update.hdmiStatus).get());
|
||||
this.updateExecutionInformation(Optional.ofNullable(update.execution).get());
|
||||
} catch (NoSuchElementException e) {
|
||||
Configuration configuration = this.editConfiguration();
|
||||
|
||||
configuration.put(HueSyncConstants.REGISTRATION_ID, "");
|
||||
configuration.put(HueSyncConstants.API_TOKEN, "");
|
||||
|
||||
this.updateConfiguration(configuration);
|
||||
|
||||
this.startTasks();
|
||||
}
|
||||
}
|
||||
|
||||
private void logMissingUpdateInformation(String api) {
|
||||
this.logger.warn("Device information - {} status missing", api);
|
||||
}
|
||||
|
||||
private void updateHdmiInformation(HueSyncHdmi hdmiStatus) {
|
||||
updateHdmiStatus(HueSyncConstants.CHANNELS.HDMI.IN_1, hdmiStatus.input1);
|
||||
updateHdmiStatus(HueSyncConstants.CHANNELS.HDMI.IN_2, hdmiStatus.input2);
|
||||
updateHdmiStatus(HueSyncConstants.CHANNELS.HDMI.IN_3, hdmiStatus.input3);
|
||||
updateHdmiStatus(HueSyncConstants.CHANNELS.HDMI.IN_4, hdmiStatus.input4);
|
||||
|
||||
updateHdmiStatus(HueSyncConstants.CHANNELS.HDMI.OUT, hdmiStatus.output);
|
||||
}
|
||||
|
||||
private void updateHdmiStatus(HdmiChannels channels, @Nullable HueSyncHdmiConnectionInfo hdmiStatusInfo) {
|
||||
if (hdmiStatusInfo != null) {
|
||||
this.updateState(channels.name, new StringType(hdmiStatusInfo.name));
|
||||
this.updateState(channels.type, new StringType(hdmiStatusInfo.type));
|
||||
this.updateState(channels.mode, new StringType(hdmiStatusInfo.lastSyncMode));
|
||||
this.updateState(channels.status, new StringType(hdmiStatusInfo.status));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFirmwareInformation(HueSyncDeviceDetailed deviceStatus) {
|
||||
State firmwareState = new StringType(deviceStatus.firmwareVersion);
|
||||
State firmwareAvailableState = new StringType(
|
||||
deviceStatus.updatableFirmwareVersion != null ? deviceStatus.updatableFirmwareVersion
|
||||
: deviceStatus.firmwareVersion);
|
||||
|
||||
setProperty(Thing.PROPERTY_FIRMWARE_VERSION, deviceStatus.firmwareVersion);
|
||||
setProperty(HueSyncHandler.PROPERTY_API_VERSION, String.format("%d", deviceStatus.apiLevel));
|
||||
|
||||
this.updateState(HueSyncConstants.CHANNELS.DEVICE.INFORMATION.FIRMWARE, firmwareState);
|
||||
this.updateState(HueSyncConstants.CHANNELS.DEVICE.INFORMATION.FIRMWARE_AVAILABLE, firmwareAvailableState);
|
||||
}
|
||||
|
||||
private void updateExecutionInformation(HueSyncExecution executionStatus) {
|
||||
this.updateState(HueSyncConstants.CHANNELS.COMMANDS.MODE, new StringType(executionStatus.getMode()));
|
||||
this.updateState(HueSyncConstants.CHANNELS.COMMANDS.SYNC,
|
||||
executionStatus.syncActive ? OnOffType.ON : OnOffType.OFF);
|
||||
this.updateState(HueSyncConstants.CHANNELS.COMMANDS.HDMI,
|
||||
executionStatus.hdmiActive ? OnOffType.ON : OnOffType.OFF);
|
||||
this.updateState(HueSyncConstants.CHANNELS.COMMANDS.SOURCE, new StringType(executionStatus.hdmiSource));
|
||||
this.updateState(HueSyncConstants.CHANNELS.COMMANDS.BRIGHTNESS, new DecimalType(executionStatus.brightness));
|
||||
}
|
||||
|
||||
private void handleRegistration(HueSyncRegistration registration) {
|
||||
this.stopTasks();
|
||||
|
||||
setProperty(HueSyncConstants.REGISTRATION_ID, registration.registrationId);
|
||||
|
||||
Configuration configuration = this.editConfiguration();
|
||||
|
||||
configuration.put(HueSyncConstants.REGISTRATION_ID, registration.registrationId);
|
||||
configuration.put(HueSyncConstants.API_TOKEN, registration.accessToken);
|
||||
|
||||
this.updateConfiguration(configuration);
|
||||
|
||||
this.startTasks();
|
||||
}
|
||||
|
||||
private void checkCompatibility() throws HueSyncApiException {
|
||||
try {
|
||||
HueSyncDevice deviceInformation = this.deviceInfo.orElseThrow();
|
||||
|
||||
if (deviceInformation.apiLevel < HueSyncConstants.MINIMAL_API_VERSION) {
|
||||
throw new HueSyncApiException("@text/api.minimal-version");
|
||||
}
|
||||
} catch (NoSuchElementException e) {
|
||||
throw new HueSyncApiException("@text/api.communication-problem");
|
||||
}
|
||||
}
|
||||
|
||||
private void setProperty(String key, @Nullable String value) {
|
||||
if (value != null) {
|
||||
Map<String, String> properties = this.editProperties();
|
||||
|
||||
if (properties.containsKey(key)) {
|
||||
@Nullable
|
||||
String currentValue = properties.get(key);
|
||||
if (!(value.equals(currentValue))) {
|
||||
saveProperty(key, value, properties);
|
||||
}
|
||||
} else {
|
||||
saveProperty(key, value, properties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveProperty(String key, String value, Map<String, String> properties) {
|
||||
properties.put(key, value);
|
||||
this.updateProperties(properties);
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// #region Override
|
||||
@Override
|
||||
public void initialize() {
|
||||
try {
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
|
||||
this.stopTasks();
|
||||
|
||||
scheduler.execute(initializeConnection());
|
||||
} catch (Exception e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
|
||||
this.updateStatus(ThingStatus.OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCommand(ChannelUID channelUID, Command command) {
|
||||
if (thing.getStatus() != ThingStatus.ONLINE) {
|
||||
this.logger.warn("Device status: {} - Command {} for chanel {} will be ignored",
|
||||
thing.getStatus().toString(), command.toFullString(), channelUID.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
Channel channel = thing.getChannel(channelUID);
|
||||
|
||||
if (channel == null) {
|
||||
logger.error("Channel UID:{} does not exist - please report this as an issue", channelUID);
|
||||
return;
|
||||
}
|
||||
|
||||
this.connection.executeCommand(channel, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
try {
|
||||
this.stopTasks();
|
||||
this.connection.dispose();
|
||||
} catch (Exception e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
} finally {
|
||||
this.logger.debug("Thing {} ({}) disposed.", this.thing.getLabel(), this.thing.getUID());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRemoval() {
|
||||
super.handleRemoval();
|
||||
|
||||
this.connection.unregisterDevice();
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.handler.tasks;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDevice;
|
||||
import org.openhab.binding.huesync.internal.api.dto.registration.HueSyncRegistration;
|
||||
import org.openhab.binding.huesync.internal.connection.HueSyncDeviceConnection;
|
||||
import org.openhab.binding.huesync.internal.exceptions.HueSyncConnectionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Task to handle device registration.
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncRegistrationTask implements Runnable {
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncRegistrationTask.class);
|
||||
|
||||
private final HueSyncDeviceConnection connection;
|
||||
private final HueSyncDevice deviceInfo;
|
||||
private final Consumer<HueSyncRegistration> action;
|
||||
|
||||
public HueSyncRegistrationTask(HueSyncDeviceConnection connection, HueSyncDevice deviceInfo,
|
||||
Consumer<HueSyncRegistration> action) {
|
||||
this.connection = connection;
|
||||
this.deviceInfo = deviceInfo;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
String id = this.deviceInfo.uniqueId;
|
||||
|
||||
if (this.connection.isRegistered() || id == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.debug("Listening for device registration - {} {}:{}", this.deviceInfo.name,
|
||||
this.deviceInfo.deviceType, id);
|
||||
|
||||
HueSyncRegistration registration = this.connection.registerDevice(id);
|
||||
|
||||
if (registration != null) {
|
||||
this.logger.debug("API token for {} received", this.deviceInfo.name);
|
||||
|
||||
this.action.accept(registration);
|
||||
}
|
||||
} catch (HueSyncConnectionException e) {
|
||||
this.logger.warn("{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.handler.tasks;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDevice;
|
||||
import org.openhab.binding.huesync.internal.connection.HueSyncDeviceConnection;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Task to handle device information update.
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncUpdateTask implements Runnable {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(HueSyncUpdateTask.class);
|
||||
|
||||
private final HueSyncDeviceConnection connection;
|
||||
private final HueSyncDevice deviceInfo;
|
||||
|
||||
private final Consumer<@Nullable HueSyncUpdateTaskResult> action;
|
||||
|
||||
public HueSyncUpdateTask(HueSyncDeviceConnection connection, HueSyncDevice deviceInfo,
|
||||
Consumer<@Nullable HueSyncUpdateTaskResult> action) {
|
||||
this.connection = connection;
|
||||
this.deviceInfo = deviceInfo;
|
||||
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
this.logger.debug("Status update query for {} {}:{}", this.deviceInfo.name, this.deviceInfo.deviceType,
|
||||
this.deviceInfo.uniqueId);
|
||||
|
||||
if (!this.connection.isRegistered()) {
|
||||
this.action.accept(null);
|
||||
}
|
||||
|
||||
HueSyncUpdateTaskResult updateInfo = new HueSyncUpdateTaskResult();
|
||||
|
||||
updateInfo.deviceStatus = this.connection.getDetailedDeviceInfo();
|
||||
updateInfo.hdmiStatus = this.connection.getHdmiInfo();
|
||||
updateInfo.execution = this.connection.getExecutionInfo();
|
||||
|
||||
this.action.accept(updateInfo);
|
||||
} catch (Exception e) {
|
||||
this.logger.debug("{}", e.getMessage());
|
||||
this.action.accept(null);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.handler.tasks;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.huesync.internal.api.dto.device.HueSyncDeviceDetailed;
|
||||
import org.openhab.binding.huesync.internal.api.dto.execution.HueSyncExecution;
|
||||
import org.openhab.binding.huesync.internal.api.dto.hdmi.HueSyncHdmi;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncUpdateTaskResult {
|
||||
public @Nullable HueSyncDeviceDetailed deviceStatus;
|
||||
public @Nullable HueSyncHdmi hdmiStatus;
|
||||
public @Nullable HueSyncExecution execution;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2010-2024 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.huesync.internal.i18n;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.i18n.TranslationProvider;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Patrik Gfeller - Initial Contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class HueSyncLocalizer {
|
||||
private static final Locale LOCALE = Locale.ENGLISH;
|
||||
private static final BundleContext BUNDLE_CONTEXT = FrameworkUtil.getBundle(HueSyncLocalizer.class)
|
||||
.getBundleContext();
|
||||
private static final ServiceReference<TranslationProvider> SERVICE_REFERENCE = BUNDLE_CONTEXT
|
||||
.getServiceReference(TranslationProvider.class);
|
||||
private static final Bundle BUNDLE = BUNDLE_CONTEXT.getBundle();
|
||||
|
||||
public static String getResourceString(String key) {
|
||||
String lookupKey = key.replace("@text/", "");
|
||||
|
||||
String missingKey = "Missing Translation: " + key;
|
||||
|
||||
String result = (BUNDLE_CONTEXT
|
||||
.getService(SERVICE_REFERENCE) instanceof TranslationProvider translationProvider)
|
||||
? translationProvider.getText(BUNDLE, lookupKey, missingKey, LOCALE)
|
||||
: missingKey;
|
||||
|
||||
return result == null ? missingKey : result;
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<addon:addon id="huesync" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:addon="https://openhab.org/schemas/addon/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/addon/v1.0.0 https://openhab.org/schemas/addon-1.0.0.xsd">
|
||||
|
||||
<type>binding</type>
|
||||
<name>Hue HDMI Sync Box Binding</name>
|
||||
<description>Binding for the Hue HDMI Sync Box.</description>
|
||||
<connection>local</connection>
|
||||
|
||||
<discovery-methods>
|
||||
<discovery-method>
|
||||
<service-type>mdns</service-type>
|
||||
<discovery-parameters>
|
||||
<discovery-parameter>
|
||||
<name>mdnsServiceType</name>
|
||||
<value>_huesync._tcp.local.</value>
|
||||
</discovery-parameter>
|
||||
</discovery-parameters>
|
||||
</discovery-method>
|
||||
</discovery-methods>
|
||||
|
||||
</addon:addon>
|
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0 https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="thing-type:box:thing">
|
||||
<parameter-group name="connection">
|
||||
<label>Connection</label>
|
||||
</parameter-group>
|
||||
|
||||
<parameter name="host" type="text" groupName="connection">
|
||||
<context>network-address</context>
|
||||
<label>Address</label>
|
||||
<description>Network address of the HDMI Sync Box.</description>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="port" type="integer" min="1" max="65535" groupName="connection">
|
||||
<context></context>
|
||||
<label>Port</label>
|
||||
<description>Port of the HDMI Sync Box.</description>
|
||||
<advanced>true</advanced>
|
||||
<default>443</default>
|
||||
<required>true</required>
|
||||
</parameter>
|
||||
<parameter name="registrationId" type="text" groupName="connection">
|
||||
<context></context>
|
||||
<label>Registration Id</label>
|
||||
<description>The id of the API registration.</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="apiAccessToken" type="text" groupName="connection">
|
||||
<context>password</context>
|
||||
<label>Access Token</label>
|
||||
<description>To enable the binding to communicate with the device, a registration is required. Once the registration
|
||||
process is completed, the acquired token will authorize the binding to interact with the device. After initial
|
||||
discovery and thing creation the device will stay offline. Press the registration button on the sync box for 3
|
||||
seconds to grant the binding the required permissions.</description>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="statusUpdateInterval" type="integer" min="1" step="1" unit="s" groupName="connection">
|
||||
<label>Update Interval</label>
|
||||
<description>Seconds between fetching values from the Hue Sync Box.</description>
|
||||
<advanced>true</advanced>
|
||||
<required>true</required>
|
||||
<default>10</default>
|
||||
<unitLabel>Seconds</unitLabel>
|
||||
</parameter>
|
||||
</config-description>
|
||||
</config-description:config-descriptions>
|
@ -0,0 +1,110 @@
|
||||
# add-on
|
||||
|
||||
addon.huesync.name = Hue HDMI Sync Box Binding
|
||||
addon.huesync.description = Binding for the Hue HDMI Sync Box.
|
||||
|
||||
# thing types
|
||||
|
||||
thing-type.huesync.box.label = HDMI Sync Box
|
||||
thing-type.huesync.box.description = Sync your smart lights to your on-screen TV content with the Philips Hue Play HDMI Sync Box. Four HDMI inputs allow you to connect your media devices to your Hue setup, resulting in a fast, seamless display of colorful smart light that responds to and reflects the content you watch or listen to.
|
||||
|
||||
# thing types config
|
||||
|
||||
thing-type.config.box.thing.apiAccessToken.label = Access Token
|
||||
thing-type.config.box.thing.apiAccessToken.description = To enable the binding to communicate with the device, a registration is required. Once the registration process is completed, the acquired token will authorize the binding to interact with the device. After initial discovery and thing creation the device will stay offline. Press the registration button on the sync box for 3 seconds to grant the binding the required permissions.
|
||||
thing-type.config.box.thing.group.connection.label = Connection
|
||||
thing-type.config.box.thing.host.label = Address
|
||||
thing-type.config.box.thing.host.description = Network address of the HDMI Sync Box.
|
||||
thing-type.config.box.thing.port.label = Port
|
||||
thing-type.config.box.thing.port.description = Port of the HDMI Sync Box.
|
||||
thing-type.config.box.thing.registrationId.label = Registration Id
|
||||
thing-type.config.box.thing.registrationId.description = The id of the API registration.
|
||||
thing-type.config.box.thing.statusUpdateInterval.label = Update Interval
|
||||
thing-type.config.box.thing.statusUpdateInterval.description = Seconds between fetching values from the Hue Sync Box.
|
||||
|
||||
# channel group types
|
||||
|
||||
channel-group-type.huesync.device-commands.label = Commands
|
||||
channel-group-type.huesync.device-commands.description = Commands are used to control the real-time behavior of the hue sync box. These commands allow you to influence how the lights react to your entertainment.
|
||||
channel-group-type.huesync.device-firmware.label = Firmware
|
||||
channel-group-type.huesync.device-firmware.description = Information about the installed device firmware and available updates.
|
||||
channel-group-type.huesync.device-hdmi-connection-in.label = HDMI Input
|
||||
channel-group-type.huesync.device-hdmi-connection-in.description = HDMI connection
|
||||
channel-group-type.huesync.device-hdmi-connection-out.label = HDMI Output
|
||||
channel-group-type.huesync.device-hdmi-connection-out.description = HDMI connection
|
||||
|
||||
# channel types
|
||||
|
||||
channel-type.huesync.connection-last-sync-mode.label = Last Mode
|
||||
channel-type.huesync.connection-last-sync-mode.description = Last sync mode used for this channel
|
||||
channel-type.huesync.connection-last-sync-mode.command.option.video = Video
|
||||
channel-type.huesync.connection-last-sync-mode.command.option.game = Game
|
||||
channel-type.huesync.connection-last-sync-mode.command.option.music = Music
|
||||
channel-type.huesync.connection-name.label = HDMI Name
|
||||
channel-type.huesync.connection-name.description = Friendly name of the HDMI connection
|
||||
channel-type.huesync.connection-status.label = HDMI Status
|
||||
channel-type.huesync.connection-status.description = Status of the HDMI input
|
||||
channel-type.huesync.connection-status.command.option.unplugged = Unplugged
|
||||
channel-type.huesync.connection-status.command.option.plugged = Plugged
|
||||
channel-type.huesync.connection-status.command.option.linked = Linked
|
||||
channel-type.huesync.connection-status.command.option.unknown = Unknown
|
||||
channel-type.huesync.connection-type.label = HDMI Type
|
||||
channel-type.huesync.connection-type.description = Type of the connected HDMI device
|
||||
channel-type.huesync.connection-type.command.option.generic = Generic
|
||||
channel-type.huesync.connection-type.command.option.video = Video
|
||||
channel-type.huesync.connection-type.command.option.game = Game
|
||||
channel-type.huesync.connection-type.command.option.music = Music
|
||||
channel-type.huesync.connection-type.command.option.xbox = XBox
|
||||
channel-type.huesync.connection-type.command.option.playstation = PlayStation
|
||||
channel-type.huesync.connection-type.command.option.nintendoswitch = Nintendo Switch
|
||||
channel-type.huesync.connection-type.command.option.phone = Phone
|
||||
channel-type.huesync.connection-type.command.option.desktop = Desktop
|
||||
channel-type.huesync.connection-type.command.option.laptop = Laptop
|
||||
channel-type.huesync.connection-type.command.option.appletv = Apple TV
|
||||
channel-type.huesync.connection-type.command.option.roku = Roku
|
||||
channel-type.huesync.connection-type.command.option.shield = Nvidia Shield
|
||||
channel-type.huesync.connection-type.command.option.chromecast = Chromecast
|
||||
channel-type.huesync.connection-type.command.option.firetv = Amazon Fire TV
|
||||
channel-type.huesync.connection-type.command.option.diskplayer = Disk Player
|
||||
channel-type.huesync.connection-type.command.option.settopbox = Set-top box
|
||||
channel-type.huesync.connection-type.command.option.satellite = Satellite
|
||||
channel-type.huesync.connection-type.command.option.avreceiver = AV receiver
|
||||
channel-type.huesync.connection-type.command.option.soundbar = Soundbar
|
||||
channel-type.huesync.connection-type.command.option.hdmiswitch = HDMI switch
|
||||
channel-type.huesync.device-info-firmware-available.label = Latest Firmware
|
||||
channel-type.huesync.device-info-firmware-available.description = Latest available firmware version
|
||||
channel-type.huesync.device-info-firmware.label = Firmware
|
||||
channel-type.huesync.device-info-firmware.description = Installed firmware version
|
||||
channel-type.huesync.execution-brightness.label = Brightness
|
||||
channel-type.huesync.execution-brightness.description = <p> 0 ... 200 <ul> <li>0 = max reduction</li> <li>100 = no brightness reduction/boost compared to input</li> <li>200 = max boost</li> </ul> </p>
|
||||
channel-type.huesync.execution-hdmi-active.label = HDMI Active
|
||||
channel-type.huesync.execution-hdmi-active.description = <p> <b>OFF</b> in case of <i>powersave</i> mode and <b>ON</b> in case of <i>passthrough</i>, <i>video</i>, <i>game</i> or <i>music</i> mode. </p> <p> When changed from <b>OFF</b> to <b>ON</b>, it will set <i>passthrough</i> mode. When changed from <b>ON</b> to <b>OFF</b>, will set <i>powersave</i> mode. </p>
|
||||
channel-type.huesync.execution-hdmi-source.label = HDMI Input
|
||||
channel-type.huesync.execution-hdmi-source.description = <p> <ul> <li>input1</li> <li>input2</li> <li>input3</li> <li>input4</li> </ul> </p>
|
||||
channel-type.huesync.execution-mode.label = Mode
|
||||
channel-type.huesync.execution-mode.description = <p> <ul> <li> <b>"Video":</b> <p> Analyzes the on-screen visuals, translating colors and brightness into corresponding light effects for an immersive movie-watching experience. </p> </li> <li> <b>"Music":</b> <p> Analyzes the rhythm and beat of your music, creating dynamic light along to your tunes. </p> </li> <li> <b>"Game":</b> <p> Reacts to the action on your screen, intensifying the in-game atmosphere with bursts of light that correspond to explosions, gunfire, and other gameplay events.</p> </li> <li><b>"Passthrough"</b></li> <li><b>"Powersave"</b></li> </ul> </p>
|
||||
channel-type.huesync.execution-mode.command.option.powersave = Powersave
|
||||
channel-type.huesync.execution-mode.command.option.passthrough = Passthrough
|
||||
channel-type.huesync.execution-mode.command.option.video = Video
|
||||
channel-type.huesync.execution-mode.command.option.game = Game
|
||||
channel-type.huesync.execution-mode.command.option.music = Music
|
||||
channel-type.huesync.execution-sync-active.label = Synchronization Active
|
||||
channel-type.huesync.execution-sync-active.description = <p> <b>OFF</b> in case of <i>powersave</i> or <i>passthrough</i> mode, and <b>ON</b> in case of <i>video</i>, <i>game</i> or <i>music</i> mode. </p> <p> When changed from <b>OFF</b> to <b>ON</b>, it will start syncing in last used mode for current source. When changed from <b>ON</b> to <b>OFF</b>, will set <i>passthrough</i> mode. </p>
|
||||
|
||||
# *** exceptions ***
|
||||
|
||||
exception.generic.connection = "Unable to connect to device."
|
||||
|
||||
# api & connection exceptions
|
||||
|
||||
api.minimal-version = Only devices with API level >= 7 are supported
|
||||
api.communication-problem = Communication problem with the device
|
||||
connection.invalid-login = Invalid or missing credentials
|
||||
|
||||
# registration
|
||||
|
||||
thing.config.huesync.box.registration = Device registration pending. Please press the HDMI Sync Box device button for 3 seconds.
|
||||
|
||||
# logger (to keep text in sync with on-screen messages, log messages will always be in locale.english)
|
||||
|
||||
logger.initialization-problem = Unable to initialize handler for {} ({}): {}
|
@ -0,0 +1,225 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="huesync"
|
||||
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">
|
||||
|
||||
<channel-type id="device-info-firmware">
|
||||
<item-type>String</item-type>
|
||||
<label>Firmware</label>
|
||||
<description>Installed firmware version</description>
|
||||
<category>text</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="device-info-firmware-available">
|
||||
<item-type>String</item-type>
|
||||
<label>Latest Firmware</label>
|
||||
<description>Latest available firmware version</description>
|
||||
<category>text</category>
|
||||
<state readOnly="true"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="connection-name">
|
||||
<item-type>String</item-type>
|
||||
<label>HDMI Name</label>
|
||||
<description>Friendly name of the HDMI connection</description>
|
||||
<category>text</category>
|
||||
<state readOnly="true"></state>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="connection-status">
|
||||
<item-type>String</item-type>
|
||||
<label>HDMI Status</label>
|
||||
<description>Status of the HDMI input</description>
|
||||
<category>status</category>
|
||||
<state readOnly="true"></state>
|
||||
<command>
|
||||
<options>
|
||||
<option value="unplugged">Unplugged</option>
|
||||
<option value="plugged">Plugged</option>
|
||||
<option value="linked">Linked</option>
|
||||
<option value="unknown">Unknown</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="connection-type">
|
||||
<item-type>String</item-type>
|
||||
<label>HDMI Type</label>
|
||||
<description>Type of the connected HDMI device</description>
|
||||
<category>text</category>
|
||||
<state readOnly="true"></state>
|
||||
<command>
|
||||
<options>
|
||||
<option value="generic">Generic</option>
|
||||
<option value="video">Video</option>
|
||||
<option value="game">Game</option>
|
||||
<option value="music">Music</option>
|
||||
<option value="xbox">XBox</option>
|
||||
<option value="playstation">PlayStation</option>
|
||||
<option value="nintendoswitch">Nintendo Switch</option>
|
||||
<option value="phone">Phone</option>
|
||||
<option value="desktop">Desktop</option>
|
||||
<option value="laptop">Laptop</option>
|
||||
<option value="appletv">Apple TV</option>
|
||||
<option value="roku">Roku</option>
|
||||
<option value="shield">Nvidia Shield</option>
|
||||
<option value="chromecast">Chromecast</option>
|
||||
<option value="firetv">Amazon Fire TV</option>
|
||||
<option value="diskplayer">Disk Player</option>
|
||||
<option value="settopbox">Set-top box</option>
|
||||
<option value="satellite">Satellite</option>
|
||||
<option value="avreceiver">AV receiver</option>
|
||||
<option value="soundbar">Soundbar</option>
|
||||
<option value="hdmiswitch">HDMI switch</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="connection-last-sync-mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Last Mode</label>
|
||||
<description>Last sync mode used for this channel</description>
|
||||
<category>text</category>
|
||||
<state readOnly="true"></state>
|
||||
<command>
|
||||
<options>
|
||||
<option value="video">Video</option>
|
||||
<option value="game">Game</option>
|
||||
<option value="music">Music</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="execution-mode">
|
||||
<item-type>String</item-type>
|
||||
<label>Mode</label>
|
||||
<description>
|
||||
<![CDATA[
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
<b>"Video":</b>
|
||||
<p>
|
||||
Analyzes the on-screen visuals, translating colors and brightness into corresponding light
|
||||
effects for an immersive movie-watching experience.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>"Music":</b>
|
||||
<p>
|
||||
Analyzes the rhythm and beat of your music, creating
|
||||
dynamic light along to your tunes.
|
||||
</p>
|
||||
</li>
|
||||
<li>
|
||||
<b>"Game":</b>
|
||||
<p>
|
||||
Reacts to the action on your screen, intensifying the in-game atmosphere
|
||||
with bursts of light that correspond to explosions, gunfire, and other gameplay events.</p>
|
||||
</li>
|
||||
<li><b>"Passthrough"</b></li>
|
||||
<li><b>"Powersave"</b></li>
|
||||
</ul>
|
||||
</p>
|
||||
]]>
|
||||
</description>
|
||||
<category>text</category>
|
||||
<command>
|
||||
<options>
|
||||
<option value="powersave">Powersave</option>
|
||||
<option value="passthrough">Passthrough</option>
|
||||
<option value="video">Video</option>
|
||||
<option value="game">Game</option>
|
||||
<option value="music">Music</option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="execution-sync-active">
|
||||
<item-type>Switch</item-type>
|
||||
<label>Synchronization Active</label>
|
||||
<description>
|
||||
<![CDATA[
|
||||
<p>
|
||||
<b>OFF</b> in case of <i>powersave</i> or <i>passthrough</i> mode, and <b>ON</b> in case of <i>video</i>, <i>game</i> or <i>music</i> mode.
|
||||
</p>
|
||||
<p>
|
||||
When changed from <b>OFF</b> to <b>ON</b>, it will start syncing in last used mode for current source.
|
||||
When changed from <b>ON</b> to <b>OFF</b>, will set <i>passthrough</i> mode.
|
||||
</p>
|
||||
]]>
|
||||
</description>
|
||||
<category>switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="execution-hdmi-active">
|
||||
<item-type>Switch</item-type>
|
||||
<label>HDMI Active</label>
|
||||
<description>
|
||||
<![CDATA[
|
||||
<p>
|
||||
<b>OFF</b> in case of <i>powersave</i> mode and <b>ON</b> in case of <i>passthrough</i>, <i>video</i>, <i>game</i> or <i>music</i> mode.
|
||||
</p>
|
||||
<p>
|
||||
When changed from <b>OFF</b> to <b>ON</b>, it will set <i>passthrough</i> mode.
|
||||
When changed from <b>ON</b> to <b>OFF</b>, will set <i>powersave</i> mode.
|
||||
</p>
|
||||
]]>
|
||||
</description>
|
||||
<category>switch</category>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="execution-hdmi-source">
|
||||
<item-type>String</item-type>
|
||||
<label>HDMI Input</label>
|
||||
<description>
|
||||
<![CDATA[
|
||||
<p>
|
||||
<ul>
|
||||
<li>input1</li>
|
||||
<li>input2</li>
|
||||
<li>input3</li>
|
||||
<li>input4</li>
|
||||
</ul>
|
||||
</p>
|
||||
]]>
|
||||
</description>
|
||||
<category>receiver</category>
|
||||
<command>
|
||||
<options>
|
||||
<option value="input1"></option>
|
||||
<option value="input2"></option>
|
||||
<option value="input3"></option>
|
||||
<option value="input4"></option>
|
||||
</options>
|
||||
</command>
|
||||
</channel-type>
|
||||
|
||||
<!--
|
||||
brightness:
|
||||
- Get, Put
|
||||
- number, uint
|
||||
- 0 ... 200 (100 = no brightness reduction/boost compared to input, 0 = max reduction, 200 = max boost)
|
||||
-->
|
||||
<channel-type id="execution-brightness">
|
||||
<item-type>Number:Dimensionless</item-type>
|
||||
<label>Brightness</label>
|
||||
<description>
|
||||
<![CDATA[
|
||||
<p>
|
||||
0 ... 200
|
||||
<ul>
|
||||
<li>0 = max reduction</li>
|
||||
<li>100 = no brightness reduction/boost compared to input</li>
|
||||
<li>200 = max boost</li>
|
||||
</ul>
|
||||
</p>
|
||||
]]>
|
||||
</description>
|
||||
<category>slider</category>
|
||||
<state min="0" max="200" step="1" pattern="%d"/>
|
||||
</channel-type>
|
||||
|
||||
</thing:thing-descriptions>
|
@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<thing:thing-descriptions bindingId="huesync"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
|
||||
|
||||
<thing-type id="box">
|
||||
<label>HDMI Sync Box</label>
|
||||
|
||||
<description>Sync your smart lights to your on-screen TV content with the Philips Hue Play HDMI Sync Box. Four HDMI
|
||||
inputs allow you to connect your media devices to your Hue setup, resulting in a fast, seamless display of colorful
|
||||
smart light that responds to and reflects the content you watch or listen to.
|
||||
</description>
|
||||
|
||||
<category>receiver</category>
|
||||
|
||||
<channel-groups>
|
||||
<channel-group id="device-firmware" typeId="device-firmware"></channel-group>
|
||||
|
||||
<channel-group id="device-hdmi-in-1" typeId="device-hdmi-connection-in"></channel-group>
|
||||
<channel-group id="device-hdmi-in-2" typeId="device-hdmi-connection-in"></channel-group>
|
||||
<channel-group id="device-hdmi-in-3" typeId="device-hdmi-connection-in"></channel-group>
|
||||
<channel-group id="device-hdmi-in-4" typeId="device-hdmi-connection-in"></channel-group>
|
||||
|
||||
<channel-group id="device-hdmi-out" typeId="device-hdmi-connection-out"></channel-group>
|
||||
|
||||
<channel-group id="device-commands" typeId="device-commands"></channel-group>
|
||||
</channel-groups>
|
||||
|
||||
<properties>
|
||||
<property name="vendor">Philips</property>
|
||||
</properties>
|
||||
|
||||
<representation-property>host</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:box:thing"/>
|
||||
</thing-type>
|
||||
|
||||
<channel-group-type id="device-firmware">
|
||||
<label>Firmware</label>
|
||||
<description>Information about the installed device firmware and available updates.</description>
|
||||
<category>text</category>
|
||||
<channels>
|
||||
<channel id="firmware" typeId="device-info-firmware"></channel>
|
||||
<channel id="available-firmware" typeId="device-info-firmware-available"></channel>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
<channel-group-type id="device-hdmi-connection-in">
|
||||
<label>HDMI Input</label>
|
||||
<description>HDMI connection</description>
|
||||
<category>settings</category>
|
||||
<channels>
|
||||
<channel id="name" typeId="connection-name"></channel>
|
||||
<channel id="type" typeId="connection-type"></channel>
|
||||
<channel id="status" typeId="connection-status"></channel>
|
||||
<channel id="mode" typeId="connection-last-sync-mode"></channel>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
<channel-group-type id="device-hdmi-connection-out">
|
||||
<label>HDMI Output</label>
|
||||
<description>HDMI connection</description>
|
||||
<category>settings</category>
|
||||
<channels>
|
||||
<channel id="name" typeId="connection-name"></channel>
|
||||
<channel id="type" typeId="connection-type"></channel>
|
||||
<channel id="status" typeId="connection-status"></channel>
|
||||
<channel id="mode" typeId="connection-last-sync-mode"></channel>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
<channel-group-type id="device-commands">
|
||||
<label>Commands</label>
|
||||
<description>Commands are used to control the real-time behavior of the hue sync box. These
|
||||
commands allow you to
|
||||
influence how the lights react to your entertainment.</description>
|
||||
<category>settings</category>
|
||||
<channels>
|
||||
<channel id="mode" typeId="execution-mode"></channel>
|
||||
<channel id="sync-active" typeId="execution-sync-active"></channel>
|
||||
<channel id="hdmi-active" typeId="execution-hdmi-active"></channel>
|
||||
<channel id="hdmi-source" typeId="execution-hdmi-source"></channel>
|
||||
<channel id="brightness" typeId="execution-brightness"></channel>
|
||||
</channels>
|
||||
</channel-group-type>
|
||||
</thing:thing-descriptions>
|
@ -195,6 +195,7 @@
|
||||
<module>org.openhab.binding.hpprinter</module>
|
||||
<module>org.openhab.binding.http</module>
|
||||
<module>org.openhab.binding.hue</module>
|
||||
<module>org.openhab.binding.huesync</module>
|
||||
<module>org.openhab.binding.hydrawise</module>
|
||||
<module>org.openhab.binding.hyperion</module>
|
||||
<module>org.openhab.binding.iammeter</module>
|
||||
|
Loading…
Reference in New Issue
Block a user