]> git.basschouten.com Git - openhab-addons.git/blob
03d94a71db48e76b7ae7f4f6c0aa72d88c9c8689
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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.openwebnet.handler;
14
15 import static org.openhab.binding.openwebnet.OpenWebNetBindingConstants.*;
16
17 import java.util.Map;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
20
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.core.thing.Bridge;
24 import org.openhab.core.thing.ChannelUID;
25 import org.openhab.core.thing.Thing;
26 import org.openhab.core.thing.ThingStatus;
27 import org.openhab.core.thing.ThingStatusDetail;
28 import org.openhab.core.thing.binding.BaseThingHandler;
29 import org.openhab.core.types.Command;
30 import org.openhab.core.types.RefreshType;
31 import org.openwebnet4j.OpenGateway;
32 import org.openwebnet4j.communication.OWNException;
33 import org.openwebnet4j.communication.Response;
34 import org.openwebnet4j.message.BaseOpenMessage;
35 import org.openwebnet4j.message.OpenMessage;
36 import org.openwebnet4j.message.Where;
37 import org.openwebnet4j.message.WhereZigBee;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * The {@link OpenWebNetThingHandler} is responsible for handling commands for a OpenWebNet device.
43  * It's the abstract class for all OpenWebNet things. It should be extended by each specific OpenWebNet category of
44  * device (WHO).
45  *
46  * @author Massimo Valla - Initial contribution
47  */
48 @NonNullByDefault
49 public abstract class OpenWebNetThingHandler extends BaseThingHandler {
50
51     private final Logger logger = LoggerFactory.getLogger(OpenWebNetThingHandler.class);
52
53     protected @Nullable OpenWebNetBridgeHandler bridgeHandler;
54     protected @Nullable String ownId; // OpenWebNet identifier for this device: WHO.WHERE
55     protected @Nullable Where deviceWhere; // this device Where address
56
57     protected @Nullable ScheduledFuture<?> refreshTimeout;
58
59     public OpenWebNetThingHandler(Thing thing) {
60         super(thing);
61     }
62
63     @Override
64     public void initialize() {
65         Bridge bridge = getBridge();
66         if (bridge != null) {
67             OpenWebNetBridgeHandler brH = (OpenWebNetBridgeHandler) bridge.getHandler();
68             if (brH != null) {
69                 bridgeHandler = brH;
70
71                 final String configDeviceWhere = (String) getConfig().get(CONFIG_PROPERTY_WHERE);
72                 if (configDeviceWhere == null) {
73                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
74                             "@text/offline.conf-error-where");
75                 } else {
76                     Where w;
77                     try {
78                         if (brH.isBusGateway()) {
79                             w = buildBusWhere(configDeviceWhere);
80                         } else {
81                             w = new WhereZigBee(configDeviceWhere);
82                         }
83                     } catch (IllegalArgumentException ia) {
84                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
85                                 "@text/offline.conf-error-where");
86                         return;
87                     }
88                     deviceWhere = w;
89                     final String oid = brH.ownIdFromDeviceWhere(w, this);
90                     ownId = oid;
91                     Map<String, String> properties = editProperties();
92                     properties.put(PROPERTY_OWNID, oid);
93                     updateProperties(properties);
94                     brH.registerDevice(oid, this);
95                     logger.debug("associated thing to bridge with ownId={}", ownId);
96                     updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.NONE, "@text/unknown.waiting-state");
97                 }
98             }
99         } else {
100             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
101                     "@text/offline.conf-error-no-bridge");
102         }
103     }
104
105     @Override
106     public void handleCommand(ChannelUID channel, Command command) {
107         logger.debug("handleCommand() (command={} - channel={})", command, channel);
108         OpenWebNetBridgeHandler handler = bridgeHandler;
109         if (handler != null) {
110             OpenGateway gw = handler.gateway;
111             if (gw != null && !gw.isConnected()) {
112                 logger.info("Cannot handle {} command for {}: gateway is not connected", command, getThing().getUID());
113                 return;
114             }
115             if (deviceWhere == null) {
116                 logger.info("Cannot handle {} command for {}: 'where' parameter is not configured or is invalid",
117                         command, getThing().getUID());
118                 return;
119             }
120             if (command instanceof RefreshType) {
121                 requestChannelState(channel);
122                 // set a schedule to put device OFFLINE if no answer is received after THING_STATE_REQ_TIMEOUT_SEC
123                 refreshTimeout = scheduler.schedule(() -> {
124                     if (thing.getStatus().equals(ThingStatus.UNKNOWN)) {
125                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
126                                 "Could not get channel state (timer expired)");
127                     }
128                 }, THING_STATE_REQ_TIMEOUT_SEC, TimeUnit.SECONDS);
129             } else {
130                 handleChannelCommand(channel, command);
131             }
132         } else {
133             logger.debug("Thing {} is not associated to any gateway, skipping command", getThing().getUID());
134         }
135     }
136
137     /**
138      * Handles a command for the specific channel for this thing.
139      * It must be implemented by each specific OpenWebNet category of device (WHO), based on channel
140      *
141      * @param channel specific ChannleUID
142      * @param command the Command to be executed
143      */
144     protected abstract void handleChannelCommand(ChannelUID channel, Command command);
145
146     /**
147      * Handle incoming message from OWN network via bridge Thing, directed to this device. It should be further
148      * implemented by each specific device handler.
149      *
150      * @param msg the message to handle
151      */
152     protected void handleMessage(BaseOpenMessage msg) {
153         ThingStatus ts = getThing().getStatus();
154         if (ThingStatus.ONLINE != ts && ThingStatus.REMOVING != ts && ThingStatus.REMOVED != ts) {
155             updateStatus(ThingStatus.ONLINE);
156         }
157     }
158
159     /**
160      * Helper method to send OWN messages from ThingHandlers
161      */
162     protected @Nullable Response send(OpenMessage msg) throws OWNException {
163         OpenWebNetBridgeHandler bh = bridgeHandler;
164         if (bh != null) {
165             OpenGateway gw = bh.gateway;
166             if (gw != null) {
167                 return gw.send(msg);
168             }
169         }
170         logger.warn("Couldn't send message {}: handler or gateway is null", msg);
171         return null;
172     }
173
174     /**
175      * Helper method to send with high priority OWN messages from ThingsHandlers
176      */
177     protected @Nullable Response sendHighPriority(OpenMessage msg) throws OWNException {
178         OpenWebNetBridgeHandler handler = bridgeHandler;
179         if (handler != null) {
180             OpenGateway gw = handler.gateway;
181             if (gw != null) {
182                 return gw.sendHighPriority(msg);
183             }
184         }
185         return null;
186     }
187
188     /**
189      * Request the state for the specified channel
190      *
191      * @param channel the {@link ChannelUID} to request the state for
192      */
193     protected abstract void requestChannelState(ChannelUID channel);
194
195     /**
196      * Refresh the device
197      *
198      * @param refreshAll set true if all devices of the binding should be refreshed with one command, if possible
199      */
200     protected abstract void refreshDevice(boolean refreshAll);
201
202     /**
203      * Abstract builder for device Where address, to be implemented by each subclass to choose the right Where subclass
204      * (the method is used only if the Thing is associated to a BUS gateway).
205      *
206      * @param wStr the WHERE string
207      */
208     protected abstract Where buildBusWhere(String wStr) throws IllegalArgumentException;
209
210     @Override
211     public void dispose() {
212         OpenWebNetBridgeHandler bh = bridgeHandler;
213         String oid = ownId;
214         if (bh != null && oid != null) {
215             bh.unregisterDevice(oid);
216         }
217         ScheduledFuture<?> sc = refreshTimeout;
218         if (sc != null) {
219             sc.cancel(true);
220         }
221         super.dispose();
222     }
223
224     /**
225      * Returns a prefix String for ownId specific for each handler. To be implemented by sub-classes.
226      *
227      * @return
228      */
229     protected abstract String ownIdPrefix();
230 }