diff --git a/bundles/org.openhab.binding.deconz/README.md b/bundles/org.openhab.binding.deconz/README.md index 26d27b74d31fe..7546554cc5c88 100644 --- a/bundles/org.openhab.binding.deconz/README.md +++ b/bundles/org.openhab.binding.deconz/README.md @@ -147,7 +147,7 @@ Other devices support | brightness | Dimmer | R/W | Brightness of the light | `dimmablelight` | | switch | Switch | R/W | State of a ON/OFF device | `onofflight` | | color | Color | R/W | Color of an multi-color light | `colorlight`, `extendedcolorlight` | -| color_temperature | Number | R/W | `0`->`100` represents cold -> warm | `colortemperaturelight`, `extendedcolorlight` | +| color_temperature | Number | R/W | Color temperature in kelvin. The value range is determined by each individual light | `colortemperaturelight`, `extendedcolorlight` | | position | Rollershutter | R/W | Position of the blind | `windowcovering` | | heatsetpoint | Number:Temperature | R/W | Target Temperature in °C | `thermostat` | | valve | Number:Dimensionless | R | Valve position in % | `thermostat` | 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 76f761456bbbe..85df47e81470d 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 @@ -107,4 +107,13 @@ public class BindingConstants { public static final String CONFIG_APIKEY = "apikey"; public static final String UNIQUE_ID = "uid"; + + public static final String PROPERTY_CT_MIN = "ctmin"; + public static final String PROPERTY_CT_MAX = "ctmax"; + + // CT value range according to ZCL Spec + public static final int ZCL_CT_UNDEFINED = 0; // 0x0000 + public static final int ZCL_CT_MIN = 1; + public static final int ZCL_CT_MAX = 65279; // 0xFEFF + public static final int ZCL_CT_INVALID = 65535; // 0xFFFF } 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 f087470cb5cbf..b49b513995835 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 @@ -35,4 +35,27 @@ public static String buildUrl(String host, int port, String... urlParts) { return url.toString(); } + + public static int miredToKelvin(int miredValue) { + return (int) (1000000.0 / miredValue); + } + + public static int kelvinToMired(int kelvinValue) { + return (int) (1000000.0 / kelvinValue); + } + + public static int constrainToRange(int intValue, int min, int max) { + return Math.max(min, Math.min(intValue, max)); + } + + public static int parseIntWithFallback(String text, int defaultValue) { + if (text == null || text.isEmpty()) { + return defaultValue; + } + try { + return Integer.parseInt(text); + } catch (NumberFormatException e) { + return defaultValue; + } + } } 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 d275f7955da84..4fbcfc18fdeca 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 @@ -14,6 +14,8 @@ import static org.openhab.binding.deconz.internal.BindingConstants.*; +import java.util.HashMap; +import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -26,6 +28,7 @@ import org.eclipse.smarthome.config.discovery.DiscoveryResult; import org.eclipse.smarthome.config.discovery.DiscoveryResultBuilder; import org.eclipse.smarthome.config.discovery.DiscoveryService; +import org.eclipse.smarthome.core.thing.Thing; import org.eclipse.smarthome.core.thing.ThingTypeUID; import org.eclipse.smarthome.core.thing.ThingUID; import org.eclipse.smarthome.core.thing.binding.ThingHandler; @@ -109,9 +112,19 @@ private void addLight(String lightID, LightMessage light) { return; } - if (light.uniqueid.isEmpty()) { - logger.warn("No unique id reported for light {} ({})", light.modelid, light.name); - return; + Map properties = new HashMap<>(); + properties.put("id", lightID); + properties.put(UNIQUE_ID, light.uniqueid); + properties.put(Thing.PROPERTY_FIRMWARE_VERSION, light.swversion); + properties.put(Thing.PROPERTY_VENDOR, light.manufacturername); + properties.put(Thing.PROPERTY_MODEL_ID, light.modelid); + + if (light.ctmax != null && light.ctmin != null) { + int ctmax = (light.ctmax > ZCL_CT_MAX) ? ZCL_CT_MAX : light.ctmax; + properties.put(PROPERTY_CT_MAX, Integer.toString(ctmax)); + + int ctmin = (light.ctmin < ZCL_CT_MIN) ? ZCL_CT_MIN : light.ctmin; + properties.put(PROPERTY_CT_MIN, Integer.toString(ctmin)); } switch (lightType) { @@ -127,6 +140,7 @@ private void addLight(String lightID, LightMessage light) { thingTypeUID = THING_TYPE_COLOR_TEMPERATURE_LIGHT; break; case COLOR_DIMMABLE_LIGHT: + case COLOR_LIGHT: thingTypeUID = THING_TYPE_COLOR_LIGHT; break; case EXTENDED_COLOR_LIGHT: @@ -147,8 +161,8 @@ private void addLight(String lightID, LightMessage light) { ThingUID uid = new ThingUID(thingTypeUID, bridgeUID, light.uniqueid.replaceAll("[^a-z0-9\\[\\]]", "")); DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(uid).withBridge(bridgeUID) - .withLabel(light.name + " (" + light.manufacturername + ")").withProperty("id", lightID) - .withProperty(UNIQUE_ID, light.uniqueid).withRepresentationProperty(UNIQUE_ID).build(); + .withLabel(light.name + " (" + light.manufacturername + ")").withProperties(properties) + .withRepresentationProperty(UNIQUE_ID).build(); thingDiscovered(discoveryResult); } 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 ca1fdba4b1d87..14dc8994d3d3a 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 @@ -13,7 +13,7 @@ package org.openhab.binding.deconz.internal.handler; import static org.openhab.binding.deconz.internal.BindingConstants.*; -import static org.openhab.binding.deconz.internal.Util.buildUrl; +import static org.openhab.binding.deconz.internal.Util.*; import java.util.Set; import java.util.stream.Collectors; @@ -78,8 +78,13 @@ public class LightThingHandler extends DeconzBaseThingHandler { private LightState lightStateCache = new LightState(); private LightState lastCommand = new LightState(); + private final int ct_max; + private final int ct_min; + public LightThingHandler(Thing thing, Gson gson) { super(thing, gson); + ct_max = parseIntWithFallback(thing.getProperties().get(PROPERTY_CT_MAX), ZCL_CT_MAX); + ct_min = parseIntWithFallback(thing.getProperties().get(PROPERTY_CT_MIN), ZCL_CT_MIN); } @Override @@ -169,7 +174,8 @@ public void handleCommand(ChannelUID channelUID, Command command) { break; case CHANNEL_COLOR_TEMPERATURE: if (command instanceof DecimalType) { - newLightState.ct = unscaleColorTemperature(((DecimalType) command).doubleValue()); + int miredValue = kelvinToMired(((DecimalType) command).intValue()); + newLightState.ct = constrainToRange(miredValue,ct_min, ct_max); if (currentOn != null && !currentOn) { // sending new color temperature is only allowed when light is on @@ -263,16 +269,17 @@ private void valueUpdated(String channelId, LightState newState) { case CHANNEL_COLOR: if (on != null && on == false) { updateState(channelId, OnOffType.OFF); - } else { - double @Nullable [] xy = newState.xy; - Integer hue = newState.hue; - Integer sat = newState.sat; - if (hue != null && sat != null && bri != null) { - updateState(channelId, - new HSBType(new DecimalType(hue / HUE_FACTOR), toPercentType(sat), toPercentType(bri))); - } else if (xy != null && xy.length == 2) { - updateState(channelId, HSBType.fromXY((float) xy[0], (float) xy[1])); + } else if (bri != null && newState.colormode != null && newState.colormode.equals("xy")) { + final double @Nullable [] xy = newState.xy; + if (xy != null && xy.length == 2) { + HSBType color = HSBType.fromXY((float) xy[0], (float) xy[1]); + updateState(channelId, new HSBType(color.getHue(), color.getSaturation(), toPercentType(bri))); } + } else if (bri != null && newState.hue != null && newState.sat != null) { + final Integer hue = newState.hue; + final Integer sat = newState.sat; + updateState(channelId, + new HSBType(new DecimalType(hue / HUE_FACTOR), toPercentType(sat), toPercentType(bri))); } break; case CHANNEL_BRIGHTNESS: @@ -284,8 +291,8 @@ private void valueUpdated(String channelId, LightState newState) { break; case CHANNEL_COLOR_TEMPERATURE: Integer ct = newState.ct; - if (ct != null) { - updateState(channelId, new DecimalType(scaleColorTemperature(ct))); + if (ct != null && ct >= ct_min && ct <= ct_max) { + updateState(channelId, new DecimalType(miredToKelvin(ct))); } break; case CHANNEL_POSITION: @@ -315,14 +322,6 @@ public void messageReceived(String sensorID, DeconzBaseMessage message) { } } - private int unscaleColorTemperature(double ct) { - return (int) (ct / 100.0 * (500 - 153) + 153); - } - - private double scaleColorTemperature(int ct) { - return 100.0 * (ct - 153) / (500 - 153); - } - private PercentType toPercentType(int val) { int scaledValue = (int) Math.ceil(val / BRIGHTNESS_FACTOR); if (scaledValue < 0 || scaledValue > 100) { 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 1f06155bbc6c4..bf3e1d00faafa 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 @@ -238,7 +238,6 @@ protected void createTypeSpecificChannels(SensorConfig sensorConfig, SensorState createChannel(CHANNEL_GESTURE, ChannelKind.STATE); createChannel(CHANNEL_GESTUREEVENT, ChannelKind.TRIGGER); } - } @Override 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 3d979ef6fd143..578e069c0784b 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 @@ -30,6 +30,7 @@ public enum LightType { ON_OFF_LIGHT("On/Off light"), ON_OFF_PLUGIN_UNIT("On/Off plug-in unit"), EXTENDED_COLOR_LIGHT("Extended color light"), + COLOR_LIGHT("Color light"), COLOR_DIMMABLE_LIGHT("Color dimmable light"), COLOR_TEMPERATURE_LIGHT("Color temperature light"), DIMMABLE_LIGHT("Dimmable light"), diff --git a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/ThermostatModeGsonTypeAdapter.java b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/ThermostatModeGsonTypeAdapter.java index 2b727f2117cdc..652a2e13d751c 100644 --- a/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/ThermostatModeGsonTypeAdapter.java +++ b/bundles/org.openhab.binding.deconz/src/main/java/org/openhab/binding/deconz/internal/types/ThermostatModeGsonTypeAdapter.java @@ -48,6 +48,5 @@ public ThermostatMode deserialize(@Nullable JsonElement json, @Nullable Type typ public JsonElement serialize(ThermostatMode src, @Nullable Type typeOfSrc, @Nullable JsonSerializationContext context) throws JsonParseException { return src != ThermostatMode.UNKNOWN ? new JsonPrimitive(src.getDeconzValue()) : JsonNull.INSTANCE; - } } diff --git a/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/light-thing-types.xml b/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/light-thing-types.xml index 4aa8cba1d0206..6d4005e2687cf 100644 --- a/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/light-thing-types.xml +++ b/bundles/org.openhab.binding.deconz/src/main/resources/ESH-INF/thing/light-thing-types.xml @@ -121,7 +121,7 @@ Number - + 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 8c3ac5b38e3a7..5e049e650ddbd 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 @@ -508,7 +508,7 @@ - + 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 57657cc144bc4..0366f51c4f271 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 @@ -81,7 +81,7 @@ public void colorTemperatureLightUpdateTest() throws IOException { lightThingHandler.messageReceived("", lightMessage); Mockito.verify(thingHandlerCallback).stateUpdated(eq(channelUID_bri), eq(new PercentType("21"))); - Mockito.verify(thingHandlerCallback).stateUpdated(eq(channelUID_ct), eq(new DecimalType("87.03170028818444"))); + Mockito.verify(thingHandlerCallback).stateUpdated(eq(channelUID_ct), eq(new DecimalType("2500"))); } @Test diff --git a/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/colortemperature.json b/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/colortemperature.json index 0af4a94c5ca0c..0e690d172dc0f 100644 --- a/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/colortemperature.json +++ b/bundles/org.openhab.binding.deconz/src/test/resources/org/openhab/binding/deconz/colortemperature.json @@ -6,7 +6,7 @@ "alert": null, "bri": 51, "colormode": "ct", - "ct": 455, + "ct": 400, "on": true, "reachable": true },