]> git.basschouten.com Git - openhab-addons.git/blob
bd4713a35779da41a182144d099bc411a3fa940a
[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.wemo.internal.handler;
14
15 import java.math.BigDecimal;
16 import java.math.RoundingMode;
17 import java.util.Map;
18 import java.util.Map.Entry;
19 import java.util.concurrent.ConcurrentHashMap;
20
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;
37
38 /**
39  * The {@link WemoInsightHandler} is responsible for handling commands for
40  * a WeMo Insight Switch.
41  *
42  * @author Jacob Laursen - Initial contribution
43  */
44 @NonNullByDefault
45 public class WemoInsightHandler extends WemoHandler {
46
47     private final Logger logger = LoggerFactory.getLogger(WemoInsightHandler.class);
48     private final Map<String, String> stateMap = new ConcurrentHashMap<String, String>();
49
50     private WemoPowerBank wemoPowerBank = new WemoPowerBank();
51     private int currentPowerSlidingSeconds;
52     private int currentPowerDeltaTrigger;
53
54     public WemoInsightHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
55         super(thing, upnpIOService, wemoHttpCaller);
56     }
57
58     @Override
59     public void initialize() {
60         logger.debug("Initializing WemoInsightHandler for thing '{}'", thing.getUID());
61
62         WemoInsightConfiguration configuration = getConfigAs(WemoInsightConfiguration.class);
63         currentPowerSlidingSeconds = configuration.currentPowerSlidingSeconds;
64         currentPowerDeltaTrigger = configuration.currentPowerDeltaTrigger;
65         wemoPowerBank = new WemoPowerBank(currentPowerSlidingSeconds);
66
67         updateStatus(ThingStatus.UNKNOWN);
68         super.initialize();
69     }
70
71     @Override
72     public void dispose() {
73         super.dispose();
74         wemoPowerBank.clear();
75     }
76
77     @Override
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() });
81
82         updateStatus(ThingStatus.ONLINE);
83
84         if (!"BinaryState".equals(variable) && !"InsightParams".equals(variable)) {
85             return;
86         }
87
88         if (variable != null && value != null) {
89             this.stateMap.put(variable, value);
90         }
91
92         if (value != null && value.length() > 1) {
93             String insightParams = stateMap.get(variable);
94
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();
101
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);
108                         if (power != null) {
109                             updateCurrentPower(power);
110                         }
111                     }
112                 }
113
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()));
121                     }
122                 }
123             }
124         }
125     }
126
127     private boolean updateCurrentPower(QuantityType<?> power) {
128         double value = power.doubleValue();
129         var roundedValueState = new QuantityType<>(new BigDecimal(value).setScale(0, RoundingMode.HALF_UP),
130                 power.getUnit());
131         if (currentPowerSlidingSeconds == 0 || currentPowerDeltaTrigger == 0) {
132             updateState(WemoBindingConstants.CHANNEL_CURRENT_POWER, roundedValueState);
133             return true;
134         }
135
136         wemoPowerBank.apply(value);
137         double averageValue = wemoPowerBank.getCalculatedAverage(value);
138
139         var roundedAverageValueState = new QuantityType<>(
140                 new BigDecimal(averageValue).setScale(0, RoundingMode.HALF_UP), power.getUnit());
141
142         if (roundedValueState.equals(wemoPowerBank.getPreviousCurrentPower())) {
143             // No change, skip.
144             return false;
145         }
146
147         double roundedValue = roundedValueState.doubleValue();
148         QuantityType<?> previousCurrentPower = wemoPowerBank.getPreviousCurrentPower();
149
150         if (previousCurrentPower == null) {
151             // Always update initially.
152             return updateCurrentPowerBalanced(roundedValue);
153         }
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);
159         }
160         if (roundedValueState.equals(roundedAverageValueState)) {
161             // Update when rounded value has stabilized.
162             return updateCurrentPowerBalanced(roundedValue);
163         }
164         return false;
165     }
166
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);
171         return true;
172     }
173 }