]> git.basschouten.com Git - openhab-addons.git/blob
b46412e42653978ffca6f453fabe56a75a8ad502
[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.tellstick.internal.handler;
14
15 import static org.openhab.binding.tellstick.internal.TellstickBindingConstants.*;
16
17 import java.math.BigDecimal;
18 import java.time.ZoneId;
19 import java.time.ZonedDateTime;
20 import java.util.Calendar;
21
22 import org.openhab.binding.tellstick.internal.TellstickBindingConstants;
23 import org.openhab.binding.tellstick.internal.live.xml.DataTypeValue;
24 import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensor;
25 import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensorEvent;
26 import org.openhab.core.config.core.Configuration;
27 import org.openhab.core.library.types.DateTimeType;
28 import org.openhab.core.library.types.DecimalType;
29 import org.openhab.core.library.types.PercentType;
30 import org.openhab.core.library.types.QuantityType;
31 import org.openhab.core.library.unit.SIUnits;
32 import org.openhab.core.thing.Bridge;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.Thing;
35 import org.openhab.core.thing.ThingStatus;
36 import org.openhab.core.thing.ThingStatusDetail;
37 import org.openhab.core.thing.ThingStatusInfo;
38 import org.openhab.core.thing.binding.BaseThingHandler;
39 import org.openhab.core.types.Command;
40 import org.openhab.core.types.RefreshType;
41 import org.openhab.core.types.State;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.tellstick.device.TellstickDeviceEvent;
45 import org.tellstick.device.TellstickException;
46 import org.tellstick.device.TellstickSensor;
47 import org.tellstick.device.TellstickSensorEvent;
48 import org.tellstick.device.iface.Device;
49 import org.tellstick.device.iface.DimmableDevice;
50 import org.tellstick.device.iface.TellstickEvent;
51 import org.tellstick.enums.DataType;
52 import org.tellstick.enums.DeviceType;
53
54 /**
55  * Handler for telldus and tellstick devices. This sends the commands to the correct bridge.
56  *
57  * @author Jarle Hjortland - Initial contribution
58  */
59 public class TelldusDevicesHandler extends BaseThingHandler implements DeviceStatusListener {
60
61     private Logger logger = LoggerFactory.getLogger(TelldusDevicesHandler.class);
62     private String deviceId;
63     private Boolean isDimmer = Boolean.FALSE;
64     private int resend = 1;
65     private TelldusBridgeHandler bridgeHandler = null;
66     private final ChannelUID stateChannel;
67     private final ChannelUID dimChannel;
68     private final ChannelUID humidityChannel;
69     private final ChannelUID tempChannel;
70     private final ChannelUID raintTotChannel;
71     private final ChannelUID rainRateChannel;
72     private final ChannelUID windAverageChannel;
73     private final ChannelUID windDirectionChannel;
74     private final ChannelUID windGuestChannel;
75     private final ChannelUID wattChannel;
76     private final ChannelUID ampereChannel;
77     private final ChannelUID luxChannel;
78     private final ChannelUID timestampChannel;
79
80     public TelldusDevicesHandler(Thing thing) {
81         super(thing);
82         stateChannel = new ChannelUID(getThing().getUID(), CHANNEL_STATE);
83         dimChannel = new ChannelUID(getThing().getUID(), CHANNEL_DIMMER);
84         humidityChannel = new ChannelUID(getThing().getUID(), CHANNEL_HUMIDITY);
85         tempChannel = new ChannelUID(getThing().getUID(), CHANNEL_TEMPERATURE);
86         raintTotChannel = new ChannelUID(getThing().getUID(), CHANNEL_RAINTOTAL);
87         rainRateChannel = new ChannelUID(getThing().getUID(), CHANNEL_RAINRATE);
88         windAverageChannel = new ChannelUID(getThing().getUID(), CHANNEL_WINDAVERAGE);
89         windDirectionChannel = new ChannelUID(getThing().getUID(), CHANNEL_WINDDIRECTION);
90         windGuestChannel = new ChannelUID(getThing().getUID(), CHANNEL_WINDGUST);
91         wattChannel = new ChannelUID(getThing().getUID(), CHANNEL_WATT);
92         ampereChannel = new ChannelUID(getThing().getUID(), CHANNEL_AMPERE);
93         timestampChannel = new ChannelUID(getThing().getUID(), CHANNEL_TIMESTAMP);
94         luxChannel = new ChannelUID(getThing().getUID(), CHANNEL_LUX);
95     }
96
97     @Override
98     public void handleCommand(ChannelUID channelUID, Command command) {
99         logger.debug("Handle event {} for {}", command, channelUID);
100         TelldusBridgeHandler bridgeHandler = getTellstickBridgeHandler();
101         if (bridgeHandler == null) {
102             logger.warn("Tellstick bridge handler not found. Cannot handle command without bridge.");
103             return;
104         }
105         Device dev = getDevice(bridgeHandler, deviceId);
106
107         if (dev == null) {
108             logger.warn("Device not found. Can't send command to device '{}'", deviceId);
109             return;
110         }
111         if (command instanceof RefreshType) {
112             getBridge().getHandler().handleCommand(channelUID, command);
113             refreshDevice(dev);
114             return;
115         }
116         if (channelUID.getId().equals(CHANNEL_DIMMER) || channelUID.getId().equals(CHANNEL_STATE)) {
117             try {
118                 if (dev.getDeviceType() == DeviceType.DEVICE) {
119                     getTellstickBridgeHandler().getController().handleSendEvent(dev, resend, isDimmer, command);
120                 } else {
121                     logger.warn("{} is not an updateable device. Read-only", dev);
122                 }
123             } catch (TellstickException e) {
124                 logger.debug("Failed to send command to tellstick", e);
125                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
126             } catch (Exception e) {
127                 logger.error("Failed to send command to tellstick", e);
128                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
129             }
130         } else {
131             logger.warn("Setting of channel {} not possible. Read-only", channelUID);
132         }
133     }
134
135     private void refreshDevice(Device dev) {
136         if (deviceId != null && isSensor()) {
137             updateSensorStates(dev);
138         } else if (deviceId != null) {
139             updateDeviceState(dev);
140         }
141     }
142
143     @Override
144     public void initialize() {
145         Configuration config = getConfig();
146         logger.debug("Initialize TelldusDeviceHandler {}. class {}", config, config.getClass());
147         final Object configDeviceId = config.get(TellstickBindingConstants.DEVICE_ID);
148         if (configDeviceId != null) {
149             deviceId = configDeviceId.toString();
150         } else {
151             logger.debug("Initialized TellStick device missing serialNumber configuration... troubles ahead");
152             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR);
153         }
154         final Boolean isADimmer = (Boolean) config.get(TellstickBindingConstants.DEVICE_ISDIMMER);
155         if (isADimmer != null) {
156             this.isDimmer = isADimmer;
157         }
158         final BigDecimal repeatCount = (BigDecimal) config.get(TellstickBindingConstants.DEVICE_RESEND_COUNT);
159         if (repeatCount != null) {
160             resend = repeatCount.intValue();
161         }
162         if (getBridge() != null) {
163             bridgeStatusChanged(getBridge().getStatusInfo());
164         }
165     }
166
167     @Override
168     public void bridgeStatusChanged(ThingStatusInfo bridgeStatusInfo) {
169         logger.debug("device: {} bridgeStatusChanged: {}", deviceId, bridgeStatusInfo);
170         if (bridgeStatusInfo.getStatus() == ThingStatus.ONLINE) {
171             try {
172                 TelldusBridgeHandler tellHandler = (TelldusBridgeHandler) getBridge().getHandler();
173                 logger.debug("Init bridge for {}, bridge:{}", deviceId, tellHandler);
174                 if (tellHandler != null) {
175                     this.bridgeHandler = tellHandler;
176                     this.bridgeHandler.registerDeviceStatusListener(this);
177                     Configuration config = editConfiguration();
178                     Device dev = getDevice(tellHandler, deviceId);
179                     if (dev != null) {
180                         if (dev.getName() != null) {
181                             config.put(TellstickBindingConstants.DEVICE_NAME, dev.getName());
182                         }
183                         if (dev.getProtocol() != null) {
184                             config.put(TellstickBindingConstants.DEVICE_PROTOCOL, dev.getProtocol());
185                         }
186                         if (dev.getModel() != null) {
187                             config.put(TellstickBindingConstants.DEVICE_MODEL, dev.getModel());
188                         }
189                         updateConfiguration(config);
190
191                         updateStatus(ThingStatus.ONLINE);
192                     } else {
193                         logger.warn(
194                                 "Could not find {}, please make sure it is defined and that telldus service is running",
195                                 deviceId);
196                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
197                     }
198                 }
199             } catch (Exception e) {
200                 logger.error("Failed to init bridge for {}", deviceId, e);
201                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR);
202             }
203         } else {
204             updateStatus(ThingStatus.OFFLINE, bridgeStatusInfo.getStatusDetail());
205         }
206     }
207
208     private Device getDevice(TelldusBridgeHandler tellHandler, String deviceId) {
209         Device dev = null;
210         if (deviceId != null) {
211             if (isSensor()) {
212                 dev = tellHandler.getSensor(deviceId);
213             } else {
214                 dev = tellHandler.getDevice(deviceId);
215                 updateDeviceState(dev);
216             }
217         }
218         return dev;
219     }
220
221     private boolean isSensor() {
222         return (getThing().getThingTypeUID().equals(TellstickBindingConstants.SENSOR_THING_TYPE)
223                 || getThing().getThingTypeUID().equals(TellstickBindingConstants.RAINSENSOR_THING_TYPE)
224                 || getThing().getThingTypeUID().equals(TellstickBindingConstants.WINDSENSOR_THING_TYPE)
225                 || getThing().getThingTypeUID().equals(TellstickBindingConstants.POWERSENSOR_THING_TYPE));
226     }
227
228     private void updateSensorStates(Device dev) {
229         if (dev instanceof TellstickSensor) {
230             updateStatus(ThingStatus.ONLINE);
231             for (DataType type : ((TellstickSensor) dev).getData().keySet()) {
232                 updateSensorDataState(type, ((TellstickSensor) dev).getData(type));
233             }
234         } else if (dev instanceof TellstickNetSensor) {
235             if (((TellstickNetSensor) dev).getOnline()) {
236                 updateStatus(ThingStatus.ONLINE);
237             } else {
238                 updateStatus(ThingStatus.OFFLINE);
239             }
240             for (DataTypeValue type : ((TellstickNetSensor) dev).getData()) {
241                 updateSensorDataState(type);
242             }
243         }
244     }
245
246     private synchronized TelldusBridgeHandler getTellstickBridgeHandler() {
247         if (this.bridgeHandler == null) {
248             logger.debug("No available bridge handler found for {} bridge {} .", deviceId, getBridge());
249         }
250         return this.bridgeHandler;
251     }
252
253     @Override
254     public void onDeviceStateChanged(Bridge bridge, Device device, TellstickEvent event) {
255         logger.debug("Updating states of ({} {} ({}) id: {} or {}", device.getDeviceType(), device.getName(),
256                 device.getUUId(), getThing().getUID(), deviceId);
257         if (device.getUUId().equals(deviceId)) {
258             if (event instanceof TellstickDeviceEvent) {
259                 updateDeviceState(device);
260             } else if (event instanceof TellstickNetSensorEvent) {
261                 TellstickNetSensorEvent sensorevent = (TellstickNetSensorEvent) event;
262                 updateSensorDataState(sensorevent.getDataTypeValue());
263             } else if (event instanceof TellstickSensorEvent) {
264                 TellstickSensorEvent sensorevent = (TellstickSensorEvent) event;
265                 updateSensorDataState(sensorevent.getDataType(), sensorevent.getData());
266             } else {
267                 logger.debug("Unhandled Device {}.", device.getDeviceType());
268             }
269             Calendar cal = Calendar.getInstance();
270             cal.setTimeInMillis(event.getTimestamp());
271             updateState(timestampChannel,
272                     new DateTimeType(ZonedDateTime.ofInstant(cal.toInstant(), ZoneId.systemDefault())));
273         }
274     }
275
276     private void updateSensorDataState(DataType dataType, String data) {
277         switch (dataType) {
278             case HUMIDITY:
279                 updateState(humidityChannel, new QuantityType<>(new BigDecimal(data), HUMIDITY_UNIT));
280                 break;
281             case TEMPERATURE:
282                 updateState(tempChannel, new QuantityType<>(new BigDecimal(data), SIUnits.CELSIUS));
283                 break;
284             case RAINRATE:
285                 updateState(rainRateChannel, new QuantityType<>(new BigDecimal(data), RAIN_UNIT));
286                 break;
287             case RAINTOTAL:
288                 updateState(raintTotChannel, new QuantityType<>(new BigDecimal(data), RAIN_UNIT));
289                 break;
290             case WINDAVERAGE:
291                 updateState(windAverageChannel, new QuantityType<>(new BigDecimal(data), WIND_SPEED_UNIT_MS));
292                 break;
293             case WINDDIRECTION:
294                 updateState(windDirectionChannel, new QuantityType<>(new BigDecimal(data), WIND_DIRECTION_UNIT));
295                 break;
296             case WINDGUST:
297                 updateState(windGuestChannel, new QuantityType<>(new BigDecimal(data), WIND_SPEED_UNIT_MS));
298                 break;
299             default:
300         }
301     }
302
303     private void updateSensorDataState(DataTypeValue dataType) {
304         switch (dataType.getName()) {
305             case HUMIDITY:
306                 updateState(humidityChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), HUMIDITY_UNIT));
307                 break;
308             case TEMPERATURE:
309                 updateState(tempChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), SIUnits.CELSIUS));
310                 break;
311             case RAINRATE:
312                 updateState(rainRateChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), RAIN_UNIT));
313                 break;
314             case RAINTOTAL:
315                 updateState(raintTotChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), RAIN_UNIT));
316                 break;
317             case WINDAVERAGE:
318                 updateState(windAverageChannel,
319                         new QuantityType<>(new BigDecimal(dataType.getValue()), WIND_SPEED_UNIT_MS));
320                 break;
321             case WINDDIRECTION:
322                 updateState(windDirectionChannel,
323                         new QuantityType<>(new BigDecimal(dataType.getValue()), WIND_DIRECTION_UNIT));
324                 break;
325             case WINDGUST:
326                 updateState(windGuestChannel,
327                         new QuantityType<>(new BigDecimal(dataType.getValue()), WIND_SPEED_UNIT_MS));
328                 break;
329             case WATT:
330                 if (dataType.getUnit() != null && dataType.getUnit().equals("A")) {
331                     updateState(ampereChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), ELECTRIC_UNIT));
332                 } else {
333                     updateState(wattChannel, new QuantityType<>(new BigDecimal(dataType.getValue()), POWER_UNIT));
334                 }
335                 break;
336             case LUMINATION:
337                 updateState(luxChannel, new QuantityType<>(new DecimalType(dataType.getValue()), LUX_UNIT));
338                 break;
339             default:
340         }
341     }
342
343     private void updateDeviceState(Device device) {
344         if (device != null) {
345             logger.debug("Updating state of {} {} ({}) id: {}", device.getDeviceType(), device.getName(),
346                     device.getUUId(), getThing().getUID());
347             TelldusBridgeHandler bridgeHandler = getTellstickBridgeHandler();
348             State st = null;
349             if (bridgeHandler != null && bridgeHandler.getController() != null) {
350                 st = bridgeHandler.getController().calcState(device);
351             }
352             if (st != null && bridgeHandler != null) {
353                 BigDecimal dimValue = bridgeHandler.getController().calcDimValue(device);
354                 updateState(stateChannel, st);
355                 if (device instanceof DimmableDevice) {
356                     updateState(dimChannel, new PercentType(dimValue));
357                 }
358                 updateStatus(ThingStatus.ONLINE);
359             } else {
360                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
361             }
362         } else {
363             updateStatus(ThingStatus.REMOVED);
364         }
365     }
366
367     @Override
368     public void onDeviceRemoved(Bridge bridge, Device device) {
369         if (device.getUUId().equals(deviceId)) {
370             updateStatus(ThingStatus.REMOVED);
371         }
372     }
373
374     @Override
375     public void onDeviceAdded(Bridge bridge, Device device) {
376     }
377 }