]> git.basschouten.com Git - openhab-addons.git/blob
5160a41b6de483aa82b331a295c8c15fad2e0d5d
[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.plugwise.internal.handler;
14
15 import static org.openhab.binding.plugwise.internal.PlugwiseBindingConstants.*;
16
17 import java.time.Duration;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.plugwise.internal.config.PlugwiseSenseConfig;
22 import org.openhab.binding.plugwise.internal.protocol.AcknowledgementMessage;
23 import org.openhab.binding.plugwise.internal.protocol.Message;
24 import org.openhab.binding.plugwise.internal.protocol.SenseBoundariesSetRequestMessage;
25 import org.openhab.binding.plugwise.internal.protocol.SenseReportIntervalSetRequest;
26 import org.openhab.binding.plugwise.internal.protocol.SenseReportRequestMessage;
27 import org.openhab.binding.plugwise.internal.protocol.SleepSetRequestMessage;
28 import org.openhab.binding.plugwise.internal.protocol.field.BoundaryType;
29 import org.openhab.binding.plugwise.internal.protocol.field.DeviceType;
30 import org.openhab.binding.plugwise.internal.protocol.field.MACAddress;
31 import org.openhab.core.config.core.Configuration;
32 import org.openhab.core.library.types.QuantityType;
33 import org.openhab.core.library.unit.SIUnits;
34 import org.openhab.core.library.unit.Units;
35 import org.openhab.core.thing.Thing;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * <p>
41  * The {@link PlugwiseSenseHandler} handles channel updates and commands for a Plugwise Sense device.
42  * </p>
43  * <p>
44  * The Sense is a wireless temperature/humidity sensor that switches on groups of devices depending on the current
45  * temperature or humidity level. It also periodically reports back the current temperature and humidity levels.
46  * </p>
47  *
48  * @author Wouter Born - Initial contribution
49  */
50 @NonNullByDefault
51 public class PlugwiseSenseHandler extends AbstractSleepingEndDeviceHandler {
52
53     private final Logger logger = LoggerFactory.getLogger(PlugwiseSenseHandler.class);
54     private final DeviceType deviceType = DeviceType.SENSE;
55
56     private @NonNullByDefault({}) PlugwiseSenseConfig configuration;
57     private @NonNullByDefault({}) MACAddress macAddress;
58
59     // Flags that keep track of the pending Sense configuration updates. When the corresponding Thing configuration
60     // parameters change a flag is set to true. When the Sense goes online the respective command is sent to update the
61     // device configuration. When the Sense acknowledges a command the respective flag is again set to false.
62     private boolean updateBoundaryParameters;
63     private boolean updateMeasurementInterval;
64     private boolean updateSleepParameters;
65
66     public PlugwiseSenseHandler(Thing thing) {
67         super(thing);
68     }
69
70     @Override
71     protected MACAddress getMACAddress() {
72         return macAddress;
73     }
74
75     @Override
76     protected Duration getWakeupDuration() {
77         return configuration.getWakeupDuration();
78     }
79
80     @Override
81     protected void handleAcknowledgement(AcknowledgementMessage message) {
82         boolean oldConfigurationPending = isConfigurationPending();
83
84         switch (message.getExtensionCode()) {
85             case SENSE_BOUNDARIES_SET_ACK:
86                 logger.debug("Received ACK for boundaries parameters set of {} ({})", deviceType, macAddress);
87                 updateBoundaryParameters = false;
88                 break;
89             case SENSE_BOUNDARIES_SET_NACK:
90                 logger.debug("Received NACK for boundaries parameters set of {} ({})", deviceType, macAddress);
91                 break;
92             case SENSE_INTERVAL_SET_ACK:
93                 logger.debug("Received ACK for measurement interval set of {} ({})", deviceType, macAddress);
94                 updateMeasurementInterval = false;
95                 break;
96             case SENSE_INTERVAL_SET_NACK:
97                 logger.debug("Received NACK for measurement interval set of {} ({})", deviceType, macAddress);
98                 break;
99             case SLEEP_SET_ACK:
100                 logger.debug("Received ACK for sleep set of {} ({})", deviceType, macAddress);
101                 updateSleepParameters = false;
102                 break;
103             default:
104                 logger.trace("Received unhandled {} message from {} ({})", message.getType(), deviceType, macAddress);
105                 break;
106         }
107
108         boolean newConfigurationPending = isConfigurationPending();
109
110         if (oldConfigurationPending != newConfigurationPending && !newConfigurationPending) {
111             Configuration newConfiguration = editConfiguration();
112             newConfiguration.put(CONFIG_PROPERTY_UPDATE_CONFIGURATION, false);
113             updateConfiguration(newConfiguration);
114         }
115
116         super.handleAcknowledgement(message);
117     }
118
119     @Override
120     public void handleResponseMessage(Message message) {
121         switch (message.getType()) {
122             case SENSE_REPORT_REQUEST:
123                 handleSenseReportRequestMessage((SenseReportRequestMessage) message);
124                 break;
125             default:
126                 super.handleResponseMessage(message);
127                 break;
128         }
129     }
130
131     private void handleSenseReportRequestMessage(SenseReportRequestMessage message) {
132         updateLastSeen();
133         updateState(CHANNEL_HUMIDITY, new QuantityType<>(message.getHumidity().getValue(), Units.PERCENT));
134         updateState(CHANNEL_TEMPERATURE, new QuantityType<>(message.getTemperature().getValue(), SIUnits.CELSIUS));
135     }
136
137     @Override
138     public void initialize() {
139         configuration = getConfigAs(PlugwiseSenseConfig.class);
140         macAddress = configuration.getMACAddress();
141         if (!isInitialized()) {
142             setUpdateCommandFlags(null, configuration);
143         }
144         super.initialize();
145     }
146
147     @Override
148     protected boolean isConfigurationPending() {
149         return updateBoundaryParameters || updateMeasurementInterval || updateSleepParameters;
150     }
151
152     @Override
153     protected void sendConfigurationUpdateCommands() {
154         logger.debug("Sending {} ({}) configuration update commands", deviceType, macAddress);
155
156         if (updateBoundaryParameters) {
157             SenseBoundariesSetRequestMessage message;
158             if (configuration.getBoundaryType() == BoundaryType.HUMIDITY) {
159                 message = new SenseBoundariesSetRequestMessage(macAddress, configuration.getHumidityBoundaryMin(),
160                         configuration.getHumidityBoundaryMax(), configuration.getBoundaryAction());
161             } else if (configuration.getBoundaryType() == BoundaryType.TEMPERATURE) {
162                 message = new SenseBoundariesSetRequestMessage(macAddress, configuration.getTemperatureBoundaryMin(),
163                         configuration.getTemperatureBoundaryMax(), configuration.getBoundaryAction());
164             } else {
165                 message = new SenseBoundariesSetRequestMessage(macAddress);
166             }
167
168             logger.debug("Sending command to update {} ({}) boundary parameters", deviceType, macAddress);
169             sendCommandMessage(message);
170         }
171         if (updateMeasurementInterval) {
172             logger.debug("Sending command to update {} ({}) measurement interval", deviceType, macAddress);
173             sendCommandMessage(new SenseReportIntervalSetRequest(macAddress, configuration.getMeasurementInterval()));
174         }
175         if (updateSleepParameters) {
176             logger.debug("Sending command to update {} ({}) sleep parameters", deviceType, macAddress);
177             sendCommandMessage(new SleepSetRequestMessage(macAddress, configuration.getWakeupDuration(),
178                     configuration.getWakeupInterval()));
179         }
180
181         super.sendConfigurationUpdateCommands();
182     }
183
184     private void setUpdateCommandFlags(@Nullable PlugwiseSenseConfig oldConfiguration,
185             PlugwiseSenseConfig newConfiguration) {
186         boolean fullUpdate = newConfiguration.isUpdateConfiguration() && !isConfigurationPending();
187         if (fullUpdate) {
188             logger.debug("Updating all configuration properties of {} ({})", deviceType, macAddress);
189         }
190
191         updateBoundaryParameters = fullUpdate
192                 || (oldConfiguration != null && !oldConfiguration.equalBoundaryParameters(newConfiguration));
193         if (updateBoundaryParameters) {
194             logger.debug("Updating {} ({}) boundary parameters when online", deviceType, macAddress);
195         }
196
197         updateMeasurementInterval = fullUpdate || (oldConfiguration != null
198                 && !oldConfiguration.getMeasurementInterval().equals(newConfiguration.getMeasurementInterval()));
199         if (updateMeasurementInterval) {
200             logger.debug("Updating {} ({}) measurement interval when online", deviceType, macAddress);
201         }
202
203         updateSleepParameters = fullUpdate
204                 || (oldConfiguration != null && !oldConfiguration.equalSleepParameters(newConfiguration));
205         if (updateSleepParameters) {
206             logger.debug("Updating {} ({}) sleep parameters when online", deviceType, macAddress);
207         }
208     }
209
210     @Override
211     protected void updateConfiguration(Configuration configuration) {
212         PlugwiseSenseConfig oldConfiguration = this.configuration;
213         PlugwiseSenseConfig newConfiguration = configuration.as(PlugwiseSenseConfig.class);
214
215         setUpdateCommandFlags(oldConfiguration, newConfiguration);
216         configuration.put(CONFIG_PROPERTY_UPDATE_CONFIGURATION, isConfigurationPending());
217
218         super.updateConfiguration(configuration);
219     }
220 }