]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hue] Added support for publishing ChannelDescriptionChangedEvents (#10718)
authorChristoph Weitkamp <github@christophweitkamp.de>
Thu, 24 Jun 2021 10:15:49 +0000 (12:15 +0200)
committerGitHub <noreply@github.com>
Thu, 24 Jun 2021 10:15:49 +0000 (12:15 +0200)
* Added service references to DynamicStateDescriptionProvider to support publishing ChannelDescriptionChangedEvent

Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/HueThingHandlerFactory.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueBridgeHandler.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueGroupHandler.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueLightHandler.java
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueStateDescriptionOptionProvider.java [deleted file]
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueStateDescriptionProvider.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/test/java/org/openhab/binding/hue/internal/handler/HueLightHandlerTest.java

index 8644676a73a72c606cf716f8a1ea42ba0b1d112d..fb13efd35140aff0ab7984bf9efb3426568ba89f 100644 (file)
@@ -24,7 +24,7 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.hue.internal.handler.HueBridgeHandler;
 import org.openhab.binding.hue.internal.handler.HueGroupHandler;
 import org.openhab.binding.hue.internal.handler.HueLightHandler;
-import org.openhab.binding.hue.internal.handler.HueStateDescriptionOptionProvider;
+import org.openhab.binding.hue.internal.handler.HueStateDescriptionProvider;
 import org.openhab.binding.hue.internal.handler.sensors.ClipHandler;
 import org.openhab.binding.hue.internal.handler.sensors.DimmerSwitchHandler;
 import org.openhab.binding.hue.internal.handler.sensors.GeofencePresenceHandler;
@@ -67,11 +67,11 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
                     ClipHandler.SUPPORTED_THING_TYPES.stream(), HueGroupHandler.SUPPORTED_THING_TYPES.stream())
             .flatMap(i -> i).collect(Collectors.toSet()));
 
-    private final HueStateDescriptionOptionProvider stateOptionProvider;
+    private final HueStateDescriptionProvider stateDescriptionProvider;
 
     @Activate
