]> git.basschouten.com Git - openhab-addons.git/blob
2c1ed8e41c07ea104b78468adfba5bda3b43c4cf
[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.Vector;
20 import java.util.concurrent.CopyOnWriteArrayList;
21
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;
48
49 /**
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.
53  *
54  * @author Jarle Hjortland - Initial contribution
55  */
56 public class TelldusCoreBridgeHandler extends BaseBridgeHandler
57         implements DeviceChangeListener, SensorListener, TelldusBridgeHandler {
58
59     public TelldusCoreBridgeHandler(Bridge br) {
60         super(br);
61     }
62
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<>();
70
71     @Override
72     public void handleCommand(ChannelUID channelUID, Command command) {
73         if (command instanceof RefreshType) {
74             logger.debug("Refresh command received.");
75             rescanTelldusDevices();
76         } else {
77             logger.warn("No bridge commands defined.");
78         }
79     }
80
81     @Override
82     public void dispose() {
83         logger.debug("Telldus Core Handler disposed.");
84         if (deviceController != null) {
85             deviceController.dispose();
86             deviceController = null;
87         }
88         if (eventHandler != null) {
89             eventHandler.remove();
90             eventHandler = null;
91         }
92         clearDeviceList();
93         initialized = false;
94         JNA.CLibrary.INSTANCE.tdClose();
95         super.dispose();
96     }
97
98     private String init(String libraryPath) {
99         if (!initialized) {
100             if (libraryPath != null) {
101                 logger.info("Loading {} from {}", JNA.nativeLibrary, libraryPath);
102                 System.setProperty("jna.library.path", libraryPath);
103             } else {
104                 logger.info("Loading {} from system default paths", JNA.nativeLibrary);
105             }
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();
109             initialized = true;
110         }
111         return libraryPath;
112     }
113
114     @Override
115     public void initialize() {
116         logger.debug("Initializing Tellstick bridge handler.");
117         TellstickBridgeConfiguration configuration = getConfigAs(TellstickBridgeConfiguration.class);
118         init(configuration.libraryPath);
119
120         scheduler.submit(() -> {
121             rescanTelldusDevices();
122             setupListeners();
123             setupDeviceController(configuration);
124             updateStatus(ThingStatus.ONLINE);
125         });
126
127         updateStatus(ThingStatus.UNKNOWN);
128     }
129
130     private void setupDeviceController(TellstickBridgeConfiguration configuration) {
131         deviceController = new TelldusCoreDeviceController(configuration.resendInterval);
132         eventHandler.addListener((TelldusCoreDeviceController) deviceController);
133     }
134
135     @Override
136     public void rescanTelldusDevices() {
137         try {
138             deviceList = Collections.synchronizedList(TellstickDevice.getDevices());
139             for (TellstickDevice device : deviceList) {
140                 for (DeviceStatusListener listener : deviceStatusListeners) {
141                     listener.onDeviceAdded(getThing(), device);
142                 }
143                 for (DeviceStatusListener listener : deviceStatusListeners) {
144                     listener.onDeviceStateChanged(getThing(), device,
145                             new TellstickDeviceEvent(device, null, null, null, System.currentTimeMillis()));
146                 }
147             }
148
149             sensorList = Collections.synchronizedList(TellstickSensor.getAllSensors());
150             for (TellstickSensor sensor : sensorList) {
151                 for (DeviceStatusListener listener : deviceStatusListeners) {
152                     listener.onDeviceAdded(getThing(), sensor);
153                 }
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()));
159                     }
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 }