2 * Copyright (c) 2010-2020 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.openhab.core.types.State;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42 import org.tellstick.device.TellstickDeviceEvent;
43 import org.tellstick.device.TellstickException;
44 import org.tellstick.device.iface.Device;
47 * {@link TelldusLiveBridgeHandler} is the handler for Telldus Live service (Tellstick.NET and ZNET) and connects it
48 * to the framework. All {@link TelldusDevicesHandler}s use the
49 * {@link TelldusLiveDeviceController} to execute the actual commands.
51 * @author Jarle Hjortland - Initial contribution
53 public class TelldusLiveBridgeHandler extends BaseBridgeHandler implements TelldusBridgeHandler {
55 private final Logger logger = LoggerFactory.getLogger(TelldusLiveBridgeHandler.class);
57 private TellstickNetDevices deviceList = null;
58 private TellstickNetSensors sensorList = null;
59 private TelldusLiveDeviceController controller = new TelldusLiveDeviceController();
60 private List<DeviceStatusListener> deviceStatusListeners = new Vector<>();
62 private static final int REFRESH_DELAY = 10;
64 public TelldusLiveBridgeHandler(Bridge bridge) {
68 private ScheduledFuture<?> pollingJob;
69 private ScheduledFuture<?> immediateRefreshJob;
72 public void dispose() {
73 logger.debug("Live Handler disposed.");
74 if (pollingJob != null) {
75 pollingJob.cancel(true);
77 if (this.controller != null) {
78 this.controller.dispose();
86 public void initialize() {
87 logger.debug("Initializing TelldusLive bridge handler.");
88 TelldusLiveConfiguration configuration = getConfigAs(TelldusLiveConfiguration.class);
89 this.controller = new TelldusLiveDeviceController();
90 this.controller.connectHttpClient(configuration.publicKey, configuration.privateKey, configuration.token,
91 configuration.tokenSecret);
92 startAutomaticRefresh(configuration.refreshInterval);
94 updateStatus(ThingStatus.ONLINE);
97 private synchronized void startAutomaticRefresh(long refreshInterval) {
98 if (pollingJob != null && !pollingJob.isCancelled()) {
99 pollingJob.cancel(true);
101 pollingJob = scheduler.scheduleWithFixedDelay(this::refreshDeviceList, 0, refreshInterval,
102 TimeUnit.MILLISECONDS);
105 private void scheduleImmediateRefresh() {
106 // We schedule in 10 sec, to avoid multiple updates
107 logger.debug("Current remaining delay {}", pollingJob.getDelay(TimeUnit.SECONDS));
108 if (pollingJob.getDelay(TimeUnit.SECONDS) > REFRESH_DELAY) {
109 if (immediateRefreshJob == null || immediateRefreshJob.isDone()) {
110 immediateRefreshJob = scheduler.schedule(this::refreshDeviceList, REFRESH_DELAY, TimeUnit.SECONDS);
115 synchronized void refreshDeviceList() {
117 updateDevices(deviceList);
118 updateSensors(sensorList);
119 updateStatus(ThingStatus.ONLINE);
120 } catch (TellstickException e) {
121 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
122 logger.error("Failed to update", e);
123 } catch (Exception e) {
124 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
125 logger.error("Failed to update", e);
129 private synchronized void updateDevices(TellstickNetDevices previouslist) throws TellstickException {
130 TellstickNetDevices newList = controller.callRestMethod(TelldusLiveDeviceController.HTTP_TELLDUS_DEVICES,
131 TellstickNetDevices.class);
132 logger.debug("Device list {}", newList.getDevices());
133 if (newList.getDevices() != null) {
134 if (previouslist == null) {
135 logger.debug("updateDevices, Creating devices.");
136 for (TellstickNetDevice device : newList.getDevices()) {
137 device.setUpdated(true);
138 for (DeviceStatusListener listener : deviceStatusListeners) {
139 listener.onDeviceAdded(getThing(), device);
142 this.deviceList = newList;
144 logger.debug("updateDevices, Updating devices.");
145 for (TellstickNetDevice device : newList.getDevices()) {
146 int index = previouslist.getDevices().indexOf(device);
147 logger.debug("Device:{} found at {}", device, index);
149 TellstickNetDevice orgDevice = previouslist.getDevices().get(index);
150 if (device.getState() != orgDevice.getState()) {
151 orgDevice.setState(device.getState());
152 orgDevice.setStatevalue(device.getStatevalue());
153 orgDevice.setUpdated(true);
156 logger.debug("New Device - Adding:{}", device);
157 previouslist.getDevices().add(device);
158 device.setUpdated(true);
159 for (DeviceStatusListener listener : deviceStatusListeners) {
160 listener.onDeviceAdded(getThing(), device);
166 for (TellstickNetDevice device : deviceList.getDevices()) {
167 if (device.isUpdated()) {
168 logger.debug("Updated device:{}", device);
169 for (DeviceStatusListener listener : deviceStatusListeners) {
170 listener.onDeviceStateChanged(getThing(), device,
171 new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
173 device.setUpdated(false);
179 private synchronized void updateSensors(TellstickNetSensors previouslist) throws TellstickException {
180 TellstickNetSensors newList = controller.callRestMethod(TelldusLiveDeviceController.HTTP_TELLDUS_SENSORS,
181 TellstickNetSensors.class);
182 logger.debug("Updated sensors:{}", newList.getSensors());
183 if (newList.getSensors() != null) {
184 if (previouslist == null) {
185 logger.debug("First update of sensors");
186 this.sensorList = newList;
187 for (TellstickNetSensor sensor : sensorList.getSensors()) {
188 sensor.setUpdated(true);
189 for (DeviceStatusListener listener : deviceStatusListeners) {
190 listener.onDeviceAdded(getThing(), sensor);
194 logger.debug("Update sensors, reset updated flag");
195 for (TellstickNetSensor sensor : previouslist.getSensors()) {
196 sensor.setUpdated(false);
198 logger.debug("Update sensors, reset updated flag1");
200 for (TellstickNetSensor sensor : newList.getSensors()) {
201 int index = this.sensorList.getSensors().indexOf(sensor);
203 TellstickNetSensor orgSensor = this.sensorList.getSensors().get(index);
204 logger.debug("Update sensor {}, prev update {}, new update {}", sensor.getId(),
205 orgSensor.getLastUpdated(), sensor.getLastUpdated());
206 if (sensor.getLastUpdated() > orgSensor.getLastUpdated()) {
207 logger.debug("Update for sensor:{}", sensor);
208 orgSensor.setData(sensor.getData());
209 orgSensor.setLastUpdated(sensor.getLastUpdated());
210 orgSensor.setUpdated(true);
211 sensor.setUpdated(true);
214 logger.debug("Adding sensor {}, new update {}", sensor.getId(), sensor.getLastUpdated());
215 this.sensorList.getSensors().add(sensor);
216 sensor.setUpdated(true);
217 for (DeviceStatusListener listener : deviceStatusListeners) {
218 listener.onDeviceAdded(getThing(), sensor);
223 for (TellstickNetSensor sensor : sensorList.getSensors()) {
224 if (sensor.getData() != null && sensor.isUpdated()) {
225 for (DeviceStatusListener listener : deviceStatusListeners) {
226 for (DataTypeValue type : sensor.getData()) {
227 listener.onDeviceStateChanged(getThing(), sensor,
228 new TellstickNetSensorEvent(sensor.getId(), type.getValue(), type,
229 sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
232 sensor.setUpdated(false);
239 public void handleCommand(ChannelUID channelUID, Command command) {
240 if (command instanceof RefreshType) {
241 scheduleImmediateRefresh();
246 public void handleRemoval() {
247 super.handleRemoval();
251 public void handleUpdate(ChannelUID channelUID, State newState) {
252 super.handleUpdate(channelUID, newState);
256 public void thingUpdated(Thing thing) {
257 super.thingUpdated(thing);
261 public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
262 if (deviceStatusListener == null) {
263 throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
265 return deviceStatusListeners.add(deviceStatusListener);
269 public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
270 return deviceStatusListeners.remove(deviceStatusListener);
273 private Device getDevice(String id, List<TellstickNetDevice> devices) {
274 for (Device device : devices) {
275 if (device.getId() == Integer.valueOf(id)) {
282 private Device getSensor(String id, List<TellstickNetSensor> sensors) {
283 for (Device sensor : sensors) {
284 if (sensor.getId() == Integer.valueOf(id)) {
292 public Device getDevice(String serialNumber) {
293 return getDevice(serialNumber, getDevices());
296 private List<TellstickNetDevice> getDevices() {
297 if (deviceList == null) {
300 return deviceList.getDevices();
304 public Device getSensor(String deviceUUId) {
305 Device result = null;
306 if (sensorList != null) {
307 result = getSensor(deviceUUId, sensorList.getSensors());
313 public void rescanTelldusDevices() {
314 this.deviceList = null;
315 this.sensorList = null;
320 public TelldusDeviceController getController() {