[lifx] Support HEV clean cycle (#11262)

* Implement HEV packets
* Add colorhevlight thing type with a hevcycle channel
* Update documentation

Signed-off-by: Wouter Born <github@maindrain.net>
This commit is contained in:
Wouter Born
2021-09-19 11:45:06 +02:00
committed by GitHub
parent 0a7a9ae281
commit 344011c2ad
25 changed files with 1143 additions and 218 deletions

View File

@@ -13,8 +13,6 @@
package org.openhab.binding.lifx.internal;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.lifx.internal.fields.HSBK;
@@ -55,6 +53,7 @@ public class LifxBindingConstants {
public static final String CHANNEL_COLOR = "color";
public static final String CHANNEL_COLOR_ZONE = "colorzone";
public static final String CHANNEL_EFFECT = "effect";
public static final String CHANNEL_HEV_CYCLE = "hevcycle";
public static final String CHANNEL_INFRARED = "infrared";
public static final String CHANNEL_SIGNAL_STRENGTH = "signalstrength";
public static final String CHANNEL_TEMPERATURE = "temperature";
@@ -80,11 +79,12 @@ public class LifxBindingConstants {
public static final String CONFIG_PROPERTY_FADETIME = "fadetime";
// Config property for channel configuration
public static final String CONFIG_PROPERTY_HEV_CYCLE_DURATION = "hevCycleDuration";
public static final String CONFIG_PROPERTY_EFFECT_FLAME_SPEED = "effectFlameSpeed";
public static final String CONFIG_PROPERTY_EFFECT_MORPH_SPEED = "effectMorphSpeed";
public static final String CONFIG_PROPERTY_POWER_ON_BRIGHTNESS = "powerOnBrightness";
public static final String CONFIG_PROPERTY_POWER_ON_COLOR = "powerOnColor";
public static final String CONFIG_PROPERTY_POWER_ON_TEMPERATURE = "powerOnTemperature";
public static final String CONFIG_PROPERTY_EFFECT_MORPH_SPEED = "effectMorphSpeed";
public static final String CONFIG_PROPERTY_EFFECT_FLAME_SPEED = "effectFlameSpeed";
// Property keys
public static final String PROPERTY_HOST = "host";
@@ -100,12 +100,13 @@ public class LifxBindingConstants {
// List of all Thing Type UIDs
public static final ThingTypeUID THING_TYPE_COLORLIGHT = new ThingTypeUID(BINDING_ID, "colorlight");
public static final ThingTypeUID THING_TYPE_COLORHEVLIGHT = new ThingTypeUID(BINDING_ID, "colorhevlight");
public static final ThingTypeUID THING_TYPE_COLORIRLIGHT = new ThingTypeUID(BINDING_ID, "colorirlight");
public static final ThingTypeUID THING_TYPE_COLORMZLIGHT = new ThingTypeUID(BINDING_ID, "colormzlight");
public static final ThingTypeUID THING_TYPE_WHITELIGHT = new ThingTypeUID(BINDING_ID, "whitelight");
public static final ThingTypeUID THING_TYPE_TILELIGHT = new ThingTypeUID(BINDING_ID, "tilelight");
public static final ThingTypeUID THING_TYPE_WHITELIGHT = new ThingTypeUID(BINDING_ID, "whitelight");
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Stream.of(THING_TYPE_COLORLIGHT,
THING_TYPE_COLORIRLIGHT, THING_TYPE_COLORMZLIGHT, THING_TYPE_WHITELIGHT, THING_TYPE_TILELIGHT)
.collect(Collectors.toSet());
public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_COLORLIGHT,
THING_TYPE_COLORHEVLIGHT, THING_TYPE_COLORIRLIGHT, THING_TYPE_COLORMZLIGHT, THING_TYPE_TILELIGHT,
THING_TYPE_WHITELIGHT);
}

View File

@@ -25,11 +25,14 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.lifx.internal.LifxProduct.Features;
import org.openhab.binding.lifx.internal.dto.GetColorZonesRequest;
import org.openhab.binding.lifx.internal.dto.GetHevCycleRequest;
import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
import org.openhab.binding.lifx.internal.dto.GetRequest;
import org.openhab.binding.lifx.internal.dto.GetTileEffectRequest;
import org.openhab.binding.lifx.internal.dto.GetWifiInfoRequest;
import org.openhab.binding.lifx.internal.dto.HevCycleState;
import org.openhab.binding.lifx.internal.dto.Packet;
import org.openhab.binding.lifx.internal.dto.StateHevCycleResponse;
import org.openhab.binding.lifx.internal.dto.StateLightInfraredResponse;
import org.openhab.binding.lifx.internal.dto.StateLightPowerResponse;
import org.openhab.binding.lifx.internal.dto.StateMultiZoneResponse;
@@ -133,6 +136,9 @@ public class LifxLightCurrentStateUpdater {
private void sendLightStateRequests() {
communicationHandler.sendPacket(new GetRequest());
if (features.hasFeature(HEV)) {
communicationHandler.sendPacket(new GetHevCycleRequest());
}
if (features.hasFeature(INFRARED)) {
communicationHandler.sendPacket(new GetLightInfraredRequest());
}
@@ -157,14 +163,16 @@ public class LifxLightCurrentStateUpdater {
handlePowerStatus((StatePowerResponse) packet);
} else if (packet instanceof StateLightPowerResponse) {
handleLightPowerStatus((StateLightPowerResponse) packet);
} else if (packet instanceof StateHevCycleResponse) {
handleHevCycleStatus((StateHevCycleResponse) packet);
} else if (packet instanceof StateLightInfraredResponse) {
handleInfraredStatus((StateLightInfraredResponse) packet);
} else if (packet instanceof StateMultiZoneResponse) {
handleMultiZoneStatus((StateMultiZoneResponse) packet);
} else if (packet instanceof StateWifiInfoResponse) {
handleWifiInfoStatus((StateWifiInfoResponse) packet);
} else if (packet instanceof StateTileEffectResponse) {
handleTileEffectStatus((StateTileEffectResponse) packet);
} else if (packet instanceof StateWifiInfoResponse) {
handleWifiInfoStatus((StateWifiInfoResponse) packet);
}
currentLightState.setOnline();
@@ -192,6 +200,11 @@ public class LifxLightCurrentStateUpdater {
currentLightState.setPowerState(packet.getState());
}
private void handleHevCycleStatus(StateHevCycleResponse packet) {
HevCycleState hevCycleState = new HevCycleState(!packet.getRemaining().isZero(), packet.getDuration());
currentLightState.setHevCycleState(hevCycleState);
}
private void handleInfraredStatus(StateLightInfraredResponse packet) {
PercentType infrared = infraredToPercentType(packet.getInfrared());
currentLightState.setInfrared(infrared);
@@ -209,11 +222,11 @@ public class LifxLightCurrentStateUpdater {
currentLightState.setColors(colors);
}
private void handleWifiInfoStatus(StateWifiInfoResponse packet) {
currentLightState.setSignalStrength(packet.getSignalStrength());
}
private void handleTileEffectStatus(StateTileEffectResponse packet) {
currentLightState.setTileEffect(packet.getEffect());
}
private void handleWifiInfoStatus(StateWifiInfoResponse packet) {
currentLightState.setSignalStrength(packet.getSignalStrength());
}
}

View File

@@ -23,6 +23,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.lifx.internal.dto.Effect;
import org.openhab.binding.lifx.internal.dto.HevCycleState;
import org.openhab.binding.lifx.internal.dto.PowerState;
import org.openhab.binding.lifx.internal.dto.SignalStrength;
import org.openhab.binding.lifx.internal.fields.HSBK;
@@ -40,6 +41,7 @@ import org.openhab.core.library.types.PercentType;
public class LifxLightState {
private HSBK[] colors = new HSBK[] { new HSBK(DEFAULT_COLOR) };
private @Nullable HevCycleState hevCycleState;
private @Nullable PercentType infrared;
private @Nullable PowerState powerState;
private @Nullable SignalStrength signalStrength;
@@ -51,6 +53,7 @@ public class LifxLightState {
public void copy(LifxLightState other) {
this.powerState = other.getPowerState();
this.colors = other.getColors();
this.hevCycleState = other.getHevCycleState();
this.infrared = other.getInfrared();
this.signalStrength = other.getSignalStrength();
this.tileEffect = other.getTileEffect();
@@ -76,6 +79,10 @@ public class LifxLightState {
return colorsCopy;
}
public @Nullable HevCycleState getHevCycleState() {
return hevCycleState;
}
public @Nullable PercentType getInfrared() {
return infrared;
}
@@ -158,6 +165,13 @@ public class LifxLightState {
setColor(newColor, zoneIndex);
}
public void setHevCycleState(HevCycleState newHevCycleState) {
HevCycleState oldHevCycleState = this.hevCycleState;
this.hevCycleState = newHevCycleState;
updateLastChange();
listeners.forEach(listener -> listener.handleHevCycleStateChange(oldHevCycleState, newHevCycleState));
}
public void setInfrared(PercentType newInfrared) {
PercentType oldInfrared = this.infrared;
this.infrared = newInfrared;

View File

@@ -34,13 +34,16 @@ import org.openhab.binding.lifx.internal.dto.AcknowledgementResponse;
import org.openhab.binding.lifx.internal.dto.ApplicationRequest;
import org.openhab.binding.lifx.internal.dto.Effect;
import org.openhab.binding.lifx.internal.dto.GetColorZonesRequest;
import org.openhab.binding.lifx.internal.dto.GetHevCycleRequest;
import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
import org.openhab.binding.lifx.internal.dto.GetLightPowerRequest;
import org.openhab.binding.lifx.internal.dto.GetRequest;
import org.openhab.binding.lifx.internal.dto.HevCycleState;
import org.openhab.binding.lifx.internal.dto.Packet;
import org.openhab.binding.lifx.internal.dto.PowerState;
import org.openhab.binding.lifx.internal.dto.SetColorRequest;
import org.openhab.binding.lifx.internal.dto.SetColorZonesRequest;
import org.openhab.binding.lifx.internal.dto.SetHevCycleRequest;
import org.openhab.binding.lifx.internal.dto.SetLightInfraredRequest;
import org.openhab.binding.lifx.internal.dto.SetLightPowerRequest;
import org.openhab.binding.lifx.internal.dto.SetPowerRequest;
@@ -308,6 +311,17 @@ public class LifxLightStateChanger implements LifxLightStateListener {
}
}
@Override
public void handleHevCycleStateChange(@Nullable HevCycleState oldHevCycleState, HevCycleState newHevCycleState) {
// The change should be ignored when both the old and new state are disabled regardless of the cycle duration
if (!newHevCycleState.equals(oldHevCycleState)
&& (oldHevCycleState == null || oldHevCycleState.isEnable() || newHevCycleState.isEnable())) {
SetHevCycleRequest packet = new SetHevCycleRequest(newHevCycleState.isEnable(),
newHevCycleState.getDuration());
replacePacketsInMap(packet);
}
}
@Override
public void handleInfraredChange(@Nullable PercentType oldInfrared, PercentType newInfrared) {
PercentType infrared = pendingLightState.getInfrared();
@@ -325,7 +339,7 @@ public class LifxLightStateChanger implements LifxLightStateListener {
@Override
public void handleTileEffectChange(@Nullable Effect oldEffect, Effect newEffect) {
if (oldEffect == null || !oldEffect.equals(newEffect)) {
if (!newEffect.equals(oldEffect)) {
SetTileEffectRequest packet = new SetTileEffectRequest(newEffect);
replacePacketsInMap(packet);
}
@@ -360,6 +374,13 @@ public class LifxLightStateChanger implements LifxLightStateListener {
getZonesIfZonesAreSet();
} else if (sentPacket instanceof SetColorZonesRequest) {
getZonesIfZonesAreSet();
} else if (sentPacket instanceof SetHevCycleRequest) {
scheduler.schedule(() -> {
GetHevCycleRequest hevCyclePacket = new GetHevCycleRequest();
communicationHandler.sendPacket(hevCyclePacket);
GetLightPowerRequest powerPacket = new GetLightPowerRequest();
communicationHandler.sendPacket(powerPacket);
}, 600, TimeUnit.MILLISECONDS);
} else if (sentPacket instanceof SetLightInfraredRequest) {
GetLightInfraredRequest infraredPacket = new GetLightInfraredRequest();
communicationHandler.sendPacket(infraredPacket);

View File

@@ -371,12 +371,14 @@ public enum LifxProduct {
public ThingTypeUID getThingTypeUID() {
if (hasFeature(COLOR)) {
if (hasFeature(TILE_EFFECT)) {
return LifxBindingConstants.THING_TYPE_TILELIGHT;
if (hasFeature(HEV)) {
return LifxBindingConstants.THING_TYPE_COLORHEVLIGHT;
} else if (hasFeature(INFRARED)) {
return LifxBindingConstants.THING_TYPE_COLORIRLIGHT;
} else if (hasFeature(MULTIZONE)) {
return LifxBindingConstants.THING_TYPE_COLORMZLIGHT;
} else if (hasFeature(TILE_EFFECT)) {
return LifxBindingConstants.THING_TYPE_TILELIGHT;
} else {
return LifxBindingConstants.THING_TYPE_COLORLIGHT;
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
/**
* @author Wouter Born - Initial contribution
*/
public class GetHevCycleConfigurationRequest extends Packet {
public static final int TYPE = 0x91;
public GetHevCycleConfigurationRequest() {
setTagged(false);
setAddressable(true);
setResponseRequired(true);
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 0;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
// do nothing
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(0);
}
@Override
public int[] expectedResponses() {
return new int[] { StateHevCycleConfigurationResponse.TYPE };
}
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
/**
* @author Wouter Born - Initial contribution
*/
public class GetHevCycleRequest extends Packet {
public static final int TYPE = 0x8E;
public GetHevCycleRequest() {
setTagged(false);
setAddressable(true);
setResponseRequired(true);
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 0;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
// do nothing
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(0);
}
@Override
public int[] expectedResponses() {
return new int[] { StateHevCycleResponse.TYPE };
}
}

View File

@@ -0,0 +1,54 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
/**
* @author Wouter Born - Initial contribution
*/
public class GetLastHevCycleResultRequest extends Packet {
public static final int TYPE = 0x94;
public GetLastHevCycleResultRequest() {
setTagged(false);
setAddressable(true);
setResponseRequired(true);
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 0;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
// do nothing
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(0);
}
@Override
public int[] expectedResponses() {
return new int[] { StateLastHevCycleResultResponse.TYPE };
}
}

View File

@@ -0,0 +1,86 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.time.Duration;
/**
* The pending or current HEV cycle state.
*
* @author Wouter Born - Initial contribution
*/
public class HevCycleState {
public static final HevCycleState OFF = new HevCycleState(false);
public static final HevCycleState ON = new HevCycleState(true);
private boolean enable;
private Duration duration;
public HevCycleState(boolean enable) {
this.enable = enable;
this.duration = Duration.ZERO;
}
public HevCycleState(boolean enable, Duration duration) {
this.enable = enable;
this.duration = duration;
}
public boolean isEnable() {
return enable;
}
public Duration getDuration() {
return duration;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((duration == null) ? 0 : duration.hashCode());
result = prime * result + (enable ? 1231 : 1237);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
HevCycleState other = (HevCycleState) obj;
if (duration == null) {
if (other.duration != null) {
return false;
}
} else if (!duration.equals(other.duration)) {
return false;
}
if (enable != other.enable) {
return false;
}
return true;
}
@Override
public String toString() {
return "HevCycleState [enable=" + enable + ", duration=" + duration + "]";
}
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.util.Arrays;
import java.util.Optional;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Wouter Born - Initial contribution
*/
@NonNullByDefault
public enum LightLastHevCycleResult {
SUCCESS(0),
BUSY(1),
INTERRUPTED_BY_RESET(2),
INTERRUPTED_BY_HOMEKIT(3),
INTERRUPTED_BY_LAN(4),
INTERRUPTED_BY_CLOUD(5),
NONE(255);
private final int type;
LightLastHevCycleResult(int type) {
this.type = type;
}
public static LightLastHevCycleResult fromValue(int type) {
Optional<LightLastHevCycleResult> result = Arrays.stream(values()).filter((value) -> value.type == type)
.findFirst();
if (!result.isPresent()) {
throw new IllegalArgumentException("Invalid LightLastHevCycleResult type: " + type);
}
return result.get();
}
}

View File

@@ -52,10 +52,13 @@ public class PacketFactory {
register(GetColorZonesRequest.class);
register(GetEchoRequest.class);
register(GetGroupRequest.class);
register(GetHevCycleConfigurationRequest.class);
register(GetHevCycleRequest.class);
register(GetHostFirmwareRequest.class);
register(GetHostInfoRequest.class);
register(GetInfoRequest.class);
register(GetLabelRequest.class);
register(GetLastHevCycleResultRequest.class);
register(GetLightInfraredRequest.class);
register(GetLightPowerRequest.class);
register(GetLocationRequest.class);
@@ -71,16 +74,21 @@ public class PacketFactory {
register(SetColorRequest.class);
register(SetColorZonesRequest.class);
register(SetDimAbsoluteRequest.class);
register(SetHevCycleRequest.class);
register(SetHevCycleConfigurationRequest.class);
register(SetLabelRequest.class);
register(SetLightInfraredRequest.class);
register(SetLightPowerRequest.class);
register(SetPowerRequest.class);
register(SetTagsRequest.class);
register(StateGroupResponse.class);
register(StateHevCycleConfigurationResponse.class);
register(StateHevCycleResponse.class);
register(StateHostFirmwareResponse.class);
register(StateHostInfoResponse.class);
register(StateInfoResponse.class);
register(StateLabelResponse.class);
register(StateLastHevCycleResultResponse.class);
register(StateLightInfraredResponse.class);
register(StateLightPowerResponse.class);
register(StateLocationResponse.class);

View File

@@ -0,0 +1,81 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
import java.time.Duration;
import org.openhab.binding.lifx.internal.fields.BoolIntField;
import org.openhab.binding.lifx.internal.fields.Field;
import org.openhab.binding.lifx.internal.fields.UInt32Field;
/**
* @author Wouter Born - Initial contribution
*/
public class SetHevCycleConfigurationRequest extends Packet {
public static final int TYPE = 0x92;
public static final Field<Boolean> FIELD_INDICATION = new BoolIntField();
public static final Field<Long> FIELD_DURATION = new UInt32Field().little();
private boolean indication;
private long duration;
public boolean isIndication() {
return indication;
}
public Duration getDuration() {
return Duration.ofSeconds(duration);
}
public SetHevCycleConfigurationRequest() {
setTagged(false);
setAddressable(true);
setResponseRequired(true);
}
public SetHevCycleConfigurationRequest(boolean indication, Duration duration) {
this();
this.indication = indication;
this.duration = duration.toSeconds();
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 5;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
indication = FIELD_INDICATION.value(bytes);
duration = FIELD_DURATION.value(bytes);
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(packetLength()).put(FIELD_INDICATION.bytes(indication))
.put(FIELD_DURATION.bytes(duration));
}
@Override
public int[] expectedResponses() {
return new int[] { StateHevCycleConfigurationResponse.TYPE };
}
}

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
import java.time.Duration;
import org.openhab.binding.lifx.internal.fields.BoolIntField;
import org.openhab.binding.lifx.internal.fields.Field;
import org.openhab.binding.lifx.internal.fields.UInt32Field;
/**
* @author Wouter Born - Initial contribution
*/
public class SetHevCycleRequest extends Packet {
public static final int TYPE = 0x8F;
public static final Field<Boolean> FIELD_ENABLE = new BoolIntField();
public static final Field<Long> FIELD_DURATION = new UInt32Field().little();
private boolean enable;
private long duration;
public boolean isEnable() {
return enable;
}
public Duration getDuration() {
return Duration.ofSeconds(duration);
}
public SetHevCycleRequest() {
setTagged(false);
setAddressable(true);
setResponseRequired(true);
}
public SetHevCycleRequest(boolean enable) {
this();
this.enable = enable;
}
public SetHevCycleRequest(boolean enable, Duration duration) {
this();
this.enable = enable;
this.duration = duration.toSeconds();
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 5;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
enable = FIELD_ENABLE.value(bytes);
duration = FIELD_DURATION.value(bytes);
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(packetLength()).put(FIELD_ENABLE.bytes(enable)).put(FIELD_DURATION.bytes(duration));
}
@Override
public int[] expectedResponses() {
return new int[] { StateHevCycleResponse.TYPE };
}
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
import java.time.Duration;
import org.openhab.binding.lifx.internal.fields.BoolIntField;
import org.openhab.binding.lifx.internal.fields.Field;
import org.openhab.binding.lifx.internal.fields.UInt32Field;
/**
* @author Wouter Born - Initial contribution
*/
public class StateHevCycleConfigurationResponse extends Packet {
public static final int TYPE = 0x93;
public static final Field<Boolean> FIELD_INDICATION = new BoolIntField();
public static final Field<Long> FIELD_DURATION = new UInt32Field().little();
private boolean indication;
private long duration;
public boolean isIndication() {
return indication;
}
public Duration getDuration() {
return Duration.ofSeconds(duration);
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 5;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
indication = FIELD_INDICATION.value(bytes);
duration = FIELD_DURATION.value(bytes);
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(packetLength()).put(FIELD_INDICATION.bytes(indication))
.put(FIELD_DURATION.bytes(duration));
}
@Override
public int[] expectedResponses() {
return new int[] {};
}
}

View File

@@ -0,0 +1,76 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
import java.time.Duration;
import org.openhab.binding.lifx.internal.fields.BoolIntField;
import org.openhab.binding.lifx.internal.fields.Field;
import org.openhab.binding.lifx.internal.fields.UInt32Field;
/**
* @author Wouter Born - Initial contribution
*/
public class StateHevCycleResponse extends Packet {
public static final int TYPE = 0x90;
public static final Field<Long> FIELD_DURATION = new UInt32Field().little();
public static final Field<Long> FIELD_REMAINING = new UInt32Field().little();
public static final Field<Boolean> FIELD_LAST_POWER = new BoolIntField();
private long duration;
private long remaining;
private boolean lastPower;
public Duration getDuration() {
return Duration.ofSeconds(duration);
}
public Duration getRemaining() {
return Duration.ofSeconds(remaining);
}
public boolean isLastPower() {
return lastPower;
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 9;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
duration = FIELD_DURATION.value(bytes);
remaining = FIELD_REMAINING.value(bytes);
lastPower = FIELD_LAST_POWER.value(bytes);
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(packetLength()).put(FIELD_DURATION.bytes(duration))
.put(FIELD_REMAINING.bytes(remaining)).put(FIELD_LAST_POWER.bytes(lastPower));
}
@Override
public int[] expectedResponses() {
return new int[] {};
}
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.dto;
import java.nio.ByteBuffer;
import org.openhab.binding.lifx.internal.fields.Field;
import org.openhab.binding.lifx.internal.fields.UInt8Field;
/**
* @author Wouter Born - Initial contribution
*/
public class StateLastHevCycleResultResponse extends Packet {
public static final int TYPE = 0x95;
public static final Field<Integer> FIELD_RESULT = new UInt8Field().little();
private int result;
public LightLastHevCycleResult getResult() {
return LightLastHevCycleResult.fromValue(result);
}
@Override
public int packetType() {
return TYPE;
}
@Override
protected int packetLength() {
return 1;
}
@Override
protected void parsePacket(ByteBuffer bytes) {
result = FIELD_RESULT.value(bytes);
}
@Override
protected ByteBuffer packetBytes() {
return ByteBuffer.allocate(packetLength()).put(FIELD_RESULT.bytes(result));
}
@Override
public int[] expectedResponses() {
return new int[] {};
}
}

View File

@@ -0,0 +1,43 @@
/**
* Copyright (c) 2010-2021 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.lifx.internal.fields;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* @author Wouter Born - Initial contribution
*/
@NonNullByDefault
public class BoolIntField extends Field<Boolean> {
public BoolIntField() {
super(1);
}
@Override
public int defaultLength() {
return 1;
}
@Override
public Boolean value(ByteBuffer bytes) {
return bytes.get() == 1;
}
@Override
public ByteBuffer bytesInternal(Boolean value) {
return ByteBuffer.allocate(1).put((byte) (value ? 1 : 0));
}
}

View File

@@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jdt.annotation.NonNullByDefault;
@@ -42,11 +43,13 @@ import org.openhab.binding.lifx.internal.LifxLightStateChanger;
import org.openhab.binding.lifx.internal.LifxProduct;
import org.openhab.binding.lifx.internal.LifxProduct.Features;
import org.openhab.binding.lifx.internal.dto.Effect;
import org.openhab.binding.lifx.internal.dto.GetHevCycleRequest;
import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
import org.openhab.binding.lifx.internal.dto.GetLightPowerRequest;
import org.openhab.binding.lifx.internal.dto.GetRequest;
import org.openhab.binding.lifx.internal.dto.GetTileEffectRequest;
import org.openhab.binding.lifx.internal.dto.GetWifiInfoRequest;
import org.openhab.binding.lifx.internal.dto.HevCycleState;
import org.openhab.binding.lifx.internal.dto.Packet;
import org.openhab.binding.lifx.internal.dto.PowerState;
import org.openhab.binding.lifx.internal.dto.SignalStrength;
@@ -94,6 +97,7 @@ public class LifxLightHandler extends BaseThingHandler {
private final LifxChannelFactory channelFactory;
private @NonNullByDefault({}) Features features;
private Duration hevCycleDuration = Duration.ZERO;
private @Nullable PercentType powerOnBrightness;
private @Nullable HSBType powerOnColor;
private @Nullable PercentType powerOnTemperature;
@@ -191,6 +195,14 @@ public class LifxLightHandler extends BaseThingHandler {
return updateColor;
}
@Override
public void setHevCycleState(HevCycleState hevCycleState) {
if (!isStateChangePending() || hevCycleState.equals(pendingLightState.getHevCycleState())) {
updateStateIfChanged(CHANNEL_HEV_CYCLE, OnOffType.from(hevCycleState.isEnable()));
}
super.setHevCycleState(hevCycleState);
}
@Override
public void setInfrared(PercentType infrared) {
if (!isStateChangePending() || infrared.equals(pendingLightState.getInfrared())) {
@@ -263,6 +275,8 @@ public class LifxLightHandler extends BaseThingHandler {
if (speed != null) {
effectFlameSpeed = speed;
}
hevCycleDuration = getHevCycleDuration();
channelStates.clear();
currentLightState = new CurrentLightState();
pendingLightState = new LifxLightState();
@@ -410,6 +424,19 @@ public class LifxLightHandler extends BaseThingHandler {
return speed == null ? null : Double.valueOf(speed.toString());
}
private Duration getHevCycleDuration() {
ChannelUID channelUID = new ChannelUID(getThing().getUID(), LifxBindingConstants.CHANNEL_HEV_CYCLE);
Channel channel = getThing().getChannel(channelUID.getId());
if (channel == null) {
return Duration.ZERO;
}
Configuration configuration = channel.getConfiguration();
Object duration = configuration.get(LifxBindingConstants.CONFIG_PROPERTY_HEV_CYCLE_DURATION);
return duration == null ? Duration.ZERO : Duration.ofSeconds(Integer.valueOf(duration.toString()));
}
private Features getFeatures() {
LifxProduct product = getProduct();
@@ -486,118 +513,126 @@ public class LifxLightHandler extends BaseThingHandler {
@Override
public void handleCommand(ChannelUID channelUID, Command command) {
if (command instanceof RefreshType) {
channelStates.remove(channelUID.getId());
switch (channelUID.getId()) {
case CHANNEL_COLOR:
case CHANNEL_BRIGHTNESS:
sendPacket(new GetLightPowerRequest());
sendPacket(new GetRequest());
break;
case CHANNEL_TEMPERATURE:
sendPacket(new GetRequest());
break;
case CHANNEL_INFRARED:
sendPacket(new GetLightInfraredRequest());
break;
case CHANNEL_SIGNAL_STRENGTH:
sendPacket(new GetWifiInfoRequest());
break;
case CHANNEL_EFFECT:
if (features.hasFeature(TILE_EFFECT)) {
sendPacket(new GetTileEffectRequest());
}
break;
default:
break;
}
handleRefreshCommand(channelUID);
} else {
boolean supportedCommand = true;
switch (channelUID.getId()) {
case CHANNEL_COLOR:
if (command instanceof HSBType) {
handleHSBCommand((HSBType) command);
} else if (command instanceof PercentType) {
handlePercentCommand((PercentType) command);
} else if (command instanceof OnOffType) {
handleOnOffCommand((OnOffType) command);
} else if (command instanceof IncreaseDecreaseType) {
handleIncreaseDecreaseCommand((IncreaseDecreaseType) command);
} else {
supportedCommand = false;
}
break;
case CHANNEL_BRIGHTNESS:
if (command instanceof PercentType) {
handlePercentCommand((PercentType) command);
} else if (command instanceof OnOffType) {
handleOnOffCommand((OnOffType) command);
} else if (command instanceof IncreaseDecreaseType) {
handleIncreaseDecreaseCommand((IncreaseDecreaseType) command);
} else {
supportedCommand = false;
}
break;
case CHANNEL_TEMPERATURE:
if (command instanceof PercentType) {
handleTemperatureCommand((PercentType) command);
} else if (command instanceof IncreaseDecreaseType) {
handleIncreaseDecreaseTemperatureCommand((IncreaseDecreaseType) command);
} else {
supportedCommand = false;
}
break;
case CHANNEL_INFRARED:
if (command instanceof PercentType) {
handleInfraredCommand((PercentType) command);
} else if (command instanceof IncreaseDecreaseType) {
handleIncreaseDecreaseInfraredCommand((IncreaseDecreaseType) command);
} else {
supportedCommand = false;
}
break;
case CHANNEL_EFFECT:
if (command instanceof StringType && features.hasFeature(TILE_EFFECT)) {
handleTileEffectCommand((StringType) command);
} else {
supportedCommand = false;
}
break;
default:
try {
if (channelUID.getId().startsWith(CHANNEL_COLOR_ZONE)) {
int zoneIndex = Integer.parseInt(channelUID.getId().replace(CHANNEL_COLOR_ZONE, ""));
if (command instanceof HSBType) {
handleHSBCommand((HSBType) command, zoneIndex);
} else if (command instanceof PercentType) {
handlePercentCommand((PercentType) command, zoneIndex);
} else if (command instanceof IncreaseDecreaseType) {
handleIncreaseDecreaseCommand((IncreaseDecreaseType) command, zoneIndex);
} else {
supportedCommand = false;
}
} else if (channelUID.getId().startsWith(CHANNEL_TEMPERATURE_ZONE)) {
int zoneIndex = Integer.parseInt(channelUID.getId().replace(CHANNEL_TEMPERATURE_ZONE, ""));
if (command instanceof PercentType) {
handleTemperatureCommand((PercentType) command, zoneIndex);
} else if (command instanceof IncreaseDecreaseType) {
handleIncreaseDecreaseTemperatureCommand((IncreaseDecreaseType) command, zoneIndex);
} else {
supportedCommand = false;
}
} else {
supportedCommand = false;
}
} catch (NumberFormatException e) {
logger.error("Failed to parse zone index for a command of a light ({}) : {}", logId,
e.getMessage());
supportedCommand = false;
}
break;
Runnable channelCommandRunnable = getChannelCommandRunnable(channelUID, command);
if (channelCommandRunnable == null) {
return;
}
if (supportedCommand && !(command instanceof OnOffType) && !CHANNEL_INFRARED.equals(channelUID.getId())) {
getLightStateForCommand().setPowerState(PowerState.ON);
String channelId = channelUID.getId();
boolean isHevCycleChannelCommand = CHANNEL_HEV_CYCLE.equals(channelId);
boolean isInfraredChannelCommand = CHANNEL_INFRARED.equals(channelId);
boolean waitForHevCycleDisabled = false;
if (getFeatures().hasFeature(HEV) && !isHevCycleChannelCommand) {
LifxLightState lightState = getLightStateForCommand();
HevCycleState currentHevCycleState = lightState.getHevCycleState();
if (currentHevCycleState == null || currentHevCycleState.isEnable()) {
lightState.setHevCycleState(HevCycleState.OFF);
lightState.setPowerState(PowerState.OFF);
waitForHevCycleDisabled = true;
}
}
Runnable compositeCommandsRunnable = () -> {
channelCommandRunnable.run();
if (!(command instanceof OnOffType) && !isHevCycleChannelCommand && !isInfraredChannelCommand) {
getLightStateForCommand().setPowerState(PowerState.ON);
}
};
if (waitForHevCycleDisabled) {
scheduler.schedule(compositeCommandsRunnable, 200, TimeUnit.MILLISECONDS);
} else {
compositeCommandsRunnable.run();
}
}
}
private @Nullable Runnable getChannelCommandRunnable(ChannelUID channelUID, Command command) {
switch (channelUID.getId()) {
case CHANNEL_BRIGHTNESS:
if (command instanceof PercentType) {
return () -> handlePercentCommand((PercentType) command);
} else if (command instanceof OnOffType) {
return () -> handleOnOffCommand((OnOffType) command);
} else if (command instanceof IncreaseDecreaseType) {
return () -> handleIncreaseDecreaseCommand((IncreaseDecreaseType) command);
} else {
return null;
}
case CHANNEL_COLOR:
if (command instanceof HSBType) {
return () -> handleHSBCommand((HSBType) command);
} else if (command instanceof PercentType) {
return () -> handlePercentCommand((PercentType) command);
} else if (command instanceof OnOffType) {
return () -> handleOnOffCommand((OnOffType) command);
} else if (command instanceof IncreaseDecreaseType) {
return () -> handleIncreaseDecreaseCommand((IncreaseDecreaseType) command);
} else {
return null;
}
case CHANNEL_EFFECT:
if (command instanceof StringType && features.hasFeature(TILE_EFFECT)) {
return () -> handleTileEffectCommand((StringType) command);
} else {
return null;
}
case CHANNEL_HEV_CYCLE:
if (command instanceof OnOffType) {
return () -> handleHevCycleCommand((OnOffType) command);
} else {
return null;
}
case CHANNEL_INFRARED:
if (command instanceof PercentType) {
return () -> handleInfraredCommand((PercentType) command);
} else if (command instanceof IncreaseDecreaseType) {
return () -> handleIncreaseDecreaseInfraredCommand((IncreaseDecreaseType) command);
} else {
return null;
}
case CHANNEL_TEMPERATURE:
if (command instanceof PercentType) {
return () -> handleTemperatureCommand((PercentType) command);
} else if (command instanceof IncreaseDecreaseType) {
return () -> handleIncreaseDecreaseTemperatureCommand((IncreaseDecreaseType) command);
} else {
return null;
}
default:
try {
if (channelUID.getId().startsWith(CHANNEL_COLOR_ZONE)) {
int zoneIndex = Integer.parseInt(channelUID.getId().replace(CHANNEL_COLOR_ZONE, ""));
if (command instanceof HSBType) {
return () -> handleHSBCommand((HSBType) command, zoneIndex);
} else if (command instanceof PercentType) {
return () -> handlePercentCommand((PercentType) command, zoneIndex);
} else if (command instanceof IncreaseDecreaseType) {
return () -> handleIncreaseDecreaseCommand((IncreaseDecreaseType) command, zoneIndex);
} else {
return null;
}
} else if (channelUID.getId().startsWith(CHANNEL_TEMPERATURE_ZONE)) {
int zoneIndex = Integer.parseInt(channelUID.getId().replace(CHANNEL_TEMPERATURE_ZONE, ""));
if (command instanceof PercentType) {
return () -> handleTemperatureCommand((PercentType) command, zoneIndex);
} else if (command instanceof IncreaseDecreaseType) {
return () -> handleIncreaseDecreaseTemperatureCommand((IncreaseDecreaseType) command,
zoneIndex);
} else {
return null;
}
} else {
return null;
}
} catch (NumberFormatException e) {
logger.error("Failed to parse zone index for a command of a light ({}) : {}", logId,
e.getMessage());
return null;
}
}
}
@@ -612,6 +647,36 @@ public class LifxLightHandler extends BaseThingHandler {
return pendingLightState.getDurationSinceLastChange().minus(MAX_STATE_CHANGE_DURATION).isNegative();
}
private void handleRefreshCommand(ChannelUID channelUID) {
channelStates.remove(channelUID.getId());
switch (channelUID.getId()) {
case CHANNEL_COLOR:
case CHANNEL_BRIGHTNESS:
sendPacket(new GetLightPowerRequest());
sendPacket(new GetRequest());
break;
case CHANNEL_EFFECT:
if (features.hasFeature(TILE_EFFECT)) {
sendPacket(new GetTileEffectRequest());
}
break;
case CHANNEL_HEV_CYCLE:
sendPacket(new GetHevCycleRequest());
break;
case CHANNEL_INFRARED:
sendPacket(new GetLightInfraredRequest());
break;
case CHANNEL_SIGNAL_STRENGTH:
sendPacket(new GetWifiInfoRequest());
break;
case CHANNEL_TEMPERATURE:
sendPacket(new GetRequest());
break;
default:
break;
}
}
private void handleTemperatureCommand(PercentType temperature) {
HSBK newColor = getLightStateForCommand().getColor();
newColor.setSaturation(PercentType.ZERO);
@@ -688,6 +753,11 @@ public class LifxLightHandler extends BaseThingHandler {
handleTemperatureCommand(newTemperature, zoneIndex);
}
private void handleHevCycleCommand(OnOffType onOff) {
HevCycleState hevCycleState = new HevCycleState(onOff == OnOffType.ON, hevCycleDuration);
getLightStateForCommand().setHevCycleState(hevCycleState);
}
private void handleInfraredCommand(PercentType infrared) {
getLightStateForCommand().setInfrared(infrared);
}

View File

@@ -16,6 +16,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.lifx.internal.LifxLightState;
import org.openhab.binding.lifx.internal.dto.Effect;
import org.openhab.binding.lifx.internal.dto.HevCycleState;
import org.openhab.binding.lifx.internal.dto.PowerState;
import org.openhab.binding.lifx.internal.dto.SignalStrength;
import org.openhab.binding.lifx.internal.fields.HSBK;
@@ -45,6 +46,14 @@ public interface LifxLightStateListener {
*/
void handlePowerStateChange(@Nullable PowerState oldPowerState, PowerState newPowerState);
/**
* Called when the HEV cycle state property changes.
*
* @param oldHevCycleState the old HEV cycle state value
* @param newHevCycleState the new HEV cycle state value
*/
void handleHevCycleStateChange(@Nullable HevCycleState oldHevCycleState, HevCycleState newHevCycleState);
/**
* Called when the infrared property changes.
*

View File

@@ -42,6 +42,26 @@
</parameter>
</config-description>
<config-description uri="channel-type:lifx:effect">
<parameter name="effectMorphSpeed" type="decimal" min="0" max="120" step="0.1" required="false" unit="s">
<label>Morph Effect Speed</label>
<description>Speed of the morph effect in seconds.</description>
<default>3</default>
</parameter>
<parameter name="effectFlameSpeed" type="decimal" min="0" max="120" step="0.1" required="false" unit="s">
<label>Flame Effect Speed</label>
<description>Speed of the flame effect in seconds.</description>
<default>4</default>
</parameter>
</config-description>
<config-description uri="channel-type:lifx:hevcycle">
<parameter name="hevCycleDuration" type="integer" min="0" max="86400" step="1" required="false" unit="m">
<label>HEV Cycle Duration</label>
<description>HEV cycle duration in seconds. Use empty value for the cycle duration configured in the light.</description>
</parameter>
</config-description>
<config-description uri="channel-type:lifx:temperature">
<parameter name="powerOnTemperature" type="integer" min="0" max="100" required="false" unit="%">
<label>Power On Temperature</label>
@@ -50,17 +70,4 @@
</parameter>
</config-description>
<config-description uri="channel-type:lifx:effect">
<parameter name="effectMorphSpeed" type="decimal" min="0" max="120" step="0.1" required="false" unit="s">
<label>Morph effect speed</label>
<description>Speed of the morph effect in seconds.</description>
<default>3</default>
</parameter>
<parameter name="effectFlameSpeed" type="decimal" min="0" max="120" step="0.1" required="false" unit="s">
<label>Flame effect speed</label>
<description>Speed of the flame effect in seconds.</description>
<default>4</default>
</parameter>
</config-description>
</config-description:config-descriptions>

View File

@@ -4,16 +4,18 @@ binding.lifx.description = This is the binding for LIFX lights.
# thing types
thing-type.lifx.colorlight.label = LIFX Color Light
thing-type.lifx.colorhevlight.label = LIFX Color HEV Light
thing-type.lifx.colorirlight.label = LIFX Color IR Light
thing-type.lifx.colormzlight.label = LIFX Color MultiZone Light
thing-type.lifx.tilelight.label = LIFX Tile Light
thing-type.lifx.whitelight.label = LIFX White Light
# thing type configuration
thing-type.config.lifx.light.deviceId.label = LIFX device ID
thing-type.config.lifx.light.deviceId.label = LIFX Device ID
thing-type.config.lifx.light.deviceId.description = Identifies the light, e.g. "D073D5A1A1A1"
thing-type.config.lifx.light.host.label = Host
thing-type.config.lifx.light.host.description = Hostname or IP address of the light. Use empty value for automatic discovery.
thing-type.config.lifx.light.fadetime.label = Fade time
thing-type.config.lifx.light.fadetime.label = Fade Time
thing-type.config.lifx.light.fadetime.description = The time to fade to the new color value (in ms).
# channel types
@@ -21,30 +23,34 @@ channel-type.lifx.brightness.label = Brightness
channel-type.lifx.brightness.description = Sets the brightness of the light
channel-type.lifx.color.label = Color
channel-type.lifx.color.description = Selects the color of the light
channel-type.lifx.colorzone.label = Color zone {0}
channel-type.lifx.colorzone.label = Color Zone {0}
channel-type.lifx.colorzone.description = Selects the zone {0} color of the light
channel-type.lifx.infrared.label = Infrared
channel-type.lifx.infrared.description = Sets the infrared of the light
channel-type.lifx.temperature.label = Temperature
channel-type.lifx.temperature.description = Sets the temperature of the light
channel-type.lifx.temperaturezone.label = Temperature zone {0}
channel-type.lifx.temperaturezone.description = Sets the zone {0} temperature of the light
channel-type.lifx.effect.label = Effect
channel-type.lifx.effect.description = Sets the effect of the light
channel-type.lifx.effect.state.option.off = Off
channel-type.lifx.effect.state.option.morph = Morph
channel-type.lifx.effect.state.option.flame = Flame
channel-type.lifx.hevcycle.label = HEV Cycle
channel-type.lifx.hevcycle.description = Controls the HEV clean cycle of the light
channel-type.lifx.infrared.label = Infrared
channel-type.lifx.infrared.description = Sets the infrared of the light
channel-type.lifx.temperature.label = Temperature
channel-type.lifx.temperature.description = Sets the temperature of the light
channel-type.lifx.temperaturezone.label = Temperature Zone {0}
channel-type.lifx.temperaturezone.description = Sets the zone {0} temperature of the light
# channel type configuration
channel-type.config.lifx.brightness.powerOnBrightness.label = Power on brightness
channel-type.config.lifx.brightness.powerOnBrightness.label = Power On Brightness
channel-type.config.lifx.brightness.powerOnBrightness.description = Brightness level used when switching on the light. Use empty value to leave brightness as is.
channel-type.config.lifx.color.powerOnBrightness.label = Power on brightness
channel-type.config.lifx.color.powerOnBrightness.label = Power On Brightness
channel-type.config.lifx.color.powerOnBrightness.description = Brightness level used when switching on the light. Use empty value to leave brightness as is.
channel-type.config.lifx.color.powerOnColor.label = Power on color
channel-type.config.lifx.color.powerOnColor.label = Power On Color
channel-type.config.lifx.color.powerOnColor.description = Color used when switching on the light. Use empty value to leave color as is.
channel-type.config.lifx.temperature.powerOnTemperature.label = Power on color temperature
channel-type.config.lifx.temperature.powerOnTemperature.description = Color temperature used when switching on the light. Use empty value to leave color temperature as is.
channel-type.config.lifx.effect.effectMorphSpeed.label = Morph effect speed
channel-type.config.lifx.effect.effectMorphSpeed.label = Morph Effect Speed
channel-type.config.lifx.effect.effectMorphSpeed.description = Speed of the morph effect in seconds.
channel-type.config.lifx.effect.effectFlameSpeed.label = Flame effect speed
channel-type.config.lifx.effect.effectFlameSpeed.label = Flame Effect Speed
channel-type.config.lifx.effect.effectFlameSpeed.description = Speed of the flame effect in seconds.
channel-type.config.lifx.hevcycle.hevCycleDuration.label = HEV Cycle Duration
channel-type.config.lifx.hevcycle.hevCycleDuration.description = HEV cycle duration in seconds. Use empty value for the cycle duration configured in the light.
channel-type.config.lifx.temperature.powerOnTemperature.label = Power On Color Temperature
channel-type.config.lifx.temperature.powerOnTemperature.description = Color temperature used when switching on the light. Use empty value to leave color temperature as is.

View File

@@ -4,15 +4,17 @@ binding.lifx.description = Dit is de binding voor LIFX lampen.
# thing types
thing-type.lifx.colorlight.label = LIFX Kleuren Lamp
thing-type.lifx.colorhevlight.label = LIFX Kleuren HEV Lamp
thing-type.lifx.colorirlight.label = LIFX Kleuren IR Lamp
thing-type.lifx.colormzlight.label = LIFX Kleuren MultiZone Lamp
thing-type.lifx.tilelight.label = LIFX Tegel Lamp
thing-type.lifx.whitelight.label = LIFX Wittinten Lamp
# thing type configuration
thing-type.config.lifx.light.deviceId.label = LIFX apparaat ID
thing-type.config.lifx.light.deviceId.label = LIFX Apparaat ID
thing-type.config.lifx.light.deviceId.description = Identificeert de lamp, bv. "D073D5A1A1A1"
thing-type.config.lifx.light.host.label = Host
thing-type.config.lifx.light.host.description = Hostnaam of IP adres van de lamp. Gebruik lege waarde voor automatische detectie.
thing-type.config.lifx.light.host.description = Hostnaam of IP adres van de lamp. Gebruik een lege waarde voor automatische detectie.
thing-type.config.lifx.light.fadetime.label = Vervagingsduur
thing-type.config.lifx.light.fadetime.description = De tijdsduur van het vervagen naar een nieuwe kleur (in ms).
@@ -21,24 +23,34 @@ channel-type.lifx.brightness.label = Helderheid
channel-type.lifx.brightness.description = Bepaalt de helderheid van de lamp
channel-type.lifx.color.label = Kleur
channel-type.lifx.color.description = Bepaalt de kleur van de lamp
channel-type.lifx.colorzone.label = Kleur zone {0}
channel-type.lifx.colorzone.label = Kleur Zone {0}
channel-type.lifx.colorzone.description = Bepaalt de kleur van lampzone {0}
channel-type.lifx.infrared.label = Infrarood
channel-type.lifx.infrared.description = Bepaalt het infraroodniveau van de lamp
channel-type.lifx.temperature.label = Temperatuur
channel-type.lifx.temperature.description = Bepaalt de kleurtemperatuur van de lamp
channel-type.lifx.temperaturezone.label = Temperatuur zone {0}
channel-type.lifx.temperaturezone.description = Bepaalt de kleurtemperatuur van lampzone {0}
channel-type.lifx.effect.label = Effect
channel-type.lifx.effect.description = Bepaalt het lichteffect
channel-type.lifx.effect.state.option.off = Uit
channel-type.lifx.effect.state.option.morph = Morph
channel-type.lifx.effect.state.option.flame = Flamme
channel-type.lifx.effect.state.option.flame = Vlam
channel-type.lifx.hevcycle.label = HEV Cyclus
channel-type.lifx.hevcycle.description = Bedient de HEV schoonmaakcylcus van de lamp
channel-type.lifx.infrared.label = Infrarood
channel-type.lifx.infrared.description = Bepaalt het infraroodniveau van de lamp
channel-type.lifx.temperature.label = Temperatuur
channel-type.lifx.temperature.description = Bepaalt de kleurtemperatuur van de lamp
channel-type.lifx.temperaturezone.label = Temperatuur Zone {0}
channel-type.lifx.temperaturezone.description = Bepaalt de kleurtemperatuur van lampzone {0}
# channel type configuration
channel-type.config.lifx.brightness.powerOnBrightness.label = Inschakelhelderheid
channel-type.config.lifx.brightness.powerOnBrightness.description = Het helderheidsniveau bij inschakeling van de lamp. Gebruik een lege waarde om de helderheid ongewijzigd te laten.
channel-type.config.lifx.effect.effectMorphSpeed.label = Morph-effect snelheid
channel-type.config.lifx.color.powerOnBrightness.label = Inschakelhelderheid
channel-type.config.lifx.color.powerOnBrightness.description = Het helderheidsniveau bij inschakeling van de lamp. Gebruik een lege waarde om de helderheid ongewijzigd te laten.
channel-type.config.lifx.color.powerOnColor.label = Inschakelkleur
channel-type.config.lifx.color.powerOnColor.description = De kleur die gebruikt wordt bij het inschakelen van de lamp. Gebruik een lege waarde om de kleur ongewijzigd te laten.
channel-type.config.lifx.effect.effectMorphSpeed.label = Morph-effect Snelheid
channel-type.config.lifx.effect.effectMorphSpeed.description = De snelheid van het Morph-effect in seconden.
channel-type.config.lifx.effect.effectFlameSpeed.label = Vlam-effect snelheid
channel-type.config.lifx.effect.effectFlameSpeed.label = Vlam-effect Snelheid
channel-type.config.lifx.effect.effectFlameSpeed.description = De snelheid van het Vlam-effect in seconden.
channel-type.config.lifx.hevcycle.hevCycleDuration.label = HEV Cycluslooptijd
channel-type.config.lifx.hevcycle.hevCycleDuration.description = HEV cycluslooptijd in seconden. Gebruik een lege waarde om de in de lamp geconfigureerde cycluslooptijd te gebruiken.
channel-type.config.lifx.temperature.powerOnTemperature.label = Inschakelkleurtemperatuur
channel-type.config.lifx.temperature.powerOnTemperature.description = De kleurtemperatuur die gebruikt wordt bij het inschakelen van de lamp. Gebruik een lege waarde om de kleurtemperatuur ongewijzigd te laten.

View File

@@ -36,6 +36,13 @@
</tags>
</channel-type>
<channel-type id="hevcycle">
<item-type>Switch</item-type>
<label>HEV Cycle</label>
<description>Controls the HEV clean cycle of the light</description>
<config-description-ref uri="channel-type:lifx:hevcycle"/>
</channel-type>
<channel-type id="infrared">
<item-type>Dimmer</item-type>
<label>Infrared</label>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<thing:thing-descriptions bindingId="lifx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:thing="https://openhab.org/schemas/thing-description/v1.0.0"
xsi:schemaLocation="https://openhab.org/schemas/thing-description/v1.0.0 https://openhab.org/schemas/thing-description-1.0.0.xsd">
<thing-type id="colorhevlight">
<label>LIFX Color HEV Light</label>
<channels>
<channel id="color" typeId="color"/>
<channel id="temperature" typeId="temperature"/>
<channel id="hevcycle" typeId="hevcycle"/>
<channel id="signalstrength" typeId="system.signal-strength"/>
</channels>
<representation-property>macAddress</representation-property>
<config-description-ref uri="thing-type:lifx:light"/>
</thing-type>
</thing:thing-descriptions>