]> git.basschouten.com Git - openhab-addons.git/blob
03b9cf046cca75eb79d52d7682ad0050e20f30f3
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.tellstick.internal.core;
14
15 import java.util.Calendar;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.List;
19 import java.util.Set;
20 import java.util.Vector;
21 import java.util.concurrent.ConcurrentHashMap;
22
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;
49
50 /**
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.
54  *
55  * @author Jarle Hjortland - Initial contribution
56  */
57 public class TelldusCoreBridgeHandler extends BaseBridgeHandler
58         implements DeviceChangeListener, SensorListener, TelldusBridgeHandler {
59
60     public TelldusCoreBridgeHandler(Bridge br) {
61         super(br);
62     }
63
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();
71
72     @Override
73     public void handleCommand(ChannelUID channelUID, Command command) {
74         if (command instanceof RefreshType) {
75             logger.debug("Refresh command received.");
76             rescanTelldusDevices();
77         } else {
78             logger.warn("No bridge commands defined.");
79         }
80     }
81
82     @Override
83     public void dispose() {
84         logger.debug("Telldus Core Handler disposed.");
85         if (deviceController != null) {
86             deviceController.dispose();
87             deviceController = null;
88         }
89         if (eventHandler != null) {
90             eventHandler.remove();
91             eventHandler = null;
92         }
93         clearDeviceList();
94         initialized = false;
95         JNA.CLibrary.INSTANCE.tdClose();
96         super.dispose();
97     }
98
99     private String init(String libraryPath) {
100         if (!initialized) {
101             if (libraryPath != null) {
102                 logger.info("Loading {} from {}", JNA.nativeLibrary, libraryPath);
103                 System.setProperty("jna.library.path", libraryPath);
104             } else {
105                 logger.info("Loading {} from system default paths", JNA.nativeLibrary);
106             }
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();
110             initialized = true;
111         }
112         return libraryPath;
113     }
114
115     @Override
116     public void initialize() {
117         logger.debug("Initializing Tellstick bridge handler.");
118         TellstickBridgeConfiguration configuration = getConfigAs(TellstickBridgeConfiguration.class);
119         init(configuration.libraryPath);
120
121         scheduler.submit(() -> {
122             rescanTelldusDevices();
123             setupListeners();
124             setupDeviceController(configuration);
125             updateStatus(ThingStatus.ONLINE);
126         });
127
128         updateStatus(ThingStatus.UNKNOWN);
129     }
130
131     private void setupDeviceController(TellstickBridgeConfiguration configuration) {
132         deviceController = new TelldusCoreDeviceController(configuration.resendInterval);
133         eventHandler.addListener((TelldusCoreDeviceController) deviceController);
134     }
135
136     @Override
137     public void rescanTelldusDevices() {
138         try {
139             deviceList = Collections.synchronizedList(TellstickDevice.getDevices());
140             for (TellstickDevice device : deviceList) {
141                 for (DeviceStatusListener listener : deviceStatusListeners) {
142                     listener.onDeviceAdded(getThing(), device);
143                 }
144                 for (DeviceStatusListener listener : deviceStatusListeners) {
145                     listener.onDeviceStateChanged(getThing(), device,
146                             new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
147                 }
148             }
149
150             sensorList = Collections.synchronizedList(TellstickSensor.getAllSensors());
151             for (TellstickSensor sensor : sensorList) {
152                 for (DeviceStatusListener listener : deviceStatusListeners) {
153                     listener.onDeviceAdded(getThing(), sensor);
154                 }
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()));
160                     }
161
162                 }
163             }
164         } catch (SupportedMethodsException e) {
165             logger.error("Failed to get devices ", e);
166         }
167     }
168
169     private synchronized void setupListeners() {
170         eventHandler = new TellstickEventHandler(deviceList);
171         eventHandler.addListener(this);
172     }
173
174     public void onConnectionLost() {
175         logger.debug("Bridge connection lost. Updating thing status to OFFLINE.");
176         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.BRIDGE_OFFLINE);
177     }
178
179     public void onConnection() {
180         logger.debug("Bridge connected. Updating thing status to ONLINE.");
181         updateStatus(ThingStatus.ONLINE);
182     }
183
184     @Override
185     public boolean registerDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
186         if (deviceStatusListener == null) {
187             throw new IllegalArgumentException("It's not allowed to pass a null deviceStatusListener.");
188         }
189         return deviceStatusListeners.add(deviceStatusListener);
190     }
191
192     @Override
193     public boolean unregisterDeviceStatusListener(DeviceStatusListener deviceStatusListener) {
194         return deviceStatusListeners.remove(deviceStatusListener);
195     }
196
197     public void clearDeviceList() {
198         deviceList.clear();
199         sensorList.clear();
200     }
201
202     private Device getDevice(String id, List<TellstickDevice> devices) {
203         for (Device device : devices) {
204             if (device.getId() == Integer.valueOf(id)) {
205                 return device;
206             }
207         }
208         return null;
209     }
210
211     @Override
212     public Device getDevice(String serialNumber) {
213         return getDevice(serialNumber, deviceList);
214     }
215
216     @Override
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);
228             }
229         } else {
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);
242                 }
243             } else {
244                 logger.trace("Ignored update {}", newEvent);
245             }
246         }
247     }
248
249     @Override
250     public void onRequest(TellstickDeviceEvent newEvent) {
251         if (newEvent.getChangeType() == ChangeType.ADDED) {
252             for (DeviceStatusListener listener : deviceStatusListeners) {
253                 listener.onDeviceAdded(getThing(), newEvent.getDevice());
254             }
255         } else if (newEvent.getChangeType() == ChangeType.REMOVED) {
256             for (DeviceStatusListener listener : deviceStatusListeners) {
257                 listener.onDeviceRemoved(getThing(), newEvent.getDevice());
258             }
259         } else {
260             for (DeviceStatusListener listener : deviceStatusListeners) {
261                 listener.onDeviceStateChanged(getThing(), newEvent.getDevice(), newEvent);
262             }
263         }
264     }
265
266     @Override
267     public Device getSensor(String deviceUUId) {
268         for (Device device : sensorList) {
269             if (device.getUUId().equals(deviceUUId)) {
270                 return device;
271             }
272         }
273         return null;
274     }
275
276     @Override
277     public TelldusDeviceController getController() {
278         return this.deviceController;
279     }
280 }