Skip to content

Commit

Permalink
[deconz] Adjust color-temperature handling, Extend bulb support (open…
Browse files Browse the repository at this point in the history
…hab#7900)

* Add property for ct colormode upper and lower limit

Signed-off-by: Benajmin Hahn <[email protected]>
  • Loading branch information
HahnBenjamin authored and andrewfg committed Aug 31, 2020
1 parent 9b2d523 commit d9a20fd
Show file tree
Hide file tree
Showing 12 changed files with 77 additions and 33 deletions.
2 changes: 1 addition & 1 deletion bundles/org.openhab.binding.deconz/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<String, Object> 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) {
Expand All @@ -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:
Expand All @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -78,8 +78,13 @@ public class LightThingHandler extends DeconzBaseThingHandler<LightMessage> {
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ protected void createTypeSpecificChannels(SensorConfig sensorConfig, SensorState
createChannel(CHANNEL_GESTURE, ChannelKind.STATE);
createChannel(CHANNEL_GESTUREEVENT, ChannelKind.TRIGGER);
}

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
<channel-type id="ct">
<item-type>Number</item-type>
<label>Color Temperature</label>
<state pattern="%d" min="0" max="100"/>
<state pattern="%d" min="15" max="100000" step="100"/>
</channel-type>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@
<option value="AUTO">auto</option>
<option value="HEAT">heat</option>
<option value="OFF">off</option>
</options>
</options>
</state>
</channel-type>
<channel-type id="offset">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"alert": null,
"bri": 51,
"colormode": "ct",
"ct": 455,
"ct": 400,
"on": true,
"reachable": true
},
Expand Down

0 comments on commit d9a20fd

Please sign in to comment.