Skip to content

Commit 6ce5adb

Browse files
committed
implement support for thing actions
So far only transition time for color channels is supported Signed-off-by: Thomas Weißschuh <[email protected]>
1 parent 3c1417f commit 6ce5adb

19 files changed

+203
-34
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.openhab.binding.zigbee;
2+
3+
import org.eclipse.jdt.annotation.NonNullByDefault;
4+
5+
import java.util.Map;
6+
import java.util.Optional;
7+
8+
@NonNullByDefault
9+
public interface ZigBeeCommandParameter<T> {
10+
String getName();
11+
Optional<T> getFromMap(Map<String, Object> params);
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.openhab.binding.zigbee;
2+
3+
import org.openhab.binding.zigbee.internal.ZigBeeCommandParameterImpl;
4+
5+
public final class ZigBeeCommandParameters {
6+
private ZigBeeCommandParameters() { }
7+
public static final ZigBeeCommandParameter<Integer> TRANSITION_TIME =
8+
new ZigBeeCommandParameterImpl<>(Integer.class, "transitionTime");
9+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package org.openhab.binding.zigbee;
2+
3+
import org.eclipse.jdt.annotation.NonNull;
4+
import org.eclipse.jdt.annotation.NonNullByDefault;
5+
import org.eclipse.jdt.annotation.Nullable;
6+
import org.eclipse.smarthome.core.thing.ChannelUID;
7+
import org.eclipse.smarthome.core.thing.binding.ThingActions;
8+
import org.eclipse.smarthome.core.thing.binding.ThingActionsScope;
9+
import org.eclipse.smarthome.core.thing.binding.ThingHandler;
10+
import org.eclipse.smarthome.core.types.Command;
11+
import org.openhab.binding.zigbee.handler.ZigBeeThingHandler;
12+
import org.openhab.core.automation.annotation.ActionInput;
13+
import org.openhab.core.automation.annotation.RuleAction;
14+
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
18+
@SuppressWarnings("unused")
19+
@ThingActionsScope(name="zigbee")
20+
@NonNullByDefault
21+
public final class ZigBeeThingActions implements ThingActions {
22+
private @Nullable ZigBeeThingHandler handler;
23+
24+
@Override
25+
public void setThingHandler(@Nullable ThingHandler handler) {
26+
this.handler = (ZigBeeThingHandler) handler;
27+
}
28+
29+
@Override
30+
public @Nullable ThingHandler getThingHandler() {
31+
return handler;
32+
}
33+
34+
@RuleAction(label = "sendCommand")
35+
public void sendCommand(
36+
@ActionInput(name = "channelId", required = true) String channelId,
37+
@ActionInput(name = "command", required = true) Command command,
38+
@ActionInput(name = "params", required = true) Map<String, Object> params
39+
) {
40+
handleCommand(getChannel(channelId), command, params);
41+
}
42+
43+
private void handleCommand(ChannelUID channel, Command command, Map<String, Object> params) {
44+
handler.handleCommand(channel, command, params);
45+
}
46+
47+
private ChannelUID getChannel(String channelId) {
48+
return new ChannelUID(handler.getThing().getUID(), channelId);
49+
}
50+
51+
@RuleAction(label = "buildCommand")
52+
public CommandBuilder buildCommand(
53+
@ActionInput(name = "channelId", required = true) String channelId,
54+
@ActionInput(name = "command", required = true) Command command
55+
) {
56+
return new CommandBuilder(this, getChannel(channelId), command);
57+
}
58+
59+
public static class CommandBuilder {
60+
private final ZigBeeThingActions actions;
61+
private final ChannelUID channel;
62+
private final Command command;
63+
private final Map<String, Object> params = new HashMap<>();
64+
65+
private CommandBuilder(ZigBeeThingActions actions, ChannelUID channel, Command command) {
66+
this.actions = actions;
67+
this.channel = channel;
68+
this.command = command;
69+
}
70+
71+
public <@NonNull T> CommandBuilder with(ZigBeeCommandParameter<T> parameter, T value) {
72+
params.put(parameter.getName(), value);
73+
return this;
74+
}
75+
76+
public void send() {
77+
actions.handleCommand(channel, command, params);
78+
}
79+
}
80+
}

org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/converter/ZigBeeBaseChannelConverter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import java.math.BigDecimal;
1616
import java.math.RoundingMode;
17+
import java.util.Collections;
1718
import java.util.HashMap;
1819
import java.util.List;
1920
import java.util.Map;
@@ -251,7 +252,7 @@ public void handleRefresh() {
251252
*
252253
* @param command the {@link Command} to send
253254
*/
254-
public void handleCommand(final Command command) {
255+
public void handleCommand(final Command command, final Map<String, Object> params) {
255256
// Overridable if a channel can be commanded
256257
}
257258

org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/handler/ZigBeeThingHandler.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.eclipse.smarthome.core.thing.ThingStatusDetail;
4949
import org.eclipse.smarthome.core.thing.ThingStatusInfo;
5050
import org.eclipse.smarthome.core.thing.binding.BaseThingHandler;
51+
import org.eclipse.smarthome.core.thing.binding.ThingHandlerService;
5152
import org.eclipse.smarthome.core.thing.binding.builder.ThingBuilder;
5253
import org.eclipse.smarthome.core.thing.binding.firmware.Firmware;
5354
import org.eclipse.smarthome.core.thing.binding.firmware.FirmwareUpdateHandler;
@@ -64,6 +65,7 @@
6465
import org.openhab.binding.zigbee.discovery.ZigBeeNodePropertyDiscoverer;
6566
import org.openhab.binding.zigbee.internal.ZigBeeConfigDescriptionParameters;
6667
import org.openhab.binding.zigbee.internal.ZigBeeDeviceConfigHandler;
68+
import org.openhab.binding.zigbee.ZigBeeThingActions;
6769
import org.openhab.binding.zigbee.internal.converter.config.ZclClusterConfigFactory;
6870
import org.openhab.binding.zigbee.internal.converter.config.ZclClusterConfigHandler;
6971
import org.openhab.binding.zigbee.internal.converter.config.ZclReportingConfig;
@@ -692,8 +694,13 @@ public void handleConfigurationUpdate(Map<String, Object> configurationParameter
692694
}
693695
}
694696

697+
695698
@Override
696699
public void handleCommand(final ChannelUID channelUID, final Command command) {
700+
handleCommand(channelUID, command, Collections.emptyMap());
701+
}
702+
703+
public void handleCommand(final ChannelUID channelUID, final Command command, final Map<String, Object> params) {
697704
logger.debug("{}: Command for channel {} --> {} [{}]", nodeIeeeAddress, channelUID, command,
698705
command.getClass().getSimpleName());
699706

@@ -718,7 +725,7 @@ public void run() {
718725
if (command == RefreshType.REFRESH) {
719726
handler.handleRefresh();
720727
} else {
721-
handler.handleCommand(command);
728+
handler.handleCommand(command, params);
722729
}
723730
} catch (Exception e) {
724731
logger.debug("{}: Exception sending command to channel {}", nodeIeeeAddress, channelUID, e);
@@ -1006,4 +1013,9 @@ public boolean isUpdateExecutable() {
10061013
// Always allow the firmware to be updated
10071014
return true;
10081015
}
1016+
1017+
@Override
1018+
public Collection<Class<? extends ThingHandlerService>> getServices() {
1019+
return Collections.singleton(ZigBeeThingActions.class);
1020+
}
10091021
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.openhab.binding.zigbee.internal;
2+
3+
import org.eclipse.jdt.annotation.NonNullByDefault;
4+
import org.openhab.binding.zigbee.ZigBeeCommandParameter;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
8+
import java.util.Map;
9+
import java.util.Optional;
10+
11+
@NonNullByDefault
12+
public final class ZigBeeCommandParameterImpl<T> implements ZigBeeCommandParameter<T> {
13+
private final Logger logger;
14+
private final String name;
15+
private final Class<T> klazz;
16+
17+
public ZigBeeCommandParameterImpl(Class<T> klazz, String name) {
18+
this.logger = LoggerFactory.getLogger(ZigBeeCommandParameterImpl.class.getName() + "." + name);
19+
this.klazz = klazz;
20+
this.name = name;
21+
}
22+
23+
@Override
24+
public String getName() {
25+
return name;
26+
}
27+
28+
@Override
29+
public Optional<T> getFromMap(Map<String, Object> params) {
30+
Object param = params.get(getName());
31+
if (param == null) {
32+
return Optional.empty();
33+
} else if (!klazz.isInstance(param)) {
34+
logger.debug("Can not retrieve param {}: object of type {} ({}) can not be casted to {}",
35+
getName(), param.getClass(), (param), klazz.getName()
36+
);
37+
return Optional.empty();
38+
} else {
39+
return Optional.of(klazz.cast(param));
40+
}
41+
}
42+
}

org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/internal/converter/ZigBeeConverterColorColor.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.eclipse.smarthome.core.types.Command;
3535
import org.eclipse.smarthome.core.types.UnDefType;
3636
import org.openhab.binding.zigbee.ZigBeeBindingConstants;
37+
import org.openhab.binding.zigbee.ZigBeeCommandParameters;
3738
import org.openhab.binding.zigbee.converter.ZigBeeBaseChannelConverter;
3839
import org.openhab.binding.zigbee.internal.converter.config.ZclLevelControlConfig;
3940
import org.slf4j.Logger;
@@ -274,14 +275,14 @@ public void handleRefresh() {
274275
clusterColorControl.getColorMode(0);
275276
}
276277

277-
private void changeOnOff(OnOffType onoff) throws InterruptedException, ExecutionException {
278+
private void changeOnOff(OnOffType onoff, int transitionTime) throws InterruptedException, ExecutionException {
278279
boolean on = onoff == OnOffType.ON;
279280

280281
if (clusterOnOff == null) {
281282
if (clusterLevelControl == null) {
282283
logger.warn("{}: ignoring on/off command", endpoint.getIeeeAddress());
283284
} else {
284-
changeBrightness(on ? PercentType.HUNDRED : PercentType.ZERO);
285+
changeBrightness(on ? PercentType.HUNDRED : PercentType.ZERO, transitionTime);
285286
}
286287
return;
287288
}
@@ -293,12 +294,12 @@ private void changeOnOff(OnOffType onoff) throws InterruptedException, Execution
293294
}
294295
}
295296

296-
private void changeBrightness(PercentType brightness) throws InterruptedException, ExecutionException {
297+
private void changeBrightness(PercentType brightness, int transitionTime) throws InterruptedException, ExecutionException {
297298
if (clusterLevelControl == null) {
298299
if (clusterOnOff == null) {
299300
logger.warn("{}: ignoring brightness command", endpoint.getIeeeAddress());
300301
} else {
301-
changeOnOff(brightness.intValue() == 0 ? OnOffType.OFF : OnOffType.ON);
302+
changeOnOff(brightness.intValue() == 0 ? OnOffType.OFF : OnOffType.ON, transitionTime);
302303
}
303304
return;
304305
}
@@ -309,55 +310,56 @@ private void changeBrightness(PercentType brightness) throws InterruptedExceptio
309310
if (brightness.equals(PercentType.ZERO)) {
310311
clusterOnOff.offCommand();
311312
} else {
312-
clusterLevelControl.moveToLevelWithOnOffCommand(level, configLevelControl.getDefaultTransitionTime())
313+
clusterLevelControl.moveToLevelWithOnOffCommand(level, transitionTime)
313314
.get();
314315
}
315316
} else {
316-
clusterLevelControl.moveToLevelCommand(level, configLevelControl.getDefaultTransitionTime()).get();
317+
clusterLevelControl.moveToLevelCommand(level, transitionTime).get();
317318
}
318319
}
319320

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

324325
clusterColorControl
325-
.moveToHueAndSaturationCommand(hue, saturation, configLevelControl.getDefaultTransitionTime()).get();
326+
.moveToHueAndSaturationCommand(hue, saturation, transitionTime).get();
326327
}
327328

328-
private void changeColorXY(HSBType color) throws InterruptedException, ExecutionException {
329+
private void changeColorXY(HSBType color, int transitionTime) throws InterruptedException, ExecutionException {
329330
PercentType xy[] = color.toXY();
330331

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

336-
clusterColorControl.moveToColorCommand(x, y, configLevelControl.getDefaultTransitionTime()).get();
337+
clusterColorControl.moveToColorCommand(x, y, transitionTime).get();
337338
}
338339

339340
@Override
340-
public void handleCommand(final Command command) {
341+
public void handleCommand(final Command command, final Map<String, Object> params) {
342+
int transitionTime = ZigBeeCommandParameters.TRANSITION_TIME.getFromMap(params).orElseGet(configLevelControl::getDefaultTransitionTime);
341343
try {
342344
if (command instanceof HSBType) {
343345
HSBType color = (HSBType) command;
344346
PercentType brightness = color.getBrightness();
345347

346-
changeBrightness(brightness);
348+
changeBrightness(brightness, transitionTime);
347349

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

352354
if (supportsHue) {
353-
changeColorHueSaturation(color);
355+
changeColorHueSaturation(color, transitionTime);
354356
} else {
355-
changeColorXY(color);
357+
changeColorXY(color, transitionTime);
356358
}
357359
} else if (command instanceof PercentType) {
358-
changeBrightness((PercentType) command);
360+
changeBrightness((PercentType) command, transitionTime);
359361
} else if (command instanceof OnOffType) {
360-
changeOnOff((OnOffType) command);
362+
changeOnOff((OnOffType) command, transitionTime);
361363
}
362364
} catch (InterruptedException | ExecutionException e) {
363365
logger.warn("{}: Exception processing command", endpoint.getIeeeAddress(), e);

org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/internal/converter/ZigBeeConverterColorTemperature.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import static com.zsmartsystems.zigbee.zcl.clusters.ZclColorControlCluster.ATTR_COLORTEMPERATURE;
1616

17+
import java.util.Map;
1718
import java.util.concurrent.ExecutionException;
1819

1920
import org.eclipse.smarthome.core.library.types.OnOffType;
@@ -24,6 +25,7 @@
2425
import org.eclipse.smarthome.core.types.Command;
2526
import org.eclipse.smarthome.core.types.UnDefType;
2627
import org.openhab.binding.zigbee.ZigBeeBindingConstants;
28+
import org.openhab.binding.zigbee.ZigBeeCommandParameters;
2729
import org.openhab.binding.zigbee.converter.ZigBeeBaseChannelConverter;
2830
import org.slf4j.Logger;
2931
import org.slf4j.LoggerFactory;
@@ -119,7 +121,8 @@ public void handleRefresh() {
119121
}
120122

121123
@Override
122-
public void handleCommand(final Command command) {
124+
public void handleCommand(final Command command, final Map<String, Object> params) {
125+
int transitionTime = ZigBeeCommandParameters.TRANSITION_TIME.getFromMap(params).orElse(10);
123126
PercentType colorTemperaturePercentage = PercentType.ZERO;
124127
if (command instanceof PercentType) {
125128
colorTemperaturePercentage = (PercentType) command;
@@ -128,7 +131,7 @@ public void handleCommand(final Command command) {
128131
return;
129132
}
130133

131-
clusterColorControl.moveToColorTemperatureCommand(percentToMired(colorTemperaturePercentage), 10);
134+
clusterColorControl.moveToColorTemperatureCommand(percentToMired(colorTemperaturePercentage), transitionTime);
132135
}
133136

134137
@Override

org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/internal/converter/ZigBeeConverterDoorLock.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
package org.openhab.binding.zigbee.internal.converter;
1414

15+
import java.util.Map;
1516
import java.util.concurrent.ExecutionException;
1617

1718
import org.eclipse.smarthome.core.library.types.OnOffType;
@@ -95,7 +96,7 @@ public void handleRefresh() {
9596
}
9697

9798
@Override
98-
public void handleCommand(final Command command) {
99+
public void handleCommand(final Command command, final Map<String, Object> params) {
99100
if (command == OnOffType.ON) {
100101
cluster.lockDoorCommand(new ByteArray(new byte[0]));
101102
} else {

org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/internal/converter/ZigBeeConverterFanControl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
package org.openhab.binding.zigbee.internal.converter;
1414

15+
import java.util.Map;
1516
import java.util.concurrent.ExecutionException;
1617

1718
import org.eclipse.smarthome.core.library.types.DecimalType;
@@ -106,7 +107,7 @@ public void handleRefresh() {
106107
}
107108

108109
@Override
109-
public void handleCommand(final Command command) {
110+
public void handleCommand(final Command command, Map<String, Object> params) {
110111
int value;
111112
if (command instanceof OnOffType) {
112113
value = command == OnOffType.ON ? MODE_ON : MODE_OFF;

org.openhab.binding.zigbee/src/main/java/org/openhab/binding/zigbee/internal/converter/ZigBeeConverterSwitchLevel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ public void handleRefresh() {
331331
}
332332

333333
@Override
334-
public void handleCommand(final Command command) {
334+
public void handleCommand(final Command command, final Map<String, Object> params) {
335335
if (command instanceof OnOffType) {
336336
handleOnOffCommand((OnOffType) command);
337337
} else if (command instanceof PercentType) {

0 commit comments

Comments
 (0)