]> git.basschouten.com Git - openhab-addons.git/blob
20404933c824b0e9282584ea246b18159b37a2f0
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.List;
17 import java.util.Set;
18 import java.util.concurrent.ConcurrentHashMap;
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 Set<DeviceStatusListener> deviceStatusListeners = ConcurrentHashMap.newKeySet();
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         if (newList.getDevices() != null) {
115             logger.debug("Device list {}", newList.getDevices());
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         } else {
162             logger.debug("updateDevices, rest API returned null");
163         }
164     }
165
166     private synchronized void updateSensors(TellstickLocalSensorsDTO previouslist)
167             throws TellstickException, InterruptedException {
168         TellstickLocalSensorsDTO newList = controller
169                 .callRestMethod(TelldusLocalDeviceController.HTTP_LOCAL_API_SENSORS, TellstickLocalSensorsDTO.class);
170         logger.debug("Updated sensors:{}", newList.getSensors());
171         if (newList.getSensors() != null) {
172             if (previouslist == null) {
173                 this.sensorList = newList;
174                 for (TellstickLocalSensorDTO sensor : sensorList.getSensors()) {
175                     sensor.setUpdated(true);
176                     synchronized (deviceStatusListeners) {
177                         for (DeviceStatusListener listener : deviceStatusListeners) {
178                             listener.onDeviceAdded(getThing(), sensor);
179                         }
180                     }
181                 }
182             } else {
183                 for (TellstickLocalSensorDTO sensor : previouslist.getSensors()) {
184                     sensor.setUpdated(false);
185                 }
186
187                 for (TellstickLocalSensorDTO sensor : newList.getSensors()) {
188                     int index = this.sensorList.getSensors().indexOf(sensor);
189                     if (index >= 0) {
190                         TellstickLocalSensorDTO orgSensor = this.sensorList.getSensors().get(index);
191                         orgSensor.setData(sensor.getData());
192                         orgSensor.setUpdated(true);
193                         sensor.setUpdated(true);
194                     } else {
195                         this.sensorList.getSensors().add(sensor);
196                         sensor.setUpdated(true);
197                         synchronized (deviceStatusListeners) {
198                             for (DeviceStatusListener listener : deviceStatusListeners) {
199                                 listener.onDeviceAdded(getThing(), sensor);
200                             }
201                         }
202                     }
203                 }
204             }
205             for (TellstickLocalSensorDTO sensor : sensorList.getSensors()) {
206                 if (sensor.getData() != null && sensor.isUpdated()) {
207                     synchronized (deviceStatusListeners) {
208                         for (DeviceStatusListener listener : deviceStatusListeners) {
209                             for (LocalDataTypeValueDTO type : sensor.getData()) {
210                                 listener.onDeviceStateChanged(getThing(), sensor,
211                                         new TellstickLocalSensorEventDTO(sensor.getId(), type.getValue(), type,
212                                                 sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
213                             }
214                         }
215                     }
216                     sensor.setUpdated(false);
217                 }
218             }
219         }
220     }
221
222     @Override
223     public void handleCommand(ChannelUID channelUID, Command command) {
224         if (command instanceof RefreshType) {
225             refreshCache.getValue();
226         }
227     }
228
229     @Override
230     public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
231         if (deviceStatusListener == null) {
232             throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
233         }
234         return deviceStatusListeners.add(deviceStatusListener);
235     }
236
237     @Override
238     public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
239         return deviceStatusListeners.remove(deviceStatusListener);
240     }
241
242     private Device getDevice(String id, List<TellstickLocalDeviceDTO> devices) {
243         for (Device device : devices) {
244             if (device.getId() == Integer.valueOf(id)) {
245                 return device;
246             }
247         }
248         return null;
249     }
250
251     private Device getSensor(String id, List<TellstickLocalSensorDTO> sensors) {
252         for (Device sensor : sensors) {
253             if (sensor.getId() == Integer.valueOf(id)) {
254                 return sensor;
255             }
256         }
257         return null;
258     }
259
260     @Override
261     public Device getDevice(String serialNumber) {
262         return getDevice(serialNumber, getDevices());
263     }
264
265     private List<TellstickLocalDeviceDTO> getDevices() {
266         if (deviceList == null) {
267             refreshDeviceList();
268         }
269         return deviceList.getDevices();
270     }
271
272     @Override
273     public Device getSensor(String deviceUUId) {
274         Device result = null;
275         if (sensorList != null) {
276             result = getSensor(deviceUUId, sensorList.getSensors());
277         }
278         return result;
279     }
280
281     @Override
282     public void rescanTelldusDevices() {
283         this.deviceList = null;
284         this.sensorList = null;
285         refreshDeviceList();
286     }
287
288     @Override
289     public TelldusDeviceController getController() {
290         return controller;
291     }
292 }