Skip to content

Commit 6a3afb0

Browse files
Migrate controller & device node actions from config actions to Thing actions (openhab#2015)
* Migrate controller actions from config actions to Thing actions Related to openhab/openhab-addons#17992. Signed-off-by: Florian Hotze <dev@florianhotze.com> * Migrate device node actions from config actions to Thing actions Related to openhab/openhab-addons#17992. Signed-off-by: Florian Hotze <dev@florianhotze.com> # Conflicts: # src/main/java/org/openhab/binding/zwave/handler/ZWaveThingHandler.java * Localize Thing action labels and descriptions Signed-off-by: Florian Hotze <dev@florianhotze.com> * Clean-up actions group Signed-off-by: Florian Hotze <dev@florianhotze.com> * Edit the action messages Edit the action messages to address historical forum confusions. Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com> * Set some actions' visibility to expert Signed-off-by: Florian Hotze <dev@florianhotze.com> * Exclusion action: Hint how much time is left Signed-off-by: Florian Hotze <dev@florianhotze.com> --------- Signed-off-by: Florian Hotze <dev@florianhotze.com> Signed-off-by: Bob Eckhoff <katmandodo@yahoo.com> Co-authored-by: Bob Eckhoff <katmandodo@yahoo.com>
1 parent 1e73058 commit 6a3afb0

9 files changed

Lines changed: 344 additions & 104 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright (c) 2010-2025 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.zwave.actions;
14+
15+
import java.time.LocalTime;
16+
import java.time.format.DateTimeFormatter;
17+
18+
import org.eclipse.jdt.annotation.NonNullByDefault;
19+
import org.eclipse.jdt.annotation.Nullable;
20+
import org.openhab.binding.zwave.handler.ZWaveControllerHandler;
21+
import org.openhab.binding.zwave.internal.protocol.ZWaveController;
22+
import org.openhab.core.automation.Visibility;
23+
import org.openhab.core.automation.annotation.ActionOutput;
24+
import org.openhab.core.automation.annotation.RuleAction;
25+
import org.openhab.core.thing.binding.ThingActions;
26+
import org.openhab.core.thing.binding.ThingActionsScope;
27+
import org.openhab.core.thing.binding.ThingHandler;
28+
import org.osgi.service.component.annotations.Component;
29+
import org.osgi.service.component.annotations.ServiceScope;
30+
31+
/**
32+
* Implementation of the {@link ThingActions} interface used for executing Z-Wave controller actions.
33+
*
34+
* @author Florian Hotze - Initial contribution
35+
*/
36+
@Component(scope = ServiceScope.PROTOTYPE, service = ZWaveControllerActions.class)
37+
@ThingActionsScope(name = "zwave")
38+
@NonNullByDefault
39+
public class ZWaveControllerActions implements ThingActions {
40+
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
41+
42+
private @Nullable ZWaveControllerHandler handler;
43+
44+
public static boolean softReset(ThingActions actions) {
45+
if (actions instanceof ZWaveControllerActions controllerActions) {
46+
return controllerActions.softReset();
47+
} else {
48+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveControllerActions");
49+
}
50+
}
51+
52+
public static boolean hardReset(ThingActions actions) {
53+
if (actions instanceof ZWaveControllerActions controllerActions) {
54+
return controllerActions.hardReset();
55+
} else {
56+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveControllerActions");
57+
}
58+
}
59+
60+
public static String exclude(ThingActions actions) {
61+
if (actions instanceof ZWaveControllerActions controllerActions) {
62+
return controllerActions.exclude();
63+
} else {
64+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveControllerActions");
65+
}
66+
}
67+
68+
public static boolean sync(ThingActions actions) {
69+
if (actions instanceof ZWaveControllerActions controllerActions) {
70+
return controllerActions.sync();
71+
} else {
72+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveControllerActions");
73+
}
74+
}
75+
76+
@Override
77+
public void setThingHandler(@Nullable ThingHandler handler) {
78+
this.handler = (ZWaveControllerHandler) handler;
79+
}
80+
81+
@Override
82+
public @Nullable ThingHandler getThingHandler() {
83+
return handler;
84+
}
85+
86+
@RuleAction(label = "@text/actions.controller-soft-reset.label", description = "@text/actions.controller-soft-reset.description")
87+
public @ActionOutput(type = "boolean", label = "Success") boolean softReset() {
88+
ZWaveController controller = getController();
89+
if (controller != null) {
90+
controller.requestSoftReset();
91+
return true;
92+
}
93+
return false;
94+
}
95+
96+
@RuleAction(label = "@text/actions.controller-hard-reset.label", description = "@text/actions.controller-hard-reset.description")
97+
public @ActionOutput(type = "boolean", label = "Success") boolean hardReset() {
98+
ZWaveController controller = getController();
99+
if (controller != null) {
100+
controller.requestHardReset();
101+
return true;
102+
}
103+
return false;
104+
}
105+
106+
@RuleAction(label = "@text/actions.controller-exclude.label", description = "@text/actions.controller-exclude.description")
107+
public @ActionOutput(type = "String") String exclude() {
108+
ZWaveController controller = getController();
109+
if (controller != null) {
110+
Integer countdown = controller.requestRemoveNodesStart();
111+
if (countdown != null) {
112+
LocalTime time = LocalTime.now().plusSeconds(countdown);
113+
return "Controller in exclusion mode until " + time.format(TIME_FORMATTER) + ".";
114+
}
115+
}
116+
return "Failed to put controller in exclusion mode.";
117+
}
118+
119+
@RuleAction(label = "@text/actions.controller-sync.label", description = "@text/actions.controller-sync.description", visibility = Visibility.EXPERT)
120+
public @ActionOutput(type = "boolean", label = "Success") boolean sync() {
121+
ZWaveController controller = getController();
122+
if (controller != null) {
123+
controller.requestNetworkUpdate();
124+
return true;
125+
}
126+
return false;
127+
}
128+
129+
private @Nullable ZWaveController getController() {
130+
ZWaveControllerHandler handler = this.handler;
131+
if (handler != null) {
132+
return handler.getController();
133+
}
134+
return null;
135+
}
136+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright (c) 2010-2025 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.binding.zwave.actions;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.eclipse.jdt.annotation.Nullable;
17+
import org.openhab.binding.zwave.handler.ZWaveThingHandler;
18+
import org.openhab.core.automation.Visibility;
19+
import org.openhab.core.automation.annotation.ActionOutput;
20+
import org.openhab.core.automation.annotation.RuleAction;
21+
import org.openhab.core.thing.binding.ThingActions;
22+
import org.openhab.core.thing.binding.ThingActionsScope;
23+
import org.openhab.core.thing.binding.ThingHandler;
24+
import org.osgi.service.component.annotations.Component;
25+
import org.osgi.service.component.annotations.ServiceScope;
26+
27+
/**
28+
* Implementation of the {@link ThingActions} interface used for executing Z-Wave device node actions.
29+
*
30+
* @author Florian Hotze - Initial contribution
31+
*/
32+
@Component(scope = ServiceScope.PROTOTYPE, service = ZWaveThingActions.class)
33+
@ThingActionsScope(name = "zwave")
34+
@NonNullByDefault
35+
public class ZWaveThingActions implements ThingActions {
36+
private @Nullable ZWaveThingHandler handler;
37+
38+
public static boolean setNodeAsFailed(ThingActions actions) {
39+
if (actions instanceof ZWaveThingActions nodeActions) {
40+
return nodeActions.setNodeAsFailed();
41+
} else {
42+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveThingActions");
43+
}
44+
}
45+
46+
public static boolean removeFailedNode(ThingActions actions) {
47+
if (actions instanceof ZWaveThingActions nodeActions) {
48+
return nodeActions.removeFailedNode();
49+
} else {
50+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveThingActions");
51+
}
52+
}
53+
54+
public static boolean reinitNode(ThingActions actions) {
55+
if (actions instanceof ZWaveThingActions nodeActions) {
56+
return nodeActions.reinitNode();
57+
} else {
58+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveThingActions");
59+
}
60+
}
61+
62+
public static boolean healNode(ThingActions actions) {
63+
if (actions instanceof ZWaveThingActions nodeActions) {
64+
return nodeActions.healNode();
65+
} else {
66+
throw new IllegalArgumentException("The 'actions' argument is not an instance of ZWaveThingActions");
67+
}
68+
}
69+
70+
@Override
71+
public void setThingHandler(ThingHandler thingHandler) {
72+
this.handler = (ZWaveThingHandler) thingHandler;
73+
}
74+
75+
@Override
76+
public @Nullable ThingHandler getThingHandler() {
77+
return handler;
78+
}
79+
80+
@RuleAction(label = "@text/actions.node-failed.label", description = "@text/actions.node-failed.description", visibility = Visibility.EXPERT)
81+
public @ActionOutput(type = "boolean", label = "Success") boolean setNodeAsFailed() {
82+
ZWaveThingHandler handler = this.handler;
83+
if (handler != null) {
84+
return handler.setNodeAsFailed();
85+
}
86+
return false;
87+
}
88+
89+
@RuleAction(label = "@text/actions.node-remove.label", description = "@text/actions.node-remove.description", visibility = Visibility.EXPERT)
90+
public @ActionOutput(type = "boolean", label = "Success") boolean removeFailedNode() {
91+
ZWaveThingHandler handler = this.handler;
92+
if (handler != null) {
93+
return handler.removeFailedNode();
94+
}
95+
return false;
96+
}
97+
98+
@RuleAction(label = "@text/actions.node-reinit.label", description = "@text/actions.node-reinit.description")
99+
public @ActionOutput(type = "boolean", label = "Success") boolean reinitNode() {
100+
ZWaveThingHandler handler = this.handler;
101+
if (handler != null) {
102+
return handler.reinitNode();
103+
}
104+
return false;
105+
}
106+
107+
@RuleAction(label = "@text/actions.node-heal.label", description = "@text/actions.node-heal.description")
108+
public @ActionOutput(type = "boolean", label = "Success") boolean healNode() {
109+
ZWaveThingHandler handler = this.handler;
110+
if (handler != null) {
111+
return handler.healNode();
112+
}
113+
return false;
114+
}
115+
}

src/main/java/org/openhab/binding/zwave/handler/ZWaveControllerHandler.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.Collection;
2020
import java.util.HashMap;
2121
import java.util.HashSet;
22+
import java.util.List;
2223
import java.util.Map;
2324
import java.util.Map.Entry;
2425
import java.util.Objects;
@@ -28,6 +29,7 @@
2829

2930
import org.eclipse.jdt.annotation.NonNull;
3031
import org.openhab.binding.zwave.ZWaveBindingConstants;
32+
import org.openhab.binding.zwave.actions.ZWaveControllerActions;
3133
import org.openhab.binding.zwave.internal.protocol.SerialMessage;
3234
import org.openhab.binding.zwave.internal.protocol.ZWaveController;
3335
import org.openhab.binding.zwave.internal.protocol.ZWaveDeviceClass.Specific;
@@ -46,6 +48,7 @@
4648
import org.openhab.core.thing.ThingStatusDetail;
4749
import org.openhab.core.thing.UID;
4850
import org.openhab.core.thing.binding.BaseBridgeHandler;
51+
import org.openhab.core.thing.binding.ThingHandlerService;
4952
import org.openhab.core.types.Command;
5053
import org.slf4j.Logger;
5154
import org.slf4j.LoggerFactory;
@@ -83,6 +86,11 @@ public ZWaveControllerHandler(@NonNull Bridge bridge) {
8386
super(bridge);
8487
}
8588

89+
@Override
90+
public Collection<Class<? extends ThingHandlerService>> getServices() {
91+
return List.of(ZWaveControllerActions.class);
92+
}
93+
8694
@Override
8795
public void initialize() {
8896
logger.debug("Initializing ZWave Controller {}.", getThing().getUID());
@@ -170,6 +178,10 @@ public void initialize() {
170178
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE, ZWaveBindingConstants.OFFLINE_CTLR_OFFLINE);
171179
}
172180

181+
public ZWaveController getController() {
182+
return controller;
183+
}
184+
173185
/**
174186
* Common initialisation point for all ZWave controllers.
175187
* Called by bridges after they have initialised their interfaces.
@@ -325,19 +337,7 @@ public void handleConfigurationUpdate(Map<String, Object> configurationParameter
325337
continue;
326338
}
327339

328-
if (cfg[1].equals("softreset") && value instanceof Boolean && ((Boolean) value) == true) {
329-
controller.requestSoftReset();
330-
value = false;
331-
} else if (cfg[1].equals("hardreset") && value instanceof Boolean && ((Boolean) value) == true) {
332-
controller.requestHardReset();
333-
value = false;
334-
} else if (cfg[1].equals("exclude") && value instanceof Boolean && ((Boolean) value) == true) {
335-
controller.requestRemoveNodesStart();
336-
value = false;
337-
} else if (cfg[1].equals("sync") && value instanceof Boolean && ((Boolean) value) == true) {
338-
controller.requestRequestNetworkUpdate();
339-
value = false;
340-
} else if (cfg[1].equals("suc") && value instanceof Boolean) {
340+
if (cfg[1].equals("suc") && value instanceof Boolean) {
341341
// TODO: Do we need to set this immediately
342342
} else if (cfg[1].equals("inclusiontimeout") && value instanceof BigDecimal) {
343343
reinitialise = true;

0 commit comments

Comments
 (0)