]> git.basschouten.com Git - openhab-addons.git/blob
2ebed415bc32ccf945790e7cdc6198bf4da462ec
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.zway.internal.handler;
14
15 import static org.openhab.binding.zway.internal.ZWayBindingConstants.*;
16
17 import java.text.DateFormat;
18 import java.text.SimpleDateFormat;
19 import java.util.Calendar;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.concurrent.TimeUnit;
23
24 import org.openhab.binding.zway.internal.config.ZWayZWaveDeviceConfiguration;
25 import org.openhab.core.thing.Thing;
26 import org.openhab.core.thing.ThingStatus;
27 import org.openhab.core.thing.ThingStatusDetail;
28 import org.openhab.core.thing.ThingStatusInfo;
29 import org.openhab.core.thing.ThingTypeUID;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import de.fh_zwickau.informatik.sensor.model.devices.Device;
34 import de.fh_zwickau.informatik.sensor.model.devices.DeviceList;
35 import de.fh_zwickau.informatik.sensor.model.zwaveapi.devices.ZWaveDevice;
36
37 /**
38  * The {@link ZWayZWaveDeviceHandler} is responsible for handling commands, which are
39  * sent to one of the channels.
40  *
41  * @author Patrick Hecker - Initial contribution
42  */
43 public class ZWayZWaveDeviceHandler extends ZWayDeviceHandler {
44     public static final ThingTypeUID SUPPORTED_THING_TYPE = THING_TYPE_DEVICE;
45
46     private final Logger logger = LoggerFactory.getLogger(getClass());
47
48     private ZWayZWaveDeviceConfiguration mConfig;
49
50     private class Initializer implements Runnable {
51
52         @Override
53         public void run() {
54             ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
55             if (zwayBridgeHandler != null && zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
56                 ThingStatusInfo statusInfo = zwayBridgeHandler.getThing().getStatusInfo();
57                 logger.debug("Change Z-Way Z-Wave device status to bridge status: {}", statusInfo);
58
59                 // Set thing status to bridge status
60                 updateStatus(statusInfo.getStatus(), statusInfo.getStatusDetail(), statusInfo.getDescription());
61
62                 // Add all available channels
63                 logger.debug("Add all available channels");
64                 DeviceList deviceList = getZWayBridgeHandler().getZWayApi().getDevices();
65                 if (deviceList != null) {
66                     logger.debug("Z-Way devices loaded ({} physical devices)",
67                             deviceList.getDevicesGroupByNodeId().size());
68
69                     // https://community.openhab.org/t/oh2-major-bug-with-scheduled-jobs/12350/11
70                     // If any execution of the task encounters an exception, subsequent executions are
71                     // suppressed. Otherwise, the task will only terminate via cancellation or
72                     // termination of the executor.
73                     try {
74                         // physical device means all virtual devices grouped by physical device
75                         Map<Integer, List<Device>> physicalDevice = deviceList.getDevicesByNodeId(mConfig.getNodeId());
76                         if (physicalDevice != null) {
77                             logger.debug("Z-Wave device with node id {} found with {} virtual devices",
78                                     mConfig.getNodeId(), physicalDevice.get(mConfig.getNodeId()).size());
79
80                             for (Map.Entry<Integer, List<Device>> entry : physicalDevice.entrySet()) {
81                                 logger.debug("Add channels for physical device with node id: {}", mConfig.getNodeId());
82
83                                 List<Device> devices = entry.getValue();
84
85                                 for (Device device : devices) {
86                                     if (device.getVisibility() && !device.getPermanentlyHidden()) {
87                                         logger.debug("Add channel for virtual device: {}",
88                                                 device.getMetrics().getTitle());
89                                         addDeviceAsChannel(device);
90                                     } else {
91                                         logger.debug("Device {} has been skipped, because it was hidden in Z-Way.",
92                                                 device.getMetrics().getTitle());
93                                     }
94                                 }
95                             }
96                         } else {
97                             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
98                                     "Z-Way physical device with node id " + mConfig.getNodeId() + " not found.");
99                         }
100
101                         // Check command classes (only for ThermostatMode)
102                         ZWaveDevice zwaveDevice = getZWayBridgeHandler().getZWayApi()
103                                 .getZWaveDevice(mConfig.getNodeId());
104                         if (!"".equals(zwaveDevice.getInstances().get0().getCommandClasses().get64().getName())) {
105                             // Load available thermostat modes
106                             Map<Integer, String> modes = zwaveDevice.getInstances().get0().getCommandClasses().get64()
107                                     .getThermostatModes();
108
109                             logger.debug(
110                                     "Z-Wave device implements command class ThermostatMode with the following modes: {}",
111                                     modes.toString());
112
113                             addCommandClassThermostatModeAsChannel(modes, mConfig.getNodeId());
114                         }
115
116                         // Starts polling job and register all linked items
117                         completeInitialization();
118                     } catch (Throwable t) {
119                         if (t instanceof Exception) {
120                             logger.error("{}", t.getMessage());
121                         } else if (t instanceof Error) {
122                             logger.error("{}", t.getMessage());
123                         } else {
124                             logger.error("Unexpected error");
125                         }
126                         if (getThing().getStatus() == ThingStatus.ONLINE) {
127                             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
128                                     "Error occurred when adding device as channel.");
129                         }
130                     }
131                 } else {
132                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
133                             "Devices not loaded");
134                 }
135             } else {
136                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.HANDLER_INITIALIZING_ERROR,
137                         "Z-Way bridge handler not found or not ONLINE.");
138             }
139         }
140     }
141
142     public ZWayZWaveDeviceHandler(Thing thing) {
143         super(thing);
144     }
145
146     @Override
147     public void initialize() {
148         logger.debug("Initializing Z-Way device handler ...");
149
150         // Set thing status to a valid status
151         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
152                 "Checking configuration and bridge...");
153
154         // Configuration - thing status update with an error message
155         mConfig = loadAndCheckConfiguration();
156
157         if (mConfig != null) {
158             logger.debug("Configuration complete: {}", mConfig);
159
160             // Start an extra thread to check the connection, because it takes sometimes more
161             // than 5000 milliseconds and the handler will suspend (ThingStatus.UNINITIALIZED).
162             scheduler.schedule(new Initializer(), 2, TimeUnit.SECONDS);
163         } else {
164             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Z-Way node id required!");
165         }
166     }
167
168     private void completeInitialization() {
169         super.initialize(); // starts polling job and register all linked items
170     }
171
172     private ZWayZWaveDeviceConfiguration loadAndCheckConfiguration() {
173         ZWayZWaveDeviceConfiguration config = getConfigAs(ZWayZWaveDeviceConfiguration.class);
174
175         if (config.getNodeId() == null) {
176             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
177                     "Z-Wave device couldn't create, because the node id is missing.");
178             return null;
179         }
180
181         return config;
182     }
183
184     @Override
185     public void dispose() {
186         logger.debug("Dispose Z-Way Z-Wave handler ...");
187
188         if (mConfig.getNodeId() != null) {
189             mConfig.setNodeId(null);
190         }
191
192         super.dispose();
193     }
194
195     @Override
196     protected void refreshLastUpdate() {
197         logger.debug("Refresh last update for Z-Wave device");
198
199         // Check Z-Way bridge handler
200         ZWayBridgeHandler zwayBridgeHandler = getZWayBridgeHandler();
201         if (zwayBridgeHandler == null || !zwayBridgeHandler.getThing().getStatus().equals(ThingStatus.ONLINE)) {
202             logger.debug("Z-Way bridge handler not found or not ONLINE.");
203             return;
204         }
205
206         // Load and check Z-Wave device from Z-Way server (Z-Wave API)
207         ZWaveDevice zwaveDevice = zwayBridgeHandler.getZWayApi().getZWaveDevice(mConfig.getNodeId());
208         if (zwaveDevice == null) {
209             logger.debug("Z-Wave device not found.");
210             return;
211         }
212
213         Calendar lastUpdateOfDevice = Calendar.getInstance();
214         lastUpdateOfDevice
215                 .setTimeInMillis(Long.valueOf(zwaveDevice.getData().getLastReceived().getUpdateTime()) * 1000);
216
217         if (lastUpdate == null || lastUpdateOfDevice.after(lastUpdate)) {
218             lastUpdate = lastUpdateOfDevice;
219         }
220
221         DateFormat formatter = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
222         updateProperty(DEVICE_PROP_LAST_UPDATE, formatter.format(lastUpdate.getTime()));
223     }
224 }