From 2080c85524d6798c01cddabd08644ab2fb33df24 Mon Sep 17 00:00:00 2001 From: Andrew Fiddian-Green Date: Fri, 1 Nov 2024 23:07:20 +0000 Subject: [PATCH] [various] Lamp handlers expose min/max Color Temperature in state description (#17641) * Lamp handlers expose min/max Colour Temperature in state description * add color temperature validit and range checks Signed-off-by: AndrewFG --- .../resources/OH-INF/thing/channel-types.xml | 12 +++ .../resources/OH-INF/thing/thing-types.xml | 8 +- .../resources/OH-INF/update/instructions.xml | 10 +++ .../resources/OH-INF/thing/thing-types.xml | 8 +- .../lifx/internal/LifxHandlerFactory.java | 10 ++- .../internal/handler/LifxLightHandler.java | 26 +++++- .../handler/LifxStateDescriptionProvider.java | 84 +++++++++++++++++++ .../internal/NanoleafHandlerFactory.java | 9 +- .../NanoLeafStateDescriptionProvider.java | 84 +++++++++++++++++++ .../handler/NanoleafControllerHandler.java | 39 +++++---- 10 files changed, 260 insertions(+), 30 deletions(-) create mode 100644 bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxStateDescriptionProvider.java create mode 100644 bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoLeafStateDescriptionProvider.java diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml index 07bb446f06f6b..d4c3b90f89f4a 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/channel-types.xml @@ -241,4 +241,16 @@ Controls the rollershutter and states its opening level in percent + + Number:Temperature + + Controls the color temperature of the light in Kelvin + ColorLight + + Control + ColorTemperature + + + + diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml index 6342f38f39772..d34f540250a56 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/thing/thing-types.xml @@ -16,11 +16,11 @@ - + - 1 + 2 ain @@ -418,11 +418,11 @@ - + - 1 + 2 ain diff --git a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/update/instructions.xml b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/update/instructions.xml index b0106ae8cb86c..89e6dbd9980b1 100644 --- a/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/update/instructions.xml +++ b/bundles/org.openhab.binding.avmfritz/src/main/resources/OH-INF/update/instructions.xml @@ -166,6 +166,11 @@ system:color-temperature-abs + + + avmfritz:color-temperature-abs + + @@ -177,6 +182,11 @@ system:color-temperature-abs + + + avmfritz:color-temperature-abs + + diff --git a/bundles/org.openhab.binding.govee/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.govee/src/main/resources/OH-INF/thing/thing-types.xml index 002cb291f70c4..4f20a2107f7c0 100644 --- a/bundles/org.openhab.binding.govee/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.govee/src/main/resources/OH-INF/thing/thing-types.xml @@ -16,11 +16,12 @@ - + + Number:Temperature - + Controls the color temperature of the light in Kelvin - Temperature + ColorLight Control ColorTemperature @@ -28,5 +29,4 @@ - diff --git a/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/LifxHandlerFactory.java b/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/LifxHandlerFactory.java index 1a558c939e1d4..a95d334799717 100644 --- a/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/LifxHandlerFactory.java +++ b/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/LifxHandlerFactory.java @@ -17,12 +17,14 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.lifx.internal.handler.LifxLightHandler; +import org.openhab.binding.lifx.internal.handler.LifxStateDescriptionProvider; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -37,6 +39,12 @@ public class LifxHandlerFactory extends BaseThingHandlerFactory { private @NonNullByDefault({}) LifxChannelFactory channelFactory; + private final LifxStateDescriptionProvider stateDescriptionProvider; + + @Activate + public LifxHandlerFactory(@Reference LifxStateDescriptionProvider stateDescriptionProvider) { + this.stateDescriptionProvider = stateDescriptionProvider; + } @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { @@ -51,7 +59,7 @@ protected void activate(ComponentContext componentContext) { @Override protected @Nullable ThingHandler createHandler(Thing thing) { if (supportsThingType(thing.getThingTypeUID())) { - return new LifxLightHandler(thing, channelFactory); + return new LifxLightHandler(thing, channelFactory, stateDescriptionProvider); } return null; diff --git a/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxLightHandler.java b/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxLightHandler.java index f445404e2f9b1..577c952341f8a 100644 --- a/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxLightHandler.java +++ b/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxLightHandler.java @@ -42,6 +42,7 @@ 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.LifxProduct.TemperatureRange; import org.openhab.binding.lifx.internal.dto.Effect; import org.openhab.binding.lifx.internal.dto.GetHevCycleRequest; import org.openhab.binding.lifx.internal.dto.GetLightInfraredRequest; @@ -74,6 +75,7 @@ import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,6 +99,8 @@ public class LifxLightHandler extends BaseThingHandler { private static final Duration MAX_STATE_CHANGE_DURATION = Duration.ofSeconds(4); private final LifxChannelFactory channelFactory; + private final LifxStateDescriptionProvider stateDescriptionProvider; + private @NonNullByDefault({}) Features features; private Duration hevCycleDuration = Duration.ZERO; @@ -180,11 +184,23 @@ private void updateColorChannels(@Nullable PowerState powerState, HSBK[] colors) HSBK updateColor = nullSafeUpdateColor(powerState, color); HSBType hsb = updateColor.getHSB(); + State colorTemperatureState = UnDefType.UNDEF; + State colorTemperatureAbsoluteState = UnDefType.UNDEF; + TemperatureRange temperatureRange = features.getTemperatureRange(); + if (temperatureRange.getRange() > 0) { + stateDescriptionProvider.setMinMaxKelvin(new ChannelUID(thing.getUID(), CHANNEL_ABS_TEMPERATURE), + temperatureRange.getMinimum(), temperatureRange.getMaximum()); + colorTemperatureState = kelvinToPercentType(updateColor.getKelvin(), temperatureRange); + colorTemperatureAbsoluteState = QuantityType.valueOf(updateColor.getKelvin(), Units.KELVIN); + } else { + logger.warn("Thing {} invalid color temperature range {} .. {}", thing.getUID(), + temperatureRange.getMinimum(), temperatureRange.getMaximum()); + } + updateStateIfChanged(CHANNEL_COLOR, hsb); updateStateIfChanged(CHANNEL_BRIGHTNESS, hsb.getBrightness()); - updateStateIfChanged(CHANNEL_TEMPERATURE, - kelvinToPercentType(updateColor.getKelvin(), features.getTemperatureRange())); - updateStateIfChanged(CHANNEL_ABS_TEMPERATURE, new QuantityType(updateColor.getKelvin(), Units.KELVIN)); + updateStateIfChanged(CHANNEL_TEMPERATURE, colorTemperatureState); + updateStateIfChanged(CHANNEL_ABS_TEMPERATURE, colorTemperatureAbsoluteState); updateZoneChannels(powerState, colors); } @@ -249,9 +265,11 @@ private void updateZoneChannels(@Nullable PowerState powerState, HSBK[] colors) } } - public LifxLightHandler(Thing thing, LifxChannelFactory channelFactory) { + public LifxLightHandler(Thing thing, LifxChannelFactory channelFactory, + LifxStateDescriptionProvider stateDescriptionProvider) { super(thing); this.channelFactory = channelFactory; + this.stateDescriptionProvider = stateDescriptionProvider; } @Override diff --git a/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxStateDescriptionProvider.java b/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxStateDescriptionProvider.java new file mode 100644 index 0000000000000..929f778fef084 --- /dev/null +++ b/bundles/org.openhab.binding.lifx/src/main/java/org/openhab/binding/lifx/internal/handler/LifxStateDescriptionProvider.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2010-2024 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.handler; + +import java.math.BigDecimal; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.events.EventPublisher; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider; +import org.openhab.core.thing.events.ThingEventFactory; +import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService; +import org.openhab.core.thing.link.ItemChannelLinkRegistry; +import org.openhab.core.thing.type.DynamicStateDescriptionProvider; +import org.openhab.core.types.StateDescription; +import org.openhab.core.types.StateDescriptionFragment; +import org.openhab.core.types.StateDescriptionFragmentBuilder; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link LifxStateDescriptionProvider} provides dynamic state description minimum and maximum vales of color + * temperature channels whose capabilities are dynamically determined at runtime. + * + * @author Andrew Fiddian-Green - Initial contribution + * + */ +@NonNullByDefault +@Component(service = { DynamicStateDescriptionProvider.class, LifxStateDescriptionProvider.class }) +public class LifxStateDescriptionProvider extends BaseDynamicStateDescriptionProvider { + + private final Map stateDescriptionFragments = new ConcurrentHashMap<>(); + + @Activate + public LifxStateDescriptionProvider(final @Reference EventPublisher eventPublisher, + final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, + final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) { + this.eventPublisher = eventPublisher; + this.itemChannelLinkRegistry = itemChannelLinkRegistry; + this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService; + } + + @Override + public @Nullable StateDescription getStateDescription(Channel channel, @Nullable StateDescription original, + @Nullable Locale locale) { + StateDescriptionFragment stateDescriptionFragment = stateDescriptionFragments.get(channel.getUID()); + return stateDescriptionFragment != null ? stateDescriptionFragment.toStateDescription() + : super.getStateDescription(channel, original, locale); + } + + /** + * Set the state description minimum and maximum values and pattern in Kelvin for the given channel UID + */ + public void setMinMaxKelvin(ChannelUID channelUID, long minKelvin, long maxKelvin) { + StateDescriptionFragment oldStateDescriptionFragment = stateDescriptionFragments.get(channelUID); + StateDescriptionFragment newStateDescriptionFragment = StateDescriptionFragmentBuilder.create() + .withMinimum(BigDecimal.valueOf(minKelvin)).withMaximum(BigDecimal.valueOf(maxKelvin)) + .withStep(BigDecimal.valueOf(100)).withPattern("%.0f K").build(); + if (!newStateDescriptionFragment.equals(oldStateDescriptionFragment)) { + stateDescriptionFragments.put(channelUID, newStateDescriptionFragment); + ItemChannelLinkRegistry itemChannelLinkRegistry = this.itemChannelLinkRegistry; + postEvent(ThingEventFactory.createChannelDescriptionChangedEvent(channelUID, + itemChannelLinkRegistry != null ? itemChannelLinkRegistry.getLinkedItemNames(channelUID) : Set.of(), + newStateDescriptionFragment, oldStateDescriptionFragment)); + } + } +} diff --git a/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/NanoleafHandlerFactory.java b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/NanoleafHandlerFactory.java index 27f39bdf9a2ca..d3aa5c602108c 100644 --- a/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/NanoleafHandlerFactory.java +++ b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/NanoleafHandlerFactory.java @@ -19,6 +19,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.nanoleaf.internal.handler.NanoLeafStateDescriptionProvider; import org.openhab.binding.nanoleaf.internal.handler.NanoleafControllerHandler; import org.openhab.binding.nanoleaf.internal.handler.NanoleafPanelHandler; import org.openhab.core.io.net.http.HttpClientFactory; @@ -51,10 +52,13 @@ public class NanoleafHandlerFactory extends BaseThingHandlerFactory { private final Logger logger = LoggerFactory.getLogger(NanoleafHandlerFactory.class); private final HttpClientFactory httpClientFactory; + private final NanoLeafStateDescriptionProvider nanoLeafStateDescriptionProvider; @Activate - public NanoleafHandlerFactory(@Reference HttpClientFactory httpClientFactory) { + public NanoleafHandlerFactory(@Reference HttpClientFactory httpClientFactory, + @Reference NanoLeafStateDescriptionProvider nanoLeafStateDescriptionProvider) { this.httpClientFactory = httpClientFactory; + this.nanoLeafStateDescriptionProvider = nanoLeafStateDescriptionProvider; } @Override @@ -67,7 +71,8 @@ public boolean supportsThingType(ThingTypeUID thingTypeUID) { protected ThingHandler createHandler(Thing thing) { ThingTypeUID thingTypeUID = thing.getThingTypeUID(); if (NanoleafBindingConstants.THING_TYPE_CONTROLLER.equals(thingTypeUID)) { - NanoleafControllerHandler handler = new NanoleafControllerHandler((Bridge) thing, this.httpClientFactory); + NanoleafControllerHandler handler = new NanoleafControllerHandler((Bridge) thing, this.httpClientFactory, + this.nanoLeafStateDescriptionProvider); logger.debug("Nanoleaf controller handler created."); return handler; } else if (NanoleafBindingConstants.THING_TYPE_LIGHT_PANEL.equals(thingTypeUID)) { diff --git a/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoLeafStateDescriptionProvider.java b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoLeafStateDescriptionProvider.java new file mode 100644 index 0000000000000..6023462a84358 --- /dev/null +++ b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoLeafStateDescriptionProvider.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2010-2024 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.nanoleaf.internal.handler; + +import java.math.BigDecimal; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.events.EventPublisher; +import org.openhab.core.thing.Channel; +import org.openhab.core.thing.ChannelUID; +import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider; +import org.openhab.core.thing.events.ThingEventFactory; +import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService; +import org.openhab.core.thing.link.ItemChannelLinkRegistry; +import org.openhab.core.thing.type.DynamicStateDescriptionProvider; +import org.openhab.core.types.StateDescription; +import org.openhab.core.types.StateDescriptionFragment; +import org.openhab.core.types.StateDescriptionFragmentBuilder; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Reference; + +/** + * The {@link NanoLeafStateDescriptionProvider} provides dynamic state description minimum and maximum vales of color + * temperature channels whose capabilities are dynamically determined at runtime. + * + * @author Andrew Fiddian-Green - Initial contribution + * + */ +@NonNullByDefault +@Component(service = { DynamicStateDescriptionProvider.class, NanoLeafStateDescriptionProvider.class }) +public class NanoLeafStateDescriptionProvider extends BaseDynamicStateDescriptionProvider { + + private final Map stateDescriptionFragments = new ConcurrentHashMap<>(); + + @Activate + public NanoLeafStateDescriptionProvider(final @Reference EventPublisher eventPublisher, + final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, + final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) { + this.eventPublisher = eventPublisher; + this.itemChannelLinkRegistry = itemChannelLinkRegistry; + this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService; + } + + @Override + public @Nullable StateDescription getStateDescription(Channel channel, @Nullable StateDescription original, + @Nullable Locale locale) { + StateDescriptionFragment stateDescriptionFragment = stateDescriptionFragments.get(channel.getUID()); + return stateDescriptionFragment != null ? stateDescriptionFragment.toStateDescription() + : super.getStateDescription(channel, original, locale); + } + + /** + * Set the state description minimum and maximum values and pattern in Kelvin for the given channel UID + */ + public void setMinMaxKelvin(ChannelUID channelUID, long minKelvin, long maxKelvin) { + StateDescriptionFragment oldStateDescriptionFragment = stateDescriptionFragments.get(channelUID); + StateDescriptionFragment newStateDescriptionFragment = StateDescriptionFragmentBuilder.create() + .withMinimum(BigDecimal.valueOf(minKelvin)).withMaximum(BigDecimal.valueOf(maxKelvin)) + .withStep(BigDecimal.valueOf(100)).withPattern("%.0f K").build(); + if (!newStateDescriptionFragment.equals(oldStateDescriptionFragment)) { + stateDescriptionFragments.put(channelUID, newStateDescriptionFragment); + ItemChannelLinkRegistry itemChannelLinkRegistry = this.itemChannelLinkRegistry; + postEvent(ThingEventFactory.createChannelDescriptionChangedEvent(channelUID, + itemChannelLinkRegistry != null ? itemChannelLinkRegistry.getLinkedItemNames(channelUID) : Set.of(), + newStateDescriptionFragment, oldStateDescriptionFragment)); + } + } +} diff --git a/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoleafControllerHandler.java b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoleafControllerHandler.java index f48e3a57f6c0a..a59121ef27c3c 100644 --- a/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoleafControllerHandler.java +++ b/bundles/org.openhab.binding.nanoleaf/src/main/java/org/openhab/binding/nanoleaf/internal/handler/NanoleafControllerHandler.java @@ -94,6 +94,7 @@ import org.openhab.core.thing.util.ThingWebClientUtil; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; +import org.openhab.core.types.UnDefType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -118,6 +119,7 @@ public class NanoleafControllerHandler extends BaseBridgeHandler implements Nano private final Logger logger = LoggerFactory.getLogger(NanoleafControllerHandler.class); private final HttpClientFactory httpClientFactory; private final HttpClient httpClient; + private final NanoLeafStateDescriptionProvider stateDescriptionProvider; private @Nullable HttpClient httpClientSSETouchEvent; private @Nullable Request sseTouchjobRequest; @@ -141,10 +143,12 @@ public class NanoleafControllerHandler extends BaseBridgeHandler implements Nano private boolean touchJobRunning = false; - public NanoleafControllerHandler(Bridge bridge, HttpClientFactory httpClientFactory) { + public NanoleafControllerHandler(Bridge bridge, HttpClientFactory httpClientFactory, + NanoLeafStateDescriptionProvider nanoLeafStateDescriptionProvider) { super(bridge); this.httpClientFactory = httpClientFactory; this.httpClient = httpClientFactory.getCommonHttpClient(); + this.stateDescriptionProvider = nanoLeafStateDescriptionProvider; } private void initializeTouchHttpClient() { @@ -648,28 +652,33 @@ private void updateFromControllerInfo() throws NanoleafException { OnOffType powerState = state.getOnOff(); + org.openhab.core.types.State colorTemperatureState = UnDefType.UNDEF; + org.openhab.core.types.State colorTemperatureAbsoluteState = UnDefType.UNDEF; Ct colorTemperature = state.getColorTemperature(); - - float colorTempPercent = 0.0F; - int hue; - int saturation; if (colorTemperature != null) { - updateState(CHANNEL_COLOR_TEMPERATURE_ABS, new QuantityType(colorTemperature.getValue(), Units.KELVIN)); Integer min = colorTemperature.getMin(); - hue = min == null ? 0 : min; Integer max = colorTemperature.getMax(); - saturation = max == null ? 0 : max; - colorTempPercent = (colorTemperature.getValue() - hue) / (saturation - hue) - * PercentType.HUNDRED.intValue(); + int minKelvin = min == null ? 1000 : min; + int maxKelvin = max == null ? 10000 : max; + if (maxKelvin > minKelvin) { + stateDescriptionProvider.setMinMaxKelvin(new ChannelUID(thing.getUID(), CHANNEL_COLOR_TEMPERATURE_ABS), + minKelvin, maxKelvin); + colorTemperatureState = new PercentType( + Float.toString(100.0f * (colorTemperature.getValue() - minKelvin) / (maxKelvin - minKelvin))); + colorTemperatureAbsoluteState = QuantityType.valueOf(colorTemperature.getValue(), Units.KELVIN); + } else { + logger.warn("Thing {} invalid color temperature range {} .. {}", thing.getUID(), minKelvin, maxKelvin); + } } + updateState(CHANNEL_COLOR_TEMPERATURE, colorTemperatureState); + updateState(CHANNEL_COLOR_TEMPERATURE_ABS, colorTemperatureAbsoluteState); - updateState(CHANNEL_COLOR_TEMPERATURE, new PercentType(Float.toString(colorTempPercent))); updateState(CHANNEL_EFFECT, new StringType(controllerInfo.getEffects().getSelect())); Hue stateHue = state.getHue(); - hue = stateHue != null ? stateHue.getValue() : 0; + int hue = stateHue != null ? stateHue.getValue() : 0; Sat stateSaturation = state.getSaturation(); - saturation = stateSaturation != null ? stateSaturation.getValue() : 0; + int saturation = stateSaturation != null ? stateSaturation.getValue() : 0; Brightness stateBrightness = state.getBrightness(); int brightness = stateBrightness != null ? stateBrightness.getValue() : 0; @@ -914,8 +923,8 @@ private void sendStateCommand(String channel, Command command) throws NanoleafEx IntegerState state = new Ct(); if (command instanceof DecimalType) { state.setValue(((DecimalType) command).intValue()); - } else if (command instanceof QuantityType) { - QuantityType tempKelvin = ((QuantityType) command).toInvertibleUnit(Units.KELVIN); + } else if (command instanceof QuantityType quantityType) { + QuantityType tempKelvin = quantityType.toInvertibleUnit(Units.KELVIN); if (tempKelvin == null) { logger.warn("Cannot convert color temperature {} to Kelvin.", command); return;