[hue] Lamp handler exposes min/max Colour Temperature in state description (#17637)

* [hue] provide color temperature min/max values dynamically in state description

Signed-off-by: AndrewFG <software@whitebear.ch>
This commit is contained in:
Andrew Fiddian-Green 2024-10-28 23:01:52 +00:00 committed by GitHub
parent df365dc9a8
commit 67bb354e32
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 62 additions and 2 deletions

View File

@ -12,19 +12,32 @@
*/ */
package org.openhab.binding.hue.internal.handler; package org.openhab.binding.hue.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.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.events.EventPublisher; 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.binding.BaseDynamicStateDescriptionProvider;
import org.openhab.core.thing.events.ThingEventFactory;
import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService; import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
import org.openhab.core.thing.link.ItemChannelLinkRegistry; import org.openhab.core.thing.link.ItemChannelLinkRegistry;
import org.openhab.core.thing.type.DynamicStateDescriptionProvider; 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.Activate;
import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.Reference;
/** /**
* The {@link Clip2StateDescriptionProvider} provides dynamic state descriptions of scene channels whose list of options * The {@link Clip2StateDescriptionProvider} provides dynamic state descriptions of alert, effect, scene, and colour
* is determined at runtime. * temperature channels whose capabilities are dynamically determined at runtime.
* *
* @author Andrew Fiddian-Green - Initial contribution * @author Andrew Fiddian-Green - Initial contribution
* *
@ -33,6 +46,8 @@ import org.osgi.service.component.annotations.Reference;
@Component(service = { DynamicStateDescriptionProvider.class, Clip2StateDescriptionProvider.class }) @Component(service = { DynamicStateDescriptionProvider.class, Clip2StateDescriptionProvider.class })
public class Clip2StateDescriptionProvider extends BaseDynamicStateDescriptionProvider { public class Clip2StateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
private final Map<ChannelUID, StateDescriptionFragment> stateDescriptionFragments = new ConcurrentHashMap<>();
@Activate @Activate
public Clip2StateDescriptionProvider(final @Reference EventPublisher eventPublisher, public Clip2StateDescriptionProvider(final @Reference EventPublisher eventPublisher,
final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry,
@ -41,4 +56,29 @@ public class Clip2StateDescriptionProvider extends BaseDynamicStateDescriptionPr
this.itemChannelLinkRegistry = itemChannelLinkRegistry; this.itemChannelLinkRegistry = itemChannelLinkRegistry;
this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService; 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));
}
}
} }

View File

@ -38,6 +38,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.hue.internal.action.DynamicsActions; import org.openhab.binding.hue.internal.action.DynamicsActions;
import org.openhab.binding.hue.internal.api.dto.clip2.Alerts; import org.openhab.binding.hue.internal.api.dto.clip2.Alerts;
import org.openhab.binding.hue.internal.api.dto.clip2.ColorTemperature;
import org.openhab.binding.hue.internal.api.dto.clip2.ColorXy; import org.openhab.binding.hue.internal.api.dto.clip2.ColorXy;
import org.openhab.binding.hue.internal.api.dto.clip2.Dimming; import org.openhab.binding.hue.internal.api.dto.clip2.Dimming;
import org.openhab.binding.hue.internal.api.dto.clip2.Effects; import org.openhab.binding.hue.internal.api.dto.clip2.Effects;
@ -945,6 +946,7 @@ public class Clip2ThingHandler extends BaseThingHandler {
case LIGHT: case LIGHT:
if (fullUpdate) { if (fullUpdate) {
updateEffectChannel(resource); updateEffectChannel(resource);
updateColorTemperatureAbsoluteChannel(resource);
} }
updateState(CHANNEL_2_COLOR_TEMP_PERCENT, resource.getColorTemperaturePercentState(), fullUpdate); updateState(CHANNEL_2_COLOR_TEMP_PERCENT, resource.getColorTemperaturePercentState(), fullUpdate);
updateState(CHANNEL_2_COLOR_TEMP_ABSOLUTE, resource.getColorTemperatureAbsoluteState(), fullUpdate); updateState(CHANNEL_2_COLOR_TEMP_ABSOLUTE, resource.getColorTemperatureAbsoluteState(), fullUpdate);
@ -1114,6 +1116,24 @@ public class Clip2ThingHandler extends BaseThingHandler {
} }
} }
/**
* Process the incoming Resource to initialize the colour temperature absolute channel's state description based on
* the minimum and maximum values supported by the lamp's Mirek schema.
*
* @param resource a Resource possibly containing a color temperature element and respective Mirek schema element.
*/
private void updateColorTemperatureAbsoluteChannel(Resource resource) {
ColorTemperature colorTemperature = resource.getColorTemperature();
if (colorTemperature != null) {
MirekSchema mirekSchema = colorTemperature.getMirekSchema();
if (mirekSchema != null) {
stateDescriptionProvider.setMinMaxKelvin(new ChannelUID(thing.getUID(), CHANNEL_2_COLOR_TEMP_ABSOLUTE),
1000000 / mirekSchema.getMirekMaximum(), 1000000 / mirekSchema.getMirekMinimum());
logger.debug("{} -> updateColorTempAbsChannel() done", resource.getId());
}
}
}
/** /**
* Update the light properties. * Update the light properties.
* *