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