2 * Copyright (c) 2010-2023 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;
20 import java.util.Vector;
21 import java.util.concurrent.ConcurrentHashMap;
23 import org.openhab.binding.tellstick.internal.conf.TellstickBridgeConfiguration;
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.core.thing.Bridge;
29 import org.openhab.core.thing.ChannelUID;
30 import org.openhab.core.thing.ThingStatus;
31 import org.openhab.core.thing.ThingStatusDetail;
32 import org.openhab.core.thing.binding.BaseBridgeHandler;
33 import org.openhab.core.types.Command;
34 import org.openhab.core.types.RefreshType;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37 import org.tellstick.JNA;
38 import org.tellstick.device.SupportedMethodsException;
39 import org.tellstick.device.TellstickDevice;
40 import org.tellstick.device.TellstickDeviceEvent;
41 import org.tellstick.device.TellstickEventHandler;
42 import org.tellstick.device.TellstickSensor;
43 import org.tellstick.device.TellstickSensorEvent;
44 import org.tellstick.device.iface.Device;
45 import org.tellstick.device.iface.DeviceChangeListener;
46 import org.tellstick.device.iface.SensorListener;
47 import org.tellstick.enums.ChangeType;
48 import org.tellstick.enums.DataType;
51 * {@link TelldusCoreBridgeHandler} is the handler for Telldus Core (Duo and Basic) and connects it
52 * to the framework. All {@link TelldusDevicesHandler}s use the
53 * {@link TelldusCoreDeviceController} to execute the actual commands.
55 * @author Jarle Hjortland - Initial contribution
57 public class TelldusCoreBridgeHandler extends BaseBridgeHandler
58 implements DeviceChangeListener, SensorListener, TelldusBridgeHandler {
60 public TelldusCoreBridgeHandler(Bridge br) {
64 private Logger logger = LoggerFactory.getLogger(TelldusCoreBridgeHandler.class);
65 private TelldusDeviceController deviceController = null;
66 private List<TellstickDevice> deviceList = new Vector<>();
67 private List<TellstickSensor> sensorList = new Vector<>();
68 private TellstickEventHandler eventHandler;
69 private static boolean initialized = false;
70 private Set<DeviceStatusListener> deviceStatusListeners = ConcurrentHashMap.newKeySet();
73 public void handleCommand(ChannelUID channelUID, Command command) {
74 if (command instanceof RefreshType) {
75 logger.debug("Refresh command received.");
76 rescanTelldusDevices();
78 logger.warn("No bridge commands defined.");
83 public void dispose() {
84 logger.debug("Telldus Core Handler disposed.");
85 if (deviceController != null) {
86 deviceController.dispose();
87 deviceController = null;
89 if (eventHandler != null) {
90 eventHandler.remove();
95 JNA.CLibrary.INSTANCE.tdClose();
99 private String init(String libraryPath) {
101 if (libraryPath != null) {
102 logger.info("Loading {} from {}", JNA.nativeLibrary, libraryPath);
103 System.setProperty("jna.library.path", libraryPath);
105 logger.info("Loading {} from system default paths", JNA.nativeLibrary);
107 TellstickDevice.setSupportedMethods(JNA.CLibrary.TELLSTICK_BELL | JNA.CLibrary.TELLSTICK_TURNOFF
108 | JNA.CLibrary.TELLSTICK_TURNON | JNA.CLibrary.TELLSTICK_DIM);
109 JNA.CLibrary.INSTANCE.tdInit();
116 public void initialize() {
117 logger.debug("Initializing Tellstick bridge handler.");
118 TellstickBridgeConfiguration configuration = getConfigAs(TellstickBridgeConfiguration.class);
119 init(configuration.libraryPath);
121 scheduler.submit(() -> {
122 rescanTelldusDevices();
124 setupDeviceController(configuration);
125 updateStatus(ThingStatus.ONLINE);
128 updateStatus(ThingStatus.UNKNOWN);
131 private void setupDeviceController(TellstickBridgeConfiguration configuration) {
132 deviceController = new TelldusCoreDeviceController(configuration.resendInterval);
133 eventHandler.addListener((TelldusCoreDeviceController) deviceController);
137 public void rescanTelldusDevices() {
139 deviceList = Collections.synchronizedList(TellstickDevice.getDevices());
140 for (TellstickDevice device : deviceList) {
141 for (DeviceStatusListener listener : deviceStatusListeners) {
142 listener.onDeviceAdded(getThing(), device);
144 for (DeviceStatusListener listener : deviceStatusListeners) {
145 listener.onDeviceStateChanged(getThing(), device,
146 new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
150 sensorList = Collections.synchronizedList(TellstickSensor.getAllSensors());
151 for (TellstickSensor sensor : sensorList) {
152 for (DeviceStatusListener listener : deviceStatusListeners) {
153 listener.onDeviceAdded(getThing(), sensor);
155 for (DeviceStatusListener listener : deviceStatusListeners) {
156 for (DataType type : sensor.getData().keySet()) {
157 listener.onDeviceStateChanged(getThing(), sensor,
158 new TellstickSensorEvent(sensor.getId(), sensor.getData(type), type,
159 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;