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.plugwise.internal.handler;
15 import static org.openhab.binding.plugwise.internal.PlugwiseBindingConstants.*;
17 import java.time.Duration;
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;
41 * The {@link PlugwiseSenseHandler} handles channel updates and commands for a Plugwise Sense device.
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.
48 * @author Wouter Born - Initial contribution
51 public class PlugwiseSenseHandler extends AbstractSleepingEndDeviceHandler {
53 private final Logger logger = LoggerFactory.getLogger(PlugwiseSenseHandler.class);
54 private final DeviceType deviceType = DeviceType.SENSE;
56 private @NonNullByDefault({}) PlugwiseSenseConfig configuration;
57 private @NonNullByDefault({}) MACAddress macAddress;
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;
66 public PlugwiseSenseHandler(Thing thing) {
71 protected MACAddress getMACAddress() {
76 protected Duration getWakeupDuration() {
77 return configuration.getWakeupDuration();
81 protected void handleAcknowledgement(AcknowledgementMessage message) {
82 boolean oldConfigurationPending = isConfigurationPending();
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;
89 case SENSE_BOUNDARIES_SET_NACK:
90 logger.debug("Received NACK for boundaries parameters set of {} ({})", deviceType, macAddress);
92 case SENSE_INTERVAL_SET_ACK:
93 logger.debug("Received ACK for measurement interval set of {} ({})", deviceType, macAddress);
94 updateMeasurementInterval = false;
96 case SENSE_INTERVAL_SET_NACK:
97 logger.debug("Received NACK for measurement interval set of {} ({})", deviceType, macAddress);
100 logger.debug("Received ACK for sleep set of {} ({})", deviceType, macAddress);
101 updateSleepParameters = false;
104 logger.trace("Received unhandled {} message from {} ({})", message.getType(), deviceType, macAddress);
108 boolean newConfigurationPending = isConfigurationPending();
110 if (oldConfigurationPending != newConfigurationPending && !newConfigurationPending) {
111 Configuration newConfiguration = editConfiguration();
112 newConfiguration.put(CONFIG_PROPERTY_UPDATE_CONFIGURATION, false);
113 updateConfiguration(newConfiguration);
116 super.handleAcknowledgement(message);
120 public void handleReponseMessage(Message message) {
121 switch (message.getType()) {
122 case SENSE_REPORT_REQUEST:
123 handleSenseReportRequestMessage((SenseReportRequestMessage) message);
126 super.handleReponseMessage(message);
131 private void handleSenseReportRequestMessage(SenseReportRequestMessage message) {
133 updateState(CHANNEL_HUMIDITY, new QuantityType<>(message.getHumidity().getValue(), Units.PERCENT));
134 updateState(CHANNEL_TEMPERATURE, new QuantityType<>(message.getTemperature().getValue(), SIUnits.CELSIUS));
138 public void initialize() {
139 configuration = getConfigAs(PlugwiseSenseConfig.class);
140 macAddress = configuration.getMACAddress();
141 if (!isInitialized()) {
142 setUpdateCommandFlags(null, configuration);
148 protected boolean isConfigurationPending() {
149 return updateBoundaryParameters || updateMeasurementInterval || updateSleepParameters;
153 protected void sendConfigurationUpdateCommands() {
154 logger.debug("Sending {} ({}) configuration update commands", deviceType, macAddress);
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());
165 message = new SenseBoundariesSetRequestMessage(macAddress);
168 logger.debug("Sending command to update {} ({}) boundary parameters", deviceType, macAddress);
169 sendCommandMessage(message);
171 if (updateMeasurementInterval) {
172 logger.debug("Sending command to update {} ({}) measurement interval", deviceType, macAddress);
173 sendCommandMessage(new SenseReportIntervalSetRequest(macAddress, configuration.getMeasurementInterval()));
175 if (updateSleepParameters) {
176 logger.debug("Sending command to update {} ({}) sleep parameters", deviceType, macAddress);
177 sendCommandMessage(new SleepSetRequestMessage(macAddress, configuration.getWakeupDuration(),
178 configuration.getWakeupInterval()));
181 super.sendConfigurationUpdateCommands();
184 private void setUpdateCommandFlags(@Nullable PlugwiseSenseConfig oldConfiguration,
185 PlugwiseSenseConfig newConfiguration) {
186 boolean fullUpdate = newConfiguration.isUpdateConfiguration() && !isConfigurationPending();
188 logger.debug("Updating all configuration properties of {} ({})", deviceType, macAddress);
191 updateBoundaryParameters = fullUpdate
192 || (oldConfiguration != null && !oldConfiguration.equalBoundaryParameters(newConfiguration));
193 if (updateBoundaryParameters) {
194 logger.debug("Updating {} ({}) boundary parameters when online", deviceType, macAddress);
197 updateMeasurementInterval = fullUpdate || (oldConfiguration != null
198 && !oldConfiguration.getMeasurementInterval().equals(newConfiguration.getMeasurementInterval()));
199 if (updateMeasurementInterval) {
200 logger.debug("Updating {} ({}) measurement interval when online", deviceType, macAddress);
203 updateSleepParameters = fullUpdate
204 || (oldConfiguration != null && !oldConfiguration.equalSleepParameters(newConfiguration));
205 if (updateSleepParameters) {
206 logger.debug("Updating {} ({}) sleep parameters when online", deviceType, macAddress);
211 protected void updateConfiguration(Configuration configuration) {
212 PlugwiseSenseConfig oldConfiguration = this.configuration;
213 PlugwiseSenseConfig newConfiguration = configuration.as(PlugwiseSenseConfig.class);
215 setUpdateCommandFlags(oldConfiguration, newConfiguration);
216 configuration.put(CONFIG_PROPERTY_UPDATE_CONFIGURATION, isConfigurationPending());
218 super.updateConfiguration(configuration);