Skip to content

Commit

Permalink
[hue] Added LightActions to Hue light groups (#11452)
Browse files Browse the repository at this point in the history
Signed-off-by: Christoph Weitkamp <github@christophweitkamp.de>
  • Loading branch information
cweitkamp authored Oct 26, 2021
1 parent a1b3f27 commit 4d5fd84
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 73 deletions.
4 changes: 2 additions & 2 deletions bundles/org.openhab.binding.hue/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

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;
Expand All @@ -26,20 +26,19 @@
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
Expand All @@ -52,8 +51,8 @@ public void fadingLightCommand(
@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;
}
Expand All @@ -62,7 +61,6 @@ public void fadingLightCommand(
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;
Expand All @@ -72,8 +70,8 @@ public void fadingLightCommand(
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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@
* @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";

Expand Down Expand Up @@ -168,6 +169,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
handleCommand(channelUID.getId(), command, defaultFadeTime);
}

@Override
public void handleCommand(String channel, Command command, long fadeTime) {
HueClient bridgeHandler = getHueClient();
if (bridgeHandler == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@
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;
Expand All @@ -29,7 +27,6 @@
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;
Expand All @@ -47,7 +44,6 @@
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;
Expand All @@ -73,7 +69,7 @@
* @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,
Expand Down Expand Up @@ -218,6 +214,7 @@ public void handleCommand(ChannelUID channelUID, Command command) {
handleCommand(channelUID.getId(), command, defaultFadeTime);
}

@Override
public void handleCommand(String channel, Command command, long fadeTime) {
HueClient bridgeHandler = getHueClient();
if (bridgeHandler == null) {
Expand All @@ -234,95 +231,95 @@ public void handleCommand(String channel, Command command, long fadeTime) {
}

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,
Expand All @@ -336,21 +333,21 @@ public void handleCommand(String channel, Command command, long fadeTime) {
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);
}
Expand Down Expand Up @@ -601,11 +598,6 @@ private int getAlertDuration(Command command) {
return delay;
}

@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return List.of(LightActions.class);
}

@Override
public String getLightId() {
return lightId;
Expand Down
Loading

0 comments on commit 4d5fd84

Please sign in to comment.