From 8c31fde3c4ace2c0b9a947656b907f1b002a2109 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sun, 16 Aug 2020 15:08:28 +0200 Subject: [PATCH 1/7] improvements - add support for tint color control - add support for smart plug Signed-off-by: Jan N. Klug --- .../deconz/internal/BindingConstants.java | 1 + .../discovery/ThingDiscoveryService.java | 9 +++-- .../deconz/internal/dto/SensorState.java | 7 +++- .../internal/handler/LightThingHandler.java | 8 ++--- .../internal/handler/SensorThingHandler.java | 10 +++++- .../deconz/internal/types/LightType.java | 1 + .../ESH-INF/thing/sensor-thing-types.xml | 24 +++++++++++++ .../openhab/binding/deconz/LightsTest.java | 34 +++++++++++++++++++ .../binding/deconz/dimmable_overrange.json | 13 +++++++ .../binding/deconz/dimmable_underrange.json | 13 +++++++ 10 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_overrange.json create mode 100644 bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_underrange.json diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/BindingConstants.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/BindingConstants.java index fc7135f978684..f820c8f1d71a5 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/BindingConstants.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/BindingConstants.java @@ -34,6 +34,7 @@ public class BindingConstants { public static final ThingTypeUID THING_TYPE_POWER_SENSOR = new ThingTypeUID(BINDING_ID, "powersensor"); public static final ThingTypeUID THING_TYPE_CONSUMPTION_SENSOR = new ThingTypeUID(BINDING_ID, "consumptionsensor"); public static final ThingTypeUID THING_TYPE_DAYLIGHT_SENSOR = new ThingTypeUID(BINDING_ID, "daylightsensor"); + public static final ThingTypeUID THING_TYPE_COLOR_CONTROL = new ThingTypeUID(BINDING_ID, "colorcontrol"); public static final ThingTypeUID THING_TYPE_SWITCH = new ThingTypeUID(BINDING_ID, "switch"); public static final ThingTypeUID THING_TYPE_LIGHT_SENSOR = new ThingTypeUID(BINDING_ID, "lightsensor"); public static final ThingTypeUID THING_TYPE_TEMPERATURE_SENSOR = new ThingTypeUID(BINDING_ID, "temperaturesensor"); diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/discovery/ThingDiscoveryService.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/discovery/ThingDiscoveryService.java index 7bebeafd6d6b5..474e557de9b3e 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/discovery/ThingDiscoveryService.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/discovery/ThingDiscoveryService.java @@ -130,6 +130,7 @@ private void addLight(String lightID, LightMessage light) { switch (lightType) { case ON_OFF_LIGHT: case ON_OFF_PLUGIN_UNIT: + case SMART_PLUG: thingTypeUID = THING_TYPE_ONOFF_LIGHT; break; case DIMMABLE_LIGHT: @@ -158,7 +159,7 @@ private void addLight(String lightID, LightMessage light) { default: logger.debug( "Found light: {} ({}), type {} but no thing type defined for that type. This should be reported.", - light.modelid, light.name, lightType); + light.modelid, light.name, light.type); return; } @@ -191,7 +192,11 @@ private void addSensor(String sensorID, SensorMessage sensor) { } else if (sensor.type.contains("Presence")) { // ZHAPresence, CLIPPrensence thingTypeUID = THING_TYPE_PRESENCE_SENSOR; } else if (sensor.type.contains("Switch")) { // ZHASwitch - thingTypeUID = THING_TYPE_SWITCH; + if (sensor.modelid.contains("RGBW")) { + thingTypeUID = THING_TYPE_COLOR_CONTROL; + } else { + thingTypeUID = THING_TYPE_SWITCH; + } } else if (sensor.type.contains("LightLevel")) { // ZHALightLevel thingTypeUID = THING_TYPE_LIGHT_SENSOR; } else if (sensor.type.contains("ZHATemperature")) { // ZHATemperature diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/dto/SensorState.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/dto/SensorState.java index bd4f16153db03..07ebb5d33bdc9 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/dto/SensorState.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/dto/SensorState.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.deconz.internal.dto; +import java.util.Arrays; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -76,6 +78,8 @@ public class SensorState { public @Nullable Integer valve; /** deCONZ sends a last update string with every event. */ public @Nullable String lastupdated; + /** color controllers send xy values */ + public double @Nullable [] xy; @Override public String toString() { @@ -85,6 +89,7 @@ public String toString() { + ", carbonmonoxide=" + carbonmonoxide + ", pressure=" + pressure + ", presence=" + presence + ", power=" + power + ", battery=" + battery + ", consumption=" + consumption + ", voltage=" + voltage + ", current=" + current + ", status=" + status + ", buttonevent=" + buttonevent + ", gesture=" - + gesture + ", lastupdated='" + lastupdated + '\'' + '}'; + + gesture + ", valve=" + valve + ", lastupdated='" + lastupdated + '\'' + ", xy=" + Arrays.toString(xy) + + '}'; } } diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/LightThingHandler.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/LightThingHandler.java index 324d3bdf6c7b5..2ff4be82d8a32 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/LightThingHandler.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/LightThingHandler.java @@ -68,10 +68,9 @@ */ @NonNullByDefault public class LightThingHandler extends DeconzBaseThingHandler { - public static final Set SUPPORTED_THING_TYPE_UIDS = Stream - .of(THING_TYPE_COLOR_TEMPERATURE_LIGHT, THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_LIGHT, - THING_TYPE_EXTENDED_COLOR_LIGHT, THING_TYPE_ONOFF_LIGHT, THING_TYPE_WINDOW_COVERING, - THING_TYPE_WARNING_DEVICE).collect(Collectors.toSet()); + public static final Set SUPPORTED_THING_TYPE_UIDS = Stream.of(THING_TYPE_COLOR_TEMPERATURE_LIGHT, + THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_COLOR_LIGHT, THING_TYPE_EXTENDED_COLOR_LIGHT, THING_TYPE_ONOFF_LIGHT, + THING_TYPE_WINDOW_COVERING, THING_TYPE_WARNING_DEVICE).collect(Collectors.toSet()); private static final double HUE_FACTOR = 65535 / 360.0; private static final double BRIGHTNESS_FACTOR = 2.54; @@ -396,6 +395,7 @@ private PercentType toPercentType(int val) { scaledValue = scaledValue < 0 ? 0 : scaledValue; scaledValue = scaledValue > 100 ? 100 : scaledValue; } + logger.debug("val = '{}', scaledValue = '{}'", val, scaledValue); return new PercentType(scaledValue); } diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorThingHandler.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorThingHandler.java index 9d89726b6b828..8a58ec11a3209 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorThingHandler.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorThingHandler.java @@ -25,6 +25,8 @@ import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.smarthome.core.library.types.HSBType; import org.eclipse.smarthome.core.library.types.OpenClosedType; import org.eclipse.smarthome.core.library.types.QuantityType; import org.eclipse.smarthome.core.library.types.StringType; @@ -63,7 +65,7 @@ public class SensorThingHandler extends SensorBaseThingHandler { THING_TYPE_HUMIDITY_SENSOR, THING_TYPE_PRESSURE_SENSOR, THING_TYPE_SWITCH, THING_TYPE_OPENCLOSE_SENSOR, THING_TYPE_WATERLEAKAGE_SENSOR, THING_TYPE_FIRE_SENSOR, THING_TYPE_ALARM_SENSOR, THING_TYPE_VIBRATION_SENSOR, THING_TYPE_BATTERY_SENSOR, - THING_TYPE_CARBONMONOXIDE_SENSOR).collect(Collectors.toSet())); + THING_TYPE_CARBONMONOXIDE_SENSOR, THING_TYPE_COLOR_CONTROL).collect(Collectors.toSet())); private static final List CONFIG_CHANNELS = Arrays.asList(CHANNEL_BATTERY_LEVEL, CHANNEL_BATTERY_LOW, CHANNEL_TEMPERATURE); @@ -137,6 +139,12 @@ protected void valueUpdated(String channelID, SensorState newState, boolean init case CHANNEL_LIGHT_LUX: updateQuantityTypeChannel(channelID, newState.lux, LUX); break; + case CHANNEL_COLOR: + final double @Nullable [] xy = newState.xy; + if (xy != null && xy.length == 2) { + updateState(channelID, HSBType.fromXY((float) xy[0], (float) xy[1])); + } + break; case CHANNEL_LIGHT_LEVEL: updateDecimalTypeChannel(channelID, newState.lightlevel); break; diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/LightType.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/LightType.java index 4ac7c226d5004..85aba0fa38f9e 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/LightType.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/LightType.java @@ -29,6 +29,7 @@ public enum LightType { ON_OFF_LIGHT("On/Off light"), ON_OFF_PLUGIN_UNIT("On/Off plug-in unit"), + SMART_PLUG("Smart plug"), EXTENDED_COLOR_LIGHT("Extended color light"), COLOR_LIGHT("Color light"), COLOR_DIMMABLE_LIGHT("Color dimmable light"), diff --git a/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/sensor-thing-types.xml b/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/sensor-thing-types.xml index dcf2fbab71ccb..bd00412d9d812 100644 --- a/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/sensor-thing-types.xml +++ b/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/sensor-thing-types.xml @@ -106,6 +106,30 @@ + + + + + + + + + + + + + uid + + + + + + Color + + Allows to control a color + + + diff --git a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/LightsTest.java b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/LightsTest.java index ffb6e877a5cb6..d45fd91e1fa67 100644 --- a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/LightsTest.java +++ b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/LightsTest.java @@ -136,6 +136,40 @@ public void dimmableLightUpdateTest() throws IOException { Mockito.verify(thingHandlerCallback).stateUpdated(eq(channelUID_bri), eq(new PercentType("38"))); } + @Test + public void dimmableLightOverrangeUpdateTest() throws IOException { + LightMessage lightMessage = DeconzTest.getObjectFromJson("dimmable_overrange.json", LightMessage.class, gson); + Assert.assertNotNull(lightMessage); + + ThingUID thingUID = new ThingUID("deconz", "light"); + ChannelUID channelUID_bri = new ChannelUID(thingUID, CHANNEL_BRIGHTNESS); + + Thing light = ThingBuilder.create(THING_TYPE_DIMMABLE_LIGHT, thingUID) + .withChannel(ChannelBuilder.create(channelUID_bri, "Dimmer").build()).build(); + LightThingHandler lightThingHandler = new LightThingHandler(light, gson, stateDescriptionProvider); + lightThingHandler.setCallback(thingHandlerCallback); + + lightThingHandler.messageReceived("", lightMessage); + Mockito.verify(thingHandlerCallback).stateUpdated(eq(channelUID_bri), eq(new PercentType("100"))); + } + + @Test + public void dimmableLightUnderrangeUpdateTest() throws IOException { + LightMessage lightMessage = DeconzTest.getObjectFromJson("dimmable_underrange.json", LightMessage.class, gson); + Assert.assertNotNull(lightMessage); + + ThingUID thingUID = new ThingUID("deconz", "light"); + ChannelUID channelUID_bri = new ChannelUID(thingUID, CHANNEL_BRIGHTNESS); + + Thing light = ThingBuilder.create(THING_TYPE_DIMMABLE_LIGHT, thingUID) + .withChannel(ChannelBuilder.create(channelUID_bri, "Dimmer").build()).build(); + LightThingHandler lightThingHandler = new LightThingHandler(light, gson, stateDescriptionProvider); + lightThingHandler.setCallback(thingHandlerCallback); + + lightThingHandler.messageReceived("", lightMessage); + Mockito.verify(thingHandlerCallback).stateUpdated(eq(channelUID_bri), eq(new PercentType("0"))); + } + @Test public void windowCoveringUpdateTest() throws IOException { LightMessage lightMessage = DeconzTest.getObjectFromJson("windowcovering.json", LightMessage.class, gson); diff --git a/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_overrange.json b/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_overrange.json new file mode 100644 index 0000000000000..dc3a4feed6ab9 --- /dev/null +++ b/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_overrange.json @@ -0,0 +1,13 @@ +{ + "e": "changed", + "id": "4", + "r": "lights", + "state": { + "alert": null, + "bri": 270, + "on": true, + "reachable": true + }, + "t": "event", + "uniqueid": "00:0b:57:ff:fe:c5:34:c4-01" +} \ No newline at end of file diff --git a/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_underrange.json b/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_underrange.json new file mode 100644 index 0000000000000..ce2ea74e0048a --- /dev/null +++ b/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/dimmable_underrange.json @@ -0,0 +1,13 @@ +{ + "e": "changed", + "id": "4", + "r": "lights", + "state": { + "alert": null, + "bri": -1, + "on": true, + "reachable": true + }, + "t": "event", + "uniqueid": "00:0b:57:ff:fe:c5:34:c4-01" +} \ No newline at end of file From e4dac3450e59ade0e94fc764827906dfdcb08b73 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Thu, 20 Aug 2020 19:12:55 +0200 Subject: [PATCH 2/7] add documentation Signed-off-by: Jan N. Klug --- bundles/org.openhab.binding.deconz/README.md | 31 ++++++++++---------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/bundles/org.openhab.binding.deconz/README.md b/bundles/org.openhab.binding.deconz/README.md index 4a74f297c9681..ce21986e9e179 100644 --- a/bundles/org.openhab.binding.deconz/README.md +++ b/bundles/org.openhab.binding.deconz/README.md @@ -26,19 +26,20 @@ These sensors are supported: | Vibration Sensor | ZHAVibration | `vibrationsensor` | | deCONZ Artificial Daylight Sensor | deCONZ specific: simulated sensor | `daylightsensor` | | Carbon-Monoxide Sensor | ZHACarbonmonoxide | `carbonmonoxide` | +| Color Controller | ZBT-Remote-ALL-RGBW | `colorcontrol` | Additionally lights, window coverings (blinds) and thermostats are supported: -| Device type | Resource Type | Thing type | -|--------------------------------------|----------------------------------------|----------------------| -| Dimmable Light | Dimmable light, Dimmable plug-in unit | `dimmablelight` | -| On/Off Light | On/Off light, On/Off plug-in unit | `onofflight` | -| Color Light (w/o temperature) | Color dimmable light | `colorlight` | -| Extended Color Light (w/temperature) | Extended color light | `extendedcolorlight` | -| Blind / Window Covering | Window covering device | `windowcovering` | -| Thermostat | ZHAThermostat | `thermostat` | -| Warning Device (Siren) | Warning device | `warningdevice` | +| Device type | Resource Type | Thing type | +|--------------------------------------|-----------------------------------------------|----------------------| +| Dimmable Light | Dimmable light, Dimmable plug-in unit | `dimmablelight` | +| On/Off Light | On/Off light, On/Off plug-in unit, Smart plug | `onofflight` | +| Color Light (w/o temperature) | Color dimmable light | `colorlight` | +| Extended Color Light (w/temperature) | Extended color light | `extendedcolorlight` | +| Blind / Window Covering | Window covering device | `windowcovering` | +| Thermostat | ZHAThermostat | `thermostat` | +| Warning Device (Siren) | Warning device | `warningdevice` | ## Discovery @@ -122,7 +123,7 @@ The sensor devices support some of the following channels: | consumption | Number:Energy | R | Current power usage in Watts/Hour | consumptionsensor | | voltage | Number:ElectricPotential | R | Current voltage in V | some powersensors | | current | Number:ElectricCurrent | R | Current current in mA | some powersensors | -| button | Number | R | Last pressed button id on a switch | switch | +| button | Number | R | Last pressed button id on a switch | switch, colorcontrol | | gesture | Number | R | A gesture that was performed with the switch | switch | | lightlux | Number:Illuminance | R | Current light illuminance in Lux | lightsensor | | light_level | Number | R | Current light level | lightsensor | @@ -142,7 +143,7 @@ The sensor devices support some of the following channels: | battery_level | Number | R | Battery level (in %) | any battery-powered sensor | | battery_low | Switch | R | Battery level low: `ON`; `OFF` | any battery-powered sensor | | carbonmonoxide | Switch | R | `ON` = carbon monoxide detected | carbonmonoxide | - +| color | Color | R | Color set by remote | colorcontrol | **NOTE:** Beside other non mandatory channels, the `battery_level` and `battery_low` channels will be added to the Thing during runtime if the sensor is battery-powered. The specification of your sensor depends on the deCONZ capabilities. @@ -169,10 +170,10 @@ Other devices support The dimmer switch additionally supports trigger channels. -| Channel Type ID | Description | Thing types | -|-----------------|--------------------------|-------------| -| buttonevent | Event for switch pressed | switch | -| gestureevent | Event for gestures | switch | +| Channel Type ID | Description | Thing types | +|-----------------|--------------------------|----------------------| +| buttonevent | Event for switch pressed | switch, colorcontrol | +| gestureevent | Event for gestures | switch | **NOTE:** The `gestureevent` trigger channel is only available if the optional channel `gesture` is present. Both will be added during runtime if supported by the switch. From 8d7b56eb0df1daf830c6ac9951e6b556429bb048 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sat, 22 Aug 2020 12:03:57 +0200 Subject: [PATCH 3/7] improve logging Signed-off-by: Jan N. Klug --- .../deconz/internal/netutils/WebSocketConnection.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java index 07c738d063176..9b1ca90e87501 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java @@ -110,21 +110,27 @@ public void onConnect(Session session) { @SuppressWarnings("null") @OnWebSocketMessage public void onMessage(String message) { + logger.trace("Raw data received by websocket: {}", message); DeconzBaseMessage changedMessage = gson.fromJson(message, DeconzBaseMessage.class); switch (changedMessage.r) { case "sensors": WebSocketMessageListener listener = sensorListener.get(changedMessage.id); if (listener != null) { listener.messageReceived(changedMessage.id, gson.fromJson(message, SensorMessage.class)); + } else { + logger.trace("Couldn't find sensor listener for id {}", changedMessage.id); } break; case "lights": listener = lightListener.get(changedMessage.id); if (listener != null) { listener.messageReceived(changedMessage.id, gson.fromJson(message, LightMessage.class)); + } else { + logger.trace("Couldn't find light listener for id {}", changedMessage.id); } break; default: + logger.debug("Unknown message type: {}", changedMessage.r); } } From 250483792b876995e05accf3102a83c21fac24d5 Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sat, 22 Aug 2020 13:15:59 +0200 Subject: [PATCH 4/7] fix possible concurrency issue when a lot of sensors are initialized at the same time Signed-off-by: Jan N. Klug --- .../deconz/internal/netutils/WebSocketConnection.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java index 9b1ca90e87501..14773c87e1fed 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/netutils/WebSocketConnection.java @@ -13,8 +13,8 @@ package org.openhab.binding.deconz.internal.netutils; import java.net.URI; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jetty.websocket.api.Session; @@ -46,8 +46,8 @@ public class WebSocketConnection { private final WebSocketClient client; private final WebSocketConnectionListener connectionListener; - private final Map sensorListener = new HashMap<>(); - private final Map lightListener = new HashMap<>(); + private final Map sensorListener = new ConcurrentHashMap<>(); + private final Map lightListener = new ConcurrentHashMap<>(); private final Gson gson; private boolean connected = false; From 13a2bbf9f0e89fbc71aebe401f15c79aefe7761e Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sat, 22 Aug 2020 18:10:54 +0200 Subject: [PATCH 5/7] fix changed timestamp format in newer deconz fw Signed-off-by: Jan N. Klug --- .../openhab/binding/deconz/internal/Util.java | 24 +++++++++++++++++++ .../handler/SensorBaseThingHandler.java | 20 ++++------------ .../openhab/binding/deconz/DeconzTest.java | 16 +++++++++++++ 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java index ecf5508e0f87a..a50b68bd1e4b6 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java @@ -12,10 +12,16 @@ */ package org.openhab.binding.deconz.internal; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.smarthome.core.library.types.DateTimeType; /** * The {@link Util} class defines common utility methods @@ -47,4 +53,22 @@ public static int kelvinToMired(int kelvinValue) { public static int constrainToRange(int intValue, int min, int max) { return Math.max(min, Math.min(intValue, max)); } + + /** + * convert a timestamp string to a DateTimeType + * + * @param timestamp either in zoned date time or local date time format + * @return the corresponding DateTimeType + */ + public static DateTimeType convertTimestampToDateTime(String timestamp) { + if (timestamp.endsWith("Z")) { + return new DateTimeType( + ZonedDateTime.ofInstant(LocalDateTime.parse(timestamp, DateTimeFormatter.ISO_ZONED_DATE_TIME), + ZoneOffset.UTC, ZoneId.systemDefault())); + } else { + return new DateTimeType( + ZonedDateTime.ofInstant(LocalDateTime.parse(timestamp, DateTimeFormatter.ISO_LOCAL_DATE_TIME), + ZoneOffset.UTC, ZoneId.systemDefault())); + } + } } diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorBaseThingHandler.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorBaseThingHandler.java index 8b44a87c7567b..e6442a7b71732 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorBaseThingHandler.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/handler/SensorBaseThingHandler.java @@ -14,11 +14,6 @@ import static org.openhab.binding.deconz.internal.BindingConstants.*; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledFuture; @@ -28,7 +23,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; -import org.eclipse.smarthome.core.library.types.DateTimeType; import org.eclipse.smarthome.core.library.types.DecimalType; import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.types.QuantityType; @@ -41,6 +35,7 @@ import org.eclipse.smarthome.core.thing.type.ChannelKind; import org.eclipse.smarthome.core.thing.type.ChannelTypeUID; import org.eclipse.smarthome.core.types.Command; +import org.openhab.binding.deconz.internal.Util; import org.openhab.binding.deconz.internal.dto.DeconzBaseMessage; import org.openhab.binding.deconz.internal.dto.SensorConfig; import org.openhab.binding.deconz.internal.dto.SensorMessage; @@ -190,12 +185,10 @@ protected void processStateResponse(@Nullable SensorMessage stateResponse) { // "Last seen" is the last "ping" from the device, whereas "last update" is the last status changed. // For example, for a fire sensor, the device pings regularly, without necessarily updating channels. // So to monitor a sensor is still alive, the "last seen" is necessary. - if (stateResponse.lastseen != null && config.lastSeenPolling > 0) { + String lastSeen = stateResponse.lastseen; + if (lastSeen != null && config.lastSeenPolling > 0) { createChannel(CHANNEL_LAST_SEEN, ChannelKind.STATE); - updateState(CHANNEL_LAST_SEEN, - new DateTimeType(ZonedDateTime.ofInstant( - LocalDateTime.parse(stateResponse.lastseen, DateTimeFormatter.ISO_LOCAL_DATE_TIME), - ZoneOffset.UTC, ZoneId.systemDefault()))); + updateState(CHANNEL_LAST_SEEN, Util.convertTimestampToDateTime(lastSeen)); // Because "last seen" is never updated by the WebSocket API - if this is supported, then we have to // manually poll it after the defined time (default is off) if (config.lastSeenPolling > 0) { @@ -266,10 +259,7 @@ protected void valueUpdated(String channelID, SensorState newState, boolean init case CHANNEL_LAST_UPDATED: String lastUpdated = newState.lastupdated; if (lastUpdated != null && !"none".equals(lastUpdated)) { - updateState(channelID, - new DateTimeType(ZonedDateTime.ofInstant( - LocalDateTime.parse(lastUpdated, DateTimeFormatter.ISO_LOCAL_DATE_TIME), - ZoneOffset.UTC, ZoneId.systemDefault()))); + updateState(channelID, Util.convertTimestampToDateTime(lastUpdated)); } break; default: diff --git a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java index 5b965848ac014..bbc1d600fcdd4 100644 --- a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java +++ b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java @@ -18,10 +18,16 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import org.apache.commons.io.IOUtils; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.smarthome.config.discovery.DiscoveryListener; +import org.eclipse.smarthome.core.library.types.DateTimeType; import org.eclipse.smarthome.core.thing.Bridge; import org.eclipse.smarthome.core.thing.ThingUID; import org.junit.Assert; @@ -29,6 +35,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; +import org.openhab.binding.deconz.internal.Util; import org.openhab.binding.deconz.internal.discovery.ThingDiscoveryService; import org.openhab.binding.deconz.internal.dto.BridgeFullState; import org.openhab.binding.deconz.internal.handler.DeconzBridgeHandler; @@ -90,4 +97,13 @@ public static T getObjectFromJson(String filename, Class clazz, Gson gson String json = IOUtils.toString(DeconzTest.class.getResourceAsStream(filename), StandardCharsets.UTF_8.name()); return gson.fromJson(json, clazz); } + + @Test + public void dateTimeConversionTest() { + DateTimeType dateTime = Util.convertTimestampToDateTime("2020-08-22T11:09Z"); + Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 0, 0, ZoneId.systemDefault())), dateTime); + + dateTime = Util.convertTimestampToDateTime("2020-08-22T11:09:47"); + Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 47, 0, ZoneId.systemDefault())), dateTime); + } } From 01cd6cf8c303bf1ff4d2c48152db3236e84c339c Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sat, 22 Aug 2020 18:26:38 +0200 Subject: [PATCH 6/7] fix date time parsing Signed-off-by: Jan N. Klug --- .../main/java/org/openhab/binding/deconz/internal/Util.java | 3 +-- .../src/test/java/org/openhab/binding/deconz/DeconzTest.java | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java index a50b68bd1e4b6..17dabb1bce1df 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/Util.java @@ -63,8 +63,7 @@ public static int constrainToRange(int intValue, int min, int max) { public static DateTimeType convertTimestampToDateTime(String timestamp) { if (timestamp.endsWith("Z")) { return new DateTimeType( - ZonedDateTime.ofInstant(LocalDateTime.parse(timestamp, DateTimeFormatter.ISO_ZONED_DATE_TIME), - ZoneOffset.UTC, ZoneId.systemDefault())); + ZonedDateTime.parse(timestamp)); } else { return new DateTimeType( ZonedDateTime.ofInstant(LocalDateTime.parse(timestamp, DateTimeFormatter.ISO_LOCAL_DATE_TIME), diff --git a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java index bbc1d600fcdd4..8e833190de2a9 100644 --- a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java +++ b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java @@ -101,9 +101,9 @@ public static T getObjectFromJson(String filename, Class clazz, Gson gson @Test public void dateTimeConversionTest() { DateTimeType dateTime = Util.convertTimestampToDateTime("2020-08-22T11:09Z"); - Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 0, 0, ZoneId.systemDefault())), dateTime); + Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 0, 0, ZoneId.systemDefault())), dateTime.toZone(ZoneId.systemDefault())); dateTime = Util.convertTimestampToDateTime("2020-08-22T11:09:47"); - Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 47, 0, ZoneId.systemDefault())), dateTime); + Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 47, 0, ZoneId.systemDefault())), dateTime.toZone(ZoneId.systemDefault())); } } From d2d3776c3e36fa9e5a13a0c2aaca8fbb9b12610f Mon Sep 17 00:00:00 2001 From: "Jan N. Klug" Date: Sat, 22 Aug 2020 18:35:49 +0200 Subject: [PATCH 7/7] fix tests Signed-off-by: Jan N. Klug --- .../src/test/java/org/openhab/binding/deconz/DeconzTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java index 8e833190de2a9..27e0fbe1468b6 100644 --- a/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java +++ b/bundles/org.openhab.binding.deconz/src/test/java/org/openhab/binding/deconz/DeconzTest.java @@ -101,9 +101,9 @@ public static T getObjectFromJson(String filename, Class clazz, Gson gson @Test public void dateTimeConversionTest() { DateTimeType dateTime = Util.convertTimestampToDateTime("2020-08-22T11:09Z"); - Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 0, 0, ZoneId.systemDefault())), dateTime.toZone(ZoneId.systemDefault())); + Assert.assertEquals(new DateTimeType(ZonedDateTime.parse("2020-08-22T11:09:00Z")), dateTime); dateTime = Util.convertTimestampToDateTime("2020-08-22T11:09:47"); - Assert.assertEquals(new DateTimeType(ZonedDateTime.of(2020, 8, 22, 13, 9, 47, 0, ZoneId.systemDefault())), dateTime.toZone(ZoneId.systemDefault())); + Assert.assertEquals(new DateTimeType(ZonedDateTime.parse("2020-08-22T11:09:47Z")).toZone(ZoneId.systemDefault()), dateTime); } }