2 * Copyright (c) 2010-2022 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 if (newList.getDevices() != null) {
132 logger.debug("Device list {}", newList.getDevices());
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);
176 logger.debug("updateDevices, rest API returned null");
180 private synchronized void updateSensors(TellstickNetSensors previouslist) throws TellstickException {
181 TellstickNetSensors newList = controller.callRestMethod(TelldusLiveDeviceController.HTTP_TELLDUS_SENSORS,
182 TellstickNetSensors.class);
183 logger.debug("Updated sensors:{}", newList.getSensors());
184 if (newList.getSensors() != null) {
185 if (previouslist == null) {
186 logger.debug("First update of sensors");
187 this.sensorList = newList;
188 for (TellstickNetSensor sensor : sensorList.getSensors()) {
189 sensor.setUpdated(true);
190 for (DeviceStatusListener listener : deviceStatusListeners) {
191 listener.onDeviceAdded(getThing(), sensor);
195 logger.debug("Update sensors, reset updated flag");
196 for (TellstickNetSensor sensor : previouslist.getSensors()) {
197 sensor.setUpdated(false);
199 logger.debug("Update sensors, reset updated flag1");
201 for (TellstickNetSensor sensor : newList.getSensors()) {
202 int index = this.sensorList.getSensors().indexOf(sensor);
204 TellstickNetSensor orgSensor = this.sensorList.getSensors().get(index);
205 logger.debug("Update sensor {}, prev update {}, new update {}", sensor.getId(),
206 orgSensor.getLastUpdated(), sensor.getLastUpdated());
207 if (sensor.getLastUpdated() > orgSensor.getLastUpdated()) {
208 logger.debug("Update for sensor:{}", sensor);
209 orgSensor.setData(sensor.getData());
210 orgSensor.setLastUpdated(sensor.getLastUpdated());
211 orgSensor.setUpdated(true);
212 sensor.setUpdated(true);
215 logger.debug("Adding sensor {}, new update {}", sensor.getId(), sensor.getLastUpdated());
216 this.sensorList.getSensors().add(sensor);
217 sensor.setUpdated(true);
218 for (DeviceStatusListener listener : deviceStatusListeners) {
219 listener.onDeviceAdded(getThing(), sensor);
224 for (TellstickNetSensor sensor : sensorList.getSensors()) {
225 if (sensor.getData() != null && sensor.isUpdated()) {
226 for (DeviceStatusListener listener : deviceStatusListeners) {
227 for (DataTypeValue type : sensor.getData()) {
228 listener.onDeviceStateChanged(getThing(), sensor,
229 new TellstickNetSensorEvent(sensor.getId(), type.getValue(), type,
230 sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
233 sensor.setUpdated(false);
240 public void handleCommand(ChannelUID channelUID, Command command) {
241 if (command instanceof RefreshType) {
242 scheduleImmediateRefresh();
247 public void handleRemoval() {
248 super.handleRemoval();
252 public void thingUpdated(Thing thing) {
253 super.thingUpdated(thing);
257 public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
258 if (deviceStatusListener == null) {
259 throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
261 return deviceStatusListeners.add(deviceStatusListener);
265 public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
266 return deviceStatusListeners.remove(deviceStatusListener);
269 private Device getDevice(String id, List<TellstickNetDevice> devices) {
270 for (Device device : devices) {
271 if (device.getId() == Integer.valueOf(id)) {
278 private Device getSensor(String id, List<TellstickNetSensor> sensors) {
279 for (Device sensor : sensors) {
280 if (sensor.getId() == Integer.valueOf(id)) {
288 public Device getDevice(String serialNumber) {
289 return getDevice(serialNumber, getDevices());
292 private List<TellstickNetDevice> getDevices() {
293 if (deviceList == null) {
296 return deviceList.getDevices();
300 public Device getSensor(String deviceUUId) {
301 Device result = null;
302 if (sensorList != null) {
303 result = getSensor(deviceUUId, sensorList.getSensors());
309 public void rescanTelldusDevices() {
310 this.deviceList = null;
311 this.sensorList = null;
316 public TelldusDeviceController getController() {