2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.tellstick.internal.live;
15 import java.util.List;
16 import java.util.Vector;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
20 import org.openhab.binding.tellstick.internal.conf.TelldusLiveConfiguration;
21 import org.openhab.binding.tellstick.internal.handler.DeviceStatusListener;
22 import org.openhab.binding.tellstick.internal.handler.TelldusBridgeHandler;
23 import org.openhab.binding.tellstick.internal.handler.TelldusDeviceController;
24 import org.openhab.binding.tellstick.internal.handler.TelldusDevicesHandler;
25 import org.openhab.binding.tellstick.internal.live.xml.DataTypeValue;
26 import org.openhab.binding.tellstick.internal.live.xml.TellstickNetDevice;
27 import org.openhab.binding.tellstick.internal.live.xml.TellstickNetDevices;
28 import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensor;
29 import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensorEvent;
30 import org.openhab.binding.tellstick.internal.live.xml.TellstickNetSensors;
31 import org.openhab.core.thing.Bridge;
32 import org.openhab.core.thing.ChannelUID;
33 import org.openhab.core.thing.Thing;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.binding.BaseBridgeHandler;
37 import org.openhab.core.types.Command;
38 import org.openhab.core.types.RefreshType;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41 import org.tellstick.device.TellstickDeviceEvent;
42 import org.tellstick.device.TellstickException;
43 import org.tellstick.device.iface.Device;
46 * {@link TelldusLiveBridgeHandler} is the handler for Telldus Live service (Tellstick.NET and ZNET) and connects it
47 * to the framework. All {@link TelldusDevicesHandler}s use the
48 * {@link TelldusLiveDeviceController} to execute the actual commands.
50 * @author Jarle Hjortland - Initial contribution
52 public class TelldusLiveBridgeHandler extends BaseBridgeHandler implements TelldusBridgeHandler {
54 private final Logger logger = LoggerFactory.getLogger(TelldusLiveBridgeHandler.class);
56 private TellstickNetDevices deviceList = null;
57 private TellstickNetSensors sensorList = null;
58 private TelldusLiveDeviceController controller = new TelldusLiveDeviceController();
59 private List<DeviceStatusListener> deviceStatusListeners = new Vector<>();
61 private static final int REFRESH_DELAY = 10;
63 public TelldusLiveBridgeHandler(Bridge bridge) {
67 private ScheduledFuture<?> pollingJob;
68 private ScheduledFuture<?> immediateRefreshJob;
71 public void dispose() {
72 logger.debug("Live Handler disposed.");
73 if (pollingJob != null) {
74 pollingJob.cancel(true);
76 if (this.controller != null) {
77 this.controller.dispose();
85 public void initialize() {
86 logger.debug("Initializing TelldusLive bridge handler.");
87 TelldusLiveConfiguration configuration = getConfigAs(TelldusLiveConfiguration.class);
88 this.controller = new TelldusLiveDeviceController();
89 this.controller.connectHttpClient(configuration.publicKey, configuration.privateKey, configuration.token,
90 configuration.tokenSecret);
91 startAutomaticRefresh(configuration.refreshInterval);
93 updateStatus(ThingStatus.ONLINE);
96 private synchronized void startAutomaticRefresh(long refreshInterval) {
97 if (pollingJob != null && !pollingJob.isCancelled()) {
98 pollingJob.cancel(true);
100 pollingJob = scheduler.scheduleWithFixedDelay(this::refreshDeviceList, 0, refreshInterval,
101 TimeUnit.MILLISECONDS);
104 private void scheduleImmediateRefresh() {
105 // We schedule in 10 sec, to avoid multiple updates
106 logger.debug("Current remaining delay {}", pollingJob.getDelay(TimeUnit.SECONDS));
107 if (pollingJob.getDelay(TimeUnit.SECONDS) > REFRESH_DELAY) {
108 if (immediateRefreshJob == null || immediateRefreshJob.isDone()) {
109 immediateRefreshJob = scheduler.schedule(this::refreshDeviceList, REFRESH_DELAY, TimeUnit.SECONDS);
114 synchronized void refreshDeviceList() {
116 updateDevices(deviceList);
117 updateSensors(sensorList);
118 updateStatus(ThingStatus.ONLINE);
119 } catch (TellstickException e) {
120 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
121 logger.error("Failed to update", e);
122 } catch (Exception e) {
123 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
124 logger.error("Failed to update", e);
128 private synchronized void updateDevices(TellstickNetDevices previouslist) throws TellstickException {
129 TellstickNetDevices newList = controller.callRestMethod(TelldusLiveDeviceController.HTTP_TELLDUS_DEVICES,
130 TellstickNetDevices.class);
131 logger.debug("Device list {}", newList.getDevices());
132 if (newList.getDevices() != null) {
133 if (previouslist == null) {
134 logger.debug("updateDevices, Creating devices.");
135 for (TellstickNetDevice device : newList.getDevices()) {
136 device.setUpdated(true);
137 for (DeviceStatusListener listener : deviceStatusListeners) {
138 listener.onDeviceAdded(getThing(), device);
141 this.deviceList = newList;
143 logger.debug("updateDevices, Updating devices.");
144 for (TellstickNetDevice device : newList.getDevices()) {
145 int index = previouslist.getDevices().indexOf(device);
146 logger.debug("Device:{} found at {}", device, index);
148 TellstickNetDevice orgDevice = previouslist.getDevices().get(index);
149 if (device.getState() != orgDevice.getState()) {
150 orgDevice.setState(device.getState());
151 orgDevice.setStatevalue(device.getStatevalue());
152 orgDevice.setUpdated(true);
155 logger.debug("New Device - Adding:{}", device);
156 previouslist.getDevices().add(device);
157 device.setUpdated(true);
158 for (DeviceStatusListener listener : deviceStatusListeners) {
159 listener.onDeviceAdded(getThing(), device);
165 for (TellstickNetDevice device : deviceList.getDevices()) {
166 if (device.isUpdated()) {
167 logger.debug("Updated device:{}", device);
168 for (DeviceStatusListener listener : deviceStatusListeners) {
169 listener.onDeviceStateChanged(getThing(), device,
170 new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
172 device.setUpdated(false);
178 private synchronized void updateSensors(TellstickNetSensors previouslist) throws TellstickException {
179 TellstickNetSensors newList = controller.callRestMethod(TelldusLiveDeviceController.HTTP_TELLDUS_SENSORS,
180 TellstickNetSensors.class);
181 logger.debug("Updated sensors:{}", newList.getSensors());
182 if (newList.getSensors() != null) {
183 if (previouslist == null) {
184 logger.debug("First update of sensors");
185 this.sensorList = newList;
186 for (TellstickNetSensor sensor : sensorList.getSensors()) {
187 sensor.setUpdated(true);
188 for (DeviceStatusListener listener : deviceStatusListeners) {
189 listener.onDeviceAdded(getThing(), sensor);
193 logger.debug("Update sensors, reset updated flag");
194 for (TellstickNetSensor sensor : previouslist.getSensors()) {
195 sensor.setUpdated(false);
197 logger.debug("Update sensors, reset updated flag1");
199 for (TellstickNetSensor sensor : newList.getSensors()) {
200 int index = this.sensorList.getSensors().indexOf(sensor);
202 TellstickNetSensor orgSensor = this.sensorList.getSensors().get(index);
203 logger.debug("Update sensor {}, prev update {}, new update {}", sensor.getId(),
204 orgSensor.getLastUpdated(), sensor.getLastUpdated());
205 if (sensor.getLastUpdated() > orgSensor.getLastUpdated()) {
206 logger.debug("Update for sensor:{}", sensor);
207 orgSensor.setData(sensor.getData());
208 orgSensor.setLastUpdated(sensor.getLastUpdated());
209 orgSensor.setUpdated(true);
210 sensor.setUpdated(true);
213 logger.debug("Adding sensor {}, new update {}", sensor.getId(), sensor.getLastUpdated());
214 this.sensorList.getSensors().add(sensor);
215 sensor.setUpdated(true);
216 for (DeviceStatusListener listener : deviceStatusListeners) {
217 listener.onDeviceAdded(getThing(), sensor);
222 for (TellstickNetSensor sensor : sensorList.getSensors()) {
223 if (sensor.getData() != null && sensor.isUpdated()) {
224 for (DeviceStatusListener listener : deviceStatusListeners) {
225 for (DataTypeValue type : sensor.getData()) {
226 listener.onDeviceStateChanged(getThing(), sensor,
227 new TellstickNetSensorEvent(sensor.getId(), type.getValue(), type,
228 sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
231 sensor.setUpdated(false);
238 public void handleCommand(ChannelUID channelUID, Command command) {
239 if (command instanceof RefreshType) {
240 scheduleImmediateRefresh();
245 public void handleRemoval() {
246 super.handleRemoval();
250 public void thingUpdated(Thing thing) {
251 super.thingUpdated(thing);
255 public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
256 if (deviceStatusListener == null) {
257 throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
259 return deviceStatusListeners.add(deviceStatusListener);
263 public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
264 return deviceStatusListeners.remove(deviceStatusListener);
267 private Device getDevice(String id, List<TellstickNetDevice> devices) {
268 for (Device device : devices) {
269 if (device.getId() == Integer.valueOf(id)) {
276 private Device getSensor(String id, List<TellstickNetSensor> sensors) {
277 for (Device sensor : sensors) {
278 if (sensor.getId() == Integer.valueOf(id)) {
286 public Device getDevice(String serialNumber) {
287 return getDevice(serialNumber, getDevices());
290 private List<TellstickNetDevice> getDevices() {
291 if (deviceList == null) {
294 return deviceList.getDevices();
298 public Device getSensor(String deviceUUId) {
299 Device result = null;
300 if (sensorList != null) {
301 result = getSensor(deviceUUId, sensorList.getSensors());
307 public void rescanTelldusDevices() {
308 this.deviceList = null;
309 this.sensorList = null;
314 public TelldusDeviceController getController() {