[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>
Signed-off-by: Ciprian Pascu <contact@ciprianpascu.ro>
This commit is contained in:
Andrew Fiddian-Green 2024-10-28 23:01:52 +00:00 committed by Ciprian Pascu
parent db043a1811
commit e98a0c3c4f
2 changed files with 62 additions and 2 deletions

View File

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

View File

@ -38,6 +38,7 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
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.ColorTemperature;
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.Effects;
@ -945,6 +946,7 @@ public class Clip2ThingHandler extends BaseThingHandler {
case LIGHT:
if (fullUpdate) {
updateEffectChannel(resource);
updateColorTemperatureAbsoluteChannel(resource);
}
updateState(CHANNEL_2_COLOR_TEMP_PERCENT, resource.getColorTemperaturePercentState(), 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.
*