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.PlugwiseScanConfig;
22 import org.openhab.binding.plugwise.internal.protocol.AcknowledgementMessage;
23 import org.openhab.binding.plugwise.internal.protocol.LightCalibrationRequestMessage;
24 import org.openhab.binding.plugwise.internal.protocol.ScanParametersSetRequestMessage;
25 import org.openhab.binding.plugwise.internal.protocol.SleepSetRequestMessage;
26 import org.openhab.binding.plugwise.internal.protocol.field.DeviceType;
27 import org.openhab.binding.plugwise.internal.protocol.field.MACAddress;
28 import org.openhab.core.config.core.Configuration;
29 import org.openhab.core.thing.Thing;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
35 * The {@link PlugwiseScanHandler} handles channel updates and commands for a Plugwise Scan device.
38 * The Scan is a wireless PIR sensor that switches on groups of devices depending on the amount of daylight and whether
39 * motion is detected. When the daylight override setting is enabled on a Scan, the state of triggered behaves like that
40 * of a normal motion sensor.
43 * @author Wouter Born - Initial contribution
46 public class PlugwiseScanHandler extends AbstractSleepingEndDeviceHandler {
48 private final Logger logger = LoggerFactory.getLogger(PlugwiseScanHandler.class);
49 private final DeviceType deviceType = DeviceType.SCAN;
51 private @NonNullByDefault({}) PlugwiseScanConfig configuration;
52 private @NonNullByDefault({}) MACAddress macAddress;
54 // Flags that keep track of the pending Scan configuration updates. When the corresponding Thing configuration
55 // parameters change a flag is set to true. When the Scan goes online the respective command is sent to update the
56 // device configuration. When the Scan acknowledges a command the respective flag is again set to false.
57 private boolean updateScanParameters;
58 private boolean updateSleepParameters;
59 private boolean recalibrate;
61 public PlugwiseScanHandler(Thing thing) {
66 protected MACAddress getMACAddress() {
71 protected Duration getWakeupDuration() {
72 return configuration.getWakeupDuration();
76 protected void handleAcknowledgement(AcknowledgementMessage message) {
77 boolean oldConfigurationPending = isConfigurationPending();
79 switch (message.getExtensionCode()) {
80 case LIGHT_CALIBRATION_ACK:
81 logger.debug("Received ACK for daylight override calibration of {} ({})", deviceType, macAddress);
83 Configuration configuration = editConfiguration();
84 configuration.put(CONFIG_PROPERTY_RECALIBRATE, Boolean.FALSE);
85 updateConfiguration(configuration);
87 case SCAN_PARAMETERS_SET_ACK:
88 logger.debug("Received ACK for parameters set of {} ({})", deviceType, macAddress);
89 updateScanParameters = false;
91 case SCAN_PARAMETERS_SET_NACK:
92 logger.debug("Received NACK for parameters set of {} ({})", deviceType, macAddress);
95 logger.debug("Received ACK for sleep set of {} ({})", deviceType, macAddress);
96 updateSleepParameters = false;
99 logger.trace("Received unhandled {} message from {} ({})", message.getType(), deviceType, macAddress);
103 boolean newConfigurationPending = isConfigurationPending();
105 if (oldConfigurationPending != newConfigurationPending && !newConfigurationPending) {
106 Configuration newConfiguration = editConfiguration();
107 newConfiguration.put(CONFIG_PROPERTY_UPDATE_CONFIGURATION, false);
108 updateConfiguration(newConfiguration);
111 super.handleAcknowledgement(message);
115 public void initialize() {
116 configuration = getConfigAs(PlugwiseScanConfig.class);
117 macAddress = configuration.getMACAddress();
118 if (!isInitialized()) {
119 setUpdateCommandFlags(null, configuration);
125 protected boolean isConfigurationPending() {
126 return updateScanParameters || updateSleepParameters || recalibrate;
130 protected void sendConfigurationUpdateCommands() {
131 logger.debug("Sending {} ({}) configuration update commands", deviceType, macAddress);
133 if (updateScanParameters) {
134 logger.debug("Sending command to update {} ({}) parameters", deviceType, macAddress);
135 sendCommandMessage(new ScanParametersSetRequestMessage(macAddress, configuration.getSensitivity(),
136 configuration.isDaylightOverride(), configuration.getSwitchOffDelay()));
138 if (updateSleepParameters) {
139 logger.debug("Sending command to update {} ({}) sleep parameters", deviceType, macAddress);
140 sendCommandMessage(new SleepSetRequestMessage(macAddress, configuration.getWakeupDuration(),
141 configuration.getWakeupInterval()));
144 logger.debug("Sending command to recalibrate {} ({}) daylight override", deviceType, macAddress);
145 sendCommandMessage(new LightCalibrationRequestMessage(macAddress));
148 super.sendConfigurationUpdateCommands();
151 private void setUpdateCommandFlags(@Nullable PlugwiseScanConfig oldConfiguration,
152 PlugwiseScanConfig newConfiguration) {
153 boolean fullUpdate = newConfiguration.isUpdateConfiguration() && !isConfigurationPending();
155 logger.debug("Updating all configuration properties of {} ({})", deviceType, macAddress);
158 updateScanParameters = fullUpdate
159 || (oldConfiguration != null && !oldConfiguration.equalScanParameters(newConfiguration));
160 if (updateScanParameters) {
161 logger.debug("Updating {} ({}) parameters when online", deviceType, macAddress);
164 updateSleepParameters = fullUpdate
165 || (oldConfiguration != null && !oldConfiguration.equalSleepParameters(newConfiguration));
166 if (updateSleepParameters) {
167 logger.debug("Updating {} ({}) sleep parameters when online", deviceType, macAddress);
170 recalibrate = fullUpdate || newConfiguration.isRecalibrate();
172 logger.debug("Recalibrating {} ({}) daylight override when online", deviceType, macAddress);
177 protected void updateConfiguration(Configuration configuration) {
178 PlugwiseScanConfig oldConfiguration = this.configuration;
179 PlugwiseScanConfig newConfiguration = configuration.as(PlugwiseScanConfig.class);
181 setUpdateCommandFlags(oldConfiguration, newConfiguration);
183 configuration.put(CONFIG_PROPERTY_UPDATE_CONFIGURATION, isConfigurationPending());
185 super.updateConfiguration(configuration);