]> git.basschouten.com Git - openhab-addons.git/blob
d1a7dd4a09b1f02ce5a9eda53cfe3766f9c29df8
[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.local;
14
15 import java.time.Duration;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
21
22 import org.eclipse.jetty.client.HttpClient;
23 import org.openhab.binding.tellstick.internal.conf.TelldusLocalConfiguration;
24 import org.openhab.binding.tellstick.internal.handler.DeviceStatusListener;
25 import org.openhab.binding.tellstick.internal.handler.TelldusBridgeHandler;
26 import org.openhab.binding.tellstick.internal.handler.TelldusDeviceController;
27 import org.openhab.binding.tellstick.internal.handler.TelldusDevicesHandler;
28 import org.openhab.binding.tellstick.internal.local.dto.LocalDataTypeValueDTO;
29 import org.openhab.binding.tellstick.internal.local.dto.TellstickLocalDeviceDTO;
30 import org.openhab.binding.tellstick.internal.local.dto.TellstickLocalDevicesDTO;
31 import org.openhab.binding.tellstick.internal.local.dto.TellstickLocalSensorDTO;
32 import org.openhab.binding.tellstick.internal.local.dto.TellstickLocalSensorEventDTO;
33 import org.openhab.binding.tellstick.internal.local.dto.TellstickLocalSensorsDTO;
34 import org.openhab.core.cache.ExpiringCache;
35 import org.openhab.core.thing.Bridge;
36 import org.openhab.core.thing.ChannelUID;
37 import org.openhab.core.thing.ThingStatus;
38 import org.openhab.core.thing.ThingStatusDetail;
39 import org.openhab.core.thing.binding.BaseBridgeHandler;
40 import org.openhab.core.types.Command;
41 import org.openhab.core.types.RefreshType;
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.iface.Device;
47
48 /**
49  * {@link TelldusLocalBridgeHandler} is the handler for Telldus Local API (Tellstick ZNET v1/v2) and connects it
50  * to the framework. All {@link TelldusDevicesHandler}s use the
51  * {@link TelldusLocalDeviceController} to execute the actual commands.
52  *
53  * @author Jan Gustafsson- Initial contribution
54  */
55 public class TelldusLocalBridgeHandler extends BaseBridgeHandler implements TelldusBridgeHandler {
56
57     private final Logger logger = LoggerFactory.getLogger(TelldusLocalBridgeHandler.class);
58
59     private TellstickLocalDevicesDTO deviceList = null;
60     private TellstickLocalSensorsDTO sensorList = null;
61     private TelldusLocalDeviceController controller = null;
62     private List<DeviceStatusListener> deviceStatusListeners = Collections.synchronizedList(new ArrayList<>());
63     private final HttpClient httpClient;
64     private ScheduledFuture<?> pollingJob;
65     /**
66      * Use cache for refresh command to not update again when call is made within 10 seconds of previous call.
67      */
68     private final ExpiringCache<Boolean> refreshCache = new ExpiringCache<>(Duration.ofSeconds(10),
69             this::refreshDeviceList);
70
71     public TelldusLocalBridgeHandler(Bridge bridge, HttpClient httpClient) {
72         super(bridge);
73         this.httpClient = httpClient;
74     }
75
76     @Override
77     public void initialize() {
78         TelldusLocalConfiguration configuration = getConfigAs(TelldusLocalConfiguration.class);
79         this.controller = new TelldusLocalDeviceController(configuration, httpClient);
80         pollingJob = scheduler.scheduleWithFixedDelay(this::refreshDeviceList, 11, configuration.refreshInterval,
81                 TimeUnit.MILLISECONDS);
82         updateStatus(ThingStatus.UNKNOWN);
83     }
84
85     @Override
86     public void dispose() {
87         if (pollingJob != null) {
88             pollingJob.cancel(true);
89         }
90         if (this.controller != null) {
91             this.controller.dispose();
92         }
93         deviceList = null;
94         sensorList = null;
95         super.dispose();
96     }
97
98     private boolean refreshDeviceList() {
99         try {
100             updateDevices(deviceList);
101             updateSensors(sensorList);
102             updateStatus(ThingStatus.ONLINE);
103             return true;
104         } catch (TellstickException | InterruptedException e) {
105             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
106         }
107         return false;
108     }
109
110     private synchronized void updateDevices(TellstickLocalDevicesDTO previouslist)
111             throws TellstickException, InterruptedException {
112         TellstickLocalDevicesDTO newList = controller
113                 .callRestMethod(TelldusLocalDeviceController.HTTP_LOCAL_API_DEVICES, TellstickLocalDevicesDTO.class);
114         logger.debug("Device list {}", newList.getDevices());
115         if (newList.getDevices() != null) {
116             if (previouslist == null) {
117                 for (TellstickLocalDeviceDTO device : newList.getDevices()) {
118                     device.setUpdated(true);
119                     synchronized (deviceStatusListeners) {
120                         for (DeviceStatusListener listener : deviceStatusListeners) {
121                             listener.onDeviceAdded(getThing(), device);
122                         }
123                     }
124                 }
125                 this.deviceList = newList;
126             } else {
127                 for (TellstickLocalDeviceDTO device : newList.getDevices()) {
128                     int index = previouslist.getDevices().indexOf(device);
129                     logger.debug("Device:{} found at {}", device, index);
130                     if (index >= 0) {
131                         TellstickLocalDeviceDTO orgDevice = previouslist.getDevices().get(index);
132                         if (device.getState() != orgDevice.getState()) {
133                             orgDevice.setState(device.getState());
134                             orgDevice.setStatevalue(device.getStatevalue());
135                             orgDevice.setUpdated(true);
136                         }
137                     } else {
138                         logger.debug("New Device - Adding:{}", device);
139                         previouslist.getDevices().add(device);
140                         device.setUpdated(true);
141                         synchronized (deviceStatusListeners) {
142                             for (DeviceStatusListener listener : deviceStatusListeners) {
143                                 listener.onDeviceAdded(getThing(), device);
144                             }
145                         }
146                     }
147                 }
148             }
149
150             for (TellstickLocalDeviceDTO device : deviceList.getDevices()) {
151                 if (device.isUpdated()) {
152                     synchronized (deviceStatusListeners) {
153                         for (DeviceStatusListener listener : deviceStatusListeners) {
154                             listener.onDeviceStateChanged(getThing(), device,
155                                     new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
156                         }
157                     }
158                     device.setUpdated(false);
159                 }
160             }
161         }
162     }
163
164     private synchronized void updateSensors(TellstickLocalSensorsDTO previouslist)
165             throws TellstickException, InterruptedException {
166         TellstickLocalSensorsDTO newList = controller
167                 .callRestMethod(TelldusLocalDeviceController.HTTP_LOCAL_API_SENSORS, TellstickLocalSensorsDTO.class);
168         logger.debug("Updated sensors:{}", newList.getSensors());
169         if (newList.getSensors() != null) {
170             if (previouslist == null) {
171                 this.sensorList = newList;
172                 for (TellstickLocalSensorDTO sensor : sensorList.getSensors()) {
173                     sensor.setUpdated(true);
174                     synchronized (deviceStatusListeners) {
175                         for (DeviceStatusListener listener : deviceStatusListeners) {
176                             listener.onDeviceAdded(getThing(), sensor);
177                         }
178                     }
179                 }
180             } else {
181                 for (TellstickLocalSensorDTO sensor : previouslist.getSensors()) {
182                     sensor.setUpdated(false);
183                 }
184
185                 for (TellstickLocalSensorDTO sensor : newList.getSensors()) {
186                     int index = this.sensorList.getSensors().indexOf(sensor);
187                     if (index >= 0) {
188                         TellstickLocalSensorDTO orgSensor = this.sensorList.getSensors().get(index);
189                         orgSensor.setData(sensor.getData());
190                         orgSensor.setUpdated(true);
191                         sensor.setUpdated(true);
192                     } else {
193                         this.sensorList.getSensors().add(sensor);
194                         sensor.setUpdated(true);
195                         synchronized (deviceStatusListeners) {
196                             for (DeviceStatusListener listener : deviceStatusListeners) {
197                                 listener.onDeviceAdded(getThing(), sensor);
198                             }
199                         }
200                     }
201                 }
202             }
203             for (TellstickLocalSensorDTO sensor : sensorList.getSensors()) {
204                 if (sensor.getData() != null && sensor.isUpdated()) {
205                     synchronized (deviceStatusListeners) {
206                         for (DeviceStatusListener listener : deviceStatusListeners) {
207                             for (LocalDataTypeValueDTO type : sensor.getData()) {
208                                 listener.onDeviceStateChanged(getThing(), sensor,
209                                         new TellstickLocalSensorEventDTO(sensor.getId(), type.getValue(), type,
210                                                 sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
211                             }
212                         }
213                     }
214                     sensor.setUpdated(false);
215                 }
216             }
217         }
218     }
219
220     @Override
221     public void handleCommand(ChannelUID channelUID, Command command) {
222         if (command instanceof RefreshType) {
223             refreshCache.getValue();
224         }
225     }
226
227     @Override
228     public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
229         if (deviceStatusListener == null) {
230             throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
231         }
232         return deviceStatusListeners.add(deviceStatusListener);
233     }
234
235     @Override
236     public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
237         return deviceStatusListeners.remove(deviceStatusListener);
238     }
239
240     private Device getDevice(String id, List<TellstickLocalDeviceDTO> devices) {
241         for (Device device : devices) {
242             if (device.getId() == Integer.valueOf(id)) {
243                 return device;
244             }
245         }
246         return null;
247     }
248
249     private Device getSensor(String id, List<TellstickLocalSensorDTO> sensors) {
250         for (Device sensor : sensors) {
251             if (sensor.getId() == Integer.valueOf(id)) {
252                 return sensor;
253             }
254         }
255         return null;
256     }
257
258     @Override
259     public Device getDevice(String serialNumber) {
260         return getDevice(serialNumber, getDevices());
261     }
262
263     private List<TellstickLocalDeviceDTO> getDevices() {
264         if (deviceList == null) {
265             refreshDeviceList();
266         }
267         return deviceList.getDevices();
268     }
269
270     @Override
271     public Device getSensor(String deviceUUId) {
272         Device result = null;
273         if (sensorList != null) {
274             result = getSensor(deviceUUId, sensorList.getSensors());
275         }
276         return result;
277     }
278
279     @Override
280     public void rescanTelldusDevices() {
281         this.deviceList = null;
282         this.sensorList = null;
283         refreshDeviceList();
284     }
285
286     @Override
287     public TelldusDeviceController getController() {
288         return controller;
289     }
290 }