-    public HueThingHandlerFactory(final @Reference HueStateDescriptionOptionProvider stateOptionProvider) {
-        this.stateOptionProvider = stateOptionProvider;
+    public HueThingHandlerFactory(final @Reference HueStateDescriptionProvider stateDescriptionProvider) {
+        this.stateDescriptionProvider = stateDescriptionProvider;
     }
 
     @Override
@@ -142,9 +142,9 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
     @Override
     protected @Nullable ThingHandler createHandler(Thing thing) {
         if (HueBridgeHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            return new HueBridgeHandler((Bridge) thing, stateOptionProvider);
+            return new HueBridgeHandler((Bridge) thing, stateDescriptionProvider);
         } else if (HueLightHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            return new HueLightHandler(thing, stateOptionProvider);
+            return new HueLightHandler(thing, stateDescriptionProvider);
         } else if (DimmerSwitchHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
             return new DimmerSwitchHandler(thing);
         } else if (TapSwitchHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
@@ -160,7 +160,7 @@ public class HueThingHandlerFactory extends BaseThingHandlerFactory {
         } else if (ClipHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
             return new ClipHandler(thing);
         } else if (HueGroupHandler.SUPPORTED_THING_TYPES.contains(thing.getThingTypeUID())) {
-            return new HueGroupHandler(thing, stateOptionProvider);
+            return new HueGroupHandler(thing, stateDescriptionProvider);
         } else {
             return null;
         }
index 3ee5fc01eb7c236baf9e888e75f4c187b488b39c..c4baa76feb5a0d353f2275e75b8586cd8774af5d 100644 (file)
@@ -97,7 +97,7 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
     private static final long SCENE_POLLING_INTERVAL = TimeUnit.SECONDS.convert(10, TimeUnit.MINUTES);
 
     private final Logger logger = LoggerFactory.getLogger(HueBridgeHandler.class);
-    private final HueStateDescriptionOptionProvider stateDescriptionOptionProvider;
+    private final HueStateDescriptionProvider stateDescriptionOptionProvider;
 
     private final Map<String, FullLight> lastLightStates = new ConcurrentHashMap<>();
     private final Map<String, FullSensor> lastSensorStates = new ConcurrentHashMap<>();
@@ -403,7 +403,7 @@ public class HueBridgeHandler extends ConfigStatusBridgeHandler implements HueCl
 
     private List<String> consoleScenesList = new ArrayList<>();
 
-    public HueBridgeHandler(Bridge bridge, HueStateDescriptionOptionProvider stateDescriptionOptionProvider) {
+    public HueBridgeHandler(Bridge bridge, HueStateDescriptionProvider stateDescriptionOptionProvider) {
         super(bridge);
         this.stateDescriptionOptionProvider = stateDescriptionOptionProvider;
     }
index efa228f2fe1b9d095d4098d4ea4406e3f388e822..ac887ded8f57e5b28a658539548c233bca8f689b 100644 (file)
@@ -62,7 +62,7 @@ public class HueGroupHandler extends BaseThingHandler implements GroupStatusList
     public static final String PROPERTY_MEMBERS = "members";
 
     private final Logger logger = LoggerFactory.getLogger(HueGroupHandler.class);
-    private final HueStateDescriptionOptionProvider stateDescriptionOptionProvider;
+    private final HueStateDescriptionProvider stateDescriptionOptionProvider;
 
     private @NonNullByDefault({}) String groupId;
 
@@ -79,7 +79,7 @@ public class HueGroupHandler extends BaseThingHandler implements GroupStatusList
 
     private List<String> consoleScenesList = List.of();
 
-    public HueGroupHandler(Thing thing, HueStateDescriptionOptionProvider stateDescriptionOptionProvider) {
+    public HueGroupHandler(Thing thing, HueStateDescriptionProvider stateDescriptionOptionProvider) {
         super(thing);
         this.stateDescriptionOptionProvider = stateDescriptionOptionProvider;
     }
index fd727666b70bdbcea7c321f58fc1ede4c543adfc..33c90e7946708d6bb3e094a459ac0de23fbb9a54 100644 (file)
@@ -49,7 +49,7 @@ import org.openhab.core.thing.binding.BaseThingHandler;
 import org.openhab.core.thing.binding.ThingHandler;
 import org.openhab.core.thing.binding.ThingHandlerService;
 import org.openhab.core.types.Command;
-import org.openhab.core.types.StateDescription;
+import org.openhab.core.types.StateDescriptionFragment;
 import org.openhab.core.types.StateDescriptionFragmentBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -83,7 +83,7 @@ public class HueLightHandler extends BaseThingHandler implements LightStatusList
 
     private final Logger logger = LoggerFactory.getLogger(HueLightHandler.class);
 
-    private final HueStateDescriptionOptionProvider stateDescriptionOptionProvider;
+    private final HueStateDescriptionProvider stateDescriptionProvider;
 
     private @NonNullByDefault({}) String lightId;
 
@@ -105,9 +105,9 @@ public class HueLightHandler extends BaseThingHandler implements LightStatusList
 
     private @Nullable ScheduledFuture<?> scheduledFuture;
 
-    public HueLightHandler(Thing hueLight, HueStateDescriptionOptionProvider stateDescriptionOptionProvider) {
+    public HueLightHandler(Thing hueLight, HueStateDescriptionProvider stateDescriptionProvider) {
         super(hueLight);
-        this.stateDescriptionOptionProvider = stateDescriptionOptionProvider;
+        this.stateDescriptionProvider = stateDescriptionProvider;
     }
 
     @Override
@@ -185,18 +185,14 @@ public class HueLightHandler extends BaseThingHandler implements LightStatusList
                     colorTemperatureCapabilties = ct;
 
                     // minimum and maximum are inverted due to mired/Kelvin conversion!
-                    StateDescription stateDescription = StateDescriptionFragmentBuilder.create()
+                    StateDescriptionFragment stateDescriptionFragment = StateDescriptionFragmentBuilder.create()
                             .withMinimum(new BigDecimal(LightStateConverter.miredToKelvin(ct.max))) //
                             .withMaximum(new BigDecimal(LightStateConverter.miredToKelvin(ct.min))) //
                             .withStep(new BigDecimal(100)) //
                             .withPattern("%.0f K") //
-                            .build().toStateDescription();
-                    if (stateDescription != null) {
-                        stateDescriptionOptionProvider.setDescription(
-                                new ChannelUID(thing.getUID(), CHANNEL_COLORTEMPERATURE_ABS), stateDescription);
-                    } else {
-                        logger.warn("Failed to create state description in thing {}", thing.getUID());
-                    }
+                            .build();
+                    stateDescriptionProvider.setStateDescriptionFragment(
+                            new ChannelUID(thing.getUID(), CHANNEL_COLORTEMPERATURE_ABS), stateDescriptionFragment);
                 }
             }
             capabilitiesInitializedSuccessfully = true;
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueStateDescriptionOptionProvider.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueStateDescriptionOptionProvider.java
deleted file mode 100644 (file)
index 4801c59..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/**
- * 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.hue.internal.handler;
-
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.core.thing.Channel;
-import org.openhab.core.thing.ChannelUID;
-import org.openhab.core.thing.binding.BaseDynamicStateDescriptionProvider;
-import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
-import org.openhab.core.thing.type.DynamicStateDescriptionProvider;
-import org.openhab.core.types.StateDescription;
-import org.osgi.service.component.annotations.Activate;
-import org.osgi.service.component.annotations.Component;
-import org.osgi.service.component.annotations.Reference;
-
-/**
- * Dynamic provider of state options for {@link HueBridgeHandler} while leaving other state description fields as
- * original.
- *
- * @author Hengrui Jiang - Initial contribution
- */
-@Component(service = { DynamicStateDescriptionProvider.class, HueStateDescriptionOptionProvider.class })
-@NonNullByDefault
-public class HueStateDescriptionOptionProvider extends BaseDynamicStateDescriptionProvider {
-
-    private final Map<ChannelUID, StateDescription> descriptions = new ConcurrentHashMap<>();
-
-    @Activate
-    public HueStateDescriptionOptionProvider(
-            final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
-        this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
-    }
-
-    public void setDescription(ChannelUID channelUID, StateDescription description) {
-        descriptions.put(channelUID, description);
-    }
-
-    @Override
-    public @Nullable StateDescription getStateDescription(Channel channel,
-            @Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
-        StateDescription stateDescription = descriptions.get(channel.getUID());
-        return stateDescription != null ? stateDescription
-                : super.getStateDescription(channel, originalStateDescription, locale);
-    }
-}
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueStateDescriptionProvider.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueStateDescriptionProvider.java
new file mode 100644 (file)
index 0000000..3948970
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+ * 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.hue.internal.handler;
+
+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.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * Dynamic provider of state options for {@link HueBridgeHandler} while leaving other state description fields as
+ * original.
+ *
+ * @author Hengrui Jiang - Initial contribution
+ */
+@Component(service = { DynamicStateDescriptionProvider.class, HueStateDescriptionProvider.class })
+@NonNullByDefault
+public class HueStateDescriptionProvider extends BaseDynamicStateDescriptionProvider {
+
+    private final Map<ChannelUID, StateDescriptionFragment> stateDescriptionFragments = new ConcurrentHashMap<>();
+
+    @Activate
+    public HueStateDescriptionProvider(final @Reference EventPublisher eventPublisher, //
+            final @Reference ItemChannelLinkRegistry itemChannelLinkRegistry, //
+            final @Reference ChannelTypeI18nLocalizationService channelTypeI18nLocalizationService) {
+        this.eventPublisher = eventPublisher;
+        this.itemChannelLinkRegistry = itemChannelLinkRegistry;
+        this.channelTypeI18nLocalizationService = channelTypeI18nLocalizationService;
+    }
+
+    public void setStateDescriptionFragment(ChannelUID channelUID, StateDescriptionFragment stateDescriptionFragment) {
+        StateDescriptionFragment oldStateDescriptionFragment = stateDescriptionFragments.get(channelUID);
+        if (!stateDescriptionFragment.equals(oldStateDescriptionFragment)) {
+            stateDescriptionFragments.put(channelUID, stateDescriptionFragment);
+            postEvent(ThingEventFactory.createChannelDescriptionChangedEvent(channelUID,
+                    itemChannelLinkRegistry != null ? itemChannelLinkRegistry.getLinkedItemNames(channelUID) : Set.of(),
+                    stateDescriptionFragment, oldStateDescriptionFragment));
+        }
+    }
+
+    @Override
+    public @Nullable StateDescription getStateDescription(Channel channel,
+            @Nullable StateDescription originalStateDescription, @Nullable Locale locale) {
+        StateDescriptionFragment stateDescriptionFragment = stateDescriptionFragments.get(channel.getUID());
+        return stateDescriptionFragment != null ? stateDescriptionFragment.toStateDescription()
+                : super.getStateDescription(channel, originalStateDescription, locale);
+    }
+}
index 7f2398af4bb5051cccf16aea83f5990f2f24f086..bfdd8cc1c250e5564abfb07b14ea2ad2cc07bd89 100644 (file)
@@ -39,7 +39,6 @@ import org.openhab.core.thing.Thing;
 import org.openhab.core.thing.ThingStatus;
 import org.openhab.core.thing.ThingUID;
 import org.openhab.core.thing.binding.ThingHandlerCallback;
-import org.openhab.core.thing.i18n.ChannelTypeI18nLocalizationService;
 import org.openhab.core.types.Command;
 
 import com.google.gson.Gson;
@@ -385,6 +384,7 @@ public class HueLightHandlerTest {
         assertSendCommand(channel, command, currentState, expectedReply, "LCT001", "Philips");
     }
 
+    @SuppressWarnings("null")
     private void assertSendCommand(String channel, Command command, HueLightState currentState, String expectedReply,
             String expectedModel, String expectedVendor) {
         FullLight light = gson.fromJson(currentState.toString(), FullConfig.class).getLights().get(0);
@@ -400,8 +400,7 @@ public class HueLightHandlerTest {
 
         long fadeTime = 400;
 
-        HueLightHandler hueLightHandler = new HueLightHandler(mockThing,
-                new HueStateDescriptionOptionProvider(mock(ChannelTypeI18nLocalizationService.class))) {
+        HueLightHandler hueLightHandler = new HueLightHandler(mockThing, mock(HueStateDescriptionProvider.class)) {
             @Override
             protected synchronized HueClient getHueClient() {
                 return mockClient;