[deconz] initial support for scenes (#9345)
* initial support for scenes * add documentation Signed-off-by: Jan N. Klug <jan.n.klug@rub.de>
This commit is contained in:
parent
12e5e38cb0
commit
af3f8774d0
@ -163,7 +163,7 @@ Other devices support
|
|||||||
| color | Color | R/W | Color of an multi-color light | `colorlight`, `extendedcolorlight`, `lightgroup`|
|
| color | Color | R/W | Color of an multi-color light | `colorlight`, `extendedcolorlight`, `lightgroup`|
|
||||||
| color_temperature | Number | R/W | Color temperature in Kelvin. The value range is determined by each individual light | `colortemperaturelight`, `extendedcolorlight`, `lightgroup` |
|
| color_temperature | Number | R/W | Color temperature in Kelvin. The value range is determined by each individual light | `colortemperaturelight`, `extendedcolorlight`, `lightgroup` |
|
||||||
| effect | String | R/W | Effect selection. Allowed commands are set dynamically | `colorlight` |
|
| effect | String | R/W | Effect selection. Allowed commands are set dynamically | `colorlight` |
|
||||||
| effectSpeed | Number | R/W | Effect Speed | `colorlight` |
|
| effectSpeed | Number | W | Effect Speed | `colorlight` |
|
||||||
| lock | Switch | R/W | Lock (ON) or unlock (OFF) the doorlock| `doorlock` |
|
| lock | Switch | R/W | Lock (ON) or unlock (OFF) the doorlock| `doorlock` |
|
||||||
| position | Rollershutter | R/W | Position of the blind | `windowcovering` |
|
| position | Rollershutter | R/W | Position of the blind | `windowcovering` |
|
||||||
| heatsetpoint | Number:Temperature | R/W | Target Temperature in °C | `thermostat` |
|
| heatsetpoint | Number:Temperature | R/W | Target Temperature in °C | `thermostat` |
|
||||||
@ -173,11 +173,11 @@ Other devices support
|
|||||||
| alert | Switch | R/W | Turn alerts on/off | `warningdevice`, `lightgroup` |
|
| alert | Switch | R/W | Turn alerts on/off | `warningdevice`, `lightgroup` |
|
||||||
| all_on | Switch | R | All lights in group are on | `lightgroup` |
|
| all_on | Switch | R | All lights in group are on | `lightgroup` |
|
||||||
| any_on | Switch | R | Any light in group is on | `lightgroup` |
|
| any_on | Switch | R | Any light in group is on | `lightgroup` |
|
||||||
|
| scene | String | W | Recall a scene. Allowed commands are set dynamically | `lightgroup` |
|
||||||
|
|
||||||
**NOTE:** For groups `color` and `color_temperature` are used for sending commands to the group.
|
**NOTE:** For groups `color` and `color_temperature` are used for sending commands to the group.
|
||||||
Their state represents the last command send to the group, not necessarily the actual state of the group.
|
Their state represents the last command send to the group, not necessarily the actual state of the group.
|
||||||
|
|
||||||
|
|
||||||
### Trigger Channels
|
### Trigger Channels
|
||||||
|
|
||||||
The dimmer switch additionally supports trigger channels.
|
The dimmer switch additionally supports trigger channels.
|
||||||
|
|||||||
@ -116,6 +116,7 @@ public class BindingConstants {
|
|||||||
public static final String CHANNEL_LOCK = "lock";
|
public static final String CHANNEL_LOCK = "lock";
|
||||||
public static final String CHANNEL_EFFECT = "effect";
|
public static final String CHANNEL_EFFECT = "effect";
|
||||||
public static final String CHANNEL_EFFECT_SPEED = "effectSpeed";
|
public static final String CHANNEL_EFFECT_SPEED = "effectSpeed";
|
||||||
|
public static final String CHANNEL_SCENE = "scene";
|
||||||
|
|
||||||
// channel uids
|
// channel uids
|
||||||
public static final ChannelTypeUID CHANNEL_EFFECT_TYPE_UID = new ChannelTypeUID(BINDING_ID, CHANNEL_EFFECT);
|
public static final ChannelTypeUID CHANNEL_EFFECT_TYPE_UID = new ChannelTypeUID(BINDING_ID, CHANNEL_EFFECT);
|
||||||
|
|||||||
@ -94,7 +94,7 @@ public class DeconzHandlerFactory extends BaseThingHandlerFactory {
|
|||||||
} else if (SensorThermostatThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
} else if (SensorThermostatThingHandler.SUPPORTED_THING_TYPES.contains(thingTypeUID)) {
|
||||||
return new SensorThermostatThingHandler(thing, gson);
|
return new SensorThermostatThingHandler(thing, gson);
|
||||||
} else if (GroupThingHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) {
|
} else if (GroupThingHandler.SUPPORTED_THING_TYPE_UIDS.contains(thingTypeUID)) {
|
||||||
return new GroupThingHandler(thing, gson);
|
return new GroupThingHandler(thing, gson, commandDescriptionProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.deconz.internal.dto;
|
package org.openhab.binding.deconz.internal.dto;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
@ -27,20 +27,22 @@ import org.openhab.binding.deconz.internal.types.GroupType;
|
|||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class GroupMessage extends DeconzBaseMessage {
|
public class GroupMessage extends DeconzBaseMessage {
|
||||||
public @Nullable GroupAction action;
|
public @Nullable GroupAction action;
|
||||||
public String @Nullable [] devicemembership;
|
public List<String> devicemembership = List.of();
|
||||||
public @Nullable Boolean hidden;
|
public @Nullable Boolean hidden;
|
||||||
public String @Nullable [] lights;
|
public List<String> lights = List.of();
|
||||||
public String @Nullable [] lightsequence;
|
public List<String> lightsequence = List.of();
|
||||||
public String @Nullable [] multideviceids;
|
public List<String> multideviceids = List.of();
|
||||||
public Scene @Nullable [] scenes;
|
public List<Scene> scenes = List.of();
|
||||||
public @Nullable GroupState state;
|
public @Nullable GroupState state;
|
||||||
public @Nullable GroupType type;
|
public @Nullable GroupType type;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "GroupMessage{" + "action=" + action + ", devicemembership=" + Arrays.toString(devicemembership)
|
return "GroupMessage{" + "e='" + e + '\'' + ", r=" + r + ", t='" + t + '\'' + ", id='" + id + '\''
|
||||||
+ ", hidden=" + hidden + ", lights=" + Arrays.toString(lights) + ", lightsequence="
|
+ ", manufacturername='" + manufacturername + '\'' + ", modelid='" + modelid + '\'' + ", name='" + name
|
||||||
+ Arrays.toString(lightsequence) + ", multideviceids=" + Arrays.toString(multideviceids) + ", scenes="
|
+ '\'' + ", swversion='" + swversion + '\'' + ", ep='" + ep + '\'' + ", lastseen='" + lastseen + '\''
|
||||||
+ Arrays.toString(scenes) + ", state=" + state + ", type=" + type + '}';
|
+ ", uniqueid='" + uniqueid + '\'' + ", action=" + action + ", devicemembership=" + devicemembership
|
||||||
|
+ ", hidden=" + hidden + ", lights=" + lights + ", lightsequence=" + lightsequence + ", multideviceids="
|
||||||
|
+ multideviceids + ", scenes=" + scenes + ", state=" + state + ", type=" + type + '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -159,23 +159,37 @@ public abstract class DeconzBaseThingHandler extends BaseThingHandler implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sends a command to the bridge
|
* sends a command to the bridge with the default command URL
|
||||||
*
|
*
|
||||||
* @param object must be serializable and contain the command
|
* @param object must be serializable and contain the command
|
||||||
* @param originalCommand the original openHAB command (used for logging purposes)
|
* @param originalCommand the original openHAB command (used for logging purposes)
|
||||||
* @param channelUID the channel that this command was send to (used for logging purposes)
|
* @param channelUID the channel that this command was send to (used for logging purposes)
|
||||||
* @param acceptProcessing additional processing after the command was successfully send (might be null)
|
* @param acceptProcessing additional processing after the command was successfully send (might be null)
|
||||||
*/
|
*/
|
||||||
protected void sendCommand(Object object, Command originalCommand, ChannelUID channelUID,
|
protected void sendCommand(@Nullable Object object, Command originalCommand, ChannelUID channelUID,
|
||||||
@Nullable Runnable acceptProcessing) {
|
@Nullable Runnable acceptProcessing) {
|
||||||
|
sendCommand(object, originalCommand, channelUID, resourceType.getCommandUrl(), acceptProcessing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends a command to the bridge with a caller-defined command URL
|
||||||
|
*
|
||||||
|
* @param object must be serializable and contain the command
|
||||||
|
* @param originalCommand the original openHAB command (used for logging purposes)
|
||||||
|
* @param channelUID the channel that this command was send to (used for logging purposes)
|
||||||
|
* @param commandUrl the command URL
|
||||||
|
* @param acceptProcessing additional processing after the command was successfully send (might be null)
|
||||||
|
*/
|
||||||
|
protected void sendCommand(@Nullable Object object, Command originalCommand, ChannelUID channelUID,
|
||||||
|
String commandUrl, @Nullable Runnable acceptProcessing) {
|
||||||
AsyncHttpClient asyncHttpClient = http;
|
AsyncHttpClient asyncHttpClient = http;
|
||||||
if (asyncHttpClient == null) {
|
if (asyncHttpClient == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String url = buildUrl(bridgeConfig.host, bridgeConfig.httpPort, bridgeConfig.apikey,
|
String url = buildUrl(bridgeConfig.host, bridgeConfig.httpPort, bridgeConfig.apikey,
|
||||||
resourceType.getIdentifier(), config.id, resourceType.getCommandUrl());
|
resourceType.getIdentifier(), config.id, commandUrl);
|
||||||
|
|
||||||
String json = gson.toJson(object);
|
String json = object == null ? null : gson.toJson(object);
|
||||||
logger.trace("Sending {} to {} {} via {}", json, resourceType, config.id, url);
|
logger.trace("Sending {} to {} {} via {}", json, resourceType, config.id, url);
|
||||||
|
|
||||||
asyncHttpClient.put(url, json, bridgeConfig.timeout).thenAccept(v -> {
|
asyncHttpClient.put(url, json, bridgeConfig.timeout).thenAccept(v -> {
|
||||||
|
|||||||
@ -178,7 +178,7 @@ public class DeconzBridgeHandler extends BaseBridgeHandler implements WebSocketC
|
|||||||
} else if (t instanceof SocketTimeoutException || t instanceof TimeoutException
|
} else if (t instanceof SocketTimeoutException || t instanceof TimeoutException
|
||||||
|| t instanceof CompletionException) {
|
|| t instanceof CompletionException) {
|
||||||
logger.debug("Get full state failed", t);
|
logger.debug("Get full state failed", t);
|
||||||
} else if (t != null) {
|
} else {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, t.getMessage());
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, t.getMessage());
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
|
|||||||
@ -14,24 +14,26 @@ package org.openhab.binding.deconz.internal.handler;
|
|||||||
|
|
||||||
import static org.openhab.binding.deconz.internal.BindingConstants.*;
|
import static org.openhab.binding.deconz.internal.BindingConstants.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.deconz.internal.CommandDescriptionProvider;
|
||||||
import org.openhab.binding.deconz.internal.Util;
|
import org.openhab.binding.deconz.internal.Util;
|
||||||
import org.openhab.binding.deconz.internal.dto.DeconzBaseMessage;
|
import org.openhab.binding.deconz.internal.dto.DeconzBaseMessage;
|
||||||
import org.openhab.binding.deconz.internal.dto.GroupAction;
|
import org.openhab.binding.deconz.internal.dto.GroupAction;
|
||||||
import org.openhab.binding.deconz.internal.dto.GroupMessage;
|
import org.openhab.binding.deconz.internal.dto.GroupMessage;
|
||||||
import org.openhab.binding.deconz.internal.dto.GroupState;
|
import org.openhab.binding.deconz.internal.dto.GroupState;
|
||||||
import org.openhab.binding.deconz.internal.types.ResourceType;
|
import org.openhab.binding.deconz.internal.types.ResourceType;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.*;
|
||||||
import org.openhab.core.library.types.HSBType;
|
|
||||||
import org.openhab.core.library.types.OnOffType;
|
|
||||||
import org.openhab.core.library.types.PercentType;
|
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
|
import org.openhab.core.types.CommandDescriptionBuilder;
|
||||||
|
import org.openhab.core.types.CommandOption;
|
||||||
import org.openhab.core.types.RefreshType;
|
import org.openhab.core.types.RefreshType;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -39,31 +41,25 @@ import org.slf4j.LoggerFactory;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This light thing doesn't establish any connections, that is done by the bridge Thing.
|
* This group thing doesn't establish any connections, that is done by the bridge Thing.
|
||||||
*
|
*
|
||||||
* It waits for the bridge to come online, grab the websocket connection and bridge configuration
|
* It waits for the bridge to come online, grab the websocket connection and bridge configuration
|
||||||
* and registers to the websocket connection as a listener.
|
* and registers to the websocket connection as a listener.
|
||||||
*
|
*
|
||||||
* A REST API call is made to get the initial light/rollershutter state.
|
|
||||||
*
|
|
||||||
* Every light and rollershutter is supported by this Thing, because a unified state is kept
|
|
||||||
* in {@link #groupStateCache}. Every field that got received by the REST API for this specific
|
|
||||||
* sensor is published to the framework.
|
|
||||||
*
|
|
||||||
* @author Jan N. Klug - Initial contribution
|
* @author Jan N. Klug - Initial contribution
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class GroupThingHandler extends DeconzBaseThingHandler {
|
public class GroupThingHandler extends DeconzBaseThingHandler {
|
||||||
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Set.of(THING_TYPE_LIGHTGROUP);
|
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPE_UIDS = Set.of(THING_TYPE_LIGHTGROUP);
|
||||||
private final Logger logger = LoggerFactory.getLogger(GroupThingHandler.class);
|
private final Logger logger = LoggerFactory.getLogger(GroupThingHandler.class);
|
||||||
|
private final CommandDescriptionProvider commandDescriptionProvider;
|
||||||
|
|
||||||
/**
|
private Map<String, String> scenes = Map.of();
|
||||||
* The group state.
|
|
||||||
*/
|
|
||||||
private GroupState groupStateCache = new GroupState();
|
private GroupState groupStateCache = new GroupState();
|
||||||
|
|
||||||
public GroupThingHandler(Thing thing, Gson gson) {
|
public GroupThingHandler(Thing thing, Gson gson, CommandDescriptionProvider commandDescriptionProvider) {
|
||||||
super(thing, gson, ResourceType.GROUPS);
|
super(thing, gson, ResourceType.GROUPS);
|
||||||
|
this.commandDescriptionProvider = commandDescriptionProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -113,6 +109,17 @@ public class GroupThingHandler extends DeconzBaseThingHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CHANNEL_SCENE:
|
||||||
|
if (command instanceof StringType) {
|
||||||
|
String sceneId = scenes.get(command.toString());
|
||||||
|
if (sceneId != null) {
|
||||||
|
sendCommand(null, command, channelUID, "scene/" + sceneId + "/recall", null);
|
||||||
|
} else {
|
||||||
|
logger.debug("Ignoring command {} for {}, scene is not found in available scenes: {}", command,
|
||||||
|
channelUID, scenes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -127,6 +134,16 @@ public class GroupThingHandler extends DeconzBaseThingHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void processStateResponse(DeconzBaseMessage stateResponse) {
|
protected void processStateResponse(DeconzBaseMessage stateResponse) {
|
||||||
|
if (stateResponse instanceof GroupMessage) {
|
||||||
|
GroupMessage groupMessage = (GroupMessage) stateResponse;
|
||||||
|
scenes = groupMessage.scenes.stream().collect(Collectors.toMap(scene -> scene.name, scene -> scene.id));
|
||||||
|
ChannelUID channelUID = new ChannelUID(thing.getUID(), CHANNEL_SCENE);
|
||||||
|
commandDescriptionProvider.setDescription(channelUID,
|
||||||
|
CommandDescriptionBuilder.create().withCommandOptions(groupMessage.scenes.stream()
|
||||||
|
.map(scene -> new CommandOption(scene.name, scene.name)).collect(Collectors.toList()))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
}
|
||||||
messageReceived(config.id, stateResponse);
|
messageReceived(config.id, stateResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -282,7 +282,8 @@ public class LightThingHandler extends DeconzBaseThingHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lightMessage.state.effect != null) {
|
LightState lightState = lightMessage.state;
|
||||||
|
if (lightState != null && lightState.effect != null) {
|
||||||
checkAndUpdateEffectChannels(lightMessage);
|
checkAndUpdateEffectChannels(lightMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -198,7 +198,8 @@ public class SensorThermostatThingHandler extends SensorBaseThingHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SensorMessage sensorMessage = (SensorMessage) stateResponse;
|
SensorMessage sensorMessage = (SensorMessage) stateResponse;
|
||||||
if (sensorMessage.state.windowopen != null && thing.getChannel(CHANNEL_WINDOWOPEN) == null) {
|
SensorState sensorState = sensorMessage.state;
|
||||||
|
if (sensorState != null && sensorState.windowopen != null && thing.getChannel(CHANNEL_WINDOWOPEN) == null) {
|
||||||
ThingBuilder thingBuilder = editThing();
|
ThingBuilder thingBuilder = editThing();
|
||||||
thingBuilder.withChannel(ChannelBuilder.create(new ChannelUID(thing.getUID(), CHANNEL_WINDOWOPEN), "String")
|
thingBuilder.withChannel(ChannelBuilder.create(new ChannelUID(thing.getUID(), CHANNEL_WINDOWOPEN), "String")
|
||||||
.withType(new ChannelTypeUID(BINDING_ID, "open")).build());
|
.withType(new ChannelTypeUID(BINDING_ID, "open")).build());
|
||||||
|
|||||||
@ -60,7 +60,7 @@ public class AsyncHttpClient {
|
|||||||
* @param timeout A timeout
|
* @param timeout A timeout
|
||||||
* @return The result
|
* @return The result
|
||||||
*/
|
*/
|
||||||
public CompletableFuture<Result> put(String address, String jsonString, int timeout) {
|
public CompletableFuture<Result> put(String address, @Nullable String jsonString, int timeout) {
|
||||||
return doNetwork(HttpMethod.PUT, address, jsonString, timeout);
|
return doNetwork(HttpMethod.PUT, address, jsonString, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,7 @@ package org.openhab.binding.deconz.internal.netutils;
|
|||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
@ -104,12 +105,12 @@ public class WebSocketConnection {
|
|||||||
connectionListener.connectionEstablished();
|
connectionListener.connectionEstablished();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("null, unused")
|
@SuppressWarnings({ "null", "unused" })
|
||||||
@OnWebSocketMessage
|
@OnWebSocketMessage
|
||||||
public void onMessage(String message) {
|
public void onMessage(String message) {
|
||||||
logger.trace("Raw data received by websocket {}: {}", socketName, message);
|
logger.trace("Raw data received by websocket {}: {}", socketName, message);
|
||||||
|
|
||||||
DeconzBaseMessage changedMessage = gson.fromJson(message, DeconzBaseMessage.class);
|
DeconzBaseMessage changedMessage = Objects.requireNonNull(gson.fromJson(message, DeconzBaseMessage.class));
|
||||||
if (changedMessage.r == ResourceType.UNKNOWN) {
|
if (changedMessage.r == ResourceType.UNKNOWN) {
|
||||||
logger.trace("Received message has unknown resource type. Skipping message.");
|
logger.trace("Received message has unknown resource type. Skipping message.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
<channel typeId="alert" id="alert"/>
|
<channel typeId="alert" id="alert"/>
|
||||||
<channel typeId="color" id="color"/>
|
<channel typeId="color" id="color"/>
|
||||||
<channel typeId="ct" id="color_temperature"/>
|
<channel typeId="ct" id="color_temperature"/>
|
||||||
|
<channel typeId="scene" id="scene"/>
|
||||||
</channels>
|
</channels>
|
||||||
|
|
||||||
<representation-property>uid</representation-property>
|
<representation-property>uid</representation-property>
|
||||||
@ -67,4 +68,13 @@
|
|||||||
<state pattern="%d K" min="15" max="100000" step="100"/>
|
<state pattern="%d K" min="15" max="100000" step="100"/>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="scene">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Recall Scene</label>
|
||||||
|
<tags>
|
||||||
|
<tag>Lighting</tag>
|
||||||
|
</tags>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
|
||||||
</thing:thing-descriptions>
|
</thing:thing-descriptions>
|
||||||
|
|||||||
@ -17,9 +17,11 @@ import static org.mockito.ArgumentMatchers.any;
|
|||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@ -90,8 +92,17 @@ public class DeconzTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T getObjectFromJson(String filename, Class<T> clazz, Gson gson) throws IOException {
|
public static <T> T getObjectFromJson(String filename, Class<T> clazz, Gson gson) throws IOException {
|
||||||
String json = new String(DeconzTest.class.getResourceAsStream(filename).readAllBytes(), StandardCharsets.UTF_8);
|
try (InputStream inputStream = DeconzTest.class.getResourceAsStream(filename)) {
|
||||||
return gson.fromJson(json, clazz);
|
if (inputStream == null) {
|
||||||
|
throw new IOException("inputstream is null");
|
||||||
|
}
|
||||||
|
byte[] bytes = inputStream.readAllBytes();
|
||||||
|
if (bytes == null) {
|
||||||
|
throw new IOException("Resulting byte-array empty");
|
||||||
|
}
|
||||||
|
String json = new String(bytes, StandardCharsets.UTF_8);
|
||||||
|
return Objects.requireNonNull(gson.fromJson(json, clazz));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user