mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-10 15:11:59 +01:00
[hue] Changed discovery to mDNS; added HTTPS handling; refactor HTTPClient to use jetty shared client (#11842)
* Changed discovery to MDNS; added HTTPS handling; refactor HTTPClient to use jetty shared client Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
This commit is contained in:
parent
d2efe69a73
commit
ee34d92c17
@ -1,15 +1,15 @@
|
|||||||
# Philips Hue Binding
|
# Philips Hue Binding
|
||||||
|
|
||||||
This binding integrates the [Philips Hue Lighting system](https://www.meethue.com).
|
This binding integrates the [Philips Hue Lighting system](https://www.meethue.com).
|
||||||
The integration happens through the Hue bridge, which acts as an IP gateway to the ZigBee devices.
|
The integration happens through the Hue Bridge, which acts as an IP gateway to the ZigBee devices.
|
||||||
|
|
||||||
![Philips Hue](doc/hue.jpg)
|
![Philips Hue](doc/hue.jpg)
|
||||||
|
|
||||||
## Supported Things
|
## Supported Things
|
||||||
|
|
||||||
The Hue bridge is required as a "bridge" for accessing any other Hue device.
|
The Hue Bridge is required as a "bridge" for accessing any other Hue device.
|
||||||
It supports the ZigBee LightLink protocol as well as the upwards compatible ZigBee 3.0 protocol.
|
It supports the ZigBee LightLink protocol as well as the upwards compatible ZigBee 3.0 protocol.
|
||||||
There are two types of Hue bridges, generally referred to as v1 (the rounded version) and v2 (the squared version).
|
There are two types of Hue Bridges, generally referred to as v1 (the rounded version) and v2 (the squared version).
|
||||||
Only noticeable difference between the two generation of bridges is the added support for Apple HomeKit in v2.
|
Only noticeable difference between the two generation of bridges is the added support for Apple HomeKit in v2.
|
||||||
Both bridges are fully supported by this binding.
|
Both bridges are fully supported by this binding.
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ Almost all available Hue devices are supported by this binding.
|
|||||||
This includes not only the "Friends of Hue", but also products like the LivingWhites adapter.
|
This includes not only the "Friends of Hue", but also products like the LivingWhites adapter.
|
||||||
Additionally, it is possible to use OSRAM Lightify devices as well as other ZigBee LightLink compatible products, including the IKEA TRÅDFRI lights (when updated).
|
Additionally, it is possible to use OSRAM Lightify devices as well as other ZigBee LightLink compatible products, including the IKEA TRÅDFRI lights (when updated).
|
||||||
Beside bulbs and luminaires the Hue binding also supports some ZigBee sensors. Currently only Hue specific sensors are tested successfully (Hue Motion Sensor and Hue Dimmer Switch).
|
Beside bulbs and luminaires the Hue binding also supports some ZigBee sensors. Currently only Hue specific sensors are tested successfully (Hue Motion Sensor and Hue Dimmer Switch).
|
||||||
Please note that the devices need to be registered with the Hue bridge before it is possible for this binding to use them.
|
Please note that the devices need to be registered with the Hue Bridge before it is possible for this binding to use them.
|
||||||
|
|
||||||
The Hue binding supports all seven types of lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/docs/en/user-guide/JN-UG-3091.pdf).
|
The Hue binding supports all seven types of lighting devices defined for ZigBee LightLink ([see page 24, table 2](https://www.nxp.com/docs/en/user-guide/JN-UG-3091.pdf).
|
||||||
These are:
|
These are:
|
||||||
@ -65,28 +65,35 @@ They are presented by the following ZigBee Device ID and _Thing type_:
|
|||||||
|
|
||||||
The Hue Dimmer Switch has 4 buttons and registers as a Non-Colour Controller switch, while the Hue Tap (also 4 buttons) registers as a Non-Colour Scene Controller in accordance with the ZLL standard.
|
The Hue Dimmer Switch has 4 buttons and registers as a Non-Colour Controller switch, while the Hue Tap (also 4 buttons) registers as a Non-Colour Scene Controller in accordance with the ZLL standard.
|
||||||
|
|
||||||
Also, Hue bridge support CLIP Generic Status Sensor and CLIP Generic Flag Sensor.
|
Also, Hue Bridge support CLIP Generic Status Sensor and CLIP Generic Flag Sensor.
|
||||||
These sensors save state for rules and calculate what actions to do.
|
These sensors save state for rules and calculate what actions to do.
|
||||||
CLIP Sensor set or get by JSON through IP.
|
CLIP Sensor set or get by JSON through IP.
|
||||||
|
|
||||||
Finally, the Hue binding also supports the groups of lights and rooms set up on the Hue bridge.
|
Finally, the Hue binding also supports the groups of lights and rooms set up on the Hue Bridge.
|
||||||
|
|
||||||
## Discovery
|
## Discovery
|
||||||
|
|
||||||
The Hue bridge is discovered through UPnP in the local network.
|
The Hue Bridge is discovered through mDNS in the local network.
|
||||||
|
Auto-discovery is enabled by default.
|
||||||
|
To disable it, you can add the following line to `<openHAB-conf>/services/runtime.cfg`:
|
||||||
|
|
||||||
|
```
|
||||||
|
discovery.hue:background=false
|
||||||
|
```
|
||||||
|
|
||||||
Once it is added as a Thing, its authentication button (in the middle) needs to be pressed in order to authorize the binding to access it.
|
Once it is added as a Thing, its authentication button (in the middle) needs to be pressed in order to authorize the binding to access it.
|
||||||
Once the binding is authorized, it automatically reads all devices and groups that are set up on the Hue bridge and puts them into the Inbox.
|
Once the binding is authorized, it automatically reads all devices and groups that are set up on the Hue Bridge and puts them into the Inbox.
|
||||||
|
|
||||||
## Thing Configuration
|
## Thing Configuration
|
||||||
|
|
||||||
The Hue bridge requires the IP address as a configuration value in order for the binding to know where to access it.
|
The Hue Bridge requires the IP address as a configuration value in order for the binding to know where to access it.
|
||||||
In the thing file, this looks e.g. like
|
In the thing file, this looks e.g. like
|
||||||
|
|
||||||
```
|
```
|
||||||
Bridge hue:bridge:1 [ ipAddress="192.168.0.64" ]
|
Bridge hue:bridge:1 [ ipAddress="192.168.0.64" ]
|
||||||
```
|
```
|
||||||
|
|
||||||
A user to authenticate against the Hue bridge is automatically generated.
|
A user to authenticate against the Hue Bridge is automatically generated.
|
||||||
Please note that the generated user name cannot be written automatically to the `.thing` file, and has to be set manually.
|
Please note that the generated user name cannot be written automatically to the `.thing` file, and has to be set manually.
|
||||||
The generated user name can be found, after pressing the authentication button on the bridge, with the following console command: `hue <bridgeUID> username`.
|
The generated user name can be found, after pressing the authentication button on the bridge, with the following console command: `hue <bridgeUID> username`.
|
||||||
The user name can be set using the `userName` configuration value, e.g.:
|
The user name can be set using the `userName` configuration value, e.g.:
|
||||||
@ -95,17 +102,19 @@ The user name can be set using the `userName` configuration value, e.g.:
|
|||||||
Bridge hue:bridge:1 [ ipAddress="192.168.0.64", userName="qwertzuiopasdfghjklyxcvbnm1234" ]
|
Bridge hue:bridge:1 [ ipAddress="192.168.0.64", userName="qwertzuiopasdfghjklyxcvbnm1234" ]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| ipAddress | Network address of the Hue bridge. **Mandatory** |
|
| ipAddress | Network address of the Hue Bridge. **Mandatory**. |
|
||||||
| port | Port of the Hue bridge. Optional, default value is 80 or 443, derived from protocol, otherwise user-defined. |
|
| port | Port of the Hue Bridge. Optional, default value is 80 or 443, derived from protocol, otherwise user-defined. |
|
||||||
| userName | Name of a registered Hue bridge user, that allows to access the API. **Mandatory** |
|
| protocol | Protocol to connect to the Hue Bridge ("http" or "https"), default value is "https"). |
|
||||||
| pollingInterval | Seconds between fetching light values from the Hue bridge. Optional, the default value is 10 (min="1", step="1"). |
|
| useSelfSignedCertificate | Use self-signed certificate for HTTPS connection to Hue Bridge. **Advanced**, default value is `true`. |
|
||||||
| sensorPollingInterval | Milliseconds between fetching sensor-values from the Hue bridge. A higher value means more delay for the sensor values, but a too low value can cause congestion on the bridge. Optional, the default value is 500. Default value will be considered if the value is lower than 50. Use 0 to disable the polling for sensors. |
|
| userName | Name of a registered Hue Bridge user, that allows to access the API. **Mandatory** |
|
||||||
|
| pollingInterval | Seconds between fetching light values from the Hue Bridge. Optional, the default value is 10 (min="1", step="1"). |
|
||||||
|
| sensorPollingInterval | Milliseconds between fetching sensor-values from the Hue Bridge. A higher value means more delay for the sensor values, but a too low value can cause congestion on the bridge. Optional, the default value is 500. Default value will be considered if the value is lower than 50. Use 0 to disable the polling for sensors. |
|
||||||
|
|
||||||
### Devices
|
### Devices
|
||||||
|
|
||||||
The devices are identified by the number that the Hue bridge assigns to them (also shown in the Hue App as an identifier).
|
The devices are identified by the number that the Hue Bridge assigns to them (also shown in the Hue App as an identifier).
|
||||||
Thus, all it needs for manual configuration is this single value like
|
Thus, all it needs for manual configuration is this single value like
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -130,13 +139,13 @@ The following device types also have an optional configuration value to specify
|
|||||||
|
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
|-----------|-------------------------------------------------------------------------------|
|
|-----------|-------------------------------------------------------------------------------|
|
||||||
| lightId | Number of the device provided by the Hue bridge. **Mandatory** |
|
| lightId | Number of the device provided by the Hue Bridge. **Mandatory** |
|
||||||
| fadetime | Fade time in Milliseconds to a new state (min="0", step="100", default="400") |
|
| fadetime | Fade time in Milliseconds to a new state (min="0", step="100", default="400") |
|
||||||
|
|
||||||
|
|
||||||
### Groups
|
### Groups
|
||||||
|
|
||||||
The groups are identified by the number that the Hue bridge assigns to them.
|
The groups are identified by the number that the Hue Bridge assigns to them.
|
||||||
Thus, all it needs for manual configuration is this single value like
|
Thus, all it needs for manual configuration is this single value like
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -149,7 +158,7 @@ The group type also have an optional configuration value to specify the fade tim
|
|||||||
|
|
||||||
| Parameter | Description |
|
| Parameter | Description |
|
||||||
|-----------|-------------------------------------------------------------------------------|
|
|-----------|-------------------------------------------------------------------------------|
|
||||||
| groupId | Number of the group provided by the Hue bridge. **Mandatory** |
|
| groupId | Number of the group provided by the Hue Bridge. **Mandatory** |
|
||||||
| fadetime | Fade time in Milliseconds to a new state (min="0", step="100", default="400") |
|
| fadetime | Fade time in Milliseconds to a new state (min="0", step="100", default="400") |
|
||||||
|
|
||||||
|
|
||||||
@ -179,7 +188,7 @@ The devices support some of the following channels:
|
|||||||
| last_updated | DateTime | This channel the date and time when the sensor was last updated. | 0820, 0830, 0840, 0850, 0106, 0107, 0302 |
|
| last_updated | DateTime | This channel the date and time when the sensor was last updated. | 0820, 0830, 0840, 0850, 0106, 0107, 0302 |
|
||||||
| battery_level | Number | This channel shows the battery level. | 0820, 0106, 0107, 0302 |
|
| battery_level | Number | This channel shows the battery level. | 0820, 0106, 0107, 0302 |
|
||||||
| battery_low | Switch | This channel indicates whether the battery is low or not. | 0820, 0106, 0107, 0302 |
|
| battery_low | Switch | This channel indicates whether the battery is low or not. | 0820, 0106, 0107, 0302 |
|
||||||
| scene | String | This channel activates the scene with the given ID String. The ID String of each scene is assigned by the Hue bridge. | bridge, group |
|
| scene | String | This channel activates the scene with the given ID String. The ID String of each scene is assigned by the Hue Bridge. | bridge, group |
|
||||||
|
|
||||||
To load a hue scene inside a rule for example, the ID of the scene will be required.
|
To load a hue scene inside a rule for example, the ID of the scene will be required.
|
||||||
You can list all the scene IDs with the following console commands: `hue <bridgeUID> scenes` and `hue <groupThingUID> scenes`.
|
You can list all the scene IDs with the following console commands: `hue <bridgeUID> scenes` and `hue <groupThingUID> scenes`.
|
||||||
@ -366,11 +375,3 @@ if (receivedEvent == "1000.0")) {
|
|||||||
//do stuff
|
//do stuff
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### UPnP Discovery: Inbox 'Grace Period'
|
|
||||||
|
|
||||||
The Hue Bridge can sometimes be late in sending its UPnP 'ssdp:alive' notifications even though it has not really gone offline.
|
|
||||||
This means that the Hue Bridge could be repeatedly removed from, and (re)added to, the InBox.
|
|
||||||
Which would lead to confusion in the UI, and repeated logger messages.
|
|
||||||
To prevent this, the binding tells the OpenHAB core to wait for a further period of time ('grace period') before actually removing the Bridge from the Inbox.
|
|
||||||
The 'grace period' has a default value of 50 seconds, but it can be fine tuned in the main UI via Settings | Bindings | Hue | Configure.
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
<feature name="openhab-binding-hue" description="Hue Binding" version="${project.version}">
|
<feature name="openhab-binding-hue" description="Hue Binding" version="${project.version}">
|
||||||
<feature>openhab-runtime-base</feature>
|
<feature>openhab-runtime-base</feature>
|
||||||
<feature>openhab-transport-upnp</feature>
|
<feature>openhab-transport-mdns</feature>
|
||||||
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.hue/${project.version}</bundle>
|
<bundle start-level="80">mvn:org.openhab.addons.bundles/org.openhab.binding.hue/${project.version}</bundle>
|
||||||
</feature>
|
</feature>
|
||||||
</features>
|
</features>
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
class CreateScheduleRequest {
|
|
||||||
private String name;
|
|
||||||
private String description;
|
|
||||||
private ScheduleCommand command;
|
|
||||||
private Date time;
|
|
||||||
|
|
||||||
public CreateScheduleRequest(String name, String description, ScheduleCommand command, Date time) {
|
|
||||||
if (name != null && Util.stringSize(name) > 32) {
|
|
||||||
throw new IllegalArgumentException("Schedule name can be at most 32 characters long");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (description != null && Util.stringSize(description) > 64) {
|
|
||||||
throw new IllegalArgumentException("Schedule description can be at most 64 characters long");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == null) {
|
|
||||||
throw new IllegalArgumentException("No schedule command specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.name = name;
|
|
||||||
this.description = description;
|
|
||||||
this.command = command;
|
|
||||||
this.time = time;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detailed schedule information.
|
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
|
||||||
*/
|
|
||||||
public class FullSchedule extends Schedule {
|
|
||||||
private String description;
|
|
||||||
private ScheduleCommand command; // Not really appropriate for exposure
|
|
||||||
private Date time;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the description of the schedule.
|
|
||||||
*
|
|
||||||
* @return description
|
|
||||||
*/
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the scheduled command.
|
|
||||||
*
|
|
||||||
* @return command
|
|
||||||
*/
|
|
||||||
public ScheduleCommand getCommand() {
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the time for which the command is scheduled to be ran.
|
|
||||||
*
|
|
||||||
* @return scheduled time
|
|
||||||
*/
|
|
||||||
public Date getTime() {
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,175 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
|
||||||
*/
|
|
||||||
@NonNullByDefault
|
|
||||||
public class HttpClient {
|
|
||||||
private int timeout = 1000;
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(HttpClient.class);
|
|
||||||
private final LinkedList<AsyncPutParameters> commandsQueue = new LinkedList<>();
|
|
||||||
private @Nullable Future<?> job;
|
|
||||||
|
|
||||||
@SuppressWarnings({ "null", "unused" })
|
|
||||||
private void executeCommands() {
|
|
||||||
while (true) {
|
|
||||||
try {
|
|
||||||
long delayTime = 0;
|
|
||||||
synchronized (commandsQueue) {
|
|
||||||
AsyncPutParameters payloadCallbackPair = commandsQueue.poll();
|
|
||||||
if (payloadCallbackPair != null) {
|
|
||||||
logger.debug("Async sending put to address: {} delay: {} body: {}", payloadCallbackPair.address,
|
|
||||||
payloadCallbackPair.delay, payloadCallbackPair.body);
|
|
||||||
try {
|
|
||||||
Result result = put(payloadCallbackPair.address, payloadCallbackPair.body);
|
|
||||||
payloadCallbackPair.future.complete(result);
|
|
||||||
} catch (IOException e) {
|
|
||||||
payloadCallbackPair.future.completeExceptionally(e);
|
|
||||||
}
|
|
||||||
delayTime = payloadCallbackPair.delay;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Thread.sleep(delayTime);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.debug("commandExecutorThread was interrupted", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimeout(int timeout) {
|
|
||||||
this.timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result get(String address) throws IOException {
|
|
||||||
return doNetwork(address, "GET");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result post(String address, String body) throws IOException {
|
|
||||||
return doNetwork(address, "POST", body);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result put(String address, String body) throws IOException {
|
|
||||||
return doNetwork(address, "PUT", body);
|
|
||||||
}
|
|
||||||
|
|
||||||
public CompletableFuture<Result> putAsync(String address, String body, long delay,
|
|
||||||
ScheduledExecutorService scheduler) {
|
|
||||||
AsyncPutParameters asyncPutParameters = new AsyncPutParameters(address, body, delay);
|
|
||||||
|
|
||||||
synchronized (commandsQueue) {
|
|
||||||
if (commandsQueue.isEmpty()) {
|
|
||||||
commandsQueue.offer(asyncPutParameters);
|
|
||||||
Future<?> localJob = job;
|
|
||||||
if (localJob == null || localJob.isDone()) {
|
|
||||||
job = scheduler.submit(this::executeCommands);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
commandsQueue.offer(asyncPutParameters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return asyncPutParameters.future;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Result delete(String address) throws IOException {
|
|
||||||
return doNetwork(address, "DELETE");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Result doNetwork(String address, String requestMethod) throws IOException {
|
|
||||||
return doNetwork(address, requestMethod, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Result doNetwork(String address, String requestMethod, @Nullable String body) throws IOException {
|
|
||||||
HttpURLConnection conn = (HttpURLConnection) new URL(address).openConnection();
|
|
||||||
try {
|
|
||||||
conn.setRequestMethod(requestMethod);
|
|
||||||
conn.setRequestProperty("Content-Type", "application/json");
|
|
||||||
conn.setConnectTimeout(timeout);
|
|
||||||
conn.setReadTimeout(timeout);
|
|
||||||
|
|
||||||
if (body != null && !"".equals(body)) {
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
try (Writer out = new OutputStreamWriter(conn.getOutputStream())) {
|
|
||||||
out.write(body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStream in = conn.getInputStream(); ByteArrayOutputStream result = new ByteArrayOutputStream()) {
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int length;
|
|
||||||
while ((length = in.read(buffer)) != -1) {
|
|
||||||
result.write(buffer, 0, length);
|
|
||||||
}
|
|
||||||
return new Result(result.toString(StandardCharsets.UTF_8.name()), conn.getResponseCode());
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
conn.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Result {
|
|
||||||
private final String body;
|
|
||||||
private final int responseCode;
|
|
||||||
|
|
||||||
public Result(String body, int responseCode) {
|
|
||||||
this.body = body;
|
|
||||||
this.responseCode = responseCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBody() {
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getResponseCode() {
|
|
||||||
return responseCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class AsyncPutParameters {
|
|
||||||
public final String address;
|
|
||||||
public final String body;
|
|
||||||
public final CompletableFuture<Result> future;
|
|
||||||
public final long delay;
|
|
||||||
|
|
||||||
public AsyncPutParameters(String address, String body, long delay) {
|
|
||||||
this.address = address;
|
|
||||||
this.body = body;
|
|
||||||
this.future = new CompletableFuture<>();
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -89,8 +89,6 @@ public class HueBindingConstants {
|
|||||||
|
|
||||||
// Bridge config properties
|
// Bridge config properties
|
||||||
public static final String HOST = "ipAddress";
|
public static final String HOST = "ipAddress";
|
||||||
public static final String PORT = "port";
|
|
||||||
public static final String PROTOCOL = "protocol";
|
|
||||||
public static final String USER_NAME = "userName";
|
public static final String USER_NAME = "userName";
|
||||||
|
|
||||||
// Thing configuration properties
|
// Thing configuration properties
|
||||||
@ -102,4 +100,11 @@ public class HueBindingConstants {
|
|||||||
public static final String GROUP_ID = "groupId";
|
public static final String GROUP_ID = "groupId";
|
||||||
|
|
||||||
public static final String NORMALIZE_ID_REGEX = "[^a-zA-Z0-9_]";
|
public static final String NORMALIZE_ID_REGEX = "[^a-zA-Z0-9_]";
|
||||||
|
|
||||||
|
//
|
||||||
|
public static final String TEXT_OFFLINE_COMMUNICATION_ERROR = "@text/offline.communication-error";
|
||||||
|
public static final String TEXT_OFFLINE_CONFIGURATION_ERROR_INVALID_SSL_CERIFICATE = "@text/offline.conf-error-invalid-ssl-certificate";
|
||||||
|
|
||||||
|
// Config status messages
|
||||||
|
public static final String IP_ADDRESS_MISSING = "missing-ip-address-configuration";
|
||||||
}
|
}
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal;
|
|
||||||
|
|
||||||
import org.openhab.core.config.core.status.ConfigStatusMessage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link HueConfigStatusMessage} defines
|
|
||||||
* the keys to be used for {@link ConfigStatusMessage}s.
|
|
||||||
*
|
|
||||||
* @author Alexander Kostadinov - Initial contribution
|
|
||||||
* @author Kai Kreuzer - Changed from enum to interface
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public interface HueConfigStatusMessage {
|
|
||||||
|
|
||||||
static final String IP_ADDRESS_MISSING = "missing-ip-address-configuration";
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
|
||||||
*/
|
|
||||||
class PortalDiscoveryResult {
|
|
||||||
public static final Type GSON_TYPE = new TypeToken<List<PortalDiscoveryResult>>() {
|
|
||||||
}.getType();
|
|
||||||
|
|
||||||
private String internalipaddress;
|
|
||||||
|
|
||||||
public String getIPAddress() {
|
|
||||||
return internalipaddress;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal;
|
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Information about a scheduled command.
|
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
|
||||||
*/
|
|
||||||
public class ScheduleCommand {
|
|
||||||
private String address;
|
|
||||||
private String method;
|
|
||||||
private JsonElement body;
|
|
||||||
|
|
||||||
ScheduleCommand(String address, String method, JsonElement body) {
|
|
||||||
this.address = address;
|
|
||||||
this.method = method;
|
|
||||||
this.body = body;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the relative request url.
|
|
||||||
*
|
|
||||||
* @return request url
|
|
||||||
*/
|
|
||||||
public String getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request method.
|
|
||||||
* Can be GET, PUT, POST or DELETE.
|
|
||||||
*
|
|
||||||
* @return request method
|
|
||||||
*/
|
|
||||||
public String getMethod() {
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the request body.
|
|
||||||
*
|
|
||||||
* @return request body
|
|
||||||
*/
|
|
||||||
public String getBody() {
|
|
||||||
return body.toString();
|
|
||||||
}
|
|
||||||
}
|
|
@ -26,7 +26,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link LightActions} defines {@link ThingActions} for the hue lights.
|
* The {@link LightActions} defines {@link ThingActions} for the Hue lights.
|
||||||
*
|
*
|
||||||
* @author Jochen Leopold - Initial contribution
|
* @author Jochen Leopold - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@ -26,59 +26,16 @@ public class HueBridgeConfig {
|
|||||||
public static final String HTTP = "http";
|
public static final String HTTP = "http";
|
||||||
public static final String HTTPS = "https";
|
public static final String HTTPS = "https";
|
||||||
|
|
||||||
private @Nullable String ipAddress;
|
public @Nullable String ipAddress;
|
||||||
private @Nullable Integer port;
|
public @Nullable Integer port;
|
||||||
private String protocol = HTTP;
|
public String protocol = HTTPS;
|
||||||
private @Nullable String userName;
|
public boolean useSelfSignedCertificate = true;
|
||||||
private int pollingInterval = 10;
|
public @Nullable String userName;
|
||||||
private int sensorPollingInterval = 500;
|
public int pollingInterval = 10;
|
||||||
|
public int sensorPollingInterval = 500;
|
||||||
public @Nullable String getIpAddress() {
|
|
||||||
return ipAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIpAddress(String ipAddress) {
|
|
||||||
this.ipAddress = ipAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
Integer thePort = this.port;
|
Integer thePort = port;
|
||||||
return (thePort != null) ? thePort.intValue() : HTTPS.equals(protocol) ? 443 : 80;
|
return (thePort != null) ? thePort.intValue() : HTTPS.equals(protocol) ? 443 : 80;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPort(int port) {
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getProtocol() {
|
|
||||||
return protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProtocol(String protocol) {
|
|
||||||
this.protocol = protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable String getUserName() {
|
|
||||||
return userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUserName(String userName) {
|
|
||||||
this.userName = userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPollingInterval() {
|
|
||||||
return pollingInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPollingInterval(int pollingInterval) {
|
|
||||||
this.pollingInterval = pollingInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSensorPollingInterval() {
|
|
||||||
return sensorPollingInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSensorPollingInterval(int sensorPollingInterval) {
|
|
||||||
this.sensorPollingInterval = sensorPollingInterval;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.hue.internal.connection;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
import javax.net.ssl.X509ExtendedTrustManager;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.core.io.net.http.PEMTrustManager;
|
||||||
|
import org.openhab.core.io.net.http.PEMTrustManager.CertificateInstantiationException;
|
||||||
|
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
|
||||||
|
import org.openhab.core.io.net.http.TrustAllTrustManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a {@link PEMTrustManager} to allow secure connections to any Hue Bridge.
|
||||||
|
*
|
||||||
|
* @author Christoph Weitkamp - Initial Contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class HueTlsTrustManagerProvider implements TlsTrustManagerProvider {
|
||||||
|
|
||||||
|
private static final String PEM_FILENAME = "huebridge_cacert.pem";
|
||||||
|
private final String hostname;
|
||||||
|
private final boolean useSelfSignedCertificate;
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(HueTlsTrustManagerProvider.class);
|
||||||
|
|
||||||
|
public HueTlsTrustManagerProvider(String hostname, boolean useSelfSignedCertificate) {
|
||||||
|
this.hostname = hostname;
|
||||||
|
this.useSelfSignedCertificate = useSelfSignedCertificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHostName() {
|
||||||
|
return hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public X509ExtendedTrustManager getTrustManager() {
|
||||||
|
try {
|
||||||
|
if (useSelfSignedCertificate) {
|
||||||
|
logger.trace("Use self-signed certificate downloaded from Hue Bridge.");
|
||||||
|
// use self-signed certificate downloaded from Hue Bridge
|
||||||
|
return PEMTrustManager.getInstanceFromServer("https://" + getHostName());
|
||||||
|
} else {
|
||||||
|
logger.trace("Use Signify private CA Certificate for Hue Bridges from resources.");
|
||||||
|
// use Signify private CA Certificate for Hue Bridges from resources
|
||||||
|
return getInstanceFromResource(PEM_FILENAME);
|
||||||
|
}
|
||||||
|
} catch (CertificateException | MalformedURLException e) {
|
||||||
|
logger.error("An unexpected exception occurred - returning a TrustAllTrustManager: {}", e.getMessage(), e);
|
||||||
|
}
|
||||||
|
return TrustAllTrustManager.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link PEMTrustManager} instance by reading the PEM certificate from the given file.
|
||||||
|
* This is useful if you have a private CA Certificate stored in a file.
|
||||||
|
*
|
||||||
|
* @param fileName name to the PEM file located in the resources folder
|
||||||
|
* @return a {@link PEMTrustManager} instance
|
||||||
|
* @throws CertificateInstantiationException
|
||||||
|
*/
|
||||||
|
private PEMTrustManager getInstanceFromResource(String fileName) throws CertificateException {
|
||||||
|
String pemCert = readPEMCertificateStringFromResource(fileName);
|
||||||
|
if (pemCert != null) {
|
||||||
|
return new PEMTrustManager(pemCert);
|
||||||
|
}
|
||||||
|
throw new CertificateInstantiationException(
|
||||||
|
String.format("Certificate resource '%s' not found or not accessible.", fileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private @Nullable String readPEMCertificateStringFromResource(String fileName) {
|
||||||
|
URL resource = Thread.currentThread().getContextClassLoader().getResource(fileName);
|
||||||
|
if (resource != null) {
|
||||||
|
try (InputStream certInputStream = resource.openStream()) {
|
||||||
|
return new String(certInputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("An unexpected exception occurred: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -46,7 +46,7 @@ public class HueCommandExtension extends AbstractConsoleCommandExtension {
|
|||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
public HueCommandExtension(final @Reference ThingRegistry thingRegistry) {
|
public HueCommandExtension(final @Reference ThingRegistry thingRegistry) {
|
||||||
super("hue", "Interact with the hue binding.");
|
super("hue", "Interact with the Hue binding.");
|
||||||
this.thingRegistry = thingRegistry;
|
this.thingRegistry = thingRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ public class HueCommandExtension extends AbstractConsoleCommandExtension {
|
|||||||
console.println("No handler initialized for the thingUID '" + args[0] + "'");
|
console.println("No handler initialized for the thingUID '" + args[0] + "'");
|
||||||
printUsage(console);
|
printUsage(console);
|
||||||
} else if (bridgeHandler == null && groupHandler == null) {
|
} else if (bridgeHandler == null && groupHandler == null) {
|
||||||
console.println("'" + args[0] + "' is neither a Hue bridgeUID nor a Hue groupThingUID");
|
console.println("'" + args[0] + "' is neither a Hue BridgeUID nor a Hue groupThingUID");
|
||||||
printUsage(console);
|
printUsage(console);
|
||||||
} else {
|
} else {
|
||||||
switch (args[1]) {
|
switch (args[1]) {
|
||||||
@ -87,7 +87,7 @@ public class HueCommandExtension extends AbstractConsoleCommandExtension {
|
|||||||
String userName = bridgeHandler.getUserName();
|
String userName = bridgeHandler.getUserName();
|
||||||
console.println("Your user name is " + (userName != null ? userName : "undefined"));
|
console.println("Your user name is " + (userName != null ? userName : "undefined"));
|
||||||
} else {
|
} else {
|
||||||
console.println("'" + args[0] + "' is not a Hue bridgeUID");
|
console.println("'" + args[0] + "' is not a Hue BridgeUID");
|
||||||
printUsage(console);
|
printUsage(console);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal.discovery;
|
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
|
||||||
import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Dictionary;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
|
||||||
import org.jupnp.model.meta.DeviceDetails;
|
|
||||||
import org.jupnp.model.meta.ModelDetails;
|
|
||||||
import org.jupnp.model.meta.RemoteDevice;
|
|
||||||
import org.openhab.binding.hue.internal.HueBindingConstants;
|
|
||||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
|
||||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
|
||||||
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
|
|
||||||
import org.openhab.core.config.discovery.upnp.internal.UpnpDiscoveryService;
|
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
|
||||||
import org.openhab.core.thing.ThingUID;
|
|
||||||
import org.osgi.service.cm.Configuration;
|
|
||||||
import org.osgi.service.cm.ConfigurationAdmin;
|
|
||||||
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 HueBridgeDiscoveryParticipant} is responsible for discovering new and
|
|
||||||
* removed hue bridges. It uses the central {@link UpnpDiscoveryService}.
|
|
||||||
*
|
|
||||||
* @author Kai Kreuzer - Initial contribution
|
|
||||||
* @author Thomas Höfer - Added representation
|
|
||||||
*/
|
|
||||||
@NonNullByDefault
|
|
||||||
@Component(service = UpnpDiscoveryParticipant.class)
|
|
||||||
public class HueBridgeDiscoveryParticipant implements UpnpDiscoveryParticipant {
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(HueBridgeDiscoveryParticipant.class);
|
|
||||||
|
|
||||||
// Hue bridges have maxAge 100 seconds, so set the default grace period to half of that
|
|
||||||
private long removalGracePeriodSeconds = 50;
|
|
||||||
|
|
||||||
private final ConfigurationAdmin configAdmin;
|
|
||||||
|
|
||||||
@Activate
|
|
||||||
public HueBridgeDiscoveryParticipant(final @Reference ConfigurationAdmin configAdmin) {
|
|
||||||
this.configAdmin = configAdmin;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
|
||||||
return Collections.singleton(THING_TYPE_BRIDGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable DiscoveryResult createResult(RemoteDevice device) {
|
|
||||||
ThingUID uid = getThingUID(device);
|
|
||||||
if (uid != null) {
|
|
||||||
Map<String, Object> properties = new HashMap<>();
|
|
||||||
properties.put(HOST, device.getDetails().getBaseURL().getHost());
|
|
||||||
properties.put(PORT, device.getDetails().getBaseURL().getPort());
|
|
||||||
properties.put(PROTOCOL, device.getDetails().getBaseURL().getProtocol());
|
|
||||||
String serialNumber = device.getDetails().getSerialNumber();
|
|
||||||
DiscoveryResult result;
|
|
||||||
if (serialNumber != null && !serialNumber.isBlank()) {
|
|
||||||
properties.put(PROPERTY_SERIAL_NUMBER, serialNumber.toLowerCase());
|
|
||||||
|
|
||||||
result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
|
||||||
.withLabel(device.getDetails().getFriendlyName())
|
|
||||||
.withRepresentationProperty(PROPERTY_SERIAL_NUMBER).build();
|
|
||||||
} else {
|
|
||||||
result = DiscoveryResultBuilder.create(uid).withProperties(properties)
|
|
||||||
.withLabel(device.getDetails().getFriendlyName()).build();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable ThingUID getThingUID(RemoteDevice device) {
|
|
||||||
DeviceDetails details = device.getDetails();
|
|
||||||
if (details != null) {
|
|
||||||
ModelDetails modelDetails = details.getModelDetails();
|
|
||||||
String serialNumber = details.getSerialNumber();
|
|
||||||
if (modelDetails != null && serialNumber != null && !serialNumber.isBlank()) {
|
|
||||||
String modelName = modelDetails.getModelName();
|
|
||||||
if (modelName != null) {
|
|
||||||
if (modelName.startsWith("Philips hue bridge")) {
|
|
||||||
return new ThingUID(THING_TYPE_BRIDGE, serialNumber.toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getRemovalGracePeriodSeconds(RemoteDevice device) {
|
|
||||||
try {
|
|
||||||
Configuration conf = configAdmin.getConfiguration("binding.hue");
|
|
||||||
Dictionary<String, @Nullable Object> properties = conf.getProperties();
|
|
||||||
if (properties != null) {
|
|
||||||
Object property = properties.get(HueBindingConstants.REMOVAL_GRACE_PERIOD);
|
|
||||||
if (property != null) {
|
|
||||||
removalGracePeriodSeconds = Long.parseLong(property.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException | IllegalStateException | NumberFormatException e) {
|
|
||||||
// fall through to pre-initialised (default) value
|
|
||||||
}
|
|
||||||
logger.trace("getRemovalGracePeriodSeconds={}", removalGracePeriodSeconds);
|
|
||||||
return removalGracePeriodSeconds;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.hue.internal.discovery;
|
||||||
|
|
||||||
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
|
||||||
|
import java.util.Dictionary;
|
||||||
|
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.hue.internal.handler.HueBridgeHandler;
|
||||||
|
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.config.discovery.mdns.internal.MDNSDiscoveryService;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
|
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.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link HueBridgeMDNSDiscoveryParticipant} is responsible for discovering new and removed Hue Bridges. It uses the
|
||||||
|
* central {@link MDNSDiscoveryService}.
|
||||||
|
*
|
||||||
|
* @author Kai Kreuzer - Initial contribution
|
||||||
|
* @author Thomas Höfer - Added representation
|
||||||
|
* @author Christoph Weitkamp - Change discovery protocol to mDNS
|
||||||
|
*/
|
||||||
|
@Component(configurationPid = "discovery.hue")
|
||||||
|
@NonNullByDefault
|
||||||
|
public class HueBridgeMDNSDiscoveryParticipant implements MDNSDiscoveryParticipant {
|
||||||
|
|
||||||
|
private static final String SERVICE_TYPE = "_hue._tcp.local.";
|
||||||
|
private static final String MDNS_PROPERTY_BRIDGE_ID = "bridgeid";
|
||||||
|
private static final String MDNS_PROPERTY_MODEL_ID = "modelid";
|
||||||
|
|
||||||
|
private static final String CONFIG_PROPERTY_REMOVAL_GRACE_PERIOD = "removalGracePeriod";
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(HueBridgeMDNSDiscoveryParticipant.class);
|
||||||
|
|
||||||
|
private long removalGracePeriod = 0L;
|
||||||
|
|
||||||
|
private boolean isAutoDiscoveryEnabled = true;
|
||||||
|
|
||||||
|
@Activate
|
||||||
|
protected void activate(ComponentContext componentContext) {
|
||||||
|
activateOrModifyService(componentContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Modified
|
||||||
|
protected void modified(ComponentContext componentContext) {
|
||||||
|
activateOrModifyService(componentContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void activateOrModifyService(ComponentContext componentContext) {
|
||||||
|
Dictionary<String, @Nullable Object> properties = componentContext.getProperties();
|
||||||
|
String autoDiscoveryPropertyValue = (String) properties
|
||||||
|
.get(DiscoveryService.CONFIG_PROPERTY_BACKGROUND_DISCOVERY);
|
||||||
|
if (autoDiscoveryPropertyValue != null && !autoDiscoveryPropertyValue.isBlank()) {
|
||||||
|
isAutoDiscoveryEnabled = Boolean.valueOf(autoDiscoveryPropertyValue);
|
||||||
|
}
|
||||||
|
String removalGracePeriodPropertyValue = (String) properties.get(CONFIG_PROPERTY_REMOVAL_GRACE_PERIOD);
|
||||||
|
if (removalGracePeriodPropertyValue != null && !removalGracePeriodPropertyValue.isBlank()) {
|
||||||
|
try {
|
||||||
|
removalGracePeriod = Long.parseLong(removalGracePeriodPropertyValue);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
logger.warn("Configuration property '{}' has invalid value: {}", CONFIG_PROPERTY_REMOVAL_GRACE_PERIOD,
|
||||||
|
removalGracePeriodPropertyValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<ThingTypeUID> getSupportedThingTypeUIDs() {
|
||||||
|
return HueBridgeHandler.SUPPORTED_THING_TYPES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getServiceType() {
|
||||||
|
return SERVICE_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable DiscoveryResult createResult(ServiceInfo service) {
|
||||||
|
if (isAutoDiscoveryEnabled) {
|
||||||
|
ThingUID uid = getThingUID(service);
|
||||||
|
if (uid != null) {
|
||||||
|
String host = service.getHostAddresses()[0];
|
||||||
|
String id = service.getPropertyString(MDNS_PROPERTY_BRIDGE_ID);
|
||||||
|
String friendlyName = String.format("%s (%s)", service.getName(), host);
|
||||||
|
return DiscoveryResultBuilder.create(uid) //
|
||||||
|
.withProperties(Map.of( //
|
||||||
|
HOST, host, //
|
||||||
|
Thing.PROPERTY_MODEL_ID, service.getPropertyString(MDNS_PROPERTY_MODEL_ID), //
|
||||||
|
Thing.PROPERTY_SERIAL_NUMBER, id.toLowerCase())) //
|
||||||
|
.withLabel(friendlyName) //
|
||||||
|
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER) //
|
||||||
|
.withTTL(120L) //
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ThingUID getThingUID(ServiceInfo service) {
|
||||||
|
String id = service.getPropertyString(MDNS_PROPERTY_BRIDGE_ID);
|
||||||
|
if (id != null && !id.isBlank()) {
|
||||||
|
return new ThingUID(THING_TYPE_BRIDGE, id.toLowerCase());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getRemovalGracePeriodSeconds(ServiceInfo service) {
|
||||||
|
return removalGracePeriod;
|
||||||
|
}
|
||||||
|
}
|
@ -13,25 +13,21 @@
|
|||||||
package org.openhab.binding.hue.internal.discovery;
|
package org.openhab.binding.hue.internal.discovery;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||||
import org.openhab.core.config.discovery.DiscoveryService;
|
import org.openhab.core.config.discovery.DiscoveryService;
|
||||||
import org.openhab.core.io.net.http.HttpUtil;
|
import org.openhab.core.io.net.http.HttpUtil;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
import org.osgi.service.component.annotations.Component;
|
import org.osgi.service.component.annotations.Component;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -42,37 +38,29 @@ import com.google.gson.JsonParseException;
|
|||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HueBridgeNupnpDiscovery} is responsible for discovering new hue bridges. It uses the 'NUPnP service
|
* The {@link HueBridgeNupnpDiscovery} is responsible for discovering new Hue Bridges. It uses the 'NUPnP service
|
||||||
* provided by Philips'.
|
* provided by Philips'.
|
||||||
*
|
*
|
||||||
* @author Awelkiyar Wehabrebi - Initial contribution
|
* @author Awelkiyar Wehabrebi - Initial contribution
|
||||||
* @author Christoph Knauf - Refactorings
|
* @author Christoph Knauf - Refactorings
|
||||||
* @author Andre Fuechsel - make {@link #startScan()} asynchronous
|
* @author Andre Fuechsel - make {@link #startScan()} asynchronous
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
|
||||||
@Component(service = DiscoveryService.class, configurationPid = "discovery.hue")
|
@Component(service = DiscoveryService.class, configurationPid = "discovery.hue")
|
||||||
|
@NonNullByDefault
|
||||||
public class HueBridgeNupnpDiscovery extends AbstractDiscoveryService {
|
public class HueBridgeNupnpDiscovery extends AbstractDiscoveryService {
|
||||||
|
|
||||||
private static final String MODEL_NAME_PHILIPS_HUE = "<modelName>Philips hue";
|
private static final String MODEL_NAME_PHILIPS_HUE = "\"name\":\"Philips Hue\"";
|
||||||
|
|
||||||
protected static final String BRIDGE_INDICATOR = "fffe";
|
protected static final String BRIDGE_INDICATOR = "fffe";
|
||||||
|
|
||||||
private static final String DISCOVERY_URL = "https://discovery.meethue.com/";
|
private static final String DISCOVERY_URL = "https://discovery.meethue.com/";
|
||||||
|
protected static final String LABEL_PATTERN = "Philips Hue (%s)";
|
||||||
protected static final String LABEL_PATTERN = "Philips hue (IP)";
|
private static final String CONFIG_URL_PATTERN = "http://%s/api/0/config";
|
||||||
|
|
||||||
private static final String DESC_URL_PATTERN = "http://HOST/description.xml";
|
|
||||||
|
|
||||||
private static final int REQUEST_TIMEOUT = 5000;
|
private static final int REQUEST_TIMEOUT = 5000;
|
||||||
|
|
||||||
private static final int DISCOVERY_TIMEOUT = 10;
|
private static final int DISCOVERY_TIMEOUT = 10;
|
||||||
|
|
||||||
private static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BRIDGE);
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(HueBridgeNupnpDiscovery.class);
|
private final Logger logger = LoggerFactory.getLogger(HueBridgeNupnpDiscovery.class);
|
||||||
|
|
||||||
public HueBridgeNupnpDiscovery() {
|
public HueBridgeNupnpDiscovery() {
|
||||||
super(SUPPORTED_THING_TYPES, DISCOVERY_TIMEOUT, false);
|
super(HueBridgeHandler.SUPPORTED_THING_TYPES, DISCOVERY_TIMEOUT, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -87,37 +75,25 @@ public class HueBridgeNupnpDiscovery extends AbstractDiscoveryService {
|
|||||||
for (BridgeJsonParameters bridge : getBridgeList()) {
|
for (BridgeJsonParameters bridge : getBridgeList()) {
|
||||||
if (isReachableAndValidHueBridge(bridge)) {
|
if (isReachableAndValidHueBridge(bridge)) {
|
||||||
String host = bridge.getInternalIpAddress();
|
String host = bridge.getInternalIpAddress();
|
||||||
String serialNumber = bridge.getId().substring(0, 6) + bridge.getId().substring(10);
|
String serialNumber = bridge.getId().toLowerCase();
|
||||||
serialNumber = serialNumber.toLowerCase();
|
|
||||||
ThingUID uid = new ThingUID(THING_TYPE_BRIDGE, serialNumber);
|
ThingUID uid = new ThingUID(THING_TYPE_BRIDGE, serialNumber);
|
||||||
DiscoveryResult result = DiscoveryResultBuilder.create(uid)
|
DiscoveryResult result = DiscoveryResultBuilder.create(uid) //
|
||||||
.withProperties(buildProperties(host, serialNumber))
|
.withProperties(Map.of( //
|
||||||
.withLabel(LABEL_PATTERN.replace("IP", host)).withRepresentationProperty(PROPERTY_SERIAL_NUMBER)
|
HOST, host, //
|
||||||
|
Thing.PROPERTY_SERIAL_NUMBER, serialNumber)) //
|
||||||
|
.withLabel(String.format(LABEL_PATTERN, host)) //
|
||||||
|
.withRepresentationProperty(Thing.PROPERTY_SERIAL_NUMBER) //
|
||||||
.build();
|
.build();
|
||||||
thingDiscovered(result);
|
thingDiscovered(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the bridge properties.
|
|
||||||
*
|
|
||||||
* @param host the ip of the bridge
|
|
||||||
* @param serialNumber the id of the bridge
|
|
||||||
* @return the bridge properties
|
|
||||||
*/
|
|
||||||
private Map<String, Object> buildProperties(String host, String serialNumber) {
|
|
||||||
Map<String, Object> properties = new HashMap<>(2);
|
|
||||||
properties.put(HOST, host);
|
|
||||||
properties.put(PROPERTY_SERIAL_NUMBER, serialNumber);
|
|
||||||
return properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the Bridge is a reachable Hue Bridge with a valid id.
|
* Checks if the Bridge is a reachable Hue Bridge with a valid id.
|
||||||
*
|
*
|
||||||
* @param bridge the {@link BridgeJsonParameters}s
|
* @param bridge the {@link BridgeJsonParameters}s
|
||||||
* @return true if Bridge is a reachable Hue Bridge with a id containing
|
* @return true if Hue Bridge is a reachable Hue Bridge with a id containing
|
||||||
* BRIDGE_INDICATOR longer then 10
|
* BRIDGE_INDICATOR longer then 10
|
||||||
*/
|
*/
|
||||||
private boolean isReachableAndValidHueBridge(BridgeJsonParameters bridge) {
|
private boolean isReachableAndValidHueBridge(BridgeJsonParameters bridge) {
|
||||||
@ -136,14 +112,14 @@ public class HueBridgeNupnpDiscovery extends AbstractDiscoveryService {
|
|||||||
logger.debug("Bridge not discovered: id {} is shorter then 10.", id);
|
logger.debug("Bridge not discovered: id {} is shorter then 10.", id);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!id.substring(6, 10).equals(BRIDGE_INDICATOR)) {
|
if (!BRIDGE_INDICATOR.equals(id.substring(6, 10))) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Bridge not discovered: id {} does not contain bridge indicator {} or its at the wrong position.",
|
"Bridge not discovered: id {} does not contain bridge indicator {} or its at the wrong position.",
|
||||||
id, BRIDGE_INDICATOR);
|
id, BRIDGE_INDICATOR);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
description = doGetRequest(DESC_URL_PATTERN.replace("HOST", host));
|
description = doGetRequest(String.format(CONFIG_URL_PATTERN, host));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.debug("Bridge not discovered: Failure accessing description file for ip: {}", host);
|
logger.debug("Bridge not discovered: Failure accessing description file for ip: {}", host);
|
||||||
return false;
|
return false;
|
||||||
@ -170,10 +146,10 @@ public class HueBridgeNupnpDiscovery extends AbstractDiscoveryService {
|
|||||||
return Objects.requireNonNull(bridgeParameters);
|
return Objects.requireNonNull(bridgeParameters);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.debug("Philips Hue NUPnP service not reachable. Can't discover bridges");
|
logger.debug("Philips Hue NUPnP service not reachable. Can't discover bridges");
|
||||||
} catch (JsonParseException je) {
|
} catch (JsonParseException e) {
|
||||||
logger.debug("Invalid json respone from Hue NUPnP service. Can't discover bridges");
|
logger.debug("Invalid json respone from Hue NUPnP service. Can't discover bridges");
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +15,6 @@ package org.openhab.binding.hue.internal.discovery;
|
|||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
|
||||||
import java.util.AbstractMap.SimpleEntry;
|
import java.util.AbstractMap.SimpleEntry;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -26,10 +25,10 @@ import java.util.stream.Stream;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.FullGroup;
|
import org.openhab.binding.hue.internal.dto.FullGroup;
|
||||||
import org.openhab.binding.hue.internal.FullHueObject;
|
import org.openhab.binding.hue.internal.dto.FullHueObject;
|
||||||
import org.openhab.binding.hue.internal.FullLight;
|
import org.openhab.binding.hue.internal.dto.FullLight;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||||
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
|
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
|
||||||
import org.openhab.binding.hue.internal.handler.HueLightHandler;
|
import org.openhab.binding.hue.internal.handler.HueLightHandler;
|
||||||
@ -43,7 +42,6 @@ import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler;
|
|||||||
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
import org.openhab.core.config.discovery.AbstractDiscoveryService;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
import org.openhab.core.config.discovery.DiscoveryResultBuilder;
|
||||||
import org.openhab.core.config.discovery.DiscoveryService;
|
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
@ -53,8 +51,8 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HueBridgeServiceTracker} tracks for hue lights, sensors and groups which are connected
|
* The {@link HueBridgeServiceTracker} tracks for Hue lights, sensors and groups which are connected
|
||||||
* to a paired hue bridge. The default search time for hue is 60 seconds.
|
* to a paired Hue Bridge. The default search time for Hue is 60 seconds.
|
||||||
*
|
*
|
||||||
* @author Kai Kreuzer - Initial contribution
|
* @author Kai Kreuzer - Initial contribution
|
||||||
* @author Andre Fuechsel - changed search timeout, changed discovery result creation to support generic thing types;
|
* @author Andre Fuechsel - changed search timeout, changed discovery result creation to support generic thing types;
|
||||||
@ -67,16 +65,15 @@ import org.slf4j.LoggerFactory;
|
|||||||
* @author Laurent Garnier - Added support for groups
|
* @author Laurent Garnier - Added support for groups
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class HueDeviceDiscoveryService extends AbstractDiscoveryService
|
public class HueDeviceDiscoveryService extends AbstractDiscoveryService implements ThingHandlerService {
|
||||||
implements DiscoveryService, ThingHandlerService {
|
|
||||||
|
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.unmodifiableSet(Stream
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream
|
||||||
.of(HueLightHandler.SUPPORTED_THING_TYPES.stream(), DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(),
|
.of(HueLightHandler.SUPPORTED_THING_TYPES.stream(), DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
TapSwitchHandler.SUPPORTED_THING_TYPES.stream(), PresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
TapSwitchHandler.SUPPORTED_THING_TYPES.stream(), PresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
GeofencePresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
GeofencePresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
TemperatureHandler.SUPPORTED_THING_TYPES.stream(), LightLevelHandler.SUPPORTED_THING_TYPES.stream(),
|
TemperatureHandler.SUPPORTED_THING_TYPES.stream(), LightLevelHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
ClipHandler.SUPPORTED_THING_TYPES.stream(), HueGroupHandler.SUPPORTED_THING_TYPES.stream())
|
ClipHandler.SUPPORTED_THING_TYPES.stream(), HueGroupHandler.SUPPORTED_THING_TYPES.stream())
|
||||||
.flatMap(i -> i).collect(Collectors.toSet()));
|
.flatMap(i -> i).collect(Collectors.toUnmodifiableSet());
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
private static final Map<String, String> TYPE_TO_ZIGBEE_ID_MAP = Map.ofEntries(
|
private static final Map<String, String> TYPE_TO_ZIGBEE_ID_MAP = Map.ofEntries(
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
@ -18,9 +18,12 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
* @author Samuel Leisering - Initial contribution
|
* @author Samuel Leisering - Initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class ApiVersionUtils {
|
public final class ApiVersionUtils {
|
||||||
|
|
||||||
private static ApiVersion fullLights = new ApiVersion(1, 11, 0);
|
private static final ApiVersion FULL_LIGHTS = new ApiVersion(1, 11, 0);
|
||||||
|
|
||||||
|
ApiVersionUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starting from version 1.11, <code>GET</code>ing the Lights always returns {@link FullLight}s instead of
|
* Starting from version 1.11, <code>GET</code>ing the Lights always returns {@link FullLight}s instead of
|
||||||
@ -29,6 +32,6 @@ public class ApiVersionUtils {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static boolean supportsFullLights(ApiVersion version) {
|
public static boolean supportsFullLights(ApiVersion version) {
|
||||||
return fullLights.compare(version) <= 0;
|
return FULL_LIGHTS.compare(version) <= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of updates to the bridge configuration.
|
* Collection of updates to the bridge configuration.
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
@ -21,8 +21,8 @@ import com.google.gson.Gson;
|
|||||||
* @author Samuel Leisering - changed Command visibility to public
|
* @author Samuel Leisering - changed Command visibility to public
|
||||||
*/
|
*/
|
||||||
public class Command {
|
public class Command {
|
||||||
String key;
|
public String key;
|
||||||
Object value;
|
public Object value;
|
||||||
|
|
||||||
public Command(String key, Object value) {
|
public Command(String key, Object value) {
|
||||||
this.key = key;
|
this.key = key;
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import static java.util.stream.Collectors.joining;
|
import static java.util.stream.Collectors.joining;
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ import java.util.ArrayList;
|
|||||||
*/
|
*/
|
||||||
public class ConfigUpdate {
|
public class ConfigUpdate {
|
||||||
|
|
||||||
protected final ArrayList<Command> commands = new ArrayList<>();
|
public final ArrayList<Command> commands = new ArrayList<>();
|
||||||
|
|
||||||
public ConfigUpdate() {
|
public ConfigUpdate() {
|
||||||
super();
|
super();
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -18,7 +18,7 @@ package org.openhab.binding.hue.internal;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
class CreateUserRequest {
|
public class CreateUserRequest {
|
||||||
private String username;
|
private String username;
|
||||||
private String devicetype;
|
private String devicetype;
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -18,11 +18,10 @@ import java.util.List;
|
|||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
* @author Q42 - Initial contribution
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
class ErrorResponse {
|
public class ErrorResponse {
|
||||||
public static final Type GSON_TYPE = new TypeToken<List<ErrorResponse>>() {
|
public static final Type GSON_TYPE = new TypeToken<List<ErrorResponse>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -40,7 +40,7 @@ public class FullGroup extends Group {
|
|||||||
/**
|
/**
|
||||||
* Test constructor
|
* Test constructor
|
||||||
*/
|
*/
|
||||||
FullGroup(String id, String name, String type, State action, List<String> lights, State state) {
|
public FullGroup(String id, String name, String type, State action, List<String> lights, State state) {
|
||||||
super(id, name, type);
|
super(id, name, type);
|
||||||
this.action = action;
|
this.action = action;
|
||||||
this.lights = lights;
|
this.lights = lights;
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.NORMALIZE_ID_REGEX;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.NORMALIZE_ID_REGEX;
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detailed information about an object on the hue bridge
|
* Detailed information about an object on the Hue Bridge
|
||||||
*
|
*
|
||||||
* @author Samuel Leisering - Initial contribution
|
* @author Samuel Leisering - Initial contribution
|
||||||
* @author Christoph Weitkamp - Initial contribution
|
* @author Christoph Weitkamp - Initial contribution
|
||||||
@ -53,7 +53,7 @@ public class FullHueObject extends HueObject {
|
|||||||
/**
|
/**
|
||||||
* Set the type of the object.
|
* Set the type of the object.
|
||||||
*/
|
*/
|
||||||
protected void setType(final String type) {
|
public void setType(final String type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ public class FullHueObject extends HueObject {
|
|||||||
/**
|
/**
|
||||||
* Set the model ID of the object.
|
* Set the model ID of the object.
|
||||||
*/
|
*/
|
||||||
protected void setModelID(final String modelId) {
|
public void setModelID(final String modelId) {
|
||||||
this.modelid = modelId;
|
this.modelid = modelId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +115,7 @@ public class FullHueObject extends HueObject {
|
|||||||
/**
|
/**
|
||||||
* Sets the unique id of the object.
|
* Sets the unique id of the object.
|
||||||
*/
|
*/
|
||||||
protected void setUniqueID(final String uniqueid) {
|
public void setUniqueID(final String uniqueid) {
|
||||||
this.uniqueid = uniqueid;
|
this.uniqueid = uniqueid;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@ -18,7 +18,6 @@ import java.util.Map;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.dto.Capabilities;
|
|
||||||
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic group information.
|
* Basic group information.
|
||||||
@ -24,7 +24,7 @@ public class Group {
|
|||||||
private String name;
|
private String name;
|
||||||
private String type;
|
private String type;
|
||||||
|
|
||||||
Group() {
|
public Group() {
|
||||||
this.id = "0";
|
this.id = "0";
|
||||||
this.name = "Lightset 0";
|
this.name = "Lightset 0";
|
||||||
this.type = "LightGroup";
|
this.type = "LightGroup";
|
||||||
@ -39,11 +39,11 @@ public class Group {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setName(String name) {
|
public void setName(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setId(String id) {
|
public void setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -34,7 +34,7 @@ public class HueObject {
|
|||||||
HueObject() {
|
HueObject() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setId(String id) {
|
public void setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
@ -10,9 +10,9 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
import static org.openhab.binding.hue.internal.dto.FullSensor.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the configuration of a light level sensor
|
* Updates the configuration of a light level sensor
|
@ -10,13 +10,12 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
* @author Q42 - Initial contribution
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
class NewLightsResponse {
|
public class NewLightsResponse {
|
||||||
public String lastscan;
|
public String lastscan;
|
||||||
}
|
}
|
@ -10,9 +10,9 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
import static org.openhab.binding.hue.internal.dto.FullSensor.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the configuration of a presence sensor
|
* Updates the configuration of a presence sensor
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -51,7 +51,7 @@ public class Scene {
|
|||||||
/**
|
/**
|
||||||
* Test constructor
|
* Test constructor
|
||||||
*/
|
*/
|
||||||
Scene(String id, String name, @Nullable String groupId, List<String> lightIds, boolean recycle) {
|
public Scene(String id, String name, @Nullable String groupId, List<String> lightIds, boolean recycle) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
@ -63,7 +63,7 @@ public class Scene {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setId(String id) {
|
public void setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -30,7 +30,7 @@ public class Schedule {
|
|||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
void setId(String id) {
|
public void setId(String id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ import java.util.List;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
class SearchForLightsRequest {
|
public class SearchForLightsRequest {
|
||||||
private List<String> deviceid;
|
private List<String> deviceid;
|
||||||
|
|
||||||
public SearchForLightsRequest(List<String> deviceid) {
|
public SearchForLightsRequest(List<String> deviceid) {
|
@ -10,9 +10,9 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.CONFIG_ON;
|
import static org.openhab.binding.hue.internal.dto.FullSensor.CONFIG_ON;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of updates to the sensor configuration.
|
* Collection of updates to the sensor configuration.
|
@ -10,9 +10,13 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -20,9 +24,10 @@ import java.util.List;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
class SetAttributesRequest {
|
@NonNullByDefault
|
||||||
private String name;
|
public class SetAttributesRequest {
|
||||||
private List<String> lights;
|
private final @Nullable String name;
|
||||||
|
private final @Nullable List<String> lights;
|
||||||
|
|
||||||
public SetAttributesRequest(String name) {
|
public SetAttributesRequest(String name) {
|
||||||
this(name, null);
|
this(name, null);
|
||||||
@ -32,7 +37,7 @@ class SetAttributesRequest {
|
|||||||
this(null, lights);
|
this(null, lights);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SetAttributesRequest(String name, List<HueObject> lights) {
|
public SetAttributesRequest(@Nullable String name, @Nullable List<HueObject> lights) {
|
||||||
if (name != null && Util.stringSize(name) > 32) {
|
if (name != null && Util.stringSize(name) > 32) {
|
||||||
throw new IllegalArgumentException("Name can be at most 32 characters long");
|
throw new IllegalArgumentException("Name can be at most 32 characters long");
|
||||||
} else if (lights != null && (lights.isEmpty() || lights.size() > 16)) {
|
} else if (lights != null && (lights.isEmpty() || lights.size() > 16)) {
|
||||||
@ -40,8 +45,6 @@ class SetAttributesRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
if (lights != null) {
|
this.lights = lights == null ? null : lights.stream().map(l -> l.getId()).collect(Collectors.toList());
|
||||||
this.lights = Util.lightsToIds(lights);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Details of a bridge firmware update.
|
* Details of a bridge firmware update.
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@ -23,14 +23,14 @@ import java.util.Arrays;
|
|||||||
*/
|
*/
|
||||||
public class State {
|
public class State {
|
||||||
private boolean on;
|
private boolean on;
|
||||||
int bri;
|
public int bri;
|
||||||
int hue;
|
public int hue;
|
||||||
int sat;
|
public int sat;
|
||||||
private float[] xy;
|
private float[] xy;
|
||||||
int ct;
|
public int ct;
|
||||||
private String alert;
|
private String alert;
|
||||||
private String effect;
|
private String effect;
|
||||||
String colormode;
|
public String colormode;
|
||||||
private boolean reachable;
|
private boolean reachable;
|
||||||
|
|
||||||
public State() {
|
public State() {
|
@ -10,11 +10,10 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import org.openhab.binding.hue.internal.State.AlertMode;
|
import org.openhab.binding.hue.internal.dto.State.AlertMode;
|
||||||
import org.openhab.binding.hue.internal.State.Effect;
|
import org.openhab.binding.hue.internal.dto.State.Effect;
|
||||||
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collection of updates to the state of a light.
|
* Collection of updates to the state of a light.
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -19,11 +19,10 @@ import java.util.Map;
|
|||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
* @author Q42 - Initial contribution
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
class SuccessResponse {
|
public class SuccessResponse {
|
||||||
public static final Type GSON_TYPE = new TypeToken<List<SuccessResponse>>() {
|
public static final Type GSON_TYPE = new TypeToken<List<SuccessResponse>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
|
|
@ -10,9 +10,9 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.CONFIG_LED_INDICATION;
|
import static org.openhab.binding.hue.internal.dto.FullSensor.CONFIG_LED_INDICATION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the configuration of a temperature sensor
|
* Updates the configuration of a temperature sensor
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
@ -10,11 +10,9 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.dto;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -22,12 +20,12 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Q42 - Initial contribution
|
* @author Q42 - Initial contribution
|
||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
class Util {
|
public final class Util {
|
||||||
|
|
||||||
private Util() {
|
private Util() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,28 +34,6 @@ class Util {
|
|||||||
return str.getBytes(StandardCharsets.UTF_8).length;
|
return str.getBytes(StandardCharsets.UTF_8).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<HueObject> idsToLights(List<String> ids) {
|
|
||||||
List<HueObject> lights = new ArrayList<>();
|
|
||||||
|
|
||||||
for (String id : ids) {
|
|
||||||
HueObject light = new HueObject();
|
|
||||||
light.setId(id);
|
|
||||||
lights.add(light);
|
|
||||||
}
|
|
||||||
|
|
||||||
return lights;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> lightsToIds(List<HueObject> lights) {
|
|
||||||
List<String> ids = new ArrayList<>();
|
|
||||||
|
|
||||||
for (HueObject light : lights) {
|
|
||||||
ids.add(light.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @Nullable String quickMatch(String needle, String haystack) {
|
public static @Nullable String quickMatch(String needle, String haystack) {
|
||||||
Matcher m = Pattern.compile(needle).matcher(haystack);
|
Matcher m = Pattern.compile(needle).matcher(haystack);
|
||||||
m.find();
|
m.find();
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.exceptions;
|
package org.openhab.binding.hue.internal.exceptions;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when the API returns an unknown error.
|
* Thrown when the API returns an unknown error.
|
||||||
*
|
*
|
||||||
@ -19,6 +21,7 @@ package org.openhab.binding.hue.internal.exceptions;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@NonNullByDefault
|
||||||
public class ApiException extends Exception {
|
public class ApiException extends Exception {
|
||||||
public ApiException() {
|
public ApiException() {
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.exceptions;
|
package org.openhab.binding.hue.internal.exceptions;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when trying to change the state of a light that is off.
|
* Thrown when trying to change the state of a light that is off.
|
||||||
*
|
*
|
||||||
@ -19,6 +21,7 @@ package org.openhab.binding.hue.internal.exceptions;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@NonNullByDefault
|
||||||
public class DeviceOffException extends ApiException {
|
public class DeviceOffException extends ApiException {
|
||||||
public DeviceOffException() {
|
public DeviceOffException() {
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.exceptions;
|
package org.openhab.binding.hue.internal.exceptions;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when operating on a group, light or user that doesn't exist.
|
* Thrown when operating on a group, light or user that doesn't exist.
|
||||||
*
|
*
|
||||||
@ -19,6 +21,7 @@ package org.openhab.binding.hue.internal.exceptions;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@NonNullByDefault
|
||||||
public class EntityNotAvailableException extends ApiException {
|
public class EntityNotAvailableException extends ApiException {
|
||||||
public EntityNotAvailableException() {
|
public EntityNotAvailableException() {
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.exceptions;
|
package org.openhab.binding.hue.internal.exceptions;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when adding more than 16 groups (excluding all lights group) to a bridge.
|
* Thrown when adding more than 16 groups (excluding all lights group) to a bridge.
|
||||||
*
|
*
|
||||||
@ -19,6 +21,7 @@ package org.openhab.binding.hue.internal.exceptions;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@NonNullByDefault
|
||||||
public class GroupTableFullException extends ApiException {
|
public class GroupTableFullException extends ApiException {
|
||||||
public GroupTableFullException() {
|
public GroupTableFullException() {
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.exceptions;
|
package org.openhab.binding.hue.internal.exceptions;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when scheduling an invalid command.
|
* Thrown when scheduling an invalid command.
|
||||||
*
|
*
|
||||||
@ -19,6 +21,7 @@ package org.openhab.binding.hue.internal.exceptions;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@NonNullByDefault
|
||||||
public class InvalidCommandException extends ApiException {
|
public class InvalidCommandException extends ApiException {
|
||||||
public InvalidCommandException() {
|
public InvalidCommandException() {
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.exceptions;
|
package org.openhab.binding.hue.internal.exceptions;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown if the link button hasn't been pressed in the last 30 seconds.
|
* Thrown if the link button hasn't been pressed in the last 30 seconds.
|
||||||
*
|
*
|
||||||
@ -19,6 +21,7 @@ package org.openhab.binding.hue.internal.exceptions;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@NonNullByDefault
|
||||||
public class LinkButtonException extends ApiException {
|
public class LinkButtonException extends ApiException {
|
||||||
public LinkButtonException() {
|
public LinkButtonException() {
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.exceptions;
|
package org.openhab.binding.hue.internal.exceptions;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when the specified user is no longer whitelisted on the bridge.
|
* Thrown when the specified user is no longer whitelisted on the bridge.
|
||||||
*
|
*
|
||||||
@ -19,6 +21,7 @@ package org.openhab.binding.hue.internal.exceptions;
|
|||||||
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
* @author Denis Dudnik - moved Jue library source code inside the smarthome Hue binding
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
|
@NonNullByDefault
|
||||||
public class UnauthorizedException extends ApiException {
|
public class UnauthorizedException extends ApiException {
|
||||||
public UnauthorizedException() {
|
public UnauthorizedException() {
|
||||||
}
|
}
|
||||||
|
@ -10,17 +10,17 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal.factory;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||||
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
|
import org.openhab.binding.hue.internal.handler.HueGroupHandler;
|
||||||
import org.openhab.binding.hue.internal.handler.HueLightHandler;
|
import org.openhab.binding.hue.internal.handler.HueLightHandler;
|
||||||
@ -35,6 +35,7 @@ import org.openhab.binding.hue.internal.handler.sensors.TemperatureHandler;
|
|||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.i18n.LocaleProvider;
|
import org.openhab.core.i18n.LocaleProvider;
|
||||||
import org.openhab.core.i18n.TranslationProvider;
|
import org.openhab.core.i18n.TranslationProvider;
|
||||||
|
import org.openhab.core.io.net.http.HttpClientFactory;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
@ -60,22 +61,25 @@ import org.osgi.service.component.annotations.Reference;
|
|||||||
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.hue")
|
@Component(service = ThingHandlerFactory.class, configurationPid = "binding.hue")
|
||||||
public class HueThingHandlerFactory extends BaseThingHandlerFactory {
|
public class HueThingHandlerFactory extends BaseThingHandlerFactory {
|
||||||
|
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.unmodifiableSet(Stream
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream
|
||||||
.of(HueBridgeHandler.SUPPORTED_THING_TYPES.stream(), HueLightHandler.SUPPORTED_THING_TYPES.stream(),
|
.of(HueBridgeHandler.SUPPORTED_THING_TYPES.stream(), HueLightHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(), TapSwitchHandler.SUPPORTED_THING_TYPES.stream(),
|
DimmerSwitchHandler.SUPPORTED_THING_TYPES.stream(), TapSwitchHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
PresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
PresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
GeofencePresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
GeofencePresenceHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
TemperatureHandler.SUPPORTED_THING_TYPES.stream(), LightLevelHandler.SUPPORTED_THING_TYPES.stream(),
|
TemperatureHandler.SUPPORTED_THING_TYPES.stream(), LightLevelHandler.SUPPORTED_THING_TYPES.stream(),
|
||||||
ClipHandler.SUPPORTED_THING_TYPES.stream(), HueGroupHandler.SUPPORTED_THING_TYPES.stream())
|
ClipHandler.SUPPORTED_THING_TYPES.stream(), HueGroupHandler.SUPPORTED_THING_TYPES.stream())
|
||||||
.flatMap(i -> i).collect(Collectors.toSet()));
|
.flatMap(i -> i).collect(Collectors.toUnmodifiableSet());
|
||||||
|
|
||||||
|
private final HttpClient httpClient;
|
||||||
private final HueStateDescriptionProvider stateDescriptionProvider;
|
private final HueStateDescriptionProvider stateDescriptionProvider;
|
||||||
private final TranslationProvider i18nProvider;
|
private final TranslationProvider i18nProvider;
|
||||||
private final LocaleProvider localeProvider;
|
private final LocaleProvider localeProvider;
|
||||||
|
|
||||||
@Activate
|
@Activate
|
||||||
public HueThingHandlerFactory(final @Reference HueStateDescriptionProvider stateDescriptionProvider,
|
public HueThingHandlerFactory(final @Reference HttpClientFactory httpClientFactory,
|
||||||
|
final @Reference HueStateDescriptionProvider stateDescriptionProvider,
|
||||||
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider) {
|
final @Reference TranslationProvider i18nProvider, final @Reference LocaleProvider localeProvider) {
|
||||||
|
this.httpClient = httpClientFactory.getCommonHttpClient();
|
||||||
this.stateDescriptionProvider = stateDescriptionProvider;
|
this.stateDescriptionProvider = stateDescriptionProvider;
|
||||||
this.i18nProvider = i18nProvider;
|
this.i18nProvider = i18nProvider;
|
||||||
this.localeProvider = localeProvider;
|
this.localeProvider = localeProvider;
|
||||||
@ -103,7 +107,7 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
return super.createThing(thingTypeUID, configuration, hueGroupUID, bridgeUID);
|
return super.createThing(thingTypeUID, configuration, hueGroupUID, bridgeUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("The thing type " + thingTypeUID + " is not supported by the hue binding.");
|
throw new IllegalArgumentException("The thing type " + thingTypeUID + " is not supported by the Hue binding.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -149,7 +153,8 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
@Override
|
@Override
|
||||||
protected @Nullable ThingHandler createHandler(Thing thing) {
|
protected @Nullable ThingHandler createHandler(Thing thing) {
|
||||||
if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||||
return new HueBridgeHandler((Bridge) thing, stateDescriptionProvider, i18nProvider, localeProvider);
|
return new HueBridgeHandler((Bridge) thing, httpClient, stateDescriptionProvider, i18nProvider,
|
||||||
|
localeProvider);
|
||||||
} else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
} else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
||||||
return new HueLightHandler(thing, stateDescriptionProvider);
|
return new HueLightHandler(thing, stateDescriptionProvider);
|
||||||
} else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
} else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
|
@ -15,8 +15,8 @@ package org.openhab.binding.hue.internal.handler;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullGroup;
|
import org.openhab.binding.hue.internal.dto.FullGroup;
|
||||||
import org.openhab.binding.hue.internal.Scene;
|
import org.openhab.binding.hue.internal.dto.Scene;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link GroupStatusListener} is notified when a group status has changed or a group has been removed or added.
|
* The {@link GroupStatusListener} is notified when a group status has changed or a group has been removed or added.
|
||||||
|
@ -18,7 +18,6 @@ import static org.openhab.core.thing.Thing.*;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -33,20 +32,21 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.ApiVersionUtils;
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.openhab.binding.hue.internal.Config;
|
|
||||||
import org.openhab.binding.hue.internal.ConfigUpdate;
|
|
||||||
import org.openhab.binding.hue.internal.FullConfig;
|
|
||||||
import org.openhab.binding.hue.internal.FullGroup;
|
|
||||||
import org.openhab.binding.hue.internal.FullLight;
|
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
|
||||||
import org.openhab.binding.hue.internal.HueBridge;
|
|
||||||
import org.openhab.binding.hue.internal.HueConfigStatusMessage;
|
|
||||||
import org.openhab.binding.hue.internal.Scene;
|
|
||||||
import org.openhab.binding.hue.internal.State;
|
|
||||||
import org.openhab.binding.hue.internal.StateUpdate;
|
|
||||||
import org.openhab.binding.hue.internal.config.HueBridgeConfig;
|
import org.openhab.binding.hue.internal.config.HueBridgeConfig;
|
||||||
|
import org.openhab.binding.hue.internal.connection.HueBridge;
|
||||||
|
import org.openhab.binding.hue.internal.connection.HueTlsTrustManagerProvider;
|
||||||
import org.openhab.binding.hue.internal.discovery.HueDeviceDiscoveryService;
|
import org.openhab.binding.hue.internal.discovery.HueDeviceDiscoveryService;
|
||||||
|
import org.openhab.binding.hue.internal.dto.ApiVersionUtils;
|
||||||
|
import org.openhab.binding.hue.internal.dto.Config;
|
||||||
|
import org.openhab.binding.hue.internal.dto.ConfigUpdate;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullConfig;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullGroup;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullLight;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
|
import org.openhab.binding.hue.internal.dto.Scene;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State;
|
||||||
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
import org.openhab.binding.hue.internal.exceptions.ApiException;
|
import org.openhab.binding.hue.internal.exceptions.ApiException;
|
||||||
import org.openhab.binding.hue.internal.exceptions.DeviceOffException;
|
import org.openhab.binding.hue.internal.exceptions.DeviceOffException;
|
||||||
import org.openhab.binding.hue.internal.exceptions.EntityNotAvailableException;
|
import org.openhab.binding.hue.internal.exceptions.EntityNotAvailableException;
|
||||||
@ -54,8 +54,11 @@ import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
|
|||||||
import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
|
import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.config.core.status.ConfigStatusMessage;
|
import org.openhab.core.config.core.status.ConfigStatusMessage;
|
||||||
|
import org.openhab.core.i18n.CommunicationException;
|
||||||
|
import org.openhab.core.i18n.ConfigurationException;
|
||||||
import org.openhab.core.i18n.LocaleProvider;
|
import org.openhab.core.i18n.LocaleProvider;
|
||||||
import org.openhab.core.i18n.TranslationProvider;
|
import org.openhab.core.i18n.TranslationProvider;
|
||||||
|
import org.openhab.core.io.net.http.TlsTrustManagerProvider;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
import org.openhab.core.library.types.StringType;
|
import org.openhab.core.library.types.StringType;
|
||||||
@ -68,11 +71,13 @@ import org.openhab.core.thing.binding.ConfigStatusBridgeHandler;
|
|||||||
import org.openhab.core.thing.binding.ThingHandlerService;
|
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.StateOption;
|
import org.openhab.core.types.StateOption;
|
||||||
|
import org.osgi.framework.FrameworkUtil;
|
||||||
|
import org.osgi.framework.ServiceRegistration;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link HueBridgeHandler} is the handler for a hue bridge and connects it to
|
* {@link HueBridgeHandler} is the handler for a Hue Bridge and connects it to
|
||||||
* the framework. All {@link HueLightHandler}s use the {@link HueBridgeHandler} to execute the actual commands.
|
* the framework. All {@link HueLightHandler}s use the {@link HueBridgeHandler} to execute the actual commands.
|
||||||
*
|
*
|
||||||
* @author Dennis Nobel - Initial contribution
|
* @author Dennis Nobel - Initial contribution
|
||||||
@ -93,12 +98,13 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BRIDGE);
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_BRIDGE);
|
||||||
|
|
||||||
private static final long BYPASS_MIN_DURATION_BEFORE_CMD = 1500L;
|
private static final long BYPASS_MIN_DURATION_BEFORE_CMD = 1500L;
|
||||||
|
|
||||||
private static final String DEVICE_TYPE = "EclipseSmartHome";
|
|
||||||
|
|
||||||
private static final long SCENE_POLLING_INTERVAL = TimeUnit.SECONDS.convert(10, TimeUnit.MINUTES);
|
private static final long SCENE_POLLING_INTERVAL = TimeUnit.SECONDS.convert(10, TimeUnit.MINUTES);
|
||||||
|
|
||||||
|
private static final String DEVICE_TYPE = "openHAB";
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(HueBridgeHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(HueBridgeHandler.class);
|
||||||
|
private @Nullable ServiceRegistration<?> serviceRegistration;
|
||||||
|
private final HttpClient httpClient;
|
||||||
private final HueStateDescriptionProvider stateDescriptionOptionProvider;
|
private final HueStateDescriptionProvider stateDescriptionOptionProvider;
|
||||||
private final TranslationProvider i18nProvider;
|
private final TranslationProvider i18nProvider;
|
||||||
private final LocaleProvider localeProvider;
|
private final LocaleProvider localeProvider;
|
||||||
@ -120,8 +126,8 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
try {
|
try {
|
||||||
pollingLock.lock();
|
pollingLock.lock();
|
||||||
if (!lastBridgeConnectionState) {
|
if (!lastBridgeConnectionState) {
|
||||||
// if user is not set in configuration try to create a new user on Hue bridge
|
// if user is not set in configuration try to create a new user on Hue Bridge
|
||||||
if (hueBridgeConfig.getUserName() == null) {
|
if (hueBridgeConfig.userName == null) {
|
||||||
hueBridge.getFullConfig();
|
hueBridge.getFullConfig();
|
||||||
}
|
}
|
||||||
lastBridgeConnectionState = tryResumeBridgeConnection();
|
lastBridgeConnectionState = tryResumeBridgeConnection();
|
||||||
@ -132,6 +138,8 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
updateStatus(ThingStatus.ONLINE);
|
updateStatus(ThingStatus.ONLINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
handleConfigurationFailure(e);
|
||||||
} catch (UnauthorizedException | IllegalStateException e) {
|
} catch (UnauthorizedException | IllegalStateException e) {
|
||||||
if (isReachable(hueBridge.getIPAddress())) {
|
if (isReachable(hueBridge.getIPAddress())) {
|
||||||
lastBridgeConnectionState = false;
|
lastBridgeConnectionState = false;
|
||||||
@ -142,7 +150,7 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
lastBridgeConnectionState = false;
|
lastBridgeConnectionState = false;
|
||||||
onConnectionLost();
|
onConnectionLost();
|
||||||
}
|
}
|
||||||
} catch (ApiException | IOException e) {
|
} catch (ApiException | CommunicationException | IOException e) {
|
||||||
if (hueBridge != null && lastBridgeConnectionState) {
|
if (hueBridge != null && lastBridgeConnectionState) {
|
||||||
logger.debug("Connection to Hue Bridge {} lost: {}", hueBridge.getIPAddress(), e.getMessage(), e);
|
logger.debug("Connection to Hue Bridge {} lost: {}", hueBridge.getIPAddress(), e.getMessage(), e);
|
||||||
lastBridgeConnectionState = false;
|
lastBridgeConnectionState = false;
|
||||||
@ -165,7 +173,7 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
|
|
||||||
// If there is no connection, this line will fail
|
// If there is no connection, this line will fail
|
||||||
hueBridge.authenticate("invalid");
|
hueBridge.authenticate("invalid");
|
||||||
} catch (IOException e) {
|
} catch (ConfigurationException | IOException e) {
|
||||||
return false;
|
return false;
|
||||||
} catch (ApiException e) {
|
} catch (ApiException e) {
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
@ -407,9 +415,11 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
|
|
||||||
private List<String> consoleScenesList = new ArrayList<>();
|
private List<String> consoleScenesList = new ArrayList<>();
|
||||||
|
|
||||||
public HueBridgeHandler(Bridge bridge, HueStateDescriptionProvider stateDescriptionOptionProvider,
|
public HueBridgeHandler(Bridge bridge, HttpClient httpClient,
|
||||||
TranslationProvider i18nProvider, LocaleProvider localeProvider) {
|
HueStateDescriptionProvider stateDescriptionOptionProvider, TranslationProvider i18nProvider,
|
||||||
|
LocaleProvider localeProvider) {
|
||||||
super(bridge);
|
super(bridge);
|
||||||
|
this.httpClient = httpClient;
|
||||||
this.stateDescriptionOptionProvider = stateDescriptionOptionProvider;
|
this.stateDescriptionOptionProvider = stateDescriptionOptionProvider;
|
||||||
this.i18nProvider = i18nProvider;
|
this.i18nProvider = i18nProvider;
|
||||||
this.localeProvider = localeProvider;
|
this.localeProvider = localeProvider;
|
||||||
@ -417,7 +427,7 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||||
return Collections.singleton(HueDeviceDiscoveryService.class);
|
return Set.of(HueDeviceDiscoveryService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -596,10 +606,10 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
ScheduledFuture<?> job = lightPollingJob;
|
ScheduledFuture<?> job = lightPollingJob;
|
||||||
if (job == null || job.isCancelled()) {
|
if (job == null || job.isCancelled()) {
|
||||||
long lightPollingInterval;
|
long lightPollingInterval;
|
||||||
int configPollingInterval = hueBridgeConfig.getPollingInterval();
|
int configPollingInterval = hueBridgeConfig.pollingInterval;
|
||||||
if (configPollingInterval < 1) {
|
if (configPollingInterval < 1) {
|
||||||
lightPollingInterval = TimeUnit.SECONDS.toSeconds(10);
|
lightPollingInterval = TimeUnit.SECONDS.toSeconds(10);
|
||||||
logger.info("Wrong configuration value for polling interval. Using default value: {}s",
|
logger.warn("Wrong configuration value for polling interval. Using default value: {}s",
|
||||||
lightPollingInterval);
|
lightPollingInterval);
|
||||||
} else {
|
} else {
|
||||||
lightPollingInterval = configPollingInterval;
|
lightPollingInterval = configPollingInterval;
|
||||||
@ -621,12 +631,12 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
private void startSensorPolling() {
|
private void startSensorPolling() {
|
||||||
ScheduledFuture<?> job = sensorPollingJob;
|
ScheduledFuture<?> job = sensorPollingJob;
|
||||||
if (job == null || job.isCancelled()) {
|
if (job == null || job.isCancelled()) {
|
||||||
int configSensorPollingInterval = hueBridgeConfig.getSensorPollingInterval();
|
int configSensorPollingInterval = hueBridgeConfig.sensorPollingInterval;
|
||||||
if (configSensorPollingInterval > 0) {
|
if (configSensorPollingInterval > 0) {
|
||||||
long sensorPollingInterval;
|
long sensorPollingInterval;
|
||||||
if (configSensorPollingInterval < 50) {
|
if (configSensorPollingInterval < 50) {
|
||||||
sensorPollingInterval = TimeUnit.MILLISECONDS.toMillis(500);
|
sensorPollingInterval = TimeUnit.MILLISECONDS.toMillis(500);
|
||||||
logger.info("Wrong configuration value for sensor polling interval. Using default value: {}ms",
|
logger.warn("Wrong configuration value for sensor polling interval. Using default value: {}ms",
|
||||||
sensorPollingInterval);
|
sensorPollingInterval);
|
||||||
} else {
|
} else {
|
||||||
sensorPollingInterval = configSensorPollingInterval;
|
sensorPollingInterval = configSensorPollingInterval;
|
||||||
@ -665,7 +675,7 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose() {
|
public void dispose() {
|
||||||
logger.debug("Handler disposed.");
|
logger.debug("Disposing Hue Bridge handler ...");
|
||||||
Future<?> job = initJob;
|
Future<?> job = initJob;
|
||||||
if (job != null) {
|
if (job != null) {
|
||||||
job.cancel(true);
|
job.cancel(true);
|
||||||
@ -676,46 +686,50 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
if (hueBridge != null) {
|
if (hueBridge != null) {
|
||||||
hueBridge = null;
|
hueBridge = null;
|
||||||
}
|
}
|
||||||
|
ServiceRegistration<?> localServiceRegistration = serviceRegistration;
|
||||||
|
if (localServiceRegistration != null) {
|
||||||
|
// remove trustmanager service
|
||||||
|
localServiceRegistration.unregister();
|
||||||
|
serviceRegistration = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
logger.debug("Initializing hue bridge handler.");
|
logger.debug("Initializing Hue Bridge handler ...");
|
||||||
hueBridgeConfig = getConfigAs(HueBridgeConfig.class);
|
hueBridgeConfig = getConfigAs(HueBridgeConfig.class);
|
||||||
|
|
||||||
String ip = hueBridgeConfig.getIpAddress();
|
String ip = hueBridgeConfig.ipAddress;
|
||||||
if (ip == null || ip.isEmpty()) {
|
if (ip == null || ip.isEmpty()) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-no-ip-address");
|
"@text/offline.conf-error-no-ip-address");
|
||||||
} else {
|
} else {
|
||||||
if (hueBridge == null) {
|
if (hueBridge == null) {
|
||||||
hueBridge = new HueBridge(ip, hueBridgeConfig.getPort(), hueBridgeConfig.getProtocol(), scheduler);
|
if (HueBridgeConfig.HTTPS.equals(hueBridgeConfig.protocol)) {
|
||||||
hueBridge.setTimeout(5000);
|
// register trustmanager service
|
||||||
|
HueTlsTrustManagerProvider tlsTrustManagerProvider = new HueTlsTrustManagerProvider(
|
||||||
|
ip + ":" + hueBridgeConfig.getPort(), hueBridgeConfig.useSelfSignedCertificate);
|
||||||
|
serviceRegistration = FrameworkUtil.getBundle(getClass()).getBundleContext()
|
||||||
|
.registerService(TlsTrustManagerProvider.class.getName(), tlsTrustManagerProvider, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
hueBridge = new HueBridge(httpClient, ip, hueBridgeConfig.getPort(), hueBridgeConfig.protocol,
|
||||||
|
scheduler);
|
||||||
|
|
||||||
updateStatus(ThingStatus.UNKNOWN);
|
updateStatus(ThingStatus.UNKNOWN);
|
||||||
|
|
||||||
// Try a first connection that will fail, then try to authenticate,
|
|
||||||
// and finally change the bridge status to ONLINE
|
|
||||||
initJob = scheduler.submit(new PollingRunnable() {
|
|
||||||
@Override
|
|
||||||
protected void doConnectedRun() throws IOException, ApiException {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
onUpdate();
|
onUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable String getUserName() {
|
public @Nullable String getUserName() {
|
||||||
return hueBridgeConfig == null ? null : hueBridgeConfig.getUserName();
|
return hueBridgeConfig == null ? null : hueBridgeConfig.userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void onUpdate() {
|
private synchronized void onUpdate() {
|
||||||
if (hueBridge != null) {
|
startLightPolling();
|
||||||
startLightPolling();
|
startSensorPolling();
|
||||||
startSensorPolling();
|
startScenePolling();
|
||||||
startScenePolling();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -761,9 +775,9 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
*/
|
*/
|
||||||
private boolean tryResumeBridgeConnection() throws IOException, ApiException {
|
private boolean tryResumeBridgeConnection() throws IOException, ApiException {
|
||||||
logger.debug("Connection to Hue Bridge {} established.", hueBridge.getIPAddress());
|
logger.debug("Connection to Hue Bridge {} established.", hueBridge.getIPAddress());
|
||||||
if (hueBridgeConfig.getUserName() == null) {
|
if (hueBridgeConfig.userName == null) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"User name for Hue bridge authentication not available in configuration. Setting ThingStatus to OFFLINE.");
|
"User name for Hue Bridge authentication not available in configuration. Setting ThingStatus to OFFLINE.");
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-no-username");
|
"@text/offline.conf-error-no-username");
|
||||||
return false;
|
return false;
|
||||||
@ -780,21 +794,24 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
* If there is a user name available, it attempts to re-authenticate. Otherwise new authentication credentials will
|
* If there is a user name available, it attempts to re-authenticate. Otherwise new authentication credentials will
|
||||||
* be requested from the bridge.
|
* be requested from the bridge.
|
||||||
*
|
*
|
||||||
* @param bridge the hue bridge the connection is not authorized
|
* @param bridge the Hue Bridge the connection is not authorized
|
||||||
* @return returns {@code true} if re-authentication was successful, {@code false} otherwise
|
* @return returns {@code true} if re-authentication was successful, {@code false} otherwise
|
||||||
*/
|
*/
|
||||||
public boolean onNotAuthenticated() {
|
public boolean onNotAuthenticated() {
|
||||||
if (hueBridge == null) {
|
if (hueBridge == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
String userName = hueBridgeConfig.getUserName();
|
String userName = hueBridgeConfig.userName;
|
||||||
if (userName == null) {
|
if (userName == null) {
|
||||||
createUser();
|
createUser();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
hueBridge.authenticate(userName);
|
hueBridge.authenticate(userName);
|
||||||
return true;
|
return true;
|
||||||
|
} catch (ConfigurationException e) {
|
||||||
|
handleConfigurationFailure(e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
logger.trace("", e);
|
||||||
handleAuthenticationFailure(e, userName);
|
handleAuthenticationFailure(e, userName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -813,10 +830,10 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String createUserOnPhysicalBridge() throws IOException, ApiException {
|
private String createUserOnPhysicalBridge() throws IOException, ApiException {
|
||||||
logger.info("Creating new user on Hue bridge {} - please press the pairing button on the bridge.",
|
logger.info("Creating new user on Hue Bridge {} - please press the pairing button on the bridge.",
|
||||||
hueBridgeConfig.getIpAddress());
|
hueBridgeConfig.ipAddress);
|
||||||
String userName = hueBridge.link(DEVICE_TYPE);
|
String userName = hueBridge.link(DEVICE_TYPE);
|
||||||
logger.info("User has been successfully added to Hue bridge.");
|
logger.info("User has been successfully added to Hue Bridge.");
|
||||||
return userName;
|
return userName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,26 +846,32 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
hueBridgeConfig = getConfigAs(HueBridgeConfig.class);
|
hueBridgeConfig = getConfigAs(HueBridgeConfig.class);
|
||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
logger.trace("Configuration update failed.", e);
|
logger.trace("Configuration update failed.", e);
|
||||||
logger.warn("Unable to update configuration of Hue bridge.");
|
logger.warn("Unable to update configuration of Hue Bridge.");
|
||||||
logger.warn("Please configure the user name manually.");
|
logger.warn("Please configure the user name manually.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleConfigurationFailure(ConfigurationException ex) {
|
||||||
|
logger.warn(
|
||||||
|
"Invalid certificate for secured connection. You might want to enable the \"Use Self-Signed Certificate\" configuration.");
|
||||||
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, ex.getRawMessage());
|
||||||
|
}
|
||||||
|
|
||||||
private void handleAuthenticationFailure(Exception ex, String userName) {
|
private void handleAuthenticationFailure(Exception ex, String userName) {
|
||||||
logger.warn("User is not authenticated on Hue bridge {}", hueBridgeConfig.getIpAddress());
|
logger.warn("User is not authenticated on Hue Bridge {}", hueBridgeConfig.ipAddress);
|
||||||
logger.warn("Please configure a valid user or remove user from configuration to generate a new one.");
|
logger.warn("Please configure a valid user or remove user from configuration to generate a new one.");
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-invalid-username");
|
"@text/offline.conf-error-invalid-username");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleLinkButtonNotPressed(LinkButtonException ex) {
|
private void handleLinkButtonNotPressed(LinkButtonException ex) {
|
||||||
logger.debug("Failed creating new user on Hue bridge: {}", ex.getMessage());
|
logger.debug("Failed creating new user on Hue Bridge: {}", ex.getMessage());
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-press-pairing-button");
|
"@text/offline.conf-error-press-pairing-button");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleExceptionWhileCreatingUser(Exception ex) {
|
private void handleExceptionWhileCreatingUser(Exception ex) {
|
||||||
logger.warn("Failed creating new user on Hue bridge", ex);
|
logger.warn("Failed creating new user on Hue Bridge", ex);
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-creation-username");
|
"@text/offline.conf-error-creation-username");
|
||||||
}
|
}
|
||||||
@ -1041,10 +1064,10 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
|
|||||||
// Check whether an IP address is provided
|
// Check whether an IP address is provided
|
||||||
hueBridgeConfig = getConfigAs(HueBridgeConfig.class);
|
hueBridgeConfig = getConfigAs(HueBridgeConfig.class);
|
||||||
|
|
||||||
String ip = hueBridgeConfig.getIpAddress();
|
String ip = hueBridgeConfig.ipAddress;
|
||||||
if (ip == null || ip.isEmpty()) {
|
if (ip == null || ip.isEmpty()) {
|
||||||
return List.of(ConfigStatusMessage.Builder.error(HOST)
|
return List.of(ConfigStatusMessage.Builder.error(HOST).withMessageKeySuffix(IP_ADDRESS_MISSING)
|
||||||
.withMessageKeySuffix(HueConfigStatusMessage.IP_ADDRESS_MISSING).withArguments(HOST).build());
|
.withArguments(HOST).build());
|
||||||
} else {
|
} else {
|
||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,12 @@ package org.openhab.binding.hue.internal.handler;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.ConfigUpdate;
|
|
||||||
import org.openhab.binding.hue.internal.FullGroup;
|
|
||||||
import org.openhab.binding.hue.internal.FullLight;
|
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
|
||||||
import org.openhab.binding.hue.internal.StateUpdate;
|
|
||||||
import org.openhab.binding.hue.internal.discovery.HueDeviceDiscoveryService;
|
import org.openhab.binding.hue.internal.discovery.HueDeviceDiscoveryService;
|
||||||
|
import org.openhab.binding.hue.internal.dto.ConfigUpdate;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullGroup;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullLight;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access to the Hue system for light handlers.
|
* Access to the Hue system for light handlers.
|
||||||
|
@ -25,11 +25,11 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.FullGroup;
|
|
||||||
import org.openhab.binding.hue.internal.Scene;
|
|
||||||
import org.openhab.binding.hue.internal.State;
|
|
||||||
import org.openhab.binding.hue.internal.StateUpdate;
|
|
||||||
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullGroup;
|
||||||
|
import org.openhab.binding.hue.internal.dto.Scene;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State;
|
||||||
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||||
@ -87,7 +87,7 @@ public class HueGroupHandler extends BaseThingHandler implements HueLightActions
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
logger.debug("Initializing hue group handler.");
|
logger.debug("Initializing Hue group handler.");
|
||||||
Bridge bridge = getBridge();
|
Bridge bridge = getBridge();
|
||||||
initializeThing((bridge == null) ? null : bridge.getStatus());
|
initializeThing((bridge == null) ? null : bridge.getStatus());
|
||||||
}
|
}
|
||||||
@ -173,13 +173,13 @@ public class HueGroupHandler extends BaseThingHandler implements HueLightActions
|
|||||||
public void handleCommand(String channel, Command command, long fadeTime) {
|
public void handleCommand(String channel, Command command, long fadeTime) {
|
||||||
HueClient bridgeHandler = getHueClient();
|
HueClient bridgeHandler = getHueClient();
|
||||||
if (bridgeHandler == null) {
|
if (bridgeHandler == null) {
|
||||||
logger.debug("hue bridge handler not found. Cannot handle command without bridge.");
|
logger.debug("Hue Bridge handler not found. Cannot handle command without bridge.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FullGroup group = bridgeHandler.getGroupById(groupId);
|
FullGroup group = bridgeHandler.getGroupById(groupId);
|
||||||
if (group == null) {
|
if (group == null) {
|
||||||
logger.debug("hue group not known on bridge. Cannot handle command.");
|
logger.debug("Hue group not known on bridge. Cannot handle command.");
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-wrong-group-id");
|
"@text/offline.conf-error-wrong-group-id");
|
||||||
return;
|
return;
|
||||||
|
@ -24,11 +24,11 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.FullLight;
|
|
||||||
import org.openhab.binding.hue.internal.State;
|
|
||||||
import org.openhab.binding.hue.internal.StateUpdate;
|
|
||||||
import org.openhab.binding.hue.internal.dto.Capabilities;
|
import org.openhab.binding.hue.internal.dto.Capabilities;
|
||||||
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullLight;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State;
|
||||||
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||||
@ -51,7 +51,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link HueLightHandler} is the handler for a hue light. It uses the {@link HueClient} to execute the actual
|
* {@link HueLightHandler} is the handler for a Hue light. It uses the {@link HueClient} to execute the actual
|
||||||
* command.
|
* command.
|
||||||
*
|
*
|
||||||
* @author Dennis Nobel - Initial contribution
|
* @author Dennis Nobel - Initial contribution
|
||||||
@ -116,7 +116,7 @@ public class HueLightHandler extends BaseThingHandler implements HueLightActions
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
logger.debug("Initializing hue light handler.");
|
logger.debug("Initializing Hue light handler.");
|
||||||
Bridge bridge = getBridge();
|
Bridge bridge = getBridge();
|
||||||
initializeThing((bridge == null) ? null : bridge.getStatus());
|
initializeThing((bridge == null) ? null : bridge.getStatus());
|
||||||
}
|
}
|
||||||
@ -234,13 +234,13 @@ public class HueLightHandler extends BaseThingHandler implements HueLightActions
|
|||||||
public void handleCommand(String channel, Command command, long fadeTime) {
|
public void handleCommand(String channel, Command command, long fadeTime) {
|
||||||
HueClient bridgeHandler = getHueClient();
|
HueClient bridgeHandler = getHueClient();
|
||||||
if (bridgeHandler == null) {
|
if (bridgeHandler == null) {
|
||||||
logger.warn("hue bridge handler not found. Cannot handle command without bridge.");
|
logger.warn("Hue Bridge handler not found. Cannot handle command without bridge.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FullLight light = lastFullLight == null ? bridgeHandler.getLightById(lightId) : lastFullLight;
|
final FullLight light = lastFullLight == null ? bridgeHandler.getLightById(lightId) : lastFullLight;
|
||||||
if (light == null) {
|
if (light == null) {
|
||||||
logger.debug("hue light not known on bridge. Cannot handle command.");
|
logger.debug("Hue light not known on bridge. Cannot handle command.");
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-wrong-light-id");
|
"@text/offline.conf-error-wrong-light-id");
|
||||||
return;
|
return;
|
||||||
|
@ -12,8 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.handler;
|
package org.openhab.binding.hue.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
import static org.openhab.binding.hue.internal.dto.FullSensor.*;
|
||||||
import static org.openhab.core.thing.Thing.*;
|
import static org.openhab.core.thing.Thing.*;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -27,9 +27,9 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.StateUpdate;
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.library.types.DateTimeType;
|
import org.openhab.core.library.types.DateTimeType;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
@ -72,7 +72,7 @@ public abstract class HueSensorHandler extends BaseThingHandler implements Senso
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
logger.debug("Initializing hue sensor handler.");
|
logger.debug("Initializing Hue sensor handler.");
|
||||||
Bridge bridge = getBridge();
|
Bridge bridge = getBridge();
|
||||||
initializeThing((bridge == null) ? null : bridge.getStatus());
|
initializeThing((bridge == null) ? null : bridge.getStatus());
|
||||||
}
|
}
|
||||||
@ -167,13 +167,13 @@ public abstract class HueSensorHandler extends BaseThingHandler implements Senso
|
|||||||
protected void handleCommand(String channel, Command command) {
|
protected void handleCommand(String channel, Command command) {
|
||||||
HueClient bridgeHandler = getHueClient();
|
HueClient bridgeHandler = getHueClient();
|
||||||
if (bridgeHandler == null) {
|
if (bridgeHandler == null) {
|
||||||
logger.warn("hue bridge handler not found. Cannot handle command without bridge.");
|
logger.warn("Hue Bridge handler not found. Cannot handle command without bridge.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FullSensor sensor = lastFullSensor;
|
final FullSensor sensor = lastFullSensor;
|
||||||
if (sensor == null) {
|
if (sensor == null) {
|
||||||
logger.debug("hue sensor not known on bridge. Cannot handle command.");
|
logger.debug("Hue sensor not known on bridge. Cannot handle command.");
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-wrong-sensor-id");
|
"@text/offline.conf-error-wrong-sensor-id");
|
||||||
return;
|
return;
|
||||||
@ -206,13 +206,13 @@ public abstract class HueSensorHandler extends BaseThingHandler implements Senso
|
|||||||
if (!configUpdate.isEmpty()) {
|
if (!configUpdate.isEmpty()) {
|
||||||
HueClient hueBridge = getHueClient();
|
HueClient hueBridge = getHueClient();
|
||||||
if (hueBridge == null) {
|
if (hueBridge == null) {
|
||||||
logger.warn("hue bridge handler not found. Cannot handle configuration update without bridge.");
|
logger.warn("Hue Bridge handler not found. Cannot handle configuration update without bridge.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FullSensor sensor = lastFullSensor;
|
final FullSensor sensor = lastFullSensor;
|
||||||
if (sensor == null) {
|
if (sensor == null) {
|
||||||
logger.debug("hue sensor not known on bridge. Cannot handle configuration update.");
|
logger.debug("Hue sensor not known on bridge. Cannot handle configuration update.");
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-wrong-sensor-id");
|
"@text/offline.conf-error-wrong-sensor-id");
|
||||||
return;
|
return;
|
||||||
|
@ -14,12 +14,12 @@ package org.openhab.binding.hue.internal.handler;
|
|||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.hue.internal.State;
|
|
||||||
import org.openhab.binding.hue.internal.State.AlertMode;
|
|
||||||
import org.openhab.binding.hue.internal.State.ColorMode;
|
|
||||||
import org.openhab.binding.hue.internal.State.Effect;
|
|
||||||
import org.openhab.binding.hue.internal.StateUpdate;
|
|
||||||
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State.AlertMode;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State.ColorMode;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State.Effect;
|
||||||
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
import org.openhab.core.library.types.IncreaseDecreaseType;
|
import org.openhab.core.library.types.IncreaseDecreaseType;
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
package org.openhab.binding.hue.internal.handler;
|
package org.openhab.binding.hue.internal.handler;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullLight;
|
import org.openhab.binding.hue.internal.dto.FullLight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link LightStatusListener} is notified when a light status has changed or a light has been removed or added.
|
* The {@link LightStatusListener} is notified when a light status has changed or a light has been removed or added.
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
package org.openhab.binding.hue.internal.handler;
|
package org.openhab.binding.hue.internal.handler;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link SensorStatusListener} is notified when a sensor status has changed or a sensor has been removed or added.
|
* The {@link SensorStatusListener} is notified when a sensor status has changed or a sensor has been removed or added.
|
||||||
|
@ -20,8 +20,8 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
|
@ -21,13 +21,12 @@ import java.time.ZoneOffset;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
@ -43,7 +42,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class DimmerSwitchHandler extends HueSensorHandler {
|
public class DimmerSwitchHandler extends HueSensorHandler {
|
||||||
|
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DIMMER_SWITCH);
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_DIMMER_SWITCH);
|
||||||
|
|
||||||
public DimmerSwitchHandler(Thing thing) {
|
public DimmerSwitchHandler(Thing thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
|
@ -12,16 +12,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.handler.sensors;
|
package org.openhab.binding.hue.internal.handler.sensors;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.STATE_PRESENCE;
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
import static org.openhab.binding.hue.internal.dto.FullSensor.STATE_PRESENCE;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.library.types.OnOffType;
|
import org.openhab.core.library.types.OnOffType;
|
||||||
@ -35,7 +34,8 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class GeofencePresenceHandler extends HueSensorHandler {
|
public class GeofencePresenceHandler extends HueSensorHandler {
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_GEOFENCE_SENSOR);
|
|
||||||
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_GEOFENCE_SENSOR);
|
||||||
|
|
||||||
public GeofencePresenceHandler(Thing thing) {
|
public GeofencePresenceHandler(Thing thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
|
@ -12,18 +12,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.handler.sensors;
|
package org.openhab.binding.hue.internal.handler.sensors;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
import static org.openhab.binding.hue.internal.dto.FullSensor.*;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.LightLevelConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.LightLevelConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
@ -41,7 +40,8 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class LightLevelHandler extends HueSensorHandler {
|
public class LightLevelHandler extends HueSensorHandler {
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_LIGHT_LEVEL_SENSOR);
|
|
||||||
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_LIGHT_LEVEL_SENSOR);
|
||||||
|
|
||||||
public LightLevelHandler(Thing thing) {
|
public LightLevelHandler(Thing thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
|
@ -12,17 +12,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.handler.sensors;
|
package org.openhab.binding.hue.internal.handler.sensors;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
import static org.openhab.binding.hue.internal.dto.FullSensor.*;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.PresenceConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.PresenceConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.HueClient;
|
import org.openhab.binding.hue.internal.handler.HueClient;
|
||||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
@ -43,7 +42,8 @@ import org.slf4j.LoggerFactory;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class PresenceHandler extends HueSensorHandler {
|
public class PresenceHandler extends HueSensorHandler {
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_PRESENCE_SENSOR);
|
|
||||||
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_PRESENCE_SENSOR);
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(PresenceHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(PresenceHandler.class);
|
||||||
|
|
||||||
@ -55,13 +55,13 @@ public class PresenceHandler extends HueSensorHandler {
|
|||||||
public void handleCommand(String channel, Command command) {
|
public void handleCommand(String channel, Command command) {
|
||||||
HueClient hueBridge = getHueClient();
|
HueClient hueBridge = getHueClient();
|
||||||
if (hueBridge == null) {
|
if (hueBridge == null) {
|
||||||
logger.warn("hue bridge handler not found. Cannot handle command without bridge.");
|
logger.warn("Hue Bridge handler not found. Cannot handle command without bridge.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FullSensor sensor = lastFullSensor;
|
final FullSensor sensor = lastFullSensor;
|
||||||
if (sensor == null) {
|
if (sensor == null) {
|
||||||
logger.debug("hue sensor not known on bridge. Cannot handle command.");
|
logger.debug("Hue sensor not known on bridge. Cannot handle command.");
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||||
"@text/offline.conf-error-wrong-sensor-id");
|
"@text/offline.conf-error-wrong-sensor-id");
|
||||||
return;
|
return;
|
||||||
|
@ -21,13 +21,12 @@ import java.time.ZoneOffset;
|
|||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
@ -42,7 +41,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class TapSwitchHandler extends HueSensorHandler {
|
public class TapSwitchHandler extends HueSensorHandler {
|
||||||
|
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_TAP_SWITCH);
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_TAP_SWITCH);
|
||||||
|
|
||||||
public TapSwitchHandler(Thing thing) {
|
public TapSwitchHandler(Thing thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
|
@ -12,18 +12,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.handler.sensors;
|
package org.openhab.binding.hue.internal.handler.sensors;
|
||||||
|
|
||||||
import static org.openhab.binding.hue.internal.FullSensor.*;
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
|
import static org.openhab.binding.hue.internal.dto.FullSensor.*;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.binding.hue.internal.FullSensor;
|
import org.openhab.binding.hue.internal.dto.FullSensor;
|
||||||
import org.openhab.binding.hue.internal.SensorConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.SensorConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.TemperatureConfigUpdate;
|
import org.openhab.binding.hue.internal.dto.TemperatureConfigUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
import org.openhab.binding.hue.internal.handler.HueSensorHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.library.types.QuantityType;
|
import org.openhab.core.library.types.QuantityType;
|
||||||
@ -39,7 +38,8 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class TemperatureHandler extends HueSensorHandler {
|
public class TemperatureHandler extends HueSensorHandler {
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_TEMPERATURE_SENSOR);
|
|
||||||
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_TEMPERATURE_SENSOR);
|
||||||
|
|
||||||
public TemperatureHandler(Thing thing) {
|
public TemperatureHandler(Thing thing) {
|
||||||
super(thing);
|
super(thing);
|
||||||
|
@ -6,13 +6,4 @@
|
|||||||
<name>Hue Binding</name>
|
<name>Hue Binding</name>
|
||||||
<description>The Hue Binding integrates the Philips Hue system. It allows to control Hue bulbs.</description>
|
<description>The Hue Binding integrates the Philips Hue system. It allows to control Hue bulbs.</description>
|
||||||
|
|
||||||
<config-description>
|
|
||||||
<parameter name="removalGracePeriod" type="integer" min="0" step="1" unit="s">
|
|
||||||
<label>Removal Grace Period</label>
|
|
||||||
<description>Extra grace period (seconds) that UPnP discovery shall wait before removing a lost Bridge from the
|
|
||||||
Inbox. Default is 50 seconds.</description>
|
|
||||||
<default>50</default>
|
|
||||||
</parameter>
|
|
||||||
</config-description>
|
|
||||||
|
|
||||||
</binding:binding>
|
</binding:binding>
|
||||||
|
@ -117,7 +117,7 @@
|
|||||||
<config-description uri="thing-type:hue:group">
|
<config-description uri="thing-type:hue:group">
|
||||||
<parameter name="groupId" type="text" required="true">
|
<parameter name="groupId" type="text" required="true">
|
||||||
<label>Group ID</label>
|
<label>Group ID</label>
|
||||||
<description>The group identifier identifies one certain hue group or room.</description>
|
<description>The group identifier identifies one certain Hue group or room.</description>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
<parameter name="fadetime" type="integer" min="0" step="100" unit="ms">
|
||||||
<label>@text/config.fadetime.label</label>
|
<label>@text/config.fadetime.label</label>
|
||||||
|
@ -3,11 +3,6 @@
|
|||||||
binding.hue.name = Hue Binding
|
binding.hue.name = Hue Binding
|
||||||
binding.hue.description = The Hue Binding integrates the Philips Hue system. It allows to control Hue bulbs.
|
binding.hue.description = The Hue Binding integrates the Philips Hue system. It allows to control Hue bulbs.
|
||||||
|
|
||||||
# binding config
|
|
||||||
|
|
||||||
binding.config.hue.removalGracePeriod.label = Removal Grace Period
|
|
||||||
binding.config.hue.removalGracePeriod.description = Extra grace period (seconds) that UPnP discovery shall wait before removing a lost Bridge from the Inbox. Default is 50 seconds.
|
|
||||||
|
|
||||||
# thing types
|
# thing types
|
||||||
|
|
||||||
thing-type.hue.0000.label = On/Off Light
|
thing-type.hue.0000.label = On/Off Light
|
||||||
@ -39,7 +34,7 @@ thing-type.hue.0840.description = A generic sensor object for IP sensor use.
|
|||||||
thing-type.hue.0850.label = CLIP Generic Flag Sensor
|
thing-type.hue.0850.label = CLIP Generic Flag Sensor
|
||||||
thing-type.hue.0850.description = A generic sensor object for IP sensor use.
|
thing-type.hue.0850.description = A generic sensor object for IP sensor use.
|
||||||
thing-type.hue.bridge.label = Hue Bridge
|
thing-type.hue.bridge.label = Hue Bridge
|
||||||
thing-type.hue.bridge.description = The Hue bridge represents the Philips Hue bridge.
|
thing-type.hue.bridge.description = The Hue Bridge represents the Philips Hue Bridge.
|
||||||
thing-type.hue.geofencesensor.label = Geofence Sensor
|
thing-type.hue.geofencesensor.label = Geofence Sensor
|
||||||
thing-type.hue.geofencesensor.description = A sensor providing geofence based presence detection.
|
thing-type.hue.geofencesensor.description = A sensor providing geofence based presence detection.
|
||||||
thing-type.hue.group.label = Hue Group
|
thing-type.hue.group.label = Hue Group
|
||||||
@ -48,17 +43,23 @@ thing-type.hue.group.description = A group of lights or a room that could be swi
|
|||||||
# thing types config
|
# thing types config
|
||||||
|
|
||||||
thing-type.config.hue.bridge.ipAddress.label = Network Address
|
thing-type.config.hue.bridge.ipAddress.label = Network Address
|
||||||
thing-type.config.hue.bridge.ipAddress.description = Network address of the Hue bridge.
|
thing-type.config.hue.bridge.ipAddress.description = Network address of the Hue Bridge.
|
||||||
thing-type.config.hue.bridge.pollingInterval.label = Polling Interval
|
thing-type.config.hue.bridge.pollingInterval.label = Polling Interval
|
||||||
thing-type.config.hue.bridge.pollingInterval.description = Seconds between fetching values from the Hue bridge. Default is 10.
|
thing-type.config.hue.bridge.pollingInterval.description = Seconds between fetching values from the Hue Bridge. Default is 10.
|
||||||
thing-type.config.hue.bridge.port.label = Port
|
thing-type.config.hue.bridge.port.label = Port
|
||||||
thing-type.config.hue.bridge.port.description = Port of the Hue bridge.
|
thing-type.config.hue.bridge.port.description = Port of the Hue Bridge.
|
||||||
|
thing-type.config.hue.bridge.protocol.label = Protocol
|
||||||
|
thing-type.config.hue.bridge.protocol.description = Protocol to connect to the Hue Bridge (http or https).
|
||||||
|
thing-type.config.hue.bridge.protocol.option.http = HTTP
|
||||||
|
thing-type.config.hue.bridge.protocol.option.https = HTTPS
|
||||||
thing-type.config.hue.bridge.sensorPollingInterval.label = Sensor Polling Interval
|
thing-type.config.hue.bridge.sensorPollingInterval.label = Sensor Polling Interval
|
||||||
thing-type.config.hue.bridge.sensorPollingInterval.description = Milliseconds between fetching sensor-values from the Hue bridge. A higher value means more delay for the sensor values, but a too low value can cause congestion on the Hue bridge. Use 0 to disable the polling for sensors. Default is 500.
|
thing-type.config.hue.bridge.sensorPollingInterval.description = Milliseconds between fetching sensor-values from the Hue Bridge. A higher value means more delay for the sensor values, but a too low value can cause congestion on the Hue Bridge. Use 0 to disable the polling for sensors. Default is 500.
|
||||||
|
thing-type.config.hue.bridge.useSelfSignedCertificate.label = Use Self-Signed Certificate
|
||||||
|
thing-type.config.hue.bridge.useSelfSignedCertificate.description = Use self-signed certificate for HTTPS connection to Hue Bridge.
|
||||||
thing-type.config.hue.bridge.userName.label = Username
|
thing-type.config.hue.bridge.userName.label = Username
|
||||||
thing-type.config.hue.bridge.userName.description = Name of a registered Hue bridge user, that allows to access the API.
|
thing-type.config.hue.bridge.userName.description = Name of a registered Hue Bridge user, that allows to access the API.
|
||||||
thing-type.config.hue.group.groupId.label = Group ID
|
thing-type.config.hue.group.groupId.label = Group ID
|
||||||
thing-type.config.hue.group.groupId.description = The group identifier identifies one certain hue group or room.
|
thing-type.config.hue.group.groupId.description = The group identifier identifies one certain Hue group or room.
|
||||||
thing-type.config.hue.lightlevelsensor.tholddark.label = Threshold Dark
|
thing-type.config.hue.lightlevelsensor.tholddark.label = Threshold Dark
|
||||||
thing-type.config.hue.lightlevelsensor.tholddark.description = Threshold the user configured to be used in rules to determine insufficient light level (ie below threshold). Default value 16000.
|
thing-type.config.hue.lightlevelsensor.tholddark.description = Threshold the user configured to be used in rules to determine insufficient light level (ie below threshold). Default value 16000.
|
||||||
thing-type.config.hue.lightlevelsensor.tholdoffset.label = Threshold Offset
|
thing-type.config.hue.lightlevelsensor.tholdoffset.label = Threshold Offset
|
||||||
@ -132,37 +133,39 @@ config.fadetime.description = Fade time in milliseconds for changing values.
|
|||||||
config.ledindication.label = LED Indication
|
config.ledindication.label = LED Indication
|
||||||
config.ledindication.description = Turns device LED during normal operation on or off. Devices might still indicate exceptional operation (Reset, SW Update, Battery Low).
|
config.ledindication.description = Turns device LED during normal operation on or off. Devices might still indicate exceptional operation (Reset, SW Update, Battery Low).
|
||||||
config.lightId.label = Light ID
|
config.lightId.label = Light ID
|
||||||
config.lightId.description = The light identifier that is used within the hue bridge.
|
config.lightId.description = The light identifier that is used within the Hue Bridge.
|
||||||
config.plugId.label = Plug ID
|
config.plugId.label = Plug ID
|
||||||
config.plugId.description = The plug identifier that is used within the hue bridge.
|
config.plugId.description = The plug identifier that is used within the Hue Bridge.
|
||||||
config.sensorId.label = Sensor ID
|
config.sensorId.label = Sensor ID
|
||||||
config.sensorId.description = The sensor identifier that is used within the hue bridge.
|
config.sensorId.description = The sensor identifier that is used within the Hue Bridge.
|
||||||
config.on.label = Sensor Status
|
config.on.label = Sensor Status
|
||||||
config.on.description = Enables or disables the sensor.
|
config.on.description = Enables or disables the sensor.
|
||||||
|
|
||||||
# config status messages
|
# config status messages
|
||||||
|
|
||||||
config-status.error.missing-ip-address-configuration = No IP address for the Hue bridge has been provided.
|
config-status.error.missing-ip-address-configuration = No IP address for the Hue Bridge has been provided.
|
||||||
|
|
||||||
# thing status descriptions
|
# thing status descriptions
|
||||||
|
|
||||||
offline.conf-error-no-ip-address = Cannot connect to Hue bridge. IP address not available in configuration.
|
offline.communication-error = An unexpected exception occurred during execution.
|
||||||
offline.conf-error-no-username = Cannot connect to Hue bridge. User name for authentication not available in configuration.
|
offline.conf-error-invalid-ssl-certificate = Invalid certificate for secured connection. You might want to enable the "Use Self-Signed Certificate" configuration.
|
||||||
|
offline.conf-error-no-ip-address = Cannot connect to Hue Bridge. IP address not available in configuration.
|
||||||
|
offline.conf-error-no-username = Cannot connect to Hue Bridge. User name for authentication not available in configuration.
|
||||||
offline.conf-error-invalid-username = Authentication failed. Remove user name from configuration to generate a new one.
|
offline.conf-error-invalid-username = Authentication failed. Remove user name from configuration to generate a new one.
|
||||||
offline.conf-error-press-pairing-button = Not authenticated. Press pairing button on the Hue bridge or set a valid user name in configuration.
|
offline.conf-error-press-pairing-button = Not authenticated. Press pairing button on the Hue Bridge or set a valid user name in configuration.
|
||||||
offline.conf-error-creation-username = Failed to create new user on Hue bridge.
|
offline.conf-error-creation-username = Failed to create new user on Hue Bridge.
|
||||||
offline.bridge-connection-lost = Hue bridge connection lost.
|
offline.bridge-connection-lost = Hue Bridge connection lost.
|
||||||
offline.conf-error-no-light-id = Light ID not available in configuration.
|
offline.conf-error-no-light-id = Light ID not available in configuration.
|
||||||
offline.conf-error-no-sensor-id = Sensor ID not available in configuration.
|
offline.conf-error-no-sensor-id = Sensor ID not available in configuration.
|
||||||
offline.conf-error-no-group-id = Group ID not available in configuration.
|
offline.conf-error-no-group-id = Group ID not available in configuration.
|
||||||
offline.conf-error-wrong-light-id = No light with given ID available on Hue bridge.
|
offline.conf-error-wrong-light-id = No light with given ID available on Hue Bridge.
|
||||||
offline.conf-error-wrong-sensor-id = No sensor with given ID available on Hue bridge.
|
offline.conf-error-wrong-sensor-id = No sensor with given ID available on Hue Bridge.
|
||||||
offline.conf-error-wrong-group-id = No group with given ID available on Hue bridge.
|
offline.conf-error-wrong-group-id = No group with given ID available on Hue Bridge.
|
||||||
offline.light-not-reachable = Hue bridge reports light as not reachable.
|
offline.light-not-reachable = Hue Bridge reports light as not reachable.
|
||||||
offline.sensor-not-reachable = Hue bridge reports sensor as not reachable.
|
offline.sensor-not-reachable = Hue Bridge reports sensor as not reachable.
|
||||||
offline.light-removed = Hue bridge reports light as removed.
|
offline.light-removed = Hue Bridge reports light as removed.
|
||||||
offline.sensor-removed = Hue bridge reports sensor as removed.
|
offline.sensor-removed = Hue Bridge reports sensor as removed.
|
||||||
offline.group-removed = Hue bridge reports group as removed.
|
offline.group-removed = Hue Bridge reports group as removed.
|
||||||
|
|
||||||
# lightactions
|
# lightactions
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<!-- Hue Bridge -->
|
<!-- Hue Bridge -->
|
||||||
<bridge-type id="bridge">
|
<bridge-type id="bridge">
|
||||||
<label>Hue Bridge</label>
|
<label>Hue Bridge</label>
|
||||||
<description>The Hue bridge represents the Philips Hue bridge.</description>
|
<description>The Hue Bridge represents the Philips Hue Bridge.</description>
|
||||||
|
|
||||||
<channels>
|
<channels>
|
||||||
<channel id="scene" typeId="scene"/>
|
<channel id="scene" typeId="scene"/>
|
||||||
@ -21,26 +21,41 @@
|
|||||||
<parameter name="ipAddress" type="text" required="true">
|
<parameter name="ipAddress" type="text" required="true">
|
||||||
<context>network-address</context>
|
<context>network-address</context>
|
||||||
<label>Network Address</label>
|
<label>Network Address</label>
|
||||||
<description>Network address of the Hue bridge.</description>
|
<description>Network address of the Hue Bridge.</description>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="port" type="integer" required="false" min="1" max="65535">
|
<parameter name="port" type="integer" required="false" min="1" max="65535">
|
||||||
<label>Port</label>
|
<label>Port</label>
|
||||||
<description>Port of the Hue bridge.</description>
|
<description>Port of the Hue Bridge.</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="protocol" type="text">
|
||||||
|
<label>Protocol</label>
|
||||||
|
<description>Protocol to connect to the Hue Bridge (http or https).</description>
|
||||||
|
<default>https</default>
|
||||||
|
<options>
|
||||||
|
<option value="http">HTTP</option>
|
||||||
|
<option value="https">HTTPS</option>
|
||||||
|
</options>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="useSelfSignedCertificate" type="boolean">
|
||||||
|
<label>Use Self-Signed Certificate</label>
|
||||||
|
<description>Use self-signed certificate for HTTPS connection to Hue Bridge.</description>
|
||||||
|
<default>true</default>
|
||||||
|
<advanced>true</advanced>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="userName" type="text">
|
<parameter name="userName" type="text">
|
||||||
<context>password</context>
|
<context>password</context>
|
||||||
<label>Username</label>
|
<label>Username</label>
|
||||||
<description>Name of a registered Hue bridge user, that allows to access the API.</description>
|
<description>Name of a registered Hue Bridge user, that allows to access the API.</description>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s">
|
<parameter name="pollingInterval" type="integer" min="1" step="1" unit="s">
|
||||||
<label>Polling Interval</label>
|
<label>Polling Interval</label>
|
||||||
<description>Seconds between fetching values from the Hue bridge. Default is 10.</description>
|
<description>Seconds between fetching values from the Hue Bridge. Default is 10.</description>
|
||||||
<default>10</default>
|
<default>10</default>
|
||||||
</parameter>
|
</parameter>
|
||||||
<parameter name="sensorPollingInterval" type="integer" min="0" step="1" unit="ms">
|
<parameter name="sensorPollingInterval" type="integer" min="0" step="1" unit="ms">
|
||||||
<label>Sensor Polling Interval</label>
|
<label>Sensor Polling Interval</label>
|
||||||
<description>Milliseconds between fetching sensor-values from the Hue bridge. A higher value means more delay for
|
<description>Milliseconds between fetching sensor-values from the Hue Bridge. A higher value means more delay for
|
||||||
the sensor values, but a too low value can cause congestion on the Hue bridge. Use 0 to disable the polling for
|
the sensor values, but a too low value can cause congestion on the Hue Bridge. Use 0 to disable the polling for
|
||||||
sensors. Default is 500.</description>
|
sensors. Default is 500.</description>
|
||||||
<default>500</default>
|
<default>500</default>
|
||||||
</parameter>
|
</parameter>
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIICMjCCAdigAwIBAgIUO7FSLbaxikuXAljzVaurLXWmFw4wCgYIKoZIzj0EAwIw
|
||||||
|
OTELMAkGA1UEBhMCTkwxFDASBgNVBAoMC1BoaWxpcHMgSHVlMRQwEgYDVQQDDAty
|
||||||
|
b290LWJyaWRnZTAiGA8yMDE3MDEwMTAwMDAwMFoYDzIwMzgwMTE5MDMxNDA3WjA5
|
||||||
|
MQswCQYDVQQGEwJOTDEUMBIGA1UECgwLUGhpbGlwcyBIdWUxFDASBgNVBAMMC3Jv
|
||||||
|
b3QtYnJpZGdlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjNw2tx2AplOf9x86
|
||||||
|
aTdvEcL1FU65QDxziKvBpW9XXSIcibAeQiKxegpq8Exbr9v6LBnYbna2VcaK0G22
|
||||||
|
jOKkTqOBuTCBtjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNV
|
||||||
|
HQ4EFgQUZ2ONTFrDT6o8ItRnKfqWKnHFGmQwdAYDVR0jBG0wa4AUZ2ONTFrDT6o8
|
||||||
|
ItRnKfqWKnHFGmShPaQ7MDkxCzAJBgNVBAYTAk5MMRQwEgYDVQQKDAtQaGlsaXBz
|
||||||
|
IEh1ZTEUMBIGA1UEAwwLcm9vdC1icmlkZ2WCFDuxUi22sYpLlwJY81Wrqy11phcO
|
||||||
|
MAoGCCqGSM49BAMCA0gAMEUCIEBYYEOsa07TH7E5MJnGw557lVkORgit2Rm1h3B2
|
||||||
|
sFgDAiEA1Fj/C3AN5psFMjo0//mrQebo0eKd3aWRx+pQY08mk48=
|
||||||
|
-----END CERTIFICATE-----
|
@ -12,15 +12,16 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal;
|
package org.openhab.binding.hue.internal;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.openhab.binding.hue.internal.dto.ApiVersion;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
*
|
|
||||||
* @author Samuel Leisering - Initial contribution
|
* @author Samuel Leisering - Initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class ApiVersionTest {
|
public class ApiVersionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -14,35 +14,47 @@ package org.openhab.binding.hue.internal;
|
|||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.Mockito;
|
import org.openhab.binding.hue.internal.config.HueBridgeConfig;
|
||||||
import org.openhab.binding.hue.internal.HttpClient.Result;
|
import org.openhab.binding.hue.internal.connection.HueBridge;
|
||||||
|
import org.openhab.binding.hue.internal.dto.Scene;
|
||||||
import org.openhab.binding.hue.internal.exceptions.ApiException;
|
import org.openhab.binding.hue.internal.exceptions.ApiException;
|
||||||
|
import org.openhab.core.i18n.CommunicationException;
|
||||||
|
import org.openhab.core.i18n.ConfigurationException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hengrui Jiang - initial contribution
|
* @author Hengrui Jiang - initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HueBridgeTest {
|
public class HueBridgeTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetScenesExcludeRecycleScenes() throws IOException, ApiException {
|
public void testGetScenesExcludeRecycleScenes() throws IOException, ApiException {
|
||||||
HttpClient mockHttpClient = Mockito.mock(HttpClient.class);
|
HueBridge hueBridge = new HueBridge(mock(HttpClient.class), "ip", 443, HueBridgeConfig.HTTPS, "username",
|
||||||
|
Executors.newScheduledThreadPool(1)) {
|
||||||
HueBridge hueBridge = new HueBridge("ip", "baseUrl", "username", Executors.newScheduledThreadPool(1),
|
@Override
|
||||||
mockHttpClient);
|
public HueResult get(String address) throws ConfigurationException, CommunicationException {
|
||||||
|
if ("https://ip:443/api/username/lights".equals(address)) {
|
||||||
List<Scene> testScenes = Arrays.asList(new Scene("id1", "name1", "group1", Collections.emptyList(), true), //
|
return new HueResult("{}", HttpStatus.OK_200);
|
||||||
new Scene("id2", "name2", "group2", Collections.emptyList(), false));
|
} else if ("https://ip:443/api/username/scenes".equals(address)) {
|
||||||
when(mockHttpClient.get("baseUrl/username/scenes")).thenReturn(new Result(createMockResponse(testScenes), 200));
|
List<Scene> testScenes = List.of( //
|
||||||
|
new Scene("id1", "name1", "group1", List.of(), true), //
|
||||||
|
new Scene("id2", "name2", "group2", List.of(), false));
|
||||||
|
return new HueResult(createMockResponse(testScenes), HttpStatus.OK_200);
|
||||||
|
}
|
||||||
|
return super.get(address);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
List<Scene> scenes = hueBridge.getScenes();
|
List<Scene> scenes = hueBridge.getScenes();
|
||||||
assertThat(scenes.size(), is(1));
|
assertThat(scenes.size(), is(1));
|
||||||
@ -51,15 +63,22 @@ public class HueBridgeTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetScenesOrderByGroup() throws IOException, ApiException {
|
public void testGetScenesOrderByGroup() throws IOException, ApiException {
|
||||||
HttpClient mockHttpClient = Mockito.mock(HttpClient.class);
|
HueBridge hueBridge = new HueBridge(mock(HttpClient.class), "ip", 443, HueBridgeConfig.HTTPS, "username",
|
||||||
|
Executors.newScheduledThreadPool(1)) {
|
||||||
HueBridge hueBridge = new HueBridge("ip", "baseUrl", "username", Executors.newScheduledThreadPool(1),
|
@Override
|
||||||
mockHttpClient);
|
public HueResult get(String address) throws ConfigurationException, CommunicationException {
|
||||||
|
if ("https://ip:443/api/username/lights".equals(address)) {
|
||||||
List<Scene> testScenes = Arrays.asList(new Scene("id1", "name1", "group1", Collections.emptyList(), false), //
|
return new HueResult("{}", HttpStatus.OK_200);
|
||||||
new Scene("id2", "name2", "group2", Collections.emptyList(), false),
|
} else if ("https://ip:443/api/username/scenes".equals(address)) {
|
||||||
new Scene("id3", "name3", "group1", Collections.emptyList(), false));
|
List<Scene> testScenes = List.of( //
|
||||||
when(mockHttpClient.get("baseUrl/username/scenes")).thenReturn(new Result(createMockResponse(testScenes), 200));
|
new Scene("id1", "name1", "group1", List.of(), false), //
|
||||||
|
new Scene("id2", "name2", "group2", List.of(), false), //
|
||||||
|
new Scene("id3", "name3", "group1", List.of(), false));
|
||||||
|
return new HueResult(createMockResponse(testScenes), HttpStatus.OK_200);
|
||||||
|
}
|
||||||
|
return super.get(address);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
List<Scene> scenes = hueBridge.getScenes();
|
List<Scene> scenes = hueBridge.getScenes();
|
||||||
assertThat(scenes.size(), is(3));
|
assertThat(scenes.size(), is(3));
|
||||||
@ -92,8 +111,7 @@ public class HueBridgeTest {
|
|||||||
" \"version\": 2,\n" + //
|
" \"version\": 2,\n" + //
|
||||||
" \"group\": \"%s\"\n" + //
|
" \"group\": \"%s\"\n" + //
|
||||||
" }";
|
" }";
|
||||||
String lights = String.join(",",
|
String lights = scene.getLightIds().stream().map(id -> "\"" + id + "\"").collect(Collectors.joining(","));
|
||||||
scene.getLightIds().stream().map(id -> "\"" + id + "\"").collect(Collectors.toList()));
|
|
||||||
return String.format(template, scene.getId(), scene.getName(), lights, scene.isRecycle(), scene.getGroupId());
|
return String.format(template, scene.getId(), scene.getName(), lights, scene.isRecycle(), scene.getGroupId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,12 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
|
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.hue.internal.State.ColorMode;
|
|
||||||
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
import org.openhab.binding.hue.internal.dto.ColorTemperature;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State.ColorMode;
|
||||||
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
import org.openhab.binding.hue.internal.handler.LightStateConverter;
|
import org.openhab.binding.hue.internal.handler.LightStateConverter;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
@ -31,6 +34,7 @@ import org.openhab.core.library.types.PercentType;
|
|||||||
* @author Denis Dudnik - switched to internally integrated source of Jue library
|
* @author Denis Dudnik - switched to internally integrated source of Jue library
|
||||||
* @author Markus Rathgeb - migrated to plain Java test
|
* @author Markus Rathgeb - migrated to plain Java test
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class LightStateConverterTest {
|
public class LightStateConverterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -18,11 +18,16 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullGroup;
|
||||||
|
import org.openhab.binding.hue.internal.dto.Scene;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author HJiang - initial contribution
|
* @author HJiang - initial contribution
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class SceneTest {
|
public class SceneTest {
|
||||||
|
|
||||||
private static final State PLACEHOLDER_STATE = new State();
|
private static final State PLACEHOLDER_STATE = new State();
|
||||||
|
@ -23,10 +23,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
|||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.openhab.binding.hue.internal.FullConfig;
|
import org.openhab.binding.hue.internal.dto.FullConfig;
|
||||||
import org.openhab.binding.hue.internal.FullLight;
|
import org.openhab.binding.hue.internal.dto.FullLight;
|
||||||
import org.openhab.binding.hue.internal.State.ColorMode;
|
import org.openhab.binding.hue.internal.dto.State.ColorMode;
|
||||||
import org.openhab.binding.hue.internal.StateUpdate;
|
import org.openhab.binding.hue.internal.dto.StateUpdate;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
import org.openhab.core.library.types.HSBType;
|
import org.openhab.core.library.types.HSBType;
|
||||||
|
@ -12,7 +12,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.hue.internal.handler;
|
package org.openhab.binding.hue.internal.handler;
|
||||||
|
|
||||||
import org.openhab.binding.hue.internal.State.ColorMode;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.hue.internal.dto.State.ColorMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for the current state of a hue light.
|
* Builder for the current state of a hue light.
|
||||||
@ -22,6 +23,7 @@ import org.openhab.binding.hue.internal.State.ColorMode;
|
|||||||
* @author Markus Rathgeb - migrated to plain Java test
|
* @author Markus Rathgeb - migrated to plain Java test
|
||||||
* @author Christoph Weitkamp - Added support for bulbs using CIE XY colormode only
|
* @author Christoph Weitkamp - Added support for bulbs using CIE XY colormode only
|
||||||
*/
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
public class HueLightState {
|
public class HueLightState {
|
||||||
|
|
||||||
int brightness = 200;
|
int brightness = 200;
|
||||||
|
@ -26,8 +26,6 @@ Fragment-Host: org.openhab.binding.hue
|
|||||||
jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
|
jakarta.xml.bind-api;version='[2.3.3,2.3.4)',\
|
||||||
org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\
|
org.apache.servicemix.specs.activation-api-1.2.1;version='[1.2.1,1.2.2)',\
|
||||||
org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\
|
org.glassfish.hk2.osgi-resource-locator;version='[1.0.3,1.0.4)',\
|
||||||
org.objectweb.asm.commons;version='[9.0.0,9.0.1)',\
|
|
||||||
org.objectweb.asm.tree;version='[9.0.0,9.0.1)',\
|
|
||||||
jakarta.annotation-api;version='[2.0.0,2.0.1)',\
|
jakarta.annotation-api;version='[2.0.0,2.0.1)',\
|
||||||
jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\
|
jakarta.inject.jakarta.inject-api;version='[2.0.0,2.0.1)',\
|
||||||
javax.measure.unit-api;version='[2.1.2,2.1.3)',\
|
javax.measure.unit-api;version='[2.1.2,2.1.3)',\
|
||||||
@ -45,12 +43,21 @@ Fragment-Host: org.openhab.binding.hue
|
|||||||
org.apache.felix.scr;version='[2.1.30,2.1.31)',\
|
org.apache.felix.scr;version='[2.1.30,2.1.31)',\
|
||||||
org.osgi.util.function;version='[1.2.0,1.2.1)',\
|
org.osgi.util.function;version='[1.2.0,1.2.1)',\
|
||||||
org.osgi.util.promise;version='[1.2.0,1.2.1)',\
|
org.osgi.util.promise;version='[1.2.0,1.2.1)',\
|
||||||
|
org.openhab.binding.hue;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.binding.hue.tests;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.binding.xml;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.config.core;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.config.discovery;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.config.xml;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.io.console;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.io.net;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.test;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.thing;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.thing.xml;version='[3.4.0,3.4.1)',\
|
||||||
xstream;version='[1.4.19,1.4.20)',\
|
xstream;version='[1.4.19,1.4.20)',\
|
||||||
com.google.gson;version='[2.8.9,2.8.10)',\
|
com.google.gson;version='[2.8.9,2.8.10)',\
|
||||||
org.objectweb.asm;version='[9.2.0,9.2.1)',\
|
|
||||||
org.apache.felix.configadmin;version='[1.9.24,1.9.25)',\
|
org.apache.felix.configadmin;version='[1.9.24,1.9.25)',\
|
||||||
org.apache.xbean.bundleutils;version='[4.21.0,4.21.1)',\
|
|
||||||
org.apache.xbean.finder;version='[4.21.0,4.21.1)',\
|
|
||||||
org.eclipse.jetty.client;version='[9.4.46,9.4.47)',\
|
org.eclipse.jetty.client;version='[9.4.46,9.4.47)',\
|
||||||
org.eclipse.jetty.http;version='[9.4.46,9.4.47)',\
|
org.eclipse.jetty.http;version='[9.4.46,9.4.47)',\
|
||||||
org.eclipse.jetty.io;version='[9.4.46,9.4.47)',\
|
org.eclipse.jetty.io;version='[9.4.46,9.4.47)',\
|
||||||
@ -63,22 +70,14 @@ Fragment-Host: org.openhab.binding.hue
|
|||||||
org.eclipse.jetty.websocket.client;version='[9.4.46,9.4.47)',\
|
org.eclipse.jetty.websocket.client;version='[9.4.46,9.4.47)',\
|
||||||
org.eclipse.jetty.websocket.common;version='[9.4.46,9.4.47)',\
|
org.eclipse.jetty.websocket.common;version='[9.4.46,9.4.47)',\
|
||||||
org.ops4j.pax.logging.pax-logging-api;version='[2.0.16,2.0.17)',\
|
org.ops4j.pax.logging.pax-logging-api;version='[2.0.16,2.0.17)',\
|
||||||
org.ops4j.pax.web.pax-web-api;version='[7.3.25,7.3.26)',\
|
|
||||||
org.jupnp;version='[2.6.1,2.6.2)',\
|
|
||||||
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
|
||||||
ch.qos.logback.core;version='[1.2.11,1.2.12)',\
|
|
||||||
org.eclipse.jdt.annotation;version='[2.2.100,2.2.101)',\
|
org.eclipse.jdt.annotation;version='[2.2.100,2.2.101)',\
|
||||||
|
javax.jmdns;version='[3.5.8,3.5.9)',\
|
||||||
|
net.bytebuddy.byte-buddy;version='[1.12.1,1.12.2)',\
|
||||||
|
net.bytebuddy.byte-buddy-agent;version='[1.12.1,1.12.2)',\
|
||||||
|
org.mockito.mockito-core;version='[4.1.0,4.1.1)',\
|
||||||
|
org.objenesis;version='[3.2.0,3.2.1)',\
|
||||||
|
org.openhab.core.config.discovery.mdns;version='[3.4.0,3.4.1)',\
|
||||||
|
org.openhab.core.io.transport.mdns;version='[3.4.0,3.4.1)',\
|
||||||
biz.aQute.tester.junit-platform;version='[6.3.0,6.3.1)',\
|
biz.aQute.tester.junit-platform;version='[6.3.0,6.3.1)',\
|
||||||
org.openhab.binding.hue;version='[3.4.0,3.4.1)',\
|
ch.qos.logback.classic;version='[1.2.11,1.2.12)',\
|
||||||
org.openhab.binding.hue.tests;version='[3.4.0,3.4.1)',\
|
ch.qos.logback.core;version='[1.2.11,1.2.12)'
|
||||||
org.openhab.core;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.binding.xml;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.config.core;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.config.discovery;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.config.discovery.upnp;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.config.xml;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.io.console;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.io.net;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.test;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.thing;version='[3.4.0,3.4.1)',\
|
|
||||||
org.openhab.core.thing.xml;version='[3.4.0,3.4.1)'
|
|
||||||
|
@ -15,26 +15,35 @@ package org.openhab.binding.hue.internal;
|
|||||||
import static org.hamcrest.CoreMatchers.*;
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.openhab.binding.hue.internal.config.HueBridgeConfig;
|
||||||
|
import org.openhab.binding.hue.internal.connection.HueBridge;
|
||||||
import org.openhab.binding.hue.internal.discovery.HueDeviceDiscoveryService;
|
import org.openhab.binding.hue.internal.discovery.HueDeviceDiscoveryService;
|
||||||
|
import org.openhab.binding.hue.internal.dto.FullLight;
|
||||||
|
import org.openhab.binding.hue.internal.exceptions.ApiException;
|
||||||
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
|
||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.config.discovery.DiscoveryListener;
|
import org.openhab.core.config.discovery.DiscoveryListener;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
import org.openhab.core.config.discovery.DiscoveryResult;
|
||||||
import org.openhab.core.config.discovery.DiscoveryResultFlag;
|
import org.openhab.core.config.discovery.DiscoveryResultFlag;
|
||||||
import org.openhab.core.config.discovery.DiscoveryService;
|
import org.openhab.core.config.discovery.DiscoveryService;
|
||||||
|
import org.openhab.core.i18n.CommunicationException;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingRegistry;
|
import org.openhab.core.thing.ThingRegistry;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
@ -54,7 +63,6 @@ import org.openhab.core.thing.binding.builder.ThingStatusInfoBuilder;
|
|||||||
*/
|
*/
|
||||||
public class HueDeviceDiscoveryServiceOSGiTest extends AbstractHueOSGiTestParent {
|
public class HueDeviceDiscoveryServiceOSGiTest extends AbstractHueOSGiTestParent {
|
||||||
|
|
||||||
protected HueThingHandlerFactory hueThingHandlerFactory;
|
|
||||||
protected DiscoveryListener discoveryListener;
|
protected DiscoveryListener discoveryListener;
|
||||||
protected ThingRegistry thingRegistry;
|
protected ThingRegistry thingRegistry;
|
||||||
protected Bridge hueBridge;
|
protected Bridge hueBridge;
|
||||||
@ -74,7 +82,8 @@ public class HueDeviceDiscoveryServiceOSGiTest extends AbstractHueOSGiTestParent
|
|||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, "1.2.3.4");
|
configuration.put(HOST, "1.2.3.4");
|
||||||
configuration.put(USER_NAME, "testUserName");
|
configuration.put(USER_NAME, "testUserName");
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
|
configuration.put("useSelfSignedCertificate", false);
|
||||||
|
|
||||||
hueBridge = (Bridge) thingRegistry.createThingOfType(BRIDGE_THING_TYPE_UID, BRIDGE_THING_UID, null, "Bridge",
|
hueBridge = (Bridge) thingRegistry.createThingOfType(BRIDGE_THING_TYPE_UID, BRIDGE_THING_UID, null, "Bridge",
|
||||||
configuration);
|
configuration);
|
||||||
@ -150,45 +159,45 @@ public class HueDeviceDiscoveryServiceOSGiTest extends AbstractHueOSGiTestParent
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startSearchIsCalled() {
|
public void startSearchIsCalled() throws IOException, ApiException {
|
||||||
final AtomicBoolean searchHasBeenTriggered = new AtomicBoolean(false);
|
final AtomicBoolean searchHasBeenTriggered = new AtomicBoolean(false);
|
||||||
|
|
||||||
MockedHttpClient mockedHttpClient = new MockedHttpClient() {
|
HueBridge mockedHueBridge = new HueBridge(mock(HttpClient.class), "ip", 443, HueBridgeConfig.HTTPS, "username",
|
||||||
|
Executors.newScheduledThreadPool(1)) {
|
||||||
@Override
|
@Override
|
||||||
public Result put(String address, String body) throws IOException {
|
public HueResult get(String address) throws CommunicationException {
|
||||||
return new Result("", 200);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Result get(String address) throws IOException {
|
|
||||||
if (address.endsWith("testUserName")) {
|
if (address.endsWith("testUserName")) {
|
||||||
String body = "{\"lights\":{}}";
|
String body = "{\"lights\":{}}";
|
||||||
return new Result(body, 200);
|
return new HueResult(body, HttpStatus.OK_200);
|
||||||
} else if (address.endsWith("lights") || address.endsWith("sensors") || address.endsWith("groups")) {
|
} else if (address.endsWith("lights") || address.endsWith("sensors") || address.endsWith("groups")) {
|
||||||
String body = "{}";
|
String body = "{}";
|
||||||
return new Result(body, 200);
|
return new HueResult(body, HttpStatus.OK_200);
|
||||||
} else if (address.endsWith("testUserName/config")) {
|
} else if (address.endsWith("testUserName/config")) {
|
||||||
String body = "{ \"apiversion\": \"1.26.0\"}";
|
String body = "{\"apiversion\": \"1.26.0\"}";
|
||||||
return new Result(body, 200);
|
return new HueResult(body, HttpStatus.OK_200);
|
||||||
} else {
|
} else {
|
||||||
return new Result("", 404);
|
return new HueResult("", HttpStatus.NOT_FOUND_404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result post(String address, String body) throws IOException {
|
public HueResult post(String address, String body) throws CommunicationException {
|
||||||
if (address.endsWith("lights")) {
|
if (address.endsWith("lights")) {
|
||||||
String bodyReturn = "{\"success\": {\"/lights\": \"Searching for new devices\"}}";
|
String bodyReturn = "{\"success\": {\"/lights\": \"Searching for new devices\"}}";
|
||||||
searchHasBeenTriggered.set(true);
|
searchHasBeenTriggered.set(true);
|
||||||
return new Result(bodyReturn, 200);
|
return new HueResult(bodyReturn, HttpStatus.OK_200);
|
||||||
} else {
|
} else {
|
||||||
return new Result("", 404);
|
return new HueResult("", HttpStatus.NOT_FOUND_404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HueResult put(String address, String body) throws CommunicationException {
|
||||||
|
return new HueResult("", HttpStatus.OK_200);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
installHttpClientMock(hueBridgeHandler, mockedHttpClient);
|
installHttpClientMock(hueBridgeHandler, mockedHueBridge);
|
||||||
|
|
||||||
ThingStatusInfo online = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
|
ThingStatusInfo online = ThingStatusInfoBuilder.create(ThingStatus.ONLINE, ThingStatusDetail.NONE).build();
|
||||||
waitForAssert(() -> {
|
waitForAssert(() -> {
|
||||||
@ -201,19 +210,17 @@ public class HueDeviceDiscoveryServiceOSGiTest extends AbstractHueOSGiTestParent
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installHttpClientMock(HueBridgeHandler hueBridgeHandler, MockedHttpClient mockedHttpClient) {
|
private void installHttpClientMock(HueBridgeHandler hueBridgeHandler, HueBridge mockedHueBridge) {
|
||||||
waitForAssert(() -> {
|
waitForAssert(() -> {
|
||||||
try {
|
try {
|
||||||
// mock HttpClient
|
// mock HttpClient
|
||||||
final Field hueBridgeField = HueBridgeHandler.class.getDeclaredField("hueBridge");
|
final Field hueBridgeField = HueBridgeHandler.class.getDeclaredField("hueBridge");
|
||||||
hueBridgeField.setAccessible(true);
|
hueBridgeField.setAccessible(true);
|
||||||
|
hueBridgeField.set(hueBridgeHandler, mockedHueBridge);
|
||||||
|
|
||||||
final Object hueBridgeValue = hueBridgeField.get(hueBridgeHandler);
|
final Object hueBridgeValue = hueBridgeField.get(hueBridgeHandler);
|
||||||
assertThat(hueBridgeValue, is(notNullValue()));
|
assertThat(hueBridgeValue, is(notNullValue()));
|
||||||
|
|
||||||
final Field httpClientField = HueBridge.class.getDeclaredField("http");
|
|
||||||
httpClientField.setAccessible(true);
|
|
||||||
httpClientField.set(hueBridgeValue, mockedHttpClient);
|
|
||||||
|
|
||||||
final Field usernameField = HueBridge.class.getDeclaredField("username");
|
final Field usernameField = HueBridge.class.getDeclaredField("username");
|
||||||
usernameField.setAccessible(true);
|
usernameField.setAccessible(true);
|
||||||
usernameField.set(hueBridgeValue, hueBridgeHandler.getThing().getConfiguration().get(USER_NAME));
|
usernameField.set(hueBridgeValue, hueBridgeHandler.getThing().getConfiguration().get(USER_NAME));
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Denis Dudnik - Initial contribution
|
|
||||||
*/
|
|
||||||
public class MockedHttpClient extends HttpClient {
|
|
||||||
|
|
||||||
}
|
|
@ -1,117 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
|
||||||
*
|
|
||||||
* See the NOTICE file(s) distributed with this work for additional
|
|
||||||
* information.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.openhab.binding.hue.internal.discovery;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.*;
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
|
||||||
import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
|
|
||||||
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.jupnp.model.ValidationException;
|
|
||||||
import org.jupnp.model.meta.DeviceDetails;
|
|
||||||
import org.jupnp.model.meta.ManufacturerDetails;
|
|
||||||
import org.jupnp.model.meta.ModelDetails;
|
|
||||||
import org.jupnp.model.meta.RemoteDevice;
|
|
||||||
import org.jupnp.model.meta.RemoteDeviceIdentity;
|
|
||||||
import org.jupnp.model.meta.RemoteService;
|
|
||||||
import org.jupnp.model.types.DeviceType;
|
|
||||||
import org.jupnp.model.types.UDN;
|
|
||||||
import org.openhab.core.config.discovery.DiscoveryResult;
|
|
||||||
import org.openhab.core.config.discovery.DiscoveryResultFlag;
|
|
||||||
import org.openhab.core.config.discovery.upnp.UpnpDiscoveryParticipant;
|
|
||||||
import org.openhab.core.test.java.JavaOSGiTest;
|
|
||||||
import org.openhab.core.thing.ThingUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for {@link org.openhab.binding.hue.internal.discovery.HueBridgeDiscoveryParticipant}.
|
|
||||||
*
|
|
||||||
* @author Kai Kreuzer - Initial contribution
|
|
||||||
* @author Thomas Höfer - Added representation
|
|
||||||
* @author Markus Rathgeb - migrated to plain Java test
|
|
||||||
*/
|
|
||||||
public class HueBridgeDiscoveryParticipantOSGITest extends JavaOSGiTest {
|
|
||||||
|
|
||||||
UpnpDiscoveryParticipant discoveryParticipant;
|
|
||||||
|
|
||||||
RemoteDevice hueDevice;
|
|
||||||
RemoteDevice otherDevice;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp() {
|
|
||||||
discoveryParticipant = getService(UpnpDiscoveryParticipant.class, HueBridgeDiscoveryParticipant.class);
|
|
||||||
assertThat(discoveryParticipant, is(notNullValue()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
final RemoteService remoteService = null;
|
|
||||||
|
|
||||||
hueDevice = new RemoteDevice(
|
|
||||||
new RemoteDeviceIdentity(new UDN("123"), 60, new URL("http://hue"), null, null),
|
|
||||||
new DeviceType("namespace", "type"),
|
|
||||||
new DeviceDetails(new URL("http://1.2.3.4/"), "Hue Bridge", new ManufacturerDetails("Philips"),
|
|
||||||
new ModelDetails("Philips hue bridge"), "serial123", "upc", null),
|
|
||||||
remoteService);
|
|
||||||
|
|
||||||
otherDevice = new RemoteDevice(
|
|
||||||
new RemoteDeviceIdentity(new UDN("567"), 60, new URL("http://acme"), null, null),
|
|
||||||
new DeviceType("namespace", "type"), new DeviceDetails("Some Device",
|
|
||||||
new ManufacturerDetails("Taiwan"), new ModelDetails("$%&/"), "serial567", "upc"),
|
|
||||||
remoteService);
|
|
||||||
} catch (final ValidationException | MalformedURLException ex) {
|
|
||||||
fail("Internal test error.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void cleanUp() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void correctSupportedTypes() {
|
|
||||||
assertThat(discoveryParticipant.getSupportedThingTypeUIDs().size(), is(1));
|
|
||||||
assertThat(discoveryParticipant.getSupportedThingTypeUIDs().iterator().next(), is(THING_TYPE_BRIDGE));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void correctThingUID() {
|
|
||||||
assertThat(discoveryParticipant.getThingUID(hueDevice), is(new ThingUID("hue:bridge:serial123")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void validDiscoveryResult() {
|
|
||||||
final DiscoveryResult result = discoveryParticipant.createResult(hueDevice);
|
|
||||||
assertThat(result.getFlag(), is(DiscoveryResultFlag.NEW));
|
|
||||||
assertThat(result.getThingUID(), is(new ThingUID("hue:bridge:serial123")));
|
|
||||||
assertThat(result.getThingTypeUID(), is(THING_TYPE_BRIDGE));
|
|
||||||
assertThat(result.getBridgeUID(), is(nullValue()));
|
|
||||||
assertThat(result.getProperties().get(HOST), is("1.2.3.4"));
|
|
||||||
assertThat(result.getProperties().get(PROPERTY_SERIAL_NUMBER), is("serial123"));
|
|
||||||
assertThat(result.getRepresentationProperty(), is(PROPERTY_SERIAL_NUMBER));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void noThingUIDForUnknownDevice() {
|
|
||||||
assertThat(discoveryParticipant.getThingUID(otherDevice), is(nullValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void noDiscoveryResultForUnknownDevice() {
|
|
||||||
assertThat(discoveryParticipant.createResult(otherDevice), is(nullValue()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -37,7 +37,6 @@ import org.openhab.core.thing.ThingTypeUID;
|
|||||||
import org.openhab.core.thing.ThingUID;
|
import org.openhab.core.thing.ThingUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @author Christoph Knauf - Initial contribution
|
* @author Christoph Knauf - Initial contribution
|
||||||
* @author Markus Rathgeb - migrated to plain Java test
|
* @author Markus Rathgeb - migrated to plain Java test
|
||||||
*/
|
*/
|
||||||
@ -51,64 +50,18 @@ public class HueBridgeNupnpDiscoveryOSGITest extends JavaOSGiTest {
|
|||||||
final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID("hue", "bridge");
|
final ThingTypeUID BRIDGE_THING_TYPE_UID = new ThingTypeUID("hue", "bridge");
|
||||||
final String ip1 = "192.168.31.17";
|
final String ip1 = "192.168.31.17";
|
||||||
final String ip2 = "192.168.30.28";
|
final String ip2 = "192.168.30.28";
|
||||||
final String sn1 = "00178820057f";
|
final String sn1 = "001788fffe20057f";
|
||||||
final String sn2 = "001788141b41";
|
final String sn2 = "001788fffe141b41";
|
||||||
final ThingUID BRIDGE_THING_UID_1 = new ThingUID(BRIDGE_THING_TYPE_UID, sn1);
|
final ThingUID BRIDGE_THING_UID_1 = new ThingUID(BRIDGE_THING_TYPE_UID, sn1);
|
||||||
final ThingUID BRIDGE_THING_UID_2 = new ThingUID(BRIDGE_THING_TYPE_UID, sn2);
|
final ThingUID BRIDGE_THING_UID_2 = new ThingUID(BRIDGE_THING_TYPE_UID, sn2);
|
||||||
final String validBridgeDiscoveryResult = "[{\"id\":\"001788fffe20057f\",\"internalipaddress\":" + ip1
|
final String validBridgeDiscoveryResult = "[{\"id\":\"" + sn1 + "\",\"internalipaddress\":" + ip1 + "},{\"id\":\""
|
||||||
+ "},{\"id\":\"001788fffe141b41\",\"internalipaddress\":" + ip2 + "}]";
|
+ sn2 + "\",\"internalipaddress\":" + ip2 + "}]";
|
||||||
String discoveryResult;
|
String discoveryResult;
|
||||||
String expBridgeDescription = "" + //
|
String expBridgeDescription = "{\"name\":\"Philips Hue\",\"datastoreversion\":\"113\",\"swversion\":\"1948086000\",\"apiversion\":\"1.48.0\",\"mac\":\"00:11:22:33:44\",\"bridgeid\":\"$SN\",\"factorynew\":false,\"replacesbridgeid\":null,\"modelid\":\"BSB002\",\"starterkitid\":\"\"}";
|
||||||
"<?xml version=\"1.0\"?>" + //
|
|
||||||
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">" + //
|
|
||||||
" <specVersion>" + //
|
|
||||||
" <major>1</major>" + //
|
|
||||||
" <minor>0</minor>" + //
|
|
||||||
" </specVersion>" + //
|
|
||||||
" <URLBase>http://$IP:80/</URLBase>" + //
|
|
||||||
" <device>" + //
|
|
||||||
" <deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>" + //
|
|
||||||
" <friendlyName>Philips hue ($IP)</friendlyName>" + //
|
|
||||||
" <manufacturer>Royal Philips Electronics</manufacturer>" + //
|
|
||||||
" <manufacturerURL>http://www.philips.com</manufacturerURL>" + //
|
|
||||||
"<modelDescription>Philips hue Personal Wireless Lighting</modelDescription>" + //
|
|
||||||
"<modelName>Philips hue bridge 2012</modelName>" + //
|
|
||||||
"<modelNumber>1000000000000</modelNumber>" + //
|
|
||||||
"<modelURL>http://www.meethue.com</modelURL>" + //
|
|
||||||
" <serialNumber>93eadbeef13</serialNumber>" + //
|
|
||||||
" <UDN>uuid:01234567-89ab-cdef-0123-456789abcdef</UDN>" + //
|
|
||||||
" <serviceList>" + //
|
|
||||||
" <service>" + //
|
|
||||||
" <serviceType>(null)</serviceType>" + //
|
|
||||||
" <serviceId>(null)</serviceId>" + //
|
|
||||||
" <controlURL>(null)</controlURL>" + //
|
|
||||||
" <eventSubURL>(null)</eventSubURL>" + //
|
|
||||||
" <SCPDURL>(null)</SCPDURL>" + //
|
|
||||||
" </service>" + //
|
|
||||||
" </serviceList>" + //
|
|
||||||
" <presentationURL>index.html</presentationURL>" + //
|
|
||||||
" <iconList>" + //
|
|
||||||
" <icon>" + //
|
|
||||||
" <mimetype>image/png</mimetype>" + //
|
|
||||||
" <height>48</height>" + //
|
|
||||||
" <width>48</width>" + //
|
|
||||||
" <depth>24</depth>" + //
|
|
||||||
" <url>hue_logo_0.png</url>" + //
|
|
||||||
" </icon>" + //
|
|
||||||
" <icon>" + //
|
|
||||||
" <mimetype>image/png</mimetype>" + //
|
|
||||||
" <height>120</height>" + //
|
|
||||||
" <width>120</width>" + //
|
|
||||||
" <depth>24</depth>" + //
|
|
||||||
" <url>hue_logo_3.png</url>" + //
|
|
||||||
" </icon>" + //
|
|
||||||
" </iconList>" + //
|
|
||||||
" </device>" + //
|
|
||||||
"</root>";
|
|
||||||
|
|
||||||
private void checkDiscoveryResult(DiscoveryResult result, String expIp, String expSn) {
|
private void checkDiscoveryResult(DiscoveryResult result, String expIp, String expSn) {
|
||||||
assertThat(result.getBridgeUID(), nullValue());
|
assertThat(result.getBridgeUID(), nullValue());
|
||||||
assertThat(result.getLabel(), is(HueBridgeNupnpDiscovery.LABEL_PATTERN.replace("IP", expIp)));
|
assertThat(result.getLabel(), is(String.format(HueBridgeNupnpDiscovery.LABEL_PATTERN, expIp)));
|
||||||
assertThat(result.getProperties().get("ipAddress"), is(expIp));
|
assertThat(result.getProperties().get("ipAddress"), is(expIp));
|
||||||
assertThat(result.getProperties().get("serialNumber"), is(expSn));
|
assertThat(result.getProperties().get("serialNumber"), is(expSn));
|
||||||
}
|
}
|
||||||
@ -132,9 +85,9 @@ public class HueBridgeNupnpDiscoveryOSGITest extends JavaOSGiTest {
|
|||||||
if (url.contains("meethue")) {
|
if (url.contains("meethue")) {
|
||||||
return discoveryResult;
|
return discoveryResult;
|
||||||
} else if (url.contains(ip1)) {
|
} else if (url.contains(ip1)) {
|
||||||
return expBridgeDescription.replaceAll("$IP", ip1);
|
return expBridgeDescription.replaceAll("$SN", sn1);
|
||||||
} else if (url.contains(ip2)) {
|
} else if (url.contains(ip2)) {
|
||||||
return expBridgeDescription.replaceAll("$IP", ip2);
|
return expBridgeDescription.replaceAll("$SN", sn2);
|
||||||
}
|
}
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
}
|
}
|
||||||
|
@ -16,19 +16,19 @@ import static org.eclipse.jdt.annotation.Checks.requireNonNull;
|
|||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
import static org.openhab.binding.hue.internal.HueBindingConstants.*;
|
||||||
import static org.openhab.binding.hue.internal.config.HueBridgeConfig.HTTP;
|
|
||||||
import static org.openhab.core.thing.Thing.PROPERTY_SERIAL_NUMBER;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.client.HttpClient;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.openhab.binding.hue.internal.AbstractHueOSGiTestParent;
|
import org.openhab.binding.hue.internal.AbstractHueOSGiTestParent;
|
||||||
import org.openhab.binding.hue.internal.HueBridge;
|
import org.openhab.binding.hue.internal.config.HueBridgeConfig;
|
||||||
import org.openhab.binding.hue.internal.HueConfigStatusMessage;
|
import org.openhab.binding.hue.internal.connection.HueBridge;
|
||||||
import org.openhab.binding.hue.internal.exceptions.ApiException;
|
import org.openhab.binding.hue.internal.exceptions.ApiException;
|
||||||
import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
|
import org.openhab.binding.hue.internal.exceptions.LinkButtonException;
|
||||||
import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
|
import org.openhab.binding.hue.internal.exceptions.UnauthorizedException;
|
||||||
@ -36,6 +36,7 @@ import org.openhab.core.common.ThreadPoolManager;
|
|||||||
import org.openhab.core.config.core.Configuration;
|
import org.openhab.core.config.core.Configuration;
|
||||||
import org.openhab.core.config.core.status.ConfigStatusMessage;
|
import org.openhab.core.config.core.status.ConfigStatusMessage;
|
||||||
import org.openhab.core.thing.Bridge;
|
import org.openhab.core.thing.Bridge;
|
||||||
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingRegistry;
|
import org.openhab.core.thing.ThingRegistry;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
@ -72,18 +73,19 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
public void assertThatANewUserIsAddedToConfigIfNotExistingYet() {
|
public void assertThatANewUserIsAddedToConfigIfNotExistingYet() {
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, DUMMY_HOST);
|
configuration.put(HOST, DUMMY_HOST);
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
hueBridgeHandler.thingUpdated(bridge);
|
hueBridgeHandler.thingUpdated(bridge);
|
||||||
|
|
||||||
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
|
injectBridge(hueBridgeHandler,
|
||||||
@Override
|
new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
|
||||||
public String link(String deviceType) throws IOException, ApiException {
|
@Override
|
||||||
return TEST_USER_NAME;
|
public String link(String deviceType) throws IOException, ApiException {
|
||||||
}
|
return TEST_USER_NAME;
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
hueBridgeHandler.onNotAuthenticated();
|
hueBridgeHandler.onNotAuthenticated();
|
||||||
|
|
||||||
@ -95,17 +97,18 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, DUMMY_HOST);
|
configuration.put(HOST, DUMMY_HOST);
|
||||||
configuration.put(USER_NAME, TEST_USER_NAME);
|
configuration.put(USER_NAME, TEST_USER_NAME);
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
hueBridgeHandler.thingUpdated(bridge);
|
hueBridgeHandler.thingUpdated(bridge);
|
||||||
|
|
||||||
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
|
injectBridge(hueBridgeHandler,
|
||||||
@Override
|
new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
|
||||||
public void authenticate(String userName) throws IOException, ApiException {
|
@Override
|
||||||
}
|
public void authenticate(String userName) throws IOException, ApiException {
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
hueBridgeHandler.onNotAuthenticated();
|
hueBridgeHandler.onNotAuthenticated();
|
||||||
|
|
||||||
@ -117,18 +120,19 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, DUMMY_HOST);
|
configuration.put(HOST, DUMMY_HOST);
|
||||||
configuration.put(USER_NAME, "notAuthenticatedUser");
|
configuration.put(USER_NAME, "notAuthenticatedUser");
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
hueBridgeHandler.thingUpdated(bridge);
|
hueBridgeHandler.thingUpdated(bridge);
|
||||||
|
|
||||||
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
|
injectBridge(hueBridgeHandler,
|
||||||
@Override
|
new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
|
||||||
public void authenticate(String userName) throws IOException, ApiException {
|
@Override
|
||||||
throw new UnauthorizedException();
|
public void authenticate(String userName) throws IOException, ApiException {
|
||||||
}
|
throw new UnauthorizedException();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
hueBridgeHandler.onNotAuthenticated();
|
hueBridgeHandler.onNotAuthenticated();
|
||||||
|
|
||||||
@ -141,18 +145,19 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
public void verifyStatusIfLinkButtonIsNotPressed() {
|
public void verifyStatusIfLinkButtonIsNotPressed() {
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, DUMMY_HOST);
|
configuration.put(HOST, DUMMY_HOST);
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
hueBridgeHandler.thingUpdated(bridge);
|
hueBridgeHandler.thingUpdated(bridge);
|
||||||
|
|
||||||
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
|
injectBridge(hueBridgeHandler,
|
||||||
@Override
|
new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
|
||||||
public String link(String deviceType) throws IOException, ApiException {
|
@Override
|
||||||
throw new LinkButtonException();
|
public String link(String deviceType) throws IOException, ApiException {
|
||||||
}
|
throw new LinkButtonException();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
hueBridgeHandler.onNotAuthenticated();
|
hueBridgeHandler.onNotAuthenticated();
|
||||||
|
|
||||||
@ -165,18 +170,19 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
public void verifyStatusIfNewUserCannotBeCreated() {
|
public void verifyStatusIfNewUserCannotBeCreated() {
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, DUMMY_HOST);
|
configuration.put(HOST, DUMMY_HOST);
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
hueBridgeHandler.thingUpdated(bridge);
|
hueBridgeHandler.thingUpdated(bridge);
|
||||||
|
|
||||||
injectBridge(hueBridgeHandler, new HueBridge(DUMMY_HOST, 80, HTTP, scheduler) {
|
injectBridge(hueBridgeHandler,
|
||||||
@Override
|
new HueBridge(mock(HttpClient.class), DUMMY_HOST, 80, HueBridgeConfig.HTTP, scheduler) {
|
||||||
public String link(String deviceType) throws IOException, ApiException {
|
@Override
|
||||||
throw new ApiException();
|
public String link(String deviceType) throws IOException, ApiException {
|
||||||
}
|
throw new ApiException();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
hueBridgeHandler.onNotAuthenticated();
|
hueBridgeHandler.onNotAuthenticated();
|
||||||
|
|
||||||
@ -190,7 +196,7 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
public void verifyOfflineIsSetWithoutBridgeOfflineStatus() {
|
public void verifyOfflineIsSetWithoutBridgeOfflineStatus() {
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, DUMMY_HOST);
|
configuration.put(HOST, DUMMY_HOST);
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
@ -206,14 +212,13 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsNull() {
|
public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsNull() {
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, null);
|
configuration.put(HOST, null);
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
|
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
|
|
||||||
ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST)
|
ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST).withMessageKeySuffix(IP_ADDRESS_MISSING)
|
||||||
.withMessageKeySuffix(HueConfigStatusMessage.IP_ADDRESS_MISSING).withArguments(HOST).build();
|
.withArguments(HOST).build();
|
||||||
|
|
||||||
waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
|
waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
|
||||||
}
|
}
|
||||||
@ -222,19 +227,19 @@ public class HueBridgeHandlerOSGiTest extends AbstractHueOSGiTestParent {
|
|||||||
public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsAnEmptyString() {
|
public void assertThatAStatusConfigurationMessageForMissingBridgeIPIsProperlyReturnedIPIsAnEmptyString() {
|
||||||
Configuration configuration = new Configuration();
|
Configuration configuration = new Configuration();
|
||||||
configuration.put(HOST, "");
|
configuration.put(HOST, "");
|
||||||
configuration.put(PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
configuration.put(Thing.PROPERTY_SERIAL_NUMBER, "testSerialNumber");
|
||||||
|
|
||||||
Bridge bridge = createBridgeThing(configuration);
|
Bridge bridge = createBridgeThing(configuration);
|
||||||
|
|
||||||
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
HueBridgeHandler hueBridgeHandler = getThingHandler(bridge, HueBridgeHandler.class);
|
||||||
|
|
||||||
ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST)
|
ConfigStatusMessage expected = ConfigStatusMessage.Builder.error(HOST).withMessageKeySuffix(IP_ADDRESS_MISSING)
|
||||||
.withMessageKeySuffix(HueConfigStatusMessage.IP_ADDRESS_MISSING).withArguments(HOST).build();
|
.withArguments(HOST).build();
|
||||||
|
|
||||||
waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
|
waitForAssert(() -> assertEquals(expected, hueBridgeHandler.getConfigStatus().iterator().next()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Bridge createBridgeThing(Configuration configuration) {
|
private Bridge createBridgeThing(Configuration configuration) {
|
||||||
|
configuration.put("useSelfSignedCertificate", false);
|
||||||
Bridge bridge = (Bridge) thingRegistry.createThingOfType(BRIDGE_THING_TYPE_UID,
|
Bridge bridge = (Bridge) thingRegistry.createThingOfType(BRIDGE_THING_TYPE_UID,
|
||||||
new ThingUID(BRIDGE_THING_TYPE_UID, "testBridge"), null, "Bridge", configuration);
|
new ThingUID(BRIDGE_THING_TYPE_UID, "testBridge"), null, "Bridge", configuration);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user