Skip to content

Commit

Permalink
implement support for thing actions
Browse files Browse the repository at this point in the history
So far only transition time for color channels is supported

Signed-off-by: Thomas Weißschuh <thomas@weissschuh.net>
  • Loading branch information
t-8ch committed Feb 23, 2019
1 parent c3c9e08 commit d3f3a5b
Show file tree
Hide file tree
Showing 12 changed files with 179 additions and 24 deletions.
2 changes: 2 additions & 0 deletions org.openhab.binding.zigbee/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ Import-Package: com.thoughtworks.xstream,
org.mockito;resolution:=optional,
org.mockito.invocation;resolution:=optional,
org.mockito.stubbing;resolution:=optional,
org.openhab.core.automation.annotation;resolution:=optional,
org.objenesis;resolution:=optional,
org.osgi.framework,
org.osgi.service.component.annotations;resolution:=optional,
org.slf4j
Service-Component: OSGI-INF/*.xml
Export-Package: org.openhab.binding.zigbee,
org.openhab.binding.zigbee.action,
org.openhab.binding.zigbee.converter,
org.openhab.binding.zigbee.discovery,
org.openhab.binding.zigbee.handler
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.openhab.binding.zigbee.action;

import java.util.Map;
import java.util.Optional;

public interface ZigBeeThingActionParameter<T> {
String getName();
Optional<T> getFromMap(Map<String, Object> params);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.openhab.binding.zigbee.action;

import org.openhab.binding.zigbee.action.internal.ZigBeeThingActionParameterImpl;

public final class ZigBeeThingActionParameters {
private ZigBeeThingActionParameters() { }
public static final ZigBeeThingActionParameter<Integer> TRANSITION_TIME =
new ZigBeeThingActionParameterImpl<>(Integer.class, "transitionTime");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package org.openhab.binding.zigbee.action;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.smarthome.core.thing.ChannelUID;
import org.eclipse.smarthome.core.thing.binding.ThingActions;
import org.eclipse.smarthome.core.thing.binding.ThingActionsScope;
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
import org.eclipse.smarthome.core.types.Command;
import org.openhab.binding.zigbee.handler.ZigBeeThingHandler;
import org.openhab.core.automation.annotation.ActionInput;
import org.openhab.core.automation.annotation.RuleAction;

import java.util.HashMap;
import java.util.Map;

@SuppressWarnings("unused")
@ThingActionsScope(name="zigbee")
@NonNullByDefault
public class ZigBeeThingActions implements ThingActions {
private ZigBeeThingHandler handler;

@Override
public void setThingHandler(ThingHandler handler) {
this.handler = (ZigBeeThingHandler) handler;
}

@Override
public ThingHandler getThingHandler() {
return handler;
}

@RuleAction(label = "sendCommand")
public void sendCommand(
@ActionInput(name = "channelId", required = true) String channelId,
@ActionInput(name = "command", required = true) Command command,
@ActionInput(name = "params", required = true) Map<String, Object> params
) {
ChannelUID channel = new ChannelUID(handler.getThing().getUID(), channelId);
handleCommand(channel, command, params);
}

private void handleCommand(ChannelUID channel, Command command, Map<String, Object> params) {
handler.handleCommand(channel, command, params);
}

@RuleAction(label = "buildCommand")
public CommandBuilder buildCommand(
@ActionInput(name = "channelId", required = true) String channelId,
@ActionInput(name = "command", required = true) Command command
) {
ChannelUID channel = new ChannelUID(handler.getThing().getUID(), channelId);
return new CommandBuilder(this, channel, command);
}

public static class CommandBuilder {
private final ZigBeeThingActions actions;
private final ChannelUID channel;
private final Command command;
private final Map<String, Object> params = new HashMap<>();

private CommandBuilder(ZigBeeThingActions actions, ChannelUID channel, Command command) {
this.actions = actions;
this.channel = channel;
this.command = command;
}

public <T> CommandBuilder with(ZigBeeThingActionParameter<T> parameter, T value) {
params.put(parameter.getName(), value);
return this;
}

public void send() {
actions.handleCommand(channel, command, params);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.openhab.binding.zigbee.action.internal;

import org.openhab.binding.zigbee.action.ZigBeeThingActionParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.Optional;

public final class ZigBeeThingActionParameterImpl<T> implements ZigBeeThingActionParameter<T> {
private final Logger logger = LoggerFactory.getLogger(ZigBeeThingActionParameterImpl.class);

private final String name;
private final Class<T> klazz;

public ZigBeeThingActionParameterImpl(Class<T> klazz, String name) {
this.klazz = klazz;
this.name = name;
}

@Override
public String getName() {
return name;
}

@Override
public Optional<T> getFromMap(Map<String, Object> params) {
Object param = params.get(getName());
if (param == null) {
return Optional.empty();
} else if (!klazz.isInstance(param)) {
logger.debug("Can not retrieve param {}: object of type {} ({}) can not be casted to {}",
getName(), param.getClass(), (param), klazz.getName()
);
return Optional.empty();
} else {
return Optional.of(klazz.cast(param));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public void handleRefresh() {
*
* @param command the {@link Command} to send
*/
public void handleCommand(final Command command) {
public void handleCommand(final Command command, final Map<String, Object> params) {
// Overridable if a channel can be commanded
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/*
* Copyright (c) 2010-2018 by the respective copyright holders.
*
* All rights reserved. This program and the accompanying materials
Expand Down Expand Up @@ -42,6 +42,7 @@
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
import org.eclipse.smarthome.core.thing.ThingStatusInfo;
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
import org.eclipse.smarthome.core.thing.binding.ThingHandlerService;
import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder;
import org.eclipse.smarthome.core.thing.binding.firmware.Firmware;
import org.eclipse.smarthome.core.thing.binding.firmware.FirmwareUpdateHandler;
Expand All @@ -57,6 +58,7 @@
import org.openhab.binding.zigbee.converter.ZigBeeChannelConverterFactory;
import org.openhab.binding.zigbee.discovery.ZigBeeNodePropertyDiscoverer;
import org.openhab.binding.zigbee.internal.ZigBeeDeviceConfigHandler;
import org.openhab.binding.zigbee.action.ZigBeeThingActions;
import org.openhab.binding.zigbee.internal.converter.config.ZclClusterConfigFactory;
import org.openhab.binding.zigbee.internal.converter.config.ZclClusterConfigHandler;
import org.openhab.binding.zigbee.internal.converter.config.ZclReportingConfig;
Expand Down Expand Up @@ -595,8 +597,13 @@ public void handleConfigurationUpdate(Map<String, Object> configurationParameter
updateConfiguration(configuration);
}


@Override
public void handleCommand(final ChannelUID channelUID, final Command command) {
handleCommand(channelUID, command, Collections.emptyMap());
}

public void handleCommand(final ChannelUID channelUID, final Command command, final Map<String, Object> params) {
logger.debug("{}: Command for channel {} --> {} [{}]", nodeIeeeAddress, channelUID, command,
command.getClass().getSimpleName());

Expand All @@ -621,7 +628,7 @@ public void run() {
if (command == RefreshType.REFRESH) {
handler.handleRefresh();
} else {
handler.handleCommand(command);
handler.handleCommand(command, params);
}
} catch (Exception e) {
logger.debug("{}: Exception sending command to channel {}", nodeIeeeAddress, channelUID, e);
Expand Down Expand Up @@ -907,4 +914,9 @@ public boolean isUpdateExecutable() {
// Always allow the firmware to be updated
return true;
}

@Override
public Collection<Class<? extends ThingHandlerService>> getServices() {
return Collections.singleton(ZigBeeThingActions.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.zigbee.ZigBeeBindingConstants;
import org.openhab.binding.zigbee.action.ZigBeeThingActionParameters;
import org.openhab.binding.zigbee.converter.ZigBeeBaseChannelConverter;
import org.openhab.binding.zigbee.internal.converter.config.ZclLevelControlConfig;
import org.slf4j.Logger;
Expand Down Expand Up @@ -246,14 +247,14 @@ public void handleRefresh() {
clusterColorControl.getColorMode(0);
}

private void changeOnOff(OnOffType onoff) throws InterruptedException, ExecutionException {
private void changeOnOff(OnOffType onoff, int transitionTime) throws InterruptedException, ExecutionException {
boolean on = onoff == OnOffType.ON;

if (clusterOnOff == null) {
if (clusterLevelControl == null) {
logger.warn("{}: ignoring on/off command", endpoint.getIeeeAddress());
} else {
changeBrightness(on ? PercentType.HUNDRED : PercentType.ZERO);
changeBrightness(on ? PercentType.HUNDRED : PercentType.ZERO, transitionTime);
}
return;
}
Expand All @@ -265,12 +266,12 @@ private void changeOnOff(OnOffType onoff) throws InterruptedException, Execution
}
}

private void changeBrightness(PercentType brightness) throws InterruptedException, ExecutionException {
private void changeBrightness(PercentType brightness, int transitionTime) throws InterruptedException, ExecutionException {
if (clusterLevelControl == null) {
if (clusterOnOff == null) {
logger.warn("{}: ignoring brightness command", endpoint.getIeeeAddress());
} else {
changeOnOff(brightness.intValue() == 0 ? OnOffType.OFF : OnOffType.ON);
changeOnOff(brightness.intValue() == 0 ? OnOffType.OFF : OnOffType.ON, transitionTime);
}
return;
}
Expand All @@ -281,55 +282,56 @@ private void changeBrightness(PercentType brightness) throws InterruptedExceptio
if (brightness.equals(PercentType.ZERO)) {
clusterOnOff.offCommand();
} else {
clusterLevelControl.moveToLevelWithOnOffCommand(level, configLevelControl.getDefaultTransitionTime())
clusterLevelControl.moveToLevelWithOnOffCommand(level, transitionTime)
.get();
}
} else {
clusterLevelControl.moveToLevelCommand(level, configLevelControl.getDefaultTransitionTime()).get();
clusterLevelControl.moveToLevelCommand(level, transitionTime).get();
}
}

private void changeColorHueSaturation(HSBType color) throws InterruptedException, ExecutionException {
private void changeColorHueSaturation(HSBType color, int transitionTime) throws InterruptedException, ExecutionException {
int hue = (int) (color.getHue().floatValue() * 254.0f / 360.0f + 0.5f);
int saturation = percentToLevel(color.getSaturation());

clusterColorControl
.moveToHueAndSaturationCommand(hue, saturation, configLevelControl.getDefaultTransitionTime()).get();
.moveToHueAndSaturationCommand(hue, saturation, transitionTime).get();
}

private void changeColorXY(HSBType color) throws InterruptedException, ExecutionException {
private void changeColorXY(HSBType color, int transitionTime) throws InterruptedException, ExecutionException {
PercentType xy[] = color.toXY();

logger.debug("{}: Change Color HSV ({}, {}, {}) -> XY ({}, {})", endpoint.getIeeeAddress(), color.getHue(),
color.getSaturation(), color.getBrightness(), xy[0], xy[1]);
int x = (int) (xy[0].floatValue() / 100.0f * 65536.0f + 0.5f); // up to 65279
int y = (int) (xy[1].floatValue() / 100.0f * 65536.0f + 0.5f); // up to 65279

clusterColorControl.moveToColorCommand(x, y, configLevelControl.getDefaultTransitionTime()).get();
clusterColorControl.moveToColorCommand(x, y, transitionTime).get();
}

@Override
public void handleCommand(final Command command) {
public void handleCommand(final Command command, final Map<String, Object> params) {
int transitionTime = ZigBeeThingActionParameters.TRANSITION_TIME.getFromMap(params).orElseGet(configLevelControl::getDefaultTransitionTime);
try {
if (command instanceof HSBType) {
HSBType color = (HSBType) command;
PercentType brightness = color.getBrightness();

changeBrightness(brightness);
changeBrightness(brightness, transitionTime);

if (delayedColorChange && brightness.intValue() != lastHSB.getBrightness().intValue()) {
Thread.sleep(1100);
}

if (supportsHue) {
changeColorHueSaturation(color);
changeColorHueSaturation(color, transitionTime);
} else {
changeColorXY(color);
changeColorXY(color, transitionTime);
}
} else if (command instanceof PercentType) {
changeBrightness((PercentType) command);
changeBrightness((PercentType) command, transitionTime);
} else if (command instanceof OnOffType) {
changeOnOff((OnOffType) command);
changeOnOff((OnOffType) command, transitionTime);
}
} catch (InterruptedException | ExecutionException e) {
logger.warn("{}: Exception processing command", endpoint.getIeeeAddress(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
package org.openhab.binding.zigbee.internal.converter;

import java.util.Map;
import java.util.concurrent.ExecutionException;

import org.eclipse.smarthome.core.library.types.OnOffType;
Expand All @@ -18,6 +19,7 @@
import org.eclipse.smarthome.core.types.Command;
import org.eclipse.smarthome.core.types.UnDefType;
import org.openhab.binding.zigbee.ZigBeeBindingConstants;
import org.openhab.binding.zigbee.action.ZigBeeThingActionParameters;
import org.openhab.binding.zigbee.converter.ZigBeeBaseChannelConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -105,7 +107,8 @@ public void handleRefresh() {
}

@Override
public void handleCommand(final Command command) {
public void handleCommand(final Command command, final Map<String, Object> params) {
int transitionTime = ZigBeeThingActionParameters.TRANSITION_TIME.getFromMap(params).orElse(10);
PercentType colorTemperaturePercentage = PercentType.ZERO;
if (command instanceof PercentType) {
colorTemperaturePercentage = (PercentType) command;
Expand All @@ -114,7 +117,7 @@ public void handleCommand(final Command command) {
return;
}

clusterColorControl.moveToColorTemperatureCommand(percentToMired(colorTemperaturePercentage), 10);
clusterColorControl.moveToColorTemperatureCommand(percentToMired(colorTemperaturePercentage), transitionTime);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/
package org.openhab.binding.zigbee.internal.converter;

import java.util.Map;
import java.util.concurrent.ExecutionException;

import org.eclipse.smarthome.core.library.types.OnOffType;
Expand Down Expand Up @@ -81,7 +82,7 @@ public void handleRefresh() {
}

@Override
public void handleCommand(final Command command) {
public void handleCommand(final Command command, final Map<String, Object> params) {
if (command == OnOffType.ON) {
cluster.lockDoorCommand(new ByteArray(new byte[0]));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public void handleRefresh() {
}

@Override
public void handleCommand(final Command command) {
public void handleCommand(final Command command, final Map<String, Object> params) {
if (command instanceof OnOffType) {
handleOnOffCommand((OnOffType) command);
} else if (command instanceof PercentType) {
Expand Down
Loading

0 comments on commit d3f3a5b

Please sign in to comment.