[lifx] Improve firmware version support (#10384)
* [lifx] Improve firmware version support When the firmware of a light is upgraded the supported features can change. With these changes the binding uses the features based on the light firmware version. Also corrects some of the temperature ranges based on the LIFX products description. Signed-off-by: Wouter Born <github@maindrain.net>pull/10391/head
parent
5477fa5fb1
commit
1d34872c61
|
@ -15,6 +15,7 @@ package org.openhab.binding.lifx.internal;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.openhab.binding.lifx.internal.LifxProduct.Features;
|
||||||
import org.openhab.binding.lifx.internal.handler.LifxLightHandler;
|
import org.openhab.binding.lifx.internal.handler.LifxLightHandler;
|
||||||
import org.openhab.binding.lifx.internal.handler.LifxLightHandler.CurrentLightState;
|
import org.openhab.binding.lifx.internal.handler.LifxLightHandler.CurrentLightState;
|
||||||
|
|
||||||
|
@ -30,14 +31,14 @@ public class LifxLightContext {
|
||||||
private final LifxLightConfig configuration;
|
private final LifxLightConfig configuration;
|
||||||
private final CurrentLightState currentLightState;
|
private final CurrentLightState currentLightState;
|
||||||
private final LifxLightState pendingLightState;
|
private final LifxLightState pendingLightState;
|
||||||
private final LifxProduct product;
|
private final Features features;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
public LifxLightContext(String logId, LifxProduct product, LifxLightConfig configuration,
|
public LifxLightContext(String logId, Features features, LifxLightConfig configuration,
|
||||||
CurrentLightState currentLightState, LifxLightState pendingLightState, ScheduledExecutorService scheduler) {
|
CurrentLightState currentLightState, LifxLightState pendingLightState, ScheduledExecutorService scheduler) {
|
||||||
this.logId = logId;
|
this.logId = logId;
|
||||||
this.configuration = configuration;
|
this.configuration = configuration;
|
||||||
this.product = product;
|
this.features = features;
|
||||||
this.currentLightState = currentLightState;
|
this.currentLightState = currentLightState;
|
||||||
this.pendingLightState = pendingLightState;
|
this.pendingLightState = pendingLightState;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
|
@ -51,8 +52,8 @@ public class LifxLightContext {
|
||||||
return configuration;
|
return configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LifxProduct getProduct() {
|
public Features getFeatures() {
|
||||||
return product;
|
return features;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CurrentLightState getCurrentLightState() {
|
public CurrentLightState getCurrentLightState() {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
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.GetColorZonesRequest;
|
||||||
import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
|
import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
|
||||||
import org.openhab.binding.lifx.internal.dto.GetRequest;
|
import org.openhab.binding.lifx.internal.dto.GetRequest;
|
||||||
|
@ -56,7 +57,7 @@ public class LifxLightCurrentStateUpdater {
|
||||||
private final Logger logger = LoggerFactory.getLogger(LifxLightCurrentStateUpdater.class);
|
private final Logger logger = LoggerFactory.getLogger(LifxLightCurrentStateUpdater.class);
|
||||||
|
|
||||||
private final String logId;
|
private final String logId;
|
||||||
private final LifxProduct product;
|
private final Features features;
|
||||||
private final CurrentLightState currentLightState;
|
private final CurrentLightState currentLightState;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
private final LifxLightCommunicationHandler communicationHandler;
|
private final LifxLightCommunicationHandler communicationHandler;
|
||||||
|
@ -70,7 +71,7 @@ public class LifxLightCurrentStateUpdater {
|
||||||
|
|
||||||
public LifxLightCurrentStateUpdater(LifxLightContext context, LifxLightCommunicationHandler communicationHandler) {
|
public LifxLightCurrentStateUpdater(LifxLightContext context, LifxLightCommunicationHandler communicationHandler) {
|
||||||
this.logId = context.getLogId();
|
this.logId = context.getLogId();
|
||||||
this.product = context.getProduct();
|
this.features = context.getFeatures();
|
||||||
this.currentLightState = context.getCurrentLightState();
|
this.currentLightState = context.getCurrentLightState();
|
||||||
this.scheduler = context.getScheduler();
|
this.scheduler = context.getScheduler();
|
||||||
this.communicationHandler = communicationHandler;
|
this.communicationHandler = communicationHandler;
|
||||||
|
@ -132,13 +133,13 @@ public class LifxLightCurrentStateUpdater {
|
||||||
private void sendLightStateRequests() {
|
private void sendLightStateRequests() {
|
||||||
communicationHandler.sendPacket(new GetRequest());
|
communicationHandler.sendPacket(new GetRequest());
|
||||||
|
|
||||||
if (product.hasFeature(INFRARED)) {
|
if (features.hasFeature(INFRARED)) {
|
||||||
communicationHandler.sendPacket(new GetLightInfraredRequest());
|
communicationHandler.sendPacket(new GetLightInfraredRequest());
|
||||||
}
|
}
|
||||||
if (product.hasFeature(MULTIZONE)) {
|
if (features.hasFeature(MULTIZONE)) {
|
||||||
communicationHandler.sendPacket(new GetColorZonesRequest());
|
communicationHandler.sendPacket(new GetColorZonesRequest());
|
||||||
}
|
}
|
||||||
if (product.hasFeature(TILE_EFFECT)) {
|
if (features.hasFeature(TILE_EFFECT)) {
|
||||||
communicationHandler.sendPacket(new GetTileEffectRequest());
|
communicationHandler.sendPacket(new GetTileEffectRequest());
|
||||||
}
|
}
|
||||||
if (updateSignalStrength) {
|
if (updateSignalStrength) {
|
||||||
|
|
|
@ -298,9 +298,11 @@ public class LifxLightDiscovery extends AbstractDiscoveryService {
|
||||||
light.label = ((StateLabelResponse) packet).getLabel().trim();
|
light.label = ((StateLabelResponse) packet).getLabel().trim();
|
||||||
} else if (packet instanceof StateVersionResponse) {
|
} else if (packet instanceof StateVersionResponse) {
|
||||||
try {
|
try {
|
||||||
light.product = LifxProduct
|
LifxProduct product = LifxProduct
|
||||||
.getProductFromProductID(((StateVersionResponse) packet).getProduct());
|
.getProductFromProductID(((StateVersionResponse) packet).getProduct());
|
||||||
|
light.product = product;
|
||||||
light.productVersion = ((StateVersionResponse) packet).getVersion();
|
light.productVersion = ((StateVersionResponse) packet).getVersion();
|
||||||
|
light.supportedProduct = product.isLight();
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
logger.debug("Discovered an unsupported light ({}): {}", light.macAddress.getAsLabel(),
|
logger.debug("Discovered an unsupported light ({}): {}", light.macAddress.getAsLabel(),
|
||||||
e.getMessage());
|
e.getMessage());
|
||||||
|
@ -309,7 +311,7 @@ public class LifxLightDiscovery extends AbstractDiscoveryService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (light != null && light.isDataComplete()) {
|
if (light != null && light.supportedProduct && light.isDataComplete()) {
|
||||||
try {
|
try {
|
||||||
thingDiscovered(createDiscoveryResult(light));
|
thingDiscovered(createDiscoveryResult(light));
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
|
|
@ -29,6 +29,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.lifx.internal.LifxProduct.Features;
|
||||||
import org.openhab.binding.lifx.internal.dto.AcknowledgementResponse;
|
import org.openhab.binding.lifx.internal.dto.AcknowledgementResponse;
|
||||||
import org.openhab.binding.lifx.internal.dto.ApplicationRequest;
|
import org.openhab.binding.lifx.internal.dto.ApplicationRequest;
|
||||||
import org.openhab.binding.lifx.internal.dto.Effect;
|
import org.openhab.binding.lifx.internal.dto.Effect;
|
||||||
|
@ -74,7 +75,7 @@ public class LifxLightStateChanger implements LifxLightStateListener {
|
||||||
private final Logger logger = LoggerFactory.getLogger(LifxLightStateChanger.class);
|
private final Logger logger = LoggerFactory.getLogger(LifxLightStateChanger.class);
|
||||||
|
|
||||||
private final String logId;
|
private final String logId;
|
||||||
private final LifxProduct product;
|
private final Features features;
|
||||||
private final Duration fadeTime;
|
private final Duration fadeTime;
|
||||||
private final LifxLightState pendingLightState;
|
private final LifxLightState pendingLightState;
|
||||||
private final ScheduledExecutorService scheduler;
|
private final ScheduledExecutorService scheduler;
|
||||||
|
@ -104,7 +105,7 @@ public class LifxLightStateChanger implements LifxLightStateListener {
|
||||||
|
|
||||||
public LifxLightStateChanger(LifxLightContext context, LifxLightCommunicationHandler communicationHandler) {
|
public LifxLightStateChanger(LifxLightContext context, LifxLightCommunicationHandler communicationHandler) {
|
||||||
this.logId = context.getLogId();
|
this.logId = context.getLogId();
|
||||||
this.product = context.getProduct();
|
this.features = context.getFeatures();
|
||||||
this.fadeTime = context.getConfiguration().getFadeTime();
|
this.fadeTime = context.getConfiguration().getFadeTime();
|
||||||
this.pendingLightState = context.getPendingLightState();
|
this.pendingLightState = context.getPendingLightState();
|
||||||
this.scheduler = context.getScheduler();
|
this.scheduler = context.getScheduler();
|
||||||
|
@ -371,7 +372,7 @@ public class LifxLightStateChanger implements LifxLightStateListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getZonesIfZonesAreSet() {
|
private void getZonesIfZonesAreSet() {
|
||||||
if (product.hasFeature(MULTIZONE)) {
|
if (features.hasFeature(MULTIZONE)) {
|
||||||
List<PendingPacket> pending = pendingPacketsMap.get(SetColorZonesRequest.TYPE);
|
List<PendingPacket> pending = pendingPacketsMap.get(SetColorZonesRequest.TYPE);
|
||||||
if (pending == null || pending.isEmpty()) {
|
if (pending == null || pending.isEmpty()) {
|
||||||
GetColorZonesRequest zoneColorPacket = new GetColorZonesRequest();
|
GetColorZonesRequest zoneColorPacket = new GetColorZonesRequest();
|
||||||
|
|
|
@ -16,8 +16,9 @@ import static org.openhab.binding.lifx.internal.LifxProduct.Feature.*;
|
||||||
import static org.openhab.binding.lifx.internal.LifxProduct.TemperatureRange.*;
|
import static org.openhab.binding.lifx.internal.LifxProduct.TemperatureRange.*;
|
||||||
import static org.openhab.binding.lifx.internal.LifxProduct.Vendor.LIFX;
|
import static org.openhab.binding.lifx.internal.LifxProduct.Vendor.LIFX;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.HashSet;
|
||||||
import java.util.EnumSet;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.openhab.core.thing.ThingTypeUID;
|
import org.openhab.core.thing.ThingTypeUID;
|
||||||
|
@ -33,75 +34,99 @@ import org.openhab.core.thing.ThingTypeUID;
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public enum LifxProduct {
|
public enum LifxProduct {
|
||||||
|
|
||||||
PRODUCT_1(1, "LIFX Original 1000", TR_2500_9000, COLOR),
|
PRODUCT_1(1, "LIFX Original 1000", new Features(TR_2500_9000, COLOR)),
|
||||||
PRODUCT_3(3, "LIFX Color 650", TR_2500_9000, COLOR),
|
PRODUCT_3(3, "LIFX Color 650", new Features(TR_2500_9000, COLOR)),
|
||||||
PRODUCT_10(10, "LIFX White 800 (Low Voltage)", TR_2700_6500),
|
PRODUCT_10(10, "LIFX White 800 (Low Voltage)", new Features(TR_2700_6500)),
|
||||||
PRODUCT_11(11, "LIFX White 800 (High Voltage)", TR_2700_6500),
|
PRODUCT_11(11, "LIFX White 800 (High Voltage)", new Features(TR_2700_6500)),
|
||||||
PRODUCT_15(15, "LIFX Color 1000", TR_2500_9000, COLOR),
|
PRODUCT_15(15, "LIFX Color 1000", new Features(TR_2500_9000, COLOR)),
|
||||||
PRODUCT_18(18, "LIFX White 900 BR30 (Low Voltage)", TR_2700_6500),
|
PRODUCT_18(18, "LIFX White 900 BR30 (Low Voltage)", new Features(TR_2700_6500)),
|
||||||
PRODUCT_19(19, "LIFX White 900 BR30 (High Voltage)", TR_2700_6500),
|
PRODUCT_19(19, "LIFX White 900 BR30 (High Voltage)", new Features(TR_2700_6500)),
|
||||||
PRODUCT_20(20, "LIFX Color 1000 BR30", TR_2500_9000, COLOR),
|
PRODUCT_20(20, "LIFX Color 1000 BR30", new Features(TR_2500_9000, COLOR)),
|
||||||
PRODUCT_22(22, "LIFX Color 1000", TR_2500_9000, COLOR),
|
PRODUCT_22(22, "LIFX Color 1000", new Features(TR_2500_9000, COLOR)),
|
||||||
PRODUCT_27(27, "LIFX A19", TR_2500_9000, COLOR),
|
PRODUCT_27(27, "LIFX A19", new Features(TR_2500_9000, COLOR), //
|
||||||
PRODUCT_28(28, "LIFX BR30", TR_2500_9000, COLOR),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_29(29, "LIFX A19 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
PRODUCT_28(28, "LIFX BR30", new Features(TR_2500_9000, COLOR), //
|
||||||
PRODUCT_30(30, "LIFX BR30 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_31(31, "LIFX Z", TR_2500_9000, COLOR, MULTIZONE),
|
PRODUCT_29(29, "LIFX A19 Night Vision", new Features(TR_2500_9000, COLOR, INFRARED), //
|
||||||
PRODUCT_32(32, "LIFX Z", TR_2500_9000, COLOR, MULTIZONE),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_36(36, "LIFX Downlight", TR_2500_9000, COLOR),
|
PRODUCT_30(30, "LIFX BR30 Night Vision", new Features(TR_2500_9000, COLOR, INFRARED), //
|
||||||
PRODUCT_37(37, "LIFX Downlight", TR_2500_9000, COLOR),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_38(38, "LIFX Beam", TR_2500_9000, COLOR, MULTIZONE),
|
PRODUCT_31(31, "LIFX Z", new Features(TR_2500_9000, COLOR, MULTIZONE)),
|
||||||
PRODUCT_39(39, "LIFX Downlight White to Warm", TR_1500_9000),
|
PRODUCT_32(32, "LIFX Z", new Features(TR_2500_9000, COLOR, MULTIZONE), //
|
||||||
PRODUCT_40(40, "LIFX Downlight", TR_2500_9000, COLOR),
|
new Upgrade(2, 77, new Features(EXTENDED_MULTIZONE)), //
|
||||||
PRODUCT_43(43, "LIFX A19", TR_2500_9000, COLOR),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_44(44, "LIFX BR30", TR_2500_9000, COLOR),
|
PRODUCT_36(36, "LIFX Downlight", new Features(TR_2500_9000, COLOR), //
|
||||||
PRODUCT_45(45, "LIFX A19 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_46(46, "LIFX BR30 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
PRODUCT_37(37, "LIFX Downlight", new Features(TR_2500_9000, COLOR), //
|
||||||
PRODUCT_49(49, "LIFX Mini Color", TR_2500_9000, COLOR),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_50(50, "LIFX Mini White to Warm", TR_1500_4000),
|
PRODUCT_38(38, "LIFX Beam", new Features(TR_2500_9000, COLOR, MULTIZONE), //
|
||||||
PRODUCT_51(51, "LIFX Mini White", TR_2700_2700),
|
new Upgrade(2, 77, new Features(EXTENDED_MULTIZONE)), //
|
||||||
PRODUCT_52(52, "LIFX GU10", TR_2500_9000, COLOR),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_53(53, "LIFX GU10", TR_2500_9000, COLOR),
|
PRODUCT_39(39, "LIFX Downlight White to Warm", new Features(TR_2500_9000), //
|
||||||
PRODUCT_55(55, "LIFX Tile", TR_2500_9000, CHAIN, COLOR, MATRIX, TILE_EFFECT),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_57(57, "LIFX Candle", TR_1500_9000, COLOR, MATRIX),
|
PRODUCT_40(40, "LIFX Downlight", new Features(TR_2500_9000, COLOR), //
|
||||||
PRODUCT_59(59, "LIFX Mini Color", TR_2500_9000, COLOR),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_60(60, "LIFX Mini White to Warm", TR_1500_4000),
|
PRODUCT_43(43, "LIFX A19", new Features(TR_2500_9000, COLOR), //
|
||||||
PRODUCT_61(61, "LIFX Mini White", TR_2700_2700),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_62(62, "LIFX A19", TR_2500_9000, COLOR),
|
PRODUCT_44(44, "LIFX BR30", new Features(TR_2500_9000, COLOR), //
|
||||||
PRODUCT_63(63, "LIFX BR30", TR_2500_9000, COLOR),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_64(64, "LIFX A19 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
PRODUCT_45(45, "LIFX A19 Night Vision", new Features(TR_2500_9000, COLOR, INFRARED), //
|
||||||
PRODUCT_65(65, "LIFX BR30 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_66(66, "LIFX Mini White", TR_2700_2700),
|
PRODUCT_46(46, "LIFX BR30 Night Vision", new Features(TR_2500_9000, COLOR, INFRARED), //
|
||||||
PRODUCT_68(68, "LIFX Candle", TR_1500_9000, MATRIX),
|
new Upgrade(2, 80, new Features(TR_1500_9000))),
|
||||||
PRODUCT_81(81, "LIFX Candle White to Warm", TR_2200_6500),
|
PRODUCT_49(49, "LIFX Mini Color", new Features(TR_1500_9000, COLOR)),
|
||||||
PRODUCT_82(82, "LIFX Filament Clear", TR_2100_2100),
|
PRODUCT_50(50, "LIFX Mini White to Warm", new Features(TR_1500_6500), //
|
||||||
PRODUCT_85(85, "LIFX Filament Amber", TR_2000_2000),
|
new Upgrade(3, 70, new Features(TR_1500_9000))),
|
||||||
PRODUCT_87(87, "LIFX Mini White", TR_2700_2700),
|
PRODUCT_51(51, "LIFX Mini White", new Features(TR_2700_2700)),
|
||||||
PRODUCT_88(88, "LIFX Mini White", TR_2700_2700),
|
PRODUCT_52(52, "LIFX GU10", new Features(TR_1500_9000, COLOR)),
|
||||||
PRODUCT_90(90, "LIFX Clean", TR_2500_9000, HEV),
|
PRODUCT_53(53, "LIFX GU10", new Features(TR_1500_9000, COLOR)),
|
||||||
PRODUCT_91(91, "LIFX Color", TR_2500_9000, COLOR),
|
PRODUCT_55(55, "LIFX Tile", new Features(TR_2500_9000, CHAIN, COLOR, MATRIX, TILE_EFFECT)),
|
||||||
PRODUCT_92(92, "LIFX Color", TR_2500_9000, COLOR),
|
PRODUCT_57(57, "LIFX Candle", new Features(TR_1500_9000, COLOR, MATRIX)),
|
||||||
PRODUCT_94(94, "LIFX BR30", TR_2500_9000, COLOR),
|
PRODUCT_59(59, "LIFX Mini Color", new Features(TR_1500_9000, COLOR)),
|
||||||
PRODUCT_96(96, "LIFX Candle White to Warm", TR_2200_6500),
|
PRODUCT_60(60, "LIFX Mini White to Warm", new Features(TR_1500_6500), //
|
||||||
PRODUCT_97(97, "LIFX A19", TR_2500_9000, COLOR),
|
new Upgrade(3, 70, new Features(TR_1500_9000))),
|
||||||
PRODUCT_98(98, "LIFX BR30", TR_2500_9000, COLOR),
|
PRODUCT_61(61, "LIFX Mini White", new Features(TR_2700_2700)),
|
||||||
PRODUCT_99(99, "LIFX Clean", TR_2500_9000, HEV),
|
PRODUCT_62(62, "LIFX A19", new Features(TR_1500_9000, COLOR)),
|
||||||
PRODUCT_100(100, "LIFX Filament Clear", TR_2100_2100),
|
PRODUCT_63(63, "LIFX BR30", new Features(TR_1500_9000, COLOR)),
|
||||||
PRODUCT_101(101, "LIFX Filament Amber", TR_2000_2000),
|
PRODUCT_64(64, "LIFX A19 Night Vision", new Features(TR_1500_9000, COLOR, INFRARED)),
|
||||||
PRODUCT_109(109, "LIFX A19 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
PRODUCT_65(65, "LIFX BR30 Night Vision", new Features(TR_1500_9000, COLOR, INFRARED)),
|
||||||
PRODUCT_110(110, "LIFX BR30 Night Vision", TR_2500_9000, COLOR, INFRARED),
|
PRODUCT_66(66, "LIFX Mini White", new Features(TR_2700_2700)),
|
||||||
PRODUCT_111(111, "LIFX A19 Night Vision", TR_2500_9000, COLOR, INFRARED);
|
PRODUCT_68(68, "LIFX Candle", new Features(TR_1500_9000, MATRIX)),
|
||||||
|
PRODUCT_70(70, "LIFX Switch", new Features(BUTTONS, RELAYS)),
|
||||||
|
PRODUCT_71(71, "LIFX Switch", new Features(BUTTONS, RELAYS)),
|
||||||
|
PRODUCT_81(81, "LIFX Candle White to Warm", new Features(TR_2200_6500)),
|
||||||
|
PRODUCT_82(82, "LIFX Filament Clear", new Features(TR_2100_2100)),
|
||||||
|
PRODUCT_85(85, "LIFX Filament Amber", new Features(TR_2000_2000)),
|
||||||
|
PRODUCT_87(87, "LIFX Mini White", new Features(TR_2700_2700)),
|
||||||
|
PRODUCT_88(88, "LIFX Mini White", new Features(TR_2700_2700)),
|
||||||
|
PRODUCT_89(89, "LIFX Switch", new Features(BUTTONS, RELAYS)),
|
||||||
|
PRODUCT_90(90, "LIFX Clean", new Features(TR_1500_9000, HEV)),
|
||||||
|
PRODUCT_91(91, "LIFX Color", new Features(TR_1500_9000, COLOR)),
|
||||||
|
PRODUCT_92(92, "LIFX Color", new Features(TR_1500_9000, COLOR)),
|
||||||
|
PRODUCT_94(94, "LIFX BR30", new Features(TR_1500_9000, COLOR)),
|
||||||
|
PRODUCT_96(96, "LIFX Candle White to Warm", new Features(TR_2200_6500)),
|
||||||
|
PRODUCT_97(97, "LIFX A19", new Features(TR_1500_9000, COLOR)),
|
||||||
|
PRODUCT_98(98, "LIFX BR30", new Features(TR_1500_9000, COLOR)),
|
||||||
|
PRODUCT_99(99, "LIFX Clean", new Features(TR_1500_9000, HEV)),
|
||||||
|
PRODUCT_100(100, "LIFX Filament Clear", new Features(TR_2100_2100)),
|
||||||
|
PRODUCT_101(101, "LIFX Filament Amber", new Features(TR_2000_2000)),
|
||||||
|
PRODUCT_109(109, "LIFX A19 Night Vision", new Features(TR_1500_9000, COLOR, INFRARED)),
|
||||||
|
PRODUCT_110(110, "LIFX BR30 Night Vision", new Features(TR_1500_9000, COLOR, INFRARED)),
|
||||||
|
PRODUCT_111(111, "LIFX A19 Night Vision", new Features(TR_1500_9000, COLOR, INFRARED));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerates the product features.
|
* Enumerates the product features.
|
||||||
*/
|
*/
|
||||||
public enum Feature {
|
public enum Feature {
|
||||||
|
BUTTONS,
|
||||||
CHAIN,
|
CHAIN,
|
||||||
COLOR,
|
COLOR,
|
||||||
|
EXTENDED_MULTIZONE,
|
||||||
HEV,
|
HEV,
|
||||||
INFRARED,
|
INFRARED,
|
||||||
MATRIX,
|
MATRIX,
|
||||||
MULTIZONE,
|
MULTIZONE,
|
||||||
|
RELAYS,
|
||||||
TILE_EFFECT
|
TILE_EFFECT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,11 +157,22 @@ public enum LifxProduct {
|
||||||
* Enumerates the color temperature ranges of lights.
|
* Enumerates the color temperature ranges of lights.
|
||||||
*/
|
*/
|
||||||
public enum TemperatureRange {
|
public enum TemperatureRange {
|
||||||
|
/**
|
||||||
|
* When the temperature range is not defined for {@link Upgrade}s it is inherited from the most
|
||||||
|
* recent firmware version.
|
||||||
|
*/
|
||||||
|
NONE(0, 0),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1500-4000K
|
* 1500-4000K
|
||||||
*/
|
*/
|
||||||
TR_1500_4000(1500, 4000),
|
TR_1500_4000(1500, 4000),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1500-6500K
|
||||||
|
*/
|
||||||
|
TR_1500_6500(1500, 6500),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1500-9000K
|
* 1500-9000K
|
||||||
*/
|
*/
|
||||||
|
@ -208,30 +244,70 @@ public enum LifxProduct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Features {
|
||||||
|
private TemperatureRange temperatureRange;
|
||||||
|
private Set<Feature> features;
|
||||||
|
|
||||||
|
private Features(Feature... features) {
|
||||||
|
this(NONE, features);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Features(Features other) {
|
||||||
|
this(other.temperatureRange, other.features);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Features(TemperatureRange temperatureRange, Feature... features) {
|
||||||
|
this.temperatureRange = temperatureRange;
|
||||||
|
this.features = Set.of(features);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Features(TemperatureRange temperatureRange, Set<Feature> features) {
|
||||||
|
this.temperatureRange = temperatureRange;
|
||||||
|
this.features = Set.copyOf(features);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemperatureRange getTemperatureRange() {
|
||||||
|
return temperatureRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasFeature(Feature feature) {
|
||||||
|
return features.contains(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(Features other) {
|
||||||
|
temperatureRange = other.temperatureRange;
|
||||||
|
features = other.features;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Upgrade {
|
||||||
|
final long major;
|
||||||
|
final long minor;
|
||||||
|
final Features features;
|
||||||
|
|
||||||
|
private Upgrade(long major, long minor, Features features) {
|
||||||
|
this.major = major;
|
||||||
|
this.minor = minor;
|
||||||
|
this.features = features;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final Vendor vendor;
|
private final Vendor vendor;
|
||||||
private final long id;
|
private final long id;
|
||||||
private final String name;
|
private final String name;
|
||||||
private final TemperatureRange temperatureRange;
|
private final Features features;
|
||||||
private final EnumSet<Feature> features = EnumSet.noneOf(Feature.class);
|
private final List<Upgrade> upgrades;
|
||||||
|
|
||||||
private LifxProduct(long id, String name, TemperatureRange temperatureRange) {
|
private LifxProduct(long id, String name, Features features, Upgrade... upgrades) {
|
||||||
this(LIFX, id, name, temperatureRange);
|
this(LIFX, id, name, features, upgrades);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LifxProduct(long id, String name, TemperatureRange temperatureRange, Feature... features) {
|
private LifxProduct(Vendor vendor, long id, String name, Features features, Upgrade... upgrades) {
|
||||||
this(LIFX, id, name, temperatureRange, features);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LifxProduct(Vendor vendor, long id, String name, TemperatureRange temperatureRange) {
|
|
||||||
this(vendor, id, name, temperatureRange, new Feature[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LifxProduct(Vendor vendor, long id, String name, TemperatureRange temperatureRange, Feature... features) {
|
|
||||||
this.vendor = vendor;
|
this.vendor = vendor;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.temperatureRange = temperatureRange;
|
this.features = features;
|
||||||
this.features.addAll(Arrays.asList(features));
|
this.upgrades = List.of(upgrades);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -251,8 +327,46 @@ public enum LifxProduct {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TemperatureRange getTemperatureRange() {
|
/**
|
||||||
return temperatureRange;
|
* Returns the features of the initial product firmware version.
|
||||||
|
*
|
||||||
|
* @return the initial features
|
||||||
|
*/
|
||||||
|
public Features getFeatures() {
|
||||||
|
return new Features(features);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the features for a specific product firmware version.
|
||||||
|
*
|
||||||
|
* @param version the firmware version
|
||||||
|
* @return the composite features of all firmware upgrades for the given major and minor firmware version
|
||||||
|
*/
|
||||||
|
public Features getFeatures(String version) {
|
||||||
|
if (upgrades.isEmpty() || !version.contains(".")) {
|
||||||
|
return new Features(features);
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] majorMinorVersion = version.split("\\.");
|
||||||
|
long major = Long.valueOf(majorMinorVersion[0]);
|
||||||
|
long minor = Long.valueOf(majorMinorVersion[1]);
|
||||||
|
|
||||||
|
TemperatureRange temperatureRange = features.temperatureRange;
|
||||||
|
Set<Feature> features = new HashSet<>(this.features.features);
|
||||||
|
|
||||||
|
for (Upgrade upgrade : upgrades) {
|
||||||
|
if (upgrade.major < major || (upgrade.major == major && upgrade.minor <= minor)) {
|
||||||
|
Features upgradeFeatures = upgrade.features;
|
||||||
|
if (upgradeFeatures.temperatureRange != NONE) {
|
||||||
|
temperatureRange = upgradeFeatures.temperatureRange;
|
||||||
|
}
|
||||||
|
features.addAll(upgradeFeatures.features);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Features(temperatureRange, features);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ThingTypeUID getThingTypeUID() {
|
public ThingTypeUID getThingTypeUID() {
|
||||||
|
@ -271,8 +385,8 @@ public enum LifxProduct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasFeature(Feature feature) {
|
private boolean hasFeature(Feature feature) {
|
||||||
return features.contains(feature);
|
return features.hasFeature(feature);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -308,4 +422,12 @@ public enum LifxProduct {
|
||||||
|
|
||||||
throw new IllegalArgumentException(id + " is not a valid product ID");
|
throw new IllegalArgumentException(id + " is not a valid product ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Upgrade> getUpgrades() {
|
||||||
|
return upgrades;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLight() {
|
||||||
|
return !features.hasFeature(Feature.BUTTONS) && !features.hasFeature(Feature.RELAYS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
@ -39,6 +40,7 @@ import org.openhab.binding.lifx.internal.LifxLightPropertiesUpdater;
|
||||||
import org.openhab.binding.lifx.internal.LifxLightState;
|
import org.openhab.binding.lifx.internal.LifxLightState;
|
||||||
import org.openhab.binding.lifx.internal.LifxLightStateChanger;
|
import org.openhab.binding.lifx.internal.LifxLightStateChanger;
|
||||||
import org.openhab.binding.lifx.internal.LifxProduct;
|
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.Effect;
|
||||||
import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
|
import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest;
|
||||||
import org.openhab.binding.lifx.internal.dto.GetLightPowerRequest;
|
import org.openhab.binding.lifx.internal.dto.GetLightPowerRequest;
|
||||||
|
@ -90,7 +92,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
private static final Duration MAX_STATE_CHANGE_DURATION = Duration.ofSeconds(4);
|
private static final Duration MAX_STATE_CHANGE_DURATION = Duration.ofSeconds(4);
|
||||||
|
|
||||||
private final LifxChannelFactory channelFactory;
|
private final LifxChannelFactory channelFactory;
|
||||||
private @NonNullByDefault({}) LifxProduct product;
|
private @NonNullByDefault({}) Features features;
|
||||||
|
|
||||||
private @Nullable PercentType powerOnBrightness;
|
private @Nullable PercentType powerOnBrightness;
|
||||||
private @Nullable HSBType powerOnColor;
|
private @Nullable HSBType powerOnColor;
|
||||||
|
@ -175,7 +177,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
updateStateIfChanged(CHANNEL_COLOR, hsb);
|
updateStateIfChanged(CHANNEL_COLOR, hsb);
|
||||||
updateStateIfChanged(CHANNEL_BRIGHTNESS, hsb.getBrightness());
|
updateStateIfChanged(CHANNEL_BRIGHTNESS, hsb.getBrightness());
|
||||||
updateStateIfChanged(CHANNEL_TEMPERATURE,
|
updateStateIfChanged(CHANNEL_TEMPERATURE,
|
||||||
kelvinToPercentType(updateColor.getKelvin(), product.getTemperatureRange()));
|
kelvinToPercentType(updateColor.getKelvin(), features.getTemperatureRange()));
|
||||||
|
|
||||||
updateZoneChannels(powerState, colors);
|
updateZoneChannels(powerState, colors);
|
||||||
}
|
}
|
||||||
|
@ -210,7 +212,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateZoneChannels(@Nullable PowerState powerState, HSBK[] colors) {
|
private void updateZoneChannels(@Nullable PowerState powerState, HSBK[] colors) {
|
||||||
if (!product.hasFeature(MULTIZONE) || colors.length == 0) {
|
if (!features.hasFeature(MULTIZONE) || colors.length == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +227,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
HSBK updateColor = nullSafeUpdateColor(powerState, color);
|
HSBK updateColor = nullSafeUpdateColor(powerState, color);
|
||||||
updateStateIfChanged(CHANNEL_COLOR_ZONE + i, updateColor.getHSB());
|
updateStateIfChanged(CHANNEL_COLOR_ZONE + i, updateColor.getHSB());
|
||||||
updateStateIfChanged(CHANNEL_TEMPERATURE_ZONE + i,
|
updateStateIfChanged(CHANNEL_TEMPERATURE_ZONE + i,
|
||||||
kelvinToPercentType(updateColor.getKelvin(), product.getTemperatureRange()));
|
kelvinToPercentType(updateColor.getKelvin(), features.getTemperatureRange()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,9 +245,12 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
LifxLightConfig configuration = getConfigAs(LifxLightConfig.class);
|
LifxLightConfig configuration = getConfigAs(LifxLightConfig.class);
|
||||||
|
|
||||||
logId = getLogId(configuration.getMACAddress(), configuration.getHost());
|
logId = getLogId(configuration.getMACAddress(), configuration.getHost());
|
||||||
product = getProduct();
|
|
||||||
|
|
||||||
logger.debug("{} : Initializing handler for product {}", logId, product.getName());
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("{} : Initializing handler for product {}", logId, getProduct().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
features = getFeatures();
|
||||||
|
|
||||||
powerOnBrightness = getPowerOnBrightness();
|
powerOnBrightness = getPowerOnBrightness();
|
||||||
powerOnColor = getPowerOnColor();
|
powerOnColor = getPowerOnColor();
|
||||||
|
@ -262,7 +267,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
currentLightState = new CurrentLightState();
|
currentLightState = new CurrentLightState();
|
||||||
pendingLightState = new LifxLightState();
|
pendingLightState = new LifxLightState();
|
||||||
|
|
||||||
LifxLightContext context = new LifxLightContext(logId, product, configuration, currentLightState,
|
LifxLightContext context = new LifxLightContext(logId, features, configuration, currentLightState,
|
||||||
pendingLightState, scheduler);
|
pendingLightState, scheduler);
|
||||||
|
|
||||||
communicationHandler = new LifxLightCommunicationHandler(context);
|
communicationHandler = new LifxLightCommunicationHandler(context);
|
||||||
|
@ -338,7 +343,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
private @Nullable PercentType getPowerOnBrightness() {
|
private @Nullable PercentType getPowerOnBrightness() {
|
||||||
Channel channel = null;
|
Channel channel = null;
|
||||||
|
|
||||||
if (product.hasFeature(COLOR)) {
|
if (features.hasFeature(COLOR)) {
|
||||||
ChannelUID channelUID = new ChannelUID(getThing().getUID(), LifxBindingConstants.CHANNEL_COLOR);
|
ChannelUID channelUID = new ChannelUID(getThing().getUID(), LifxBindingConstants.CHANNEL_COLOR);
|
||||||
channel = getThing().getChannel(channelUID.getId());
|
channel = getThing().getChannel(channelUID.getId());
|
||||||
} else {
|
} else {
|
||||||
|
@ -358,7 +363,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
private @Nullable HSBType getPowerOnColor() {
|
private @Nullable HSBType getPowerOnColor() {
|
||||||
Channel channel = null;
|
Channel channel = null;
|
||||||
|
|
||||||
if (product.hasFeature(COLOR)) {
|
if (features.hasFeature(COLOR)) {
|
||||||
ChannelUID channelUID = new ChannelUID(getThing().getUID(), LifxBindingConstants.CHANNEL_COLOR);
|
ChannelUID channelUID = new ChannelUID(getThing().getUID(), LifxBindingConstants.CHANNEL_COLOR);
|
||||||
channel = getThing().getChannel(channelUID.getId());
|
channel = getThing().getChannel(channelUID.getId());
|
||||||
}
|
}
|
||||||
|
@ -391,7 +396,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
private @Nullable Double getEffectSpeed(String parameter) {
|
private @Nullable Double getEffectSpeed(String parameter) {
|
||||||
Channel channel = null;
|
Channel channel = null;
|
||||||
|
|
||||||
if (product.hasFeature(TILE_EFFECT)) {
|
if (features.hasFeature(TILE_EFFECT)) {
|
||||||
ChannelUID channelUID = new ChannelUID(getThing().getUID(), LifxBindingConstants.CHANNEL_EFFECT);
|
ChannelUID channelUID = new ChannelUID(getThing().getUID(), LifxBindingConstants.CHANNEL_EFFECT);
|
||||||
channel = getThing().getChannel(channelUID.getId());
|
channel = getThing().getChannel(channelUID.getId());
|
||||||
}
|
}
|
||||||
|
@ -405,8 +410,21 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
return speed == null ? null : Double.valueOf(speed.toString());
|
return speed == null ? null : Double.valueOf(speed.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Features getFeatures() {
|
||||||
|
LifxProduct product = getProduct();
|
||||||
|
|
||||||
|
String propertyValue = getThing().getProperties().get(LifxBindingConstants.PROPERTY_HOST_VERSION);
|
||||||
|
if (propertyValue == null) {
|
||||||
|
logger.debug("{} : Using features of initial firmware version", logId);
|
||||||
|
return product.getFeatures();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("{} : Using features of firmware version {}", logId, propertyValue);
|
||||||
|
return product.getFeatures(propertyValue);
|
||||||
|
}
|
||||||
|
|
||||||
private LifxProduct getProduct() {
|
private LifxProduct getProduct() {
|
||||||
Object propertyValue = getThing().getProperties().get(LifxBindingConstants.PROPERTY_PRODUCT_ID);
|
String propertyValue = getThing().getProperties().get(LifxBindingConstants.PROPERTY_PRODUCT_ID);
|
||||||
if (propertyValue == null) {
|
if (propertyValue == null) {
|
||||||
return LifxProduct.getLikelyProduct(getThing().getThingTypeUID());
|
return LifxProduct.getLikelyProduct(getThing().getThingTypeUID());
|
||||||
}
|
}
|
||||||
|
@ -414,7 +432,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
// Without first conversion to double, on a very first thing creation from discovery inbox,
|
// Without first conversion to double, on a very first thing creation from discovery inbox,
|
||||||
// the product type is incorrectly parsed, as framework passed it as a floating point number
|
// the product type is incorrectly parsed, as framework passed it as a floating point number
|
||||||
// (e.g. 50.0 instead of 50)
|
// (e.g. 50.0 instead of 50)
|
||||||
Double d = Double.valueOf((String) propertyValue);
|
Double d = Double.valueOf(propertyValue);
|
||||||
long productID = d.longValue();
|
long productID = d.longValue();
|
||||||
return LifxProduct.getProductFromProductID(productID);
|
return LifxProduct.getProductFromProductID(productID);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
@ -485,7 +503,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
sendPacket(new GetWifiInfoRequest());
|
sendPacket(new GetWifiInfoRequest());
|
||||||
break;
|
break;
|
||||||
case CHANNEL_EFFECT:
|
case CHANNEL_EFFECT:
|
||||||
if (product.hasFeature(TILE_EFFECT)) {
|
if (features.hasFeature(TILE_EFFECT)) {
|
||||||
sendPacket(new GetTileEffectRequest());
|
sendPacket(new GetTileEffectRequest());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -538,7 +556,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CHANNEL_EFFECT:
|
case CHANNEL_EFFECT:
|
||||||
if (command instanceof StringType && product.hasFeature(TILE_EFFECT)) {
|
if (command instanceof StringType && features.hasFeature(TILE_EFFECT)) {
|
||||||
handleTileEffectCommand((StringType) command);
|
handleTileEffectCommand((StringType) command);
|
||||||
} else {
|
} else {
|
||||||
supportedCommand = false;
|
supportedCommand = false;
|
||||||
|
@ -597,14 +615,14 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
private void handleTemperatureCommand(PercentType temperature) {
|
private void handleTemperatureCommand(PercentType temperature) {
|
||||||
HSBK newColor = getLightStateForCommand().getColor();
|
HSBK newColor = getLightStateForCommand().getColor();
|
||||||
newColor.setSaturation(PercentType.ZERO);
|
newColor.setSaturation(PercentType.ZERO);
|
||||||
newColor.setKelvin(percentTypeToKelvin(temperature, product.getTemperatureRange()));
|
newColor.setKelvin(percentTypeToKelvin(temperature, features.getTemperatureRange()));
|
||||||
getLightStateForCommand().setColor(newColor);
|
getLightStateForCommand().setColor(newColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleTemperatureCommand(PercentType temperature, int zoneIndex) {
|
private void handleTemperatureCommand(PercentType temperature, int zoneIndex) {
|
||||||
HSBK newColor = getLightStateForCommand().getColor(zoneIndex);
|
HSBK newColor = getLightStateForCommand().getColor(zoneIndex);
|
||||||
newColor.setSaturation(PercentType.ZERO);
|
newColor.setSaturation(PercentType.ZERO);
|
||||||
newColor.setKelvin(percentTypeToKelvin(temperature, product.getTemperatureRange()));
|
newColor.setKelvin(percentTypeToKelvin(temperature, features.getTemperatureRange()));
|
||||||
getLightStateForCommand().setColor(newColor, zoneIndex);
|
getLightStateForCommand().setColor(newColor, zoneIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,7 +651,7 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
PercentType localPowerOnTemperature = powerOnTemperature;
|
PercentType localPowerOnTemperature = powerOnTemperature;
|
||||||
if (localPowerOnTemperature != null && onOff == OnOffType.ON) {
|
if (localPowerOnTemperature != null && onOff == OnOffType.ON) {
|
||||||
getLightStateForCommand()
|
getLightStateForCommand()
|
||||||
.setTemperature(percentTypeToKelvin(localPowerOnTemperature, product.getTemperatureRange()));
|
.setTemperature(percentTypeToKelvin(localPowerOnTemperature, features.getTemperatureRange()));
|
||||||
}
|
}
|
||||||
|
|
||||||
PercentType powerOnBrightness = this.powerOnBrightness;
|
PercentType powerOnBrightness = this.powerOnBrightness;
|
||||||
|
@ -658,14 +676,14 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
|
|
||||||
private void handleIncreaseDecreaseTemperatureCommand(IncreaseDecreaseType increaseDecrease) {
|
private void handleIncreaseDecreaseTemperatureCommand(IncreaseDecreaseType increaseDecrease) {
|
||||||
PercentType baseTemperature = kelvinToPercentType(getLightStateForCommand().getColor().getKelvin(),
|
PercentType baseTemperature = kelvinToPercentType(getLightStateForCommand().getColor().getKelvin(),
|
||||||
product.getTemperatureRange());
|
features.getTemperatureRange());
|
||||||
PercentType newTemperature = increaseDecreasePercentType(increaseDecrease, baseTemperature);
|
PercentType newTemperature = increaseDecreasePercentType(increaseDecrease, baseTemperature);
|
||||||
handleTemperatureCommand(newTemperature);
|
handleTemperatureCommand(newTemperature);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleIncreaseDecreaseTemperatureCommand(IncreaseDecreaseType increaseDecrease, int zoneIndex) {
|
private void handleIncreaseDecreaseTemperatureCommand(IncreaseDecreaseType increaseDecrease, int zoneIndex) {
|
||||||
PercentType baseTemperature = kelvinToPercentType(getLightStateForCommand().getColor(zoneIndex).getKelvin(),
|
PercentType baseTemperature = kelvinToPercentType(getLightStateForCommand().getColor(zoneIndex).getKelvin(),
|
||||||
product.getTemperatureRange());
|
features.getTemperatureRange());
|
||||||
PercentType newTemperature = increaseDecreasePercentType(increaseDecrease, baseTemperature);
|
PercentType newTemperature = increaseDecreasePercentType(increaseDecrease, baseTemperature);
|
||||||
handleTemperatureCommand(newTemperature, zoneIndex);
|
handleTemperatureCommand(newTemperature, zoneIndex);
|
||||||
}
|
}
|
||||||
|
@ -691,7 +709,18 @@ public class LifxLightHandler extends BaseThingHandler {
|
||||||
flameSpeedInMSecs.longValue());
|
flameSpeedInMSecs.longValue());
|
||||||
getLightStateForCommand().setTileEffect(effect);
|
getLightStateForCommand().setTileEffect(effect);
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
logger.debug("Wrong effect type received as command: {}", type);
|
logger.debug("{} : Wrong effect type received as command: {}", logId, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateProperties(Map<String, String> properties) {
|
||||||
|
String oldHostVersion = getThing().getProperties().get(LifxBindingConstants.PROPERTY_HOST_VERSION);
|
||||||
|
super.updateProperties(properties);
|
||||||
|
String newHostVersion = getThing().getProperties().get(LifxBindingConstants.PROPERTY_HOST_VERSION);
|
||||||
|
|
||||||
|
if (!Objects.equals(oldHostVersion, newHostVersion)) {
|
||||||
|
features.update(getFeatures());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.hasSize;
|
||||||
|
import static org.openhab.binding.lifx.internal.LifxProduct.Feature.*;
|
||||||
|
import static org.openhab.binding.lifx.internal.LifxProduct.TemperatureRange.*;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.openhab.binding.lifx.internal.LifxProduct.Features;
|
||||||
|
import org.openhab.binding.lifx.internal.LifxProduct.Upgrade;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link LifxProduct}.
|
||||||
|
*
|
||||||
|
* @author Wouter Born - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class LifxProductTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void productIDsAreUnique() {
|
||||||
|
Set<Long> productIDs = new HashSet<>();
|
||||||
|
for (LifxProduct product : LifxProduct.values()) {
|
||||||
|
assertThat(productIDs, not(hasItem(product.getID())));
|
||||||
|
productIDs.add(product.getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void productNamesMatchProductIDs() {
|
||||||
|
for (LifxProduct product : LifxProduct.values()) {
|
||||||
|
assertThat(product.name(), is("PRODUCT_" + product.getID()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void lightsHaveDefinedTemperatureRange() {
|
||||||
|
for (LifxProduct product : LifxProduct.values()) {
|
||||||
|
if (product.isLight()) {
|
||||||
|
String reason = String.format("The %s light does not define a temperature range", product.name());
|
||||||
|
assertThat(reason, product.getFeatures().getTemperatureRange(), is(not(NONE)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void upgradesSortedByMajorMinor() {
|
||||||
|
for (LifxProduct product : LifxProduct.values()) {
|
||||||
|
long major = 0;
|
||||||
|
long minor = 0;
|
||||||
|
for (Upgrade upgrade : product.getUpgrades()) {
|
||||||
|
String reason = String.format("Upgrades for %s are not sorted by major minor (%s.%s >= %s.%s)",
|
||||||
|
product.name(), major, minor, upgrade.major, upgrade.minor);
|
||||||
|
assertThat(reason, major < upgrade.major || (major == upgrade.major && minor < upgrade.minor),
|
||||||
|
is(true));
|
||||||
|
major = upgrade.major;
|
||||||
|
minor = upgrade.minor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFeaturesForProductWithoutUpgrades() {
|
||||||
|
LifxProduct product = LifxProduct.PRODUCT_1;
|
||||||
|
assertThat(product.getUpgrades(), hasSize(0));
|
||||||
|
|
||||||
|
Features features = product.getFeatures();
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_2500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
|
||||||
|
features = product.getFeatures("1.23");
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_2500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFeaturesForProductWithUpgrades() {
|
||||||
|
LifxProduct product = LifxProduct.PRODUCT_32;
|
||||||
|
assertThat(product.getUpgrades(), hasSize(2));
|
||||||
|
|
||||||
|
Features features = product.getFeatures();
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_2500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
assertThat(features.hasFeature(EXTENDED_MULTIZONE), is(false));
|
||||||
|
assertThat(features.hasFeature(INFRARED), is(false));
|
||||||
|
assertThat(features.hasFeature(MULTIZONE), is(true));
|
||||||
|
|
||||||
|
features = product.getFeatures("2.70");
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_2500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
assertThat(features.hasFeature(EXTENDED_MULTIZONE), is(false));
|
||||||
|
assertThat(features.hasFeature(INFRARED), is(false));
|
||||||
|
assertThat(features.hasFeature(MULTIZONE), is(true));
|
||||||
|
|
||||||
|
features = product.getFeatures("2.77");
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_2500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
assertThat(features.hasFeature(EXTENDED_MULTIZONE), is(true));
|
||||||
|
assertThat(features.hasFeature(INFRARED), is(false));
|
||||||
|
assertThat(features.hasFeature(MULTIZONE), is(true));
|
||||||
|
|
||||||
|
features = product.getFeatures("2.79");
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_2500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
assertThat(features.hasFeature(EXTENDED_MULTIZONE), is(true));
|
||||||
|
assertThat(features.hasFeature(INFRARED), is(false));
|
||||||
|
assertThat(features.hasFeature(MULTIZONE), is(true));
|
||||||
|
|
||||||
|
features = product.getFeatures("2.80");
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_1500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
assertThat(features.hasFeature(EXTENDED_MULTIZONE), is(true));
|
||||||
|
assertThat(features.hasFeature(INFRARED), is(false));
|
||||||
|
assertThat(features.hasFeature(MULTIZONE), is(true));
|
||||||
|
|
||||||
|
features = product.getFeatures("2.81");
|
||||||
|
assertThat(features.getTemperatureRange(), is(TR_1500_9000));
|
||||||
|
assertThat(features.hasFeature(COLOR), is(true));
|
||||||
|
assertThat(features.hasFeature(EXTENDED_MULTIZONE), is(true));
|
||||||
|
assertThat(features.hasFeature(INFRARED), is(false));
|
||||||
|
assertThat(features.hasFeature(MULTIZONE), is(true));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue