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.wemo.internal.handler;
15 import java.math.BigDecimal;
16 import java.math.RoundingMode;
18 import java.util.Map.Entry;
19 import java.util.concurrent.ConcurrentHashMap;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.wemo.internal.InsightParser;
24 import org.openhab.binding.wemo.internal.WemoBindingConstants;
25 import org.openhab.binding.wemo.internal.WemoPowerBank;
26 import org.openhab.binding.wemo.internal.config.WemoInsightConfiguration;
27 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
28 import org.openhab.core.io.transport.upnp.UpnpIOService;
29 import org.openhab.core.library.types.OnOffType;
30 import org.openhab.core.library.types.QuantityType;
31 import org.openhab.core.library.unit.Units;
32 import org.openhab.core.thing.Thing;
33 import org.openhab.core.thing.ThingStatus;
34 import org.openhab.core.types.State;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
39 * The {@link WemoInsightHandler} is responsible for handling commands for
40 * a WeMo Insight Switch.
42 * @author Jacob Laursen - Initial contribution
45 public class WemoInsightHandler extends WemoHandler {
47 private final Logger logger = LoggerFactory.getLogger(WemoInsightHandler.class);
48 private final Map<String, String> stateMap = new ConcurrentHashMap<String, String>();
50 private WemoPowerBank wemoPowerBank = new WemoPowerBank();
51 private int currentPowerSlidingSeconds;
52 private int currentPowerDeltaTrigger;
54 public WemoInsightHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
55 super(thing, upnpIOService, wemoHttpCaller);
59 public void initialize() {
60 logger.debug("Initializing WemoInsightHandler for thing '{}'", thing.getUID());
62 WemoInsightConfiguration configuration = getConfigAs(WemoInsightConfiguration.class);
63 currentPowerSlidingSeconds = configuration.currentPowerSlidingSeconds;
64 currentPowerDeltaTrigger = configuration.currentPowerDeltaTrigger;
65 wemoPowerBank = new WemoPowerBank(currentPowerSlidingSeconds);
67 updateStatus(ThingStatus.UNKNOWN);
72 public void dispose() {
74 wemoPowerBank.clear();
78 public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
79 logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'",
80 new Object[] { variable, value, service, this.getThing().getUID() });
82 updateStatus(ThingStatus.ONLINE);
84 if (!"BinaryState".equals(variable) && !"InsightParams".equals(variable)) {
88 if (variable != null && value != null) {
89 this.stateMap.put(variable, value);
92 if (value != null && value.length() > 1) {
93 String insightParams = stateMap.get(variable);
95 if (insightParams != null) {
96 InsightParser parser = new InsightParser(insightParams);
97 Map<String, State> results = parser.parse();
98 for (Entry<String, State> entry : results.entrySet()) {
99 String channel = entry.getKey();
100 State state = entry.getValue();
102 logger.trace("New InsightParam {} '{}' for device '{}' received", channel, state,
103 getThing().getUID());
104 updateState(channel, state);
105 if (channel.equals(WemoBindingConstants.CHANNEL_CURRENT_POWER_RAW)
106 && state instanceof QuantityType) {
107 QuantityType<?> power = state.as(QuantityType.class);
109 updateCurrentPower(power);
114 // Update helper channel onStandBy by checking if currentPower > standByLimit.
115 var standByLimit = (QuantityType<?>) results.get(WemoBindingConstants.CHANNEL_STAND_BY_LIMIT);
116 if (standByLimit != null) {
117 QuantityType<?> currentPower = wemoPowerBank.getPreviousCurrentPower();
118 if (currentPower != null) {
119 updateState(WemoBindingConstants.CHANNEL_ON_STAND_BY,
120 OnOffType.from(currentPower.intValue() <= standByLimit.intValue()));
127 private boolean updateCurrentPower(QuantityType<?> power) {
128 double value = power.doubleValue();
129 var roundedValueState = new QuantityType<>(new BigDecimal(value).setScale(0, RoundingMode.HALF_UP),
131 if (currentPowerSlidingSeconds == 0 || currentPowerDeltaTrigger == 0) {
132 updateState(WemoBindingConstants.CHANNEL_CURRENT_POWER, roundedValueState);
136 wemoPowerBank.apply(value);
137 double averageValue = wemoPowerBank.getCalculatedAverage(value);
139 var roundedAverageValueState = new QuantityType<>(
140 new BigDecimal(averageValue).setScale(0, RoundingMode.HALF_UP), power.getUnit());
142 if (roundedValueState.equals(wemoPowerBank.getPreviousCurrentPower())) {
147 double roundedValue = roundedValueState.doubleValue();
148 QuantityType<?> previousCurrentPower = wemoPowerBank.getPreviousCurrentPower();
150 if (previousCurrentPower == null) {
151 // Always update initially.
152 return updateCurrentPowerBalanced(roundedValue);
154 double previousRoundedValue = previousCurrentPower.doubleValue();
155 if (roundedValue < previousRoundedValue - currentPowerDeltaTrigger
156 || roundedValue > previousRoundedValue + currentPowerDeltaTrigger) {
157 // Update immediately when delta is > 1 W.
158 return updateCurrentPowerBalanced(roundedValue);
160 if (roundedValueState.equals(roundedAverageValueState)) {
161 // Update when rounded value has stabilized.
162 return updateCurrentPowerBalanced(roundedValue);
167 private boolean updateCurrentPowerBalanced(double power) {
168 var state = new QuantityType<>(power, Units.WATT);
169 updateState(WemoBindingConstants.CHANNEL_CURRENT_POWER, state);
170 wemoPowerBank.setPreviousCurrentPower(state);