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.core;
15 import java.util.Calendar;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.List;
19 import java.util.Vector;
20 import java.util.concurrent.CopyOnWriteArrayList;
22 import org.openhab.binding.tellstick.internal.conf.TellstickBridgeConfiguration;
23 import org.openhab.binding.tellstick.internal.handler.DeviceStatusListener;
24 import org.openhab.binding.tellstick.internal.handler.TelldusBridgeHandler;
25 import org.openhab.binding.tellstick.internal.handler.TelldusDeviceController;
26 import org.openhab.binding.tellstick.internal.handler.TelldusDevicesHandler;
27 import org.openhab.core.thing.Bridge;
28 import org.openhab.core.thing.ChannelUID;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.thing.binding.BaseBridgeHandler;
32 import org.openhab.core.types.Command;
33 import org.openhab.core.types.RefreshType;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36 import org.tellstick.JNA;
37 import org.tellstick.device.SupportedMethodsException;
38 import org.tellstick.device.TellstickDevice;
39 import org.tellstick.device.TellstickDeviceEvent;
40 import org.tellstick.device.TellstickEventHandler;
41 import org.tellstick.device.TellstickSensor;
42 import org.tellstick.device.TellstickSensorEvent;
43 import org.tellstick.device.iface.Device;
44 import org.tellstick.device.iface.DeviceChangeListener;
45 import org.tellstick.device.iface.SensorListener;
46 import org.tellstick.enums.ChangeType;
47 import org.tellstick.enums.DataType;
50 * {@link TelldusCoreBridgeHandler} is the handler for Telldus Core (Duo and Basic) and connects it
51 * to the framework. All {@link TelldusDevicesHandler}s use the
52 * {@link TelldusCoreDeviceController} to execute the actual commands.
54 * @author Jarle Hjortland - Initial contribution
56 public class TelldusCoreBridgeHandler extends BaseBridgeHandler
57 implements DeviceChangeListener, SensorListener, TelldusBridgeHandler {
59 public TelldusCoreBridgeHandler(Bridge br) {
63 private Logger logger = LoggerFactory.getLogger(TelldusCoreBridgeHandler.class);
64 private TelldusDeviceController deviceController = null;
65 private List<TellstickDevice> deviceList = new Vector<>();
66 private List<TellstickSensor> sensorList = new Vector<>();
67 private TellstickEventHandler eventHandler;
68 private static boolean initialized = false;
69 private List<DeviceStatusListener> deviceStatusListeners = new CopyOnWriteArrayList<>();
72 public void handleCommand(ChannelUID channelUID, Command command) {
73 if (command instanceof RefreshType) {
74 logger.debug("Refresh command received.");
75 rescanTelldusDevices();
77 logger.warn("No bridge commands defined.");
82 public void dispose() {
83 logger.debug("Telldus Core Handler disposed.");
84 if (deviceController != null) {
85 deviceController.dispose();
86 deviceController = null;
88 if (eventHandler != null) {
89 eventHandler.remove();
94 JNA.CLibrary.INSTANCE.tdClose();
98 private String init(String libraryPath) {
100 if (libraryPath != null) {
101 logger.info("Loading {} from {}", JNA.nativeLibrary, libraryPath);
102 System.setProperty("jna.library.path", libraryPath);
104 logger.info("Loading {} from system default paths", JNA.nativeLibrary);
106 TellstickDevice.setSupportedMethods(JNA.CLibrary.TELLSTICK_BELL | JNA.CLibrary.TELLSTICK_TURNOFF
107 | JNA.CLibrary.TELLSTICK_TURNON | JNA.CLibrary.TELLSTICK_DIM);
108 JNA.CLibrary.INSTANCE.tdInit();
115 public void initialize() {
116 logger.debug("Initializing Tellstick bridge handler.");
117 TellstickBridgeConfiguration configuration = getConfigAs(TellstickBridgeConfiguration.class);
118 init(configuration.libraryPath);
120 scheduler.submit(() -> {
121 rescanTelldusDevices();
123 setupDeviceController(configuration);
124 updateStatus(ThingStatus.ONLINE);
127 updateStatus(ThingStatus.UNKNOWN);
130 private void setupDeviceController(TellstickBridgeConfiguration configuration) {
131 deviceController = new TelldusCoreDeviceController(configuration.resendInterval);
132 eventHandler.addListener((TelldusCoreDeviceController) deviceController);
136 public void rescanTelldusDevices() {
138 deviceList = Collections.synchronizedList(TellstickDevice.getDevices());
139 for (TellstickDevice device : deviceList) {
140 for (DeviceStatusListener listener : deviceStatusListeners) {
141 listener.onDeviceAdded(getThing(), device);
143 for (DeviceStatusListener listener : deviceStatusListeners) {
144 listener.onDeviceStateChanged(getThing(), device,
145 new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
149 sensorList = Collections.synchronizedList(TellstickSensor.getAllSensors());
150 for (TellstickSensor sensor : sensorList) {
151 for (DeviceStatusListener listener : deviceStatusListeners) {
152 listener.onDeviceAdded(getThing(), sensor);
154 for (DeviceStatusListener listener : deviceStatusListeners) {
155 for (DataType type : sensor.getData().keySet()) {
156 listener.onDeviceStateChanged(getThing(), sensor,
157 new TellstickSensorEvent(sensor.getId(), sensor.getData(type), type,
158 sensor.getProtocol(), sensor.getModel(), System.currentTimeMillis()));
164 } catch (SupportedMethodsException e) {
165 logger.error("Failed to get devices ", e);
169 private synchronized void setupListeners() {
170 eventHandler = new TellstickEventHandler(deviceList);
171 eventHandler.addListener(this);
174 public void onConnectionLost() {
175 logger.debug("Bridge connection lost. Updating thing status to OFFLINE.");
176 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
179 public void onConnection() {
180 logger.debug("Bridge connected. Updating thing status to ONLINE.");
181 updateStatus(ThingStatus.ONLINE);
185 public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
186 if (deviceStatusListener == null) {
187 throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
189 return deviceStatusListeners.add(deviceStatusListener);
193 public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
194 return deviceStatusListeners.remove(deviceStatusListener);
197 public void clearDeviceList() {
202 private Device getDevice(String id, List<TellstickDevice> devices) {
203 for (Device device : devices) {
204 if (device.getId() == Integer.valueOf(id)) {
212 public Device getDevice(String serialNumber) {
213 return getDevice(serialNumber, deviceList);
217 public void onRequest(TellstickSensorEvent newEvent) {
218 String uuid = TellstickSensor.createUUId(newEvent.getSensorId(), newEvent.getModel(), newEvent.getProtocol());
219 Device device = getSensor(uuid);
220 logger.debug("Sensor Event for {} event {}", device, newEvent);
221 if (device == null) {
222 TellstickSensor sensor = new TellstickSensor(newEvent.getSensorId(), newEvent.getProtocol(),
223 newEvent.getModel());
224 sensor.setData(newEvent.getDataType(), newEvent.getData());
225 sensorList.add(sensor);
226 for (DeviceStatusListener listener : deviceStatusListeners) {
227 listener.onDeviceAdded(getThing(), sensor);
230 TellstickSensor useSensor = (TellstickSensor) device;
231 String currentValue = useSensor.getData(newEvent.getDataType());
232 Calendar compdate = Calendar.getInstance();
233 compdate.add(Calendar.MINUTE, -1);
234 logger.debug("Update curr {} new {}", currentValue, newEvent.getData());
235 if (currentValue == null || !currentValue.equals(newEvent.getData())
236 || useSensor.getTimeStamp().before(compdate.getTime())) {
237 // Changed or more than 1 minute since update
238 useSensor.setData(newEvent.getDataType(), newEvent.getData());
239 useSensor.setTimeStamp(new Date(newEvent.getTimestamp()));
240 for (DeviceStatusListener listener : deviceStatusListeners) {
241 listener.onDeviceStateChanged(getThing(), useSensor, newEvent);
244 logger.trace("Ignored update {}", newEvent);
250 public void onRequest(TellstickDeviceEvent newEvent) {
251 if (newEvent.getChangeType() == ChangeType.ADDED) {
252 for (DeviceStatusListener listener : deviceStatusListeners) {
253 listener.onDeviceAdded(getThing(), newEvent.getDevice());
255 } else if (newEvent.getChangeType() == ChangeType.REMOVED) {
256 for (DeviceStatusListener listener : deviceStatusListeners) {
257 listener.onDeviceRemoved(getThing(), newEvent.getDevice());
260 for (DeviceStatusListener listener : deviceStatusListeners) {
261 listener.onDeviceStateChanged(getThing(), newEvent.getDevice(), newEvent);
267 public Device getSensor(String deviceUUId) {
268 for (Device device : sensorList) {
269 if (device.getUUId().equals(deviceUUId)) {
277 public TelldusDeviceController getController() {
278 return this.deviceController;