]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hue] Added LightActions to Hue light groups (#11452)
authorChristoph Weitkamp <github@christophweitkamp.de>
Tue, 26 Oct 2021 17:08:47 +0000 (19:08 +0200)
committerGitHub <noreply@github.com>
Tue, 26 Oct 2021 17:08:47 +0000 (19:08 +0200)
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
bundles/org.openhab.binding.hue/README.md
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/action/LightActions.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/HueLightActionsHandler.java [new file with mode: 0644]
bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueLightHandler.java
bundles/org.openhab.binding.hue/src/test/java/org/openhab/binding/hue/internal/handler/HueLightHandlerTest.java

index d6649590eb781df15583533d18fee366b5cdcf61..fee9426e00874708db3d6de1a429950899bb2ebf 100644 (file)
@@ -227,7 +227,7 @@ The `tap_switch_event` can trigger one of the following events:
 ## Rule Actions
 
 This binding includes a rule action, which allows to change a light channel with a specific fading time from within rules.
-There is a separate instance for each light, which can be retrieved e.g. through
+There is a separate instance for each light or light group, which can be retrieved e.g. through
 
 ```php
 val hueActions = getActions("hue","hue:0210:00178810d0dc:1")
@@ -244,7 +244,7 @@ hueActions.fadingLightCommand("color", new PercentType(100), new DecimalType(100
 |-----------|--------------------------------------------------------------------------------------------------|
 | channel   | The following channels have fade time support: **brightness, color, color_temperature, switch**  |
 | command   | All commands supported by the channel can be used                                                |
-| fadeTime  | Fade time in Milliseconds to a new light value (min="0", step="100")                             |
+| fadeTime  | Fade time in milliseconds to a new light value (min="0", step="100")                             |
 
 ## Full Example
 
index 8c94cb0f7337e5d54d4bce1bf13b3e6ca77e9619..14ab8e3a11916603df40362a5f027cf64cbba0c8 100644 (file)
@@ -14,7 +14,7 @@ package org.openhab.binding.hue.internal.action;
 
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
-import org.openhab.binding.hue.internal.handler.HueLightHandler;
+import org.openhab.binding.hue.internal.handler.HueLightActionsHandler;
 import org.openhab.core.automation.annotation.ActionInput;
 import org.openhab.core.automation.annotation.RuleAction;
 import org.openhab.core.library.types.DecimalType;
@@ -26,20 +26,19 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The {@link LightActions} defines the thing actions for the hue binding.
+ * The {@link LightActions} defines {@link ThingActions} for the hue lights.
  *
  * @author Jochen Leopold - Initial contribution
- * @author Laurent Garnier - new method invokeMethodOf + interface ILightActions
  */
 @ThingActionsScope(name = "hue")
 @NonNullByDefault
 public class LightActions implements ThingActions {
     private final Logger logger = LoggerFactory.getLogger(LightActions.class);
-    private @Nullable HueLightHandler handler;
+    private @Nullable HueLightActionsHandler handler;
 
     @Override
     public void setThingHandler(@Nullable ThingHandler handler) {
-        this.handler = (HueLightHandler) handler;
+        this.handler = (HueLightActionsHandler) handler;
     }
 
     @Override
@@ -52,8 +51,8 @@ public class LightActions implements ThingActions {
             @ActionInput(name = "channel", label = "@text/actionInputChannelLabel", description = "@text/actionInputChannelDesc") @Nullable String channel,
             @ActionInput(name = "command", label = "@text/actionInputCommandLabel", description = "@text/actionInputCommandDesc") @Nullable Command command,
             @ActionInput(name = "fadeTime", label = "@text/actionInputFadeTimeLabel", description = "@text/actionInputFadeTimeDesc") @Nullable DecimalType fadeTime) {
-        HueLightHandler lightHandler = handler;
-        if (lightHandler == null) {
+        HueLightActionsHandler lightActionsHandler = handler;
+        if (lightActionsHandler == null) {
             logger.warn("Hue Action service ThingHandler is null!");
             return;
         }
@@ -62,7 +61,6 @@ public class LightActions implements ThingActions {
             logger.debug("skipping Hue fadingLightCommand to channel '{}' due to null value.", channel);
             return;
         }
-
         if (command == null) {
             logger.debug("skipping Hue fadingLightCommand to command '{}' due to null value.", command);
             return;
@@ -72,8 +70,8 @@ public class LightActions implements ThingActions {
             return;
         }
 
-        lightHandler.handleCommand(channel, command, fadeTime.longValue());
-        logger.debug("send LightAction to {} with {}ms of fadeTime", channel, fadeTime);
+        lightActionsHandler.handleCommand(channel, command, fadeTime.longValue());
+        logger.debug("send fadingLightCommand to channel '{}' with fadeTime of {}ms.", channel, fadeTime);
     }
 
     public static void fadingLightCommand(ThingActions actions, @Nullable String channel, @Nullable Command command,
index ac887ded8f57e5b28a658539548c233bca8f689b..083286645897861133b394927014abd54d3188fa 100644 (file)
@@ -57,7 +57,8 @@ import org.slf4j.LoggerFactory;
  * @author Laurent Garnier - Initial contribution
  */
 @NonNullByDefault
-public class HueGroupHandler extends BaseThingHandler implements GroupStatusListener {
+public class HueGroupHandler extends BaseThingHandler implements HueLightActionsHandler, GroupStatusListener {
+
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_GROUP);
     public static final String PROPERTY_MEMBERS = "members";
 
@@ -168,6 +169,7 @@ public class HueGroupHandler extends BaseThingHandler implements GroupStatusList
         handleCommand(channelUID.getId(), command, defaultFadeTime);
     }
 
+    @Override
     public void handleCommand(String channel, Command command, long fadeTime) {
         HueClient bridgeHandler = getHueClient();
         if (bridgeHandler == null) {
diff --git a/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueLightActionsHandler.java b/bundles/org.openhab.binding.hue/src/main/java/org/openhab/binding/hue/internal/handler/HueLightActionsHandler.java
new file mode 100644 (file)
index 0000000..2db7988
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * 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.Collection;
+import java.util.Set;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.binding.hue.internal.action.LightActions;
+import org.openhab.core.thing.binding.ThingHandler;
+import org.openhab.core.thing.binding.ThingHandlerService;
+import org.openhab.core.types.Command;
+
+/**
+ * The {@link HueLightActionsHandler} defines interface handlers to handle {@link LightActions}.
+ *
+ * @author Christoph Weitkamp - Initial contribution
+ */
+@NonNullByDefault
+public interface HueLightActionsHandler extends ThingHandler {
+
+    @Override
+    default Collection<Class<? extends ThingHandlerService>> getServices() {
+        return Set.of(LightActions.class);
+    }
+
+    /**
+     * Handles a command for a given channel.
+     *
+     * @param channel the id of the channel to which the command was sent
+     * @param command the {@link Command}
+     * @param fadeTime duration for execution of the command
+     */
+    void handleCommand(String channel, Command command, long fadeTime);
+}
index 33c90e7946708d6bb3e094a459ac0de23fbb9a54..a4c7868beadf3e87533a70bd46322819d5dc8866 100644 (file)
@@ -16,8 +16,6 @@ import static org.openhab.binding.hue.internal.HueBindingConstants.*;
 import static org.openhab.core.thing.Thing.*;
 
 import java.math.BigDecimal;
-import java.util.Collection;
-import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
@@ -29,7 +27,6 @@ import org.eclipse.jdt.annotation.Nullable;
 import org.openhab.binding.hue.internal.FullLight;
 import org.openhab.binding.hue.internal.State;
 import org.openhab.binding.hue.internal.StateUpdate;
-import org.openhab.binding.hue.internal.action.LightActions;
 import org.openhab.binding.hue.internal.dto.Capabilities;
 import org.openhab.binding.hue.internal.dto.ColorTemperature;
 import org.openhab.core.library.types.DecimalType;
@@ -47,7 +44,6 @@ import org.openhab.core.thing.ThingStatusInfo;
 import org.openhab.core.thing.ThingTypeUID;
 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.StateDescriptionFragment;
 import org.openhab.core.types.StateDescriptionFragmentBuilder;
@@ -73,7 +69,7 @@ import org.slf4j.LoggerFactory;
  * @author Jochen Leopold - Added support for custom fade times
  */
 @NonNullByDefault
-public class HueLightHandler extends BaseThingHandler implements LightStatusListener {
+public class HueLightHandler extends BaseThingHandler implements HueLightActionsHandler, LightStatusListener {
 
     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Set.of(THING_TYPE_COLOR_LIGHT,
             THING_TYPE_COLOR_TEMPERATURE_LIGHT, THING_TYPE_DIMMABLE_LIGHT, THING_TYPE_EXTENDED_COLOR_LIGHT,
@@ -218,6 +214,7 @@ public class HueLightHandler extends BaseThingHandler implements LightStatusList
         handleCommand(channelUID.getId(), command, defaultFadeTime);
     }
 
+    @Override
     public void handleCommand(String channel, Command command, long fadeTime) {
         HueClient bridgeHandler = getHueClient();
         if (bridgeHandler == null) {
@@ -234,95 +231,95 @@ public class HueLightHandler extends BaseThingHandler implements LightStatusList
         }
 
         Integer lastColorTemp;
-        StateUpdate lightState = null;
+        StateUpdate newState = null;
         switch (channel) {
             case CHANNEL_COLORTEMPERATURE:
                 if (command instanceof PercentType) {
-                    lightState = LightStateConverter.toColorTemperatureLightStateFromPercentType((PercentType) command,
+                    newState = LightStateConverter.toColorTemperatureLightStateFromPercentType((PercentType) command,
                             colorTemperatureCapabilties);
-                    lightState.setTransitionTime(fadeTime);
+                    newState.setTransitionTime(fadeTime);
                 } else if (command instanceof OnOffType) {
-                    lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
+                    newState = LightStateConverter.toOnOffLightState((OnOffType) command);
                     if (isOsramPar16) {
-                        lightState = addOsramSpecificCommands(lightState, (OnOffType) command);
+                        newState = addOsramSpecificCommands(newState, (OnOffType) command);
                     }
                 } else if (command instanceof IncreaseDecreaseType) {
-                    lightState = convertColorTempChangeToStateUpdate((IncreaseDecreaseType) command, light);
-                    if (lightState != null) {
-                        lightState.setTransitionTime(fadeTime);
+                    newState = convertColorTempChangeToStateUpdate((IncreaseDecreaseType) command, light);
+                    if (newState != null) {
+                        newState.setTransitionTime(fadeTime);
                     }
                 }
                 break;
             case CHANNEL_COLORTEMPERATURE_ABS:
                 if (command instanceof DecimalType) {
-                    lightState = LightStateConverter.toColorTemperatureLightState((DecimalType) command,
+                    newState = LightStateConverter.toColorTemperatureLightState((DecimalType) command,
                             colorTemperatureCapabilties);
-                    lightState.setTransitionTime(fadeTime);
+                    newState.setTransitionTime(fadeTime);
                 }
                 break;
             case CHANNEL_BRIGHTNESS:
                 if (command instanceof PercentType) {
-                    lightState = LightStateConverter.toBrightnessLightState((PercentType) command);
-                    lightState.setTransitionTime(fadeTime);
+                    newState = LightStateConverter.toBrightnessLightState((PercentType) command);
+                    newState.setTransitionTime(fadeTime);
                 } else if (command instanceof OnOffType) {
-                    lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
+                    newState = LightStateConverter.toOnOffLightState((OnOffType) command);
                     if (isOsramPar16) {
-                        lightState = addOsramSpecificCommands(lightState, (OnOffType) command);
+                        newState = addOsramSpecificCommands(newState, (OnOffType) command);
                     }
                 } else if (command instanceof IncreaseDecreaseType) {
-                    lightState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, light);
-                    if (lightState != null) {
-                        lightState.setTransitionTime(fadeTime);
+                    newState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, light);
+                    if (newState != null) {
+                        newState.setTransitionTime(fadeTime);
                     }
                 }
                 lastColorTemp = lastSentColorTemp;
-                if (lightState != null && lastColorTemp != null) {
+                if (newState != null && lastColorTemp != null) {
                     // make sure that the light also has the latest color temp
                     // this might not have been yet set in the light, if it was off
-                    lightState.setColorTemperature(lastColorTemp, colorTemperatureCapabilties);
-                    lightState.setTransitionTime(fadeTime);
+                    newState.setColorTemperature(lastColorTemp, colorTemperatureCapabilties);
+                    newState.setTransitionTime(fadeTime);
                 }
                 break;
             case CHANNEL_SWITCH:
                 if (command instanceof OnOffType) {
-                    lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
+                    newState = LightStateConverter.toOnOffLightState((OnOffType) command);
                     if (isOsramPar16) {
-                        lightState = addOsramSpecificCommands(lightState, (OnOffType) command);
+                        newState = addOsramSpecificCommands(newState, (OnOffType) command);
                     }
                 }
                 lastColorTemp = lastSentColorTemp;
-                if (lightState != null && lastColorTemp != null) {
+                if (newState != null && lastColorTemp != null) {
                     // make sure that the light also has the latest color temp
                     // this might not have been yet set in the light, if it was off
-                    lightState.setColorTemperature(lastColorTemp, colorTemperatureCapabilties);
-                    lightState.setTransitionTime(fadeTime);
+                    newState.setColorTemperature(lastColorTemp, colorTemperatureCapabilties);
+                    newState.setTransitionTime(fadeTime);
                 }
                 break;
             case CHANNEL_COLOR:
                 if (command instanceof HSBType) {
                     HSBType hsbCommand = (HSBType) command;
                     if (hsbCommand.getBrightness().intValue() == 0) {
-                        lightState = LightStateConverter.toOnOffLightState(OnOffType.OFF);
+                        newState = LightStateConverter.toOnOffLightState(OnOffType.OFF);
                     } else {
-                        lightState = LightStateConverter.toColorLightState(hsbCommand, light.getState());
-                        lightState.setTransitionTime(fadeTime);
+                        newState = LightStateConverter.toColorLightState(hsbCommand, light.getState());
+                        newState.setTransitionTime(fadeTime);
                     }
                 } else if (command instanceof PercentType) {
-                    lightState = LightStateConverter.toBrightnessLightState((PercentType) command);
-                    lightState.setTransitionTime(fadeTime);
+                    newState = LightStateConverter.toBrightnessLightState((PercentType) command);
+                    newState.setTransitionTime(fadeTime);
                 } else if (command instanceof OnOffType) {
-                    lightState = LightStateConverter.toOnOffLightState((OnOffType) command);
+                    newState = LightStateConverter.toOnOffLightState((OnOffType) command);
                 } else if (command instanceof IncreaseDecreaseType) {
-                    lightState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, light);
-                    if (lightState != null) {
-                        lightState.setTransitionTime(fadeTime);
+                    newState = convertBrightnessChangeToStateUpdate((IncreaseDecreaseType) command, light);
+                    if (newState != null) {
+                        newState.setTransitionTime(fadeTime);
                     }
                 }
                 break;
             case CHANNEL_ALERT:
                 if (command instanceof StringType) {
-                    lightState = LightStateConverter.toAlertState((StringType) command);
-                    if (lightState == null) {
+                    newState = LightStateConverter.toAlertState((StringType) command);
+                    if (newState == null) {
                         // Unsupported StringType is passed. Log a warning
                         // message and return.
                         logger.warn("Unsupported String command: {}. Supported commands are: {}, {}, {} ", command,
@@ -336,21 +333,21 @@ public class HueLightHandler extends BaseThingHandler implements LightStatusList
                 break;
             case CHANNEL_EFFECT:
                 if (command instanceof OnOffType) {
-                    lightState = LightStateConverter.toOnOffEffectState((OnOffType) command);
+                    newState = LightStateConverter.toOnOffEffectState((OnOffType) command);
                 }
                 break;
         }
-        if (lightState != null) {
+        if (newState != null) {
             // Cache values which we have sent
-            Integer tmpBrightness = lightState.getBrightness();
+            Integer tmpBrightness = newState.getBrightness();
             if (tmpBrightness != null) {
                 lastSentBrightness = tmpBrightness;
             }
-            Integer tmpColorTemp = lightState.getColorTemperature();
+            Integer tmpColorTemp = newState.getColorTemperature();
             if (tmpColorTemp != null) {
                 lastSentColorTemp = tmpColorTemp;
             }
-            bridgeHandler.updateLightState(this, light, lightState, fadeTime);
+            bridgeHandler.updateLightState(this, light, newState, fadeTime);
         } else {
             logger.warn("Command sent to an unknown channel id: {}:{}", getThing().getUID(), channel);
         }
@@ -601,11 +598,6 @@ public class HueLightHandler extends BaseThingHandler implements LightStatusList
         return delay;
     }
 
-    @Override
-    public Collection<Class<? extends ThingHandlerService>> getServices() {
-        return List.of(LightActions.class);
-    }
-
     @Override
     public String getLightId() {
         return lightId;
index bfdd8cc1c250e5564abfb07b14ea2ad2cc07bd89..5d9c2500be9f3e1c5ec023f9419a8a5521f2fb6b 100644 (file)
@@ -19,7 +19,8 @@ import static org.openhab.binding.hue.internal.HueBindingConstants.*;
 
 import java.util.Map;
 
-import org.junit.jupiter.api.BeforeEach;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
 import org.junit.jupiter.api.Test;
 import org.mockito.ArgumentCaptor;
 import org.openhab.binding.hue.internal.FullConfig;
@@ -56,6 +57,7 @@ import com.google.gson.JsonParser;
  * @author Simon Kaufmann - migrated to plain Java test
  * @author Christoph Weitkamp - Added support for bulbs using CIE XY colormode only
  */
+@NonNullByDefault
 public class HueLightHandlerTest {
 
     private static final int MIN_COLOR_TEMPERATURE = 153;
@@ -66,12 +68,7 @@ public class HueLightHandlerTest {
     private static final String OSRAM_MODEL_TYPE = HueLightHandler.OSRAM_PAR16_50_TW_MODEL_ID;
     private static final String OSRAM_MODEL_TYPE_ID = HueLightHandler.OSRAM_PAR16_50_TW_MODEL_ID;
 
-    private Gson gson;
-
-    @BeforeEach
-    public void setUp() {
-        gson = new Gson();
-    }
+    private final Gson gson = new Gson();
 
     @Test
     public void assertCommandForOsramPar1650ForColorTemperatureChannelOn() {
@@ -402,12 +399,12 @@ public class HueLightHandlerTest {
 
         HueLightHandler hueLightHandler = new HueLightHandler(mockThing, mock(HueStateDescriptionProvider.class)) {
             @Override
-            protected synchronized HueClient getHueClient() {
+            protected synchronized @Nullable HueClient getHueClient() {
                 return mockClient;
             }
 
             @Override
-            protected Bridge getBridge() {
+            protected @Nullable Bridge getBridge() {
                 return mockBridge;
             }
         };