[wemo] Prevent excessive currentPower channel updates (#12461)
* Introduce algorithm for preventing excessive currentPower updates * Increase calculation accuracy * Rename currentPowerAccurate to currentPowerRaw * Remove duplicated line * Use interface when declaring double ended queue * Reformat README to one sentence per line * Rename constants for consistency and readability Fixes #12460 Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
parent
115f5ab534
commit
1239dda691
|
@ -10,7 +10,8 @@ The Binding also supports the Crock-Pot Smart Slow Cooker, Mr. Coffee Smart Coff
|
|||
|
||||
## Discovery
|
||||
|
||||
The WeMo devices are discovered through UPnP discovery service in the network. Devices will show up in the inbox and can be easily added as Things.
|
||||
The WeMo devices are discovered through UPnP discovery service in the network.
|
||||
Devices will show up in the inbox and can be easily added as Things.
|
||||
|
||||
## Binding Configuration
|
||||
|
||||
|
@ -18,23 +19,48 @@ The binding does not need any configuration.
|
|||
|
||||
## Thing Configuration
|
||||
|
||||
For manual Thing configuration, one needs to know the UUID of a certain WeMo device.
|
||||
In the thing file, this looks e.g. like
|
||||
For manual Thing configuration, one needs to know the UDN of a certain WeMo device.
|
||||
It can most easily be obtained by performing an auto-discovery before configuring the thing manually.
|
||||
|
||||
```
|
||||
wemo:socket:Switch1 [udn="Socket-1_0-221242K11xxxxx"]
|
||||
```
|
||||
Most devices share the `udn` configuration parameter:
|
||||
|
||||
For a WeMo Link bridge and paired LED Lights, please use the following Thing definition
|
||||
| Configuration Parameter | Description |
|
||||
|-------------------------|------------------------------------|
|
||||
| udn | The UDN identifies the WeMo device |
|
||||
|
||||
```
|
||||
Bridge wemo:bridge:Bridge-1_0-231445B01006A0 [udn="Bridge-1_0-231445B010xxxx"] {
|
||||
MZ100 94103EA2B278xxxx [ deviceID="94103EA2B278xxxx" ]
|
||||
MZ100 94103EA2B278xxxx [ deviceID="94103EA2B278xxxx" ]
|
||||
}
|
||||
```
|
||||
### WeMo LED Light
|
||||
|
||||
For LED Lights paired to a WeMo Link bridge, please use the following configuration parameter:
|
||||
|
||||
| Configuration Parameter | Description |
|
||||
|-------------------------|-------------------------------------------------|
|
||||
| deviceID | The device ID identifies one certain WeMo light |
|
||||
|
||||
### WeMo Insight Switch
|
||||
|
||||
The WeMo Insight Switch has some additional parameters for controlling the behavior for channel `currentPower`.
|
||||
This channel reports the current power consumption in Watt.
|
||||
The internal theoretical accuracy is 5 mW, i.e. three decimals.
|
||||
These raw values are reported with high frequency, often multiple updates can occur within a single second.
|
||||
For example, the sequence of 40.440 W, 40.500 W and 40.485 W would result in the channel being updated with values rounded to nearest integer, respectively 40 W, 41 W and 40 W.
|
||||
|
||||
When persisting items linked to this channel, this can result in a significant amount of data being stored.
|
||||
To mitigate this issue, a sliding window with a moving average calculation has been introduced.
|
||||
This window is defined with a one minute default period.
|
||||
This is combined with a delta trigger value, which is defaulted to 1 W.
|
||||
This means that the channel is only updated when one of the following conditions are met:
|
||||
|
||||
1. The rounded value received is equal to the rounded average for the past minute, i.e. this value has stabilized. This introduces a delay for very small changes in consumption, but on the other hand it prevents excessive logging and persistence caused by temporary small changes and rounding.
|
||||
2. The rounded value received is more than 1 W from the previous value. So when changes are happening fast, the channel will also be updated fast.
|
||||
|
||||
| Configuration Parameter | Description |
|
||||
|----------------------------|---------------------------------------------------------------------------------------|
|
||||
| udn | The UDN identifies the WeMo Insight Switch |
|
||||
| currentPowerSlidingSeconds | Sliding window in seconds for which moving average power is calculated (0 = disabled) |
|
||||
| currentPowerDeltaTrigger | Delta triggering immediate channel update (in Watt) |
|
||||
|
||||
The moving average calculation can be disabled by setting either `currentPowerSlidingSeconds` or `currentPowerDeltaTrigger` to 0.
|
||||
This will cause the channel to be updated the same way as in openHAB versions prior to 3.3.
|
||||
|
||||
## Channels
|
||||
|
||||
|
@ -52,6 +78,7 @@ Devices support some of the following channels:
|
|||
| timespan | Number | Time in seconds over which onTotal applies. Typically 2 weeks except first used. | Insight |
|
||||
| averagePower | Number:Power | Average power consumption in Watts. | Insight |
|
||||
| currentPower | Number:Power | Current power consumption of an Insight device. 0 if switched off. | Insight |
|
||||
| currentPowerRaw | Number:Power | Current power consumption of an Insight device with full precision (5 mW accuracy, three decimals). 0 if switched off. | Insight |
|
||||
| energyToday | Number:Energy | Energy in Wh used today. | Insight |
|
||||
| energyTotal | Number:Energy | Energy in Wh used in total. | Insight |
|
||||
| standbyLimit | Number:Power | Minimum energy draw in W to register device as switched on (default 8W, configurable via WeMo App). | Insight |
|
||||
|
@ -94,7 +121,6 @@ Devices support some of the following channels:
|
|||
| autoOffTime | DateTime | Time when the heater switches off | Heater |
|
||||
| heatingRemaining | Number | Shows the remaining heating time | Heater |
|
||||
|
||||
|
||||
## Full Example
|
||||
|
||||
demo.things:
|
||||
|
@ -102,6 +128,7 @@ demo.things:
|
|||
```
|
||||
wemo:socket:Switch1 "DemoSwitch" @ "Office" [udn="Socket-1_0-221242K11xxxxx"]
|
||||
wemo:motion:Sensor1 "MotionSensor" @ "Entrance" [udn="Sensor-1_0-221337L11xxxxx"]
|
||||
wemo:insight:Insight1 "Insight" @ "Attic" [udn="Insight-1_0-xxxxxxxxxxxxxx", currentPowerSlidingSeconds=120, currentPowerDeltaTrigger=2]
|
||||
|
||||
Bridge wemo:bridge:Bridge-1_0-231445B010xxxx [udn="Bridge-1_0-231445B010xxxx"] {
|
||||
MZ100 94103EA2B278xxxx "DemoLight1" @ "Living" [ deviceID="94103EA2B278xxxx" ]
|
||||
|
@ -185,7 +212,6 @@ Number currentTemp { channel="wemo:heater:HeaterB-1_0-231445B010xxxx:cu
|
|||
Number targetTemp { channel="wemo:heater:HeaterB-1_0-231445B010xxxx:targetTemp" }
|
||||
DateTime autoOffTime { channel="wemo:heater:HeaterB-1_0-231445B010xxxx:autoOffTime" }
|
||||
String heaterRemaining { channel="wemo:heater:HeaterB-1_0-231445B010xxxx:heaterRemaining" }
|
||||
|
||||
```
|
||||
|
||||
demo.sitemap:
|
||||
|
@ -266,8 +292,6 @@ sitemap demo label="Main Menu"
|
|||
Setpoint item=targetTemp
|
||||
Text item=autoOffTime
|
||||
Number item=heaterRemaining
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
@ -70,34 +70,34 @@ public class InsightParser {
|
|||
result.put(WemoBindingConstants.CHANNEL_STATE, getOnOff(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_LASTCHANGEDAT:
|
||||
result.put(WemoBindingConstants.CHANNEL_LASTCHANGEDAT, getDateTime(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_LAST_CHANGED_AT, getDateTime(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_LASTONFOR:
|
||||
result.put(WemoBindingConstants.CHANNEL_LASTONFOR, getNumber(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_LAST_ON_FOR, getNumber(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_ONTODAY:
|
||||
result.put(WemoBindingConstants.CHANNEL_ONTODAY, getNumber(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_ON_TODAY, getNumber(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_ONTOTAL:
|
||||
result.put(WemoBindingConstants.CHANNEL_ONTOTAL, getNumber(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_ON_TOTAL, getNumber(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_TIMESPAN:
|
||||
result.put(WemoBindingConstants.CHANNEL_TIMESPAN, getNumber(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_AVERAGEPOWER:
|
||||
result.put(WemoBindingConstants.CHANNEL_AVERAGEPOWER, getPowerFromWatt(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_AVERAGE_POWER, getPowerFromWatt(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_CURRENTPOWER:
|
||||
result.put(WemoBindingConstants.CHANNEL_CURRENTPOWER, getPowerFromMilliWatt(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_CURRENT_POWER_RAW, getPowerFromMilliWatt(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_ENERGYTODAY:
|
||||
result.put(WemoBindingConstants.CHANNEL_ENERGYTODAY, getEnergy(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_ENERGY_TODAY, getEnergy(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_ENERGYTOTAL:
|
||||
result.put(WemoBindingConstants.CHANNEL_ENERGYTOTAL, getEnergy(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_ENERGY_TOTAL, getEnergy(value));
|
||||
break;
|
||||
case INSIGHT_POSITION_STANDBYLIMIT:
|
||||
result.put(WemoBindingConstants.CHANNEL_STANDBYLIMIT, getPowerFromMilliWatt(value));
|
||||
result.put(WemoBindingConstants.CHANNEL_STAND_BY_LIMIT, getPowerFromMilliWatt(value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ public class InsightParser {
|
|||
}
|
||||
|
||||
private State getPowerFromMilliWatt(String value) {
|
||||
return new QuantityType<>(new BigDecimal(value).divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP),
|
||||
return new QuantityType<>(new BigDecimal(value).divide(new BigDecimal(1000), 3, RoundingMode.HALF_UP),
|
||||
Units.WATT);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,68 +49,69 @@ public class WemoBindingConstants {
|
|||
|
||||
// List of all Channel ids
|
||||
public static final String CHANNEL_STATE = "state";
|
||||
public static final String CHANNEL_MOTIONDETECTION = "motionDetection";
|
||||
public static final String CHANNEL_LASTMOTIONDETECTED = "lastMotionDetected";
|
||||
public static final String CHANNEL_LASTCHANGEDAT = "lastChangedAt";
|
||||
public static final String CHANNEL_LASTONFOR = "lastOnFor";
|
||||
public static final String CHANNEL_ONTODAY = "onToday";
|
||||
public static final String CHANNEL_ONTOTAL = "onTotal";
|
||||
public static final String CHANNEL_MOTION_DETECTION = "motionDetection";
|
||||
public static final String CHANNEL_LAST_MOTION_DETECTED = "lastMotionDetected";
|
||||
public static final String CHANNEL_LAST_CHANGED_AT = "lastChangedAt";
|
||||
public static final String CHANNEL_LAST_ON_FOR = "lastOnFor";
|
||||
public static final String CHANNEL_ON_TODAY = "onToday";
|
||||
public static final String CHANNEL_ON_TOTAL = "onTotal";
|
||||
public static final String CHANNEL_TIMESPAN = "timespan";
|
||||
public static final String CHANNEL_AVERAGEPOWER = "averagePower";
|
||||
public static final String CHANNEL_CURRENTPOWER = "currentPower";
|
||||
public static final String CHANNEL_ENERGYTODAY = "energyToday";
|
||||
public static final String CHANNEL_ENERGYTOTAL = "energyTotal";
|
||||
public static final String CHANNEL_STANDBYLIMIT = "standByLimit";
|
||||
public static final String CHANNEL_AVERAGE_POWER = "averagePower";
|
||||
public static final String CHANNEL_CURRENT_POWER = "currentPower";
|
||||
public static final String CHANNEL_CURRENT_POWER_RAW = "currentPowerRaw";
|
||||
public static final String CHANNEL_ENERGY_TODAY = "energyToday";
|
||||
public static final String CHANNEL_ENERGY_TOTAL = "energyTotal";
|
||||
public static final String CHANNEL_STAND_BY_LIMIT = "standByLimit";
|
||||
public static final String CHANNEL_BRIGHTNESS = "brightness";
|
||||
public static final String CHANNEL_RELAY = "relay";
|
||||
public static final String CHANNEL_SENSOR = "sensor";
|
||||
public static final String CHANNEL_ONSTANDBY = "onStandBy";
|
||||
public static final String CHANNEL_ON_STAND_BY = "onStandBy";
|
||||
|
||||
public static final String CHANNEL_COFFEEMODE = "coffeeMode";
|
||||
public static final String CHANNEL_MODETIME = "modeTime";
|
||||
public static final String CHANNEL_TIMEREMAINING = "timeRemaining";
|
||||
public static final String CHANNEL_WATERLEVELREACHED = "waterLevelReached";
|
||||
public static final String CHANNEL_CLEANADVISE = "cleanAdvise";
|
||||
public static final String CHANNEL_FILTERADVISE = "filterAdvise";
|
||||
public static final String CHANNEL_COFFEE_MODE = "coffeeMode";
|
||||
public static final String CHANNEL_MODE_TIME = "modeTime";
|
||||
public static final String CHANNEL_TIME_REMAINING = "timeRemaining";
|
||||
public static final String CHANNEL_WATER_LEVEL_REACHED = "waterLevelReached";
|
||||
public static final String CHANNEL_CLEAN_ADVISE = "cleanAdvise";
|
||||
public static final String CHANNEL_FILTER_ADVISE = "filterAdvise";
|
||||
public static final String CHANNEL_BREWED = "brewed";
|
||||
public static final String CHANNEL_LASTCLEANED = "lastCleaned";
|
||||
public static final String CHANNEL_LAST_CLEANED = "lastCleaned";
|
||||
|
||||
public static final String CHANNEL_FADERENABLED = "faderEnabled";
|
||||
public static final String CHANNEL_TIMERSTART = "timerStart";
|
||||
public static final String CHANNEL_FADERCOUNTDOWNTIME = "faderCountDownTime";
|
||||
public static final String CHANNEL_NIGHTMODE = "nightMode";
|
||||
public static final String CHANNEL_STARTTIME = "startTime";
|
||||
public static final String CHANNEL_ENDTIME = "endTime";
|
||||
public static final String CHANNEL_NIGHTMODEBRIGHTNESS = "nightModeBrightness";
|
||||
public static final String CHANNEL_FADER_ENABLED = "faderEnabled";
|
||||
public static final String CHANNEL_TIMER_START = "timerStart";
|
||||
public static final String CHANNEL_FADER_COUNT_DOWN_TIME = "faderCountDownTime";
|
||||
public static final String CHANNEL_NIGHT_MODE = "nightMode";
|
||||
public static final String CHANNEL_START_TIME = "startTime";
|
||||
public static final String CHANNEL_END_TIME = "endTime";
|
||||
public static final String CHANNEL_NIGHT_MODE_BRIGHTNESS = "nightModeBrightness";
|
||||
|
||||
public static final String CHANNEL_COOKMODE = "cookMode";
|
||||
public static final String CHANNEL_LOWCOOKTIME = "lowCookTime";
|
||||
public static final String CHANNEL_WARMCOOKTIME = "warmCooktime";
|
||||
public static final String CHANNEL_COOK_MODE = "cookMode";
|
||||
public static final String CHANNEL_LOW_COOK_TIME = "lowCookTime";
|
||||
public static final String CHANNEL_WARM_COOK_TIME = "warmCooktime";
|
||||
public static final String CHANNEL_HIGHCOOKTIME = "highCooktime";
|
||||
public static final String CHANNEL_COOKEDTIME = "cookedtime";
|
||||
public static final String CHANNEL_COOKED_TIME = "cookedtime";
|
||||
|
||||
public static final String CHANNEL_PURIFIERMODE = "purifierMode";
|
||||
public static final String CHANNEL_AIRQUALITY = "airQuality";
|
||||
public static final String CHANNEL_PURIFIER_MODE = "purifierMode";
|
||||
public static final String CHANNEL_AIR_QUALITY = "airQuality";
|
||||
public static final String CHANNEL_IONIZER = "ionizer";
|
||||
public static final String CHANNEL_FILTERLIFE = "filterLife";
|
||||
public static final String CHANNEL_EXPIREDFILTERTIME = "expiredFilterTime";
|
||||
public static final String CHANNEL_FILTERPRESENT = "filterPresent";
|
||||
public static final String CHANNEL_FILTER_LIFE = "filterLife";
|
||||
public static final String CHANNEL_EXPIRED_FILTER_TIME = "expiredFilterTime";
|
||||
public static final String CHANNEL_FILTER_PRESENT = "filterPresent";
|
||||
|
||||
public static final String CHANNEL_HUMIDIFIERMODE = "humidifierMode";
|
||||
public static final String CHANNEL_CURRENTHUMIDITY = "currentHumidity";
|
||||
public static final String CHANNEL_DESIREDHUMIDITY = "desiredHumidity";
|
||||
public static final String CHANNEL_WATERLEVEL = "waterLEvel";
|
||||
public static final String CHANNEL_HUMIDIFIER_MODE = "humidifierMode";
|
||||
public static final String CHANNEL_CURRENT_HUMIDITY = "currentHumidity";
|
||||
public static final String CHANNEL_DESIRED_HUMIDITY = "desiredHumidity";
|
||||
public static final String CHANNEL_WATER_LEVEL = "waterLEvel";
|
||||
|
||||
public static final String CHANNEL_HEATERMODE = "heaterMode";
|
||||
public static final String CHANNEL_CURRENTTEMP = "currentTemperature";
|
||||
public static final String CHANNEL_TARGETTEMP = "targetTemperature";
|
||||
public static final String CHANNEL_AUTOOFFTIME = "autoOffTime";
|
||||
public static final String CHANNEL_HEATINGREMAINING = "heatingRemaining";
|
||||
public static final String CHANNEL_HEATER_MODE = "heaterMode";
|
||||
public static final String CHANNEL_CURRENT_TEMPERATURE = "currentTemperature";
|
||||
public static final String CHANNEL_TARGET_TEMPERATURE = "targetTemperature";
|
||||
public static final String CHANNEL_AUTO_OFF_TIME = "autoOffTime";
|
||||
public static final String CHANNEL_HEATING_REMAINING = "heatingRemaining";
|
||||
|
||||
// List of thing configuration properties
|
||||
public static final String UDN = "udn";
|
||||
public static final String DEVICE_ID = "deviceID";
|
||||
public static final String POLLINGINTERVALL = "pollingInterval";
|
||||
public static final String POLLING_INTERVAL = "pollingInterval";
|
||||
public static final int DEFAULT_REFRESH_INTERVAL_SECONDS = 60;
|
||||
public static final int SUBSCRIPTION_DURATION_SECONDS = 600;
|
||||
public static final int LINK_DISCOVERY_SERVICE_INITIAL_DELAY = 5;
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.wemo.internal;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
|
||||
/**
|
||||
* Class for caching and processing historic values for current power.
|
||||
*
|
||||
* @author Jacob Laursen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WemoPowerBank {
|
||||
|
||||
private final Deque<CacheItem> slidingCache = new ConcurrentLinkedDeque<CacheItem>();
|
||||
|
||||
@Nullable
|
||||
private QuantityType<?> previousCurrentPower = null;
|
||||
private int slidingSeconds;
|
||||
|
||||
private class CacheItem {
|
||||
public Instant start;
|
||||
public @Nullable Instant end;
|
||||
public double power;
|
||||
|
||||
public CacheItem(double power, Instant start) {
|
||||
this.start = start;
|
||||
this.power = power;
|
||||
}
|
||||
}
|
||||
|
||||
public WemoPowerBank() {
|
||||
this.slidingSeconds = 60;
|
||||
}
|
||||
|
||||
public WemoPowerBank(int slidingSeconds) {
|
||||
this.slidingSeconds = slidingSeconds;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
slidingCache.clear();
|
||||
previousCurrentPower = null;
|
||||
}
|
||||
|
||||
public void apply(double value) {
|
||||
this.apply(value, Instant.now());
|
||||
}
|
||||
|
||||
public void apply(double value, Instant now) {
|
||||
if (slidingCache.isEmpty()) {
|
||||
slidingCache.add(new CacheItem(value, now));
|
||||
return;
|
||||
}
|
||||
@Nullable
|
||||
CacheItem last = slidingCache.getLast();
|
||||
last.end = now;
|
||||
Instant windowStart = now.minusSeconds(slidingSeconds);
|
||||
final Iterator<CacheItem> it = slidingCache.iterator();
|
||||
while (it.hasNext()) {
|
||||
CacheItem current = it.next();
|
||||
Instant end = current.end;
|
||||
end = end != null ? end.minusNanos(1) : now;
|
||||
if (end.isBefore(windowStart)) {
|
||||
it.remove();
|
||||
continue;
|
||||
}
|
||||
if (current.start.isBefore(windowStart) && end.isAfter(windowStart)) {
|
||||
// Truncate last item before sliding window.
|
||||
current.start = windowStart;
|
||||
break;
|
||||
}
|
||||
}
|
||||
slidingCache.add(new CacheItem(value, now));
|
||||
}
|
||||
|
||||
public void setPreviousCurrentPower(QuantityType<?> previousCurrentPower) {
|
||||
this.previousCurrentPower = previousCurrentPower;
|
||||
}
|
||||
|
||||
public @Nullable QuantityType<?> getPreviousCurrentPower() {
|
||||
return previousCurrentPower;
|
||||
}
|
||||
|
||||
public double getCalculatedAverage(double currentValue) {
|
||||
double historyWattMillis = 0;
|
||||
long historyMillis = 0;
|
||||
for (CacheItem item : slidingCache) {
|
||||
Instant end = item.end;
|
||||
if (end != null) {
|
||||
long millis = item.start.until(end, ChronoUnit.MILLIS);
|
||||
historyWattMillis += item.power * millis;
|
||||
historyMillis += millis;
|
||||
}
|
||||
}
|
||||
double average;
|
||||
if (historyMillis > 0) {
|
||||
average = historyWattMillis / historyMillis;
|
||||
} else {
|
||||
average = currentValue;
|
||||
}
|
||||
|
||||
return average;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.wemo.internal.config;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Configuration for a WeMo Insight Switch
|
||||
*
|
||||
* @author Jacob Laursen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WemoInsightConfiguration {
|
||||
|
||||
public static final String CURRENT_POWER_SLIDING_SECONDS = "currentPowerSlidingSeconds";
|
||||
public static final String CURRENT_POWER_DELTA_TRIGGER = "currentPowerDeltaTrigger";
|
||||
|
||||
@Nullable
|
||||
public String udn;
|
||||
public int currentPowerSlidingSeconds = 60;
|
||||
public int currentPowerDeltaTrigger = 1;
|
||||
}
|
|
@ -161,7 +161,7 @@ public class WemoCoffeeHandler extends WemoBaseThingHandler {
|
|||
wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
|
||||
updateState(CHANNEL_STATE, OnOffType.ON);
|
||||
State newMode = new StringType("Brewing");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (Exception e) {
|
||||
logger.warn("Failed to send command '{}' for device '{}': {}", command, getThing().getUID(),
|
||||
|
@ -244,69 +244,69 @@ public class WemoCoffeeHandler extends WemoBaseThingHandler {
|
|||
case "0":
|
||||
updateState(CHANNEL_STATE, OnOffType.ON);
|
||||
newMode = new StringType("Refill");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "1":
|
||||
updateState(CHANNEL_STATE, OnOffType.OFF);
|
||||
newMode = new StringType("PlaceCarafe");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "2":
|
||||
updateState(CHANNEL_STATE, OnOffType.OFF);
|
||||
newMode = new StringType("RefillWater");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "3":
|
||||
updateState(CHANNEL_STATE, OnOffType.OFF);
|
||||
newMode = new StringType("Ready");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "4":
|
||||
updateState(CHANNEL_STATE, OnOffType.ON);
|
||||
newMode = new StringType("Brewing");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "5":
|
||||
updateState(CHANNEL_STATE, OnOffType.OFF);
|
||||
newMode = new StringType("Brewed");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "6":
|
||||
updateState(CHANNEL_STATE, OnOffType.OFF);
|
||||
newMode = new StringType("CleaningBrewing");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "7":
|
||||
updateState(CHANNEL_STATE, OnOffType.OFF);
|
||||
newMode = new StringType("CleaningSoaking");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
case "8":
|
||||
updateState(CHANNEL_STATE, OnOffType.OFF);
|
||||
newMode = new StringType("BrewFailCarafeRemoved");
|
||||
updateState(CHANNEL_COFFEEMODE, newMode);
|
||||
updateState(CHANNEL_COFFEE_MODE, newMode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "ModeTime":
|
||||
newAttributeValue = new DecimalType(attributeValue);
|
||||
updateState(CHANNEL_MODETIME, newAttributeValue);
|
||||
updateState(CHANNEL_MODE_TIME, newAttributeValue);
|
||||
break;
|
||||
case "TimeRemaining":
|
||||
newAttributeValue = new DecimalType(attributeValue);
|
||||
updateState(CHANNEL_TIMEREMAINING, newAttributeValue);
|
||||
updateState(CHANNEL_TIME_REMAINING, newAttributeValue);
|
||||
break;
|
||||
case "WaterLevelReached":
|
||||
newAttributeValue = new DecimalType(attributeValue);
|
||||
updateState(CHANNEL_WATERLEVELREACHED, newAttributeValue);
|
||||
updateState(CHANNEL_WATER_LEVEL_REACHED, newAttributeValue);
|
||||
break;
|
||||
case "CleanAdvise":
|
||||
newAttributeValue = "0".equals(attributeValue) ? OnOffType.OFF : OnOffType.ON;
|
||||
updateState(CHANNEL_CLEANADVISE, newAttributeValue);
|
||||
updateState(CHANNEL_CLEAN_ADVISE, newAttributeValue);
|
||||
break;
|
||||
case "FilterAdvise":
|
||||
newAttributeValue = "0".equals(attributeValue) ? OnOffType.OFF : OnOffType.ON;
|
||||
updateState(CHANNEL_FILTERADVISE, newAttributeValue);
|
||||
updateState(CHANNEL_FILTER_ADVISE, newAttributeValue);
|
||||
break;
|
||||
case "Brewed":
|
||||
newAttributeValue = getDateTimeState(attributeValue);
|
||||
|
@ -317,7 +317,7 @@ public class WemoCoffeeHandler extends WemoBaseThingHandler {
|
|||
case "LastCleaned":
|
||||
newAttributeValue = getDateTimeState(attributeValue);
|
||||
if (newAttributeValue != null) {
|
||||
updateState(CHANNEL_LASTCLEANED, newAttributeValue);
|
||||
updateState(CHANNEL_LAST_CLEANED, newAttributeValue);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ public class WemoCrockpotHandler extends WemoBaseThingHandler {
|
|||
|
||||
if (command instanceof RefreshType) {
|
||||
updateWemoState();
|
||||
} else if (CHANNEL_COOKMODE.equals(channelUID.getId())) {
|
||||
} else if (CHANNEL_COOK_MODE.equals(channelUID.getId())) {
|
||||
String commandString = command.toString();
|
||||
switch (commandString) {
|
||||
case "OFF":
|
||||
|
@ -202,12 +202,12 @@ public class WemoCrockpotHandler extends WemoBaseThingHandler {
|
|||
case "50":
|
||||
newMode = new StringType("WARM");
|
||||
State warmTime = DecimalType.valueOf(time);
|
||||
updateState(CHANNEL_WARMCOOKTIME, warmTime);
|
||||
updateState(CHANNEL_WARM_COOK_TIME, warmTime);
|
||||
break;
|
||||
case "51":
|
||||
newMode = new StringType("LOW");
|
||||
State lowTime = DecimalType.valueOf(time);
|
||||
updateState(CHANNEL_LOWCOOKTIME, lowTime);
|
||||
updateState(CHANNEL_LOW_COOK_TIME, lowTime);
|
||||
break;
|
||||
case "52":
|
||||
newMode = new StringType("HIGH");
|
||||
|
@ -215,8 +215,8 @@ public class WemoCrockpotHandler extends WemoBaseThingHandler {
|
|||
updateState(CHANNEL_HIGHCOOKTIME, highTime);
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_COOKMODE, newMode);
|
||||
updateState(CHANNEL_COOKEDTIME, newCoockedTime);
|
||||
updateState(CHANNEL_COOK_MODE, newMode);
|
||||
updateState(CHANNEL_COOKED_TIME, newCoockedTime);
|
||||
updateStatus(ThingStatus.ONLINE);
|
||||
} catch (IOException e) {
|
||||
logger.debug("Failed to get actual state for device '{}': {}", getThing().getUID(), e.getMessage(), e);
|
||||
|
|
|
@ -152,7 +152,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
if (command.equals(OnOffType.OFF)) {
|
||||
State brightnessState = new PercentType("0");
|
||||
updateState(CHANNEL_BRIGHTNESS, brightnessState);
|
||||
updateState(CHANNEL_TIMERSTART, OnOffType.OFF);
|
||||
updateState(CHANNEL_TIMER_START, OnOffType.OFF);
|
||||
} else {
|
||||
State brightnessState = new PercentType(currentBrightness);
|
||||
updateState(CHANNEL_BRIGHTNESS, brightnessState);
|
||||
|
@ -211,7 +211,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
setBinaryState(action, argument, value);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_FADERCOUNTDOWNTIME:
|
||||
case CHANNEL_FADER_COUNT_DOWN_TIME:
|
||||
argument = "Fader";
|
||||
if (command instanceof DecimalType) {
|
||||
int commandValue = Integer.valueOf(String.valueOf(command));
|
||||
|
@ -223,7 +223,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
setBinaryState(action, argument, value);
|
||||
}
|
||||
break;
|
||||
case CHANNEL_FADERENABLED:
|
||||
case CHANNEL_FADER_ENABLED:
|
||||
argument = "Fader";
|
||||
if (command.equals(OnOffType.ON)) {
|
||||
value = "<BinaryState></BinaryState>" + "<Duration></Duration>" + "<EndAction></EndAction>"
|
||||
|
@ -234,7 +234,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
}
|
||||
setBinaryState(action, argument, value);
|
||||
break;
|
||||
case CHANNEL_TIMERSTART:
|
||||
case CHANNEL_TIMER_START:
|
||||
argument = "Fader";
|
||||
long ts = System.currentTimeMillis() / 1000;
|
||||
timeStamp = String.valueOf(ts);
|
||||
|
@ -265,7 +265,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
}
|
||||
setBinaryState(action, argument, value);
|
||||
break;
|
||||
case CHANNEL_NIGHTMODE:
|
||||
case CHANNEL_NIGHT_MODE:
|
||||
action = "ConfigureNightMode";
|
||||
argument = "NightModeConfiguration";
|
||||
String nightModeBrightness = String.valueOf(currentNightModeBrightness);
|
||||
|
@ -278,7 +278,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
}
|
||||
setBinaryState(action, argument, value);
|
||||
break;
|
||||
case CHANNEL_NIGHTMODEBRIGHTNESS:
|
||||
case CHANNEL_NIGHT_MODE_BRIGHTNESS:
|
||||
action = "ConfigureNightMode";
|
||||
argument = "NightModeConfiguration";
|
||||
if (command instanceof PercentType) {
|
||||
|
@ -334,7 +334,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
logger.debug("State '{}' for device '{}' received", state, getThing().getUID());
|
||||
updateState(CHANNEL_BRIGHTNESS, state);
|
||||
if (state.equals(OnOffType.OFF)) {
|
||||
updateState(CHANNEL_TIMERSTART, OnOffType.OFF);
|
||||
updateState(CHANNEL_TIMER_START, OnOffType.OFF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -358,13 +358,13 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
State faderMinutes = new DecimalType(faderSeconds / 60);
|
||||
logger.debug("faderTime '{} minutes' for device '{}' received", faderMinutes,
|
||||
getThing().getUID());
|
||||
updateState(CHANNEL_FADERCOUNTDOWNTIME, faderMinutes);
|
||||
updateState(CHANNEL_FADER_COUNT_DOWN_TIME, faderMinutes);
|
||||
}
|
||||
if (splitFader[1] != null) {
|
||||
State isTimerRunning = splitFader[1].equals("-1") ? OnOffType.OFF : OnOffType.ON;
|
||||
logger.debug("isTimerRunning '{}' for device '{}' received", isTimerRunning,
|
||||
getThing().getUID());
|
||||
updateState(CHANNEL_TIMERSTART, isTimerRunning);
|
||||
updateState(CHANNEL_TIMER_START, isTimerRunning);
|
||||
if (isTimerRunning.equals(OnOffType.ON)) {
|
||||
updateState(CHANNEL_STATE, OnOffType.ON);
|
||||
}
|
||||
|
@ -373,27 +373,27 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
State isFaderEnabled = splitFader[1].equals("0") ? OnOffType.OFF : OnOffType.ON;
|
||||
logger.debug("isFaderEnabled '{}' for device '{}' received", isFaderEnabled,
|
||||
getThing().getUID());
|
||||
updateState(CHANNEL_FADERENABLED, isFaderEnabled);
|
||||
updateState(CHANNEL_FADER_ENABLED, isFaderEnabled);
|
||||
}
|
||||
break;
|
||||
case "nightMode":
|
||||
State nightModeState = "0".equals(value) ? OnOffType.OFF : OnOffType.ON;
|
||||
currentNightModeState = value;
|
||||
logger.debug("nightModeState '{}' for device '{}' received", nightModeState, getThing().getUID());
|
||||
updateState(CHANNEL_NIGHTMODE, nightModeState);
|
||||
updateState(CHANNEL_NIGHT_MODE, nightModeState);
|
||||
break;
|
||||
case "startTime":
|
||||
State startTimeState = getDateTimeState(value);
|
||||
logger.debug("startTimeState '{}' for device '{}' received", startTimeState, getThing().getUID());
|
||||
if (startTimeState != null) {
|
||||
updateState(CHANNEL_STARTTIME, startTimeState);
|
||||
updateState(CHANNEL_START_TIME, startTimeState);
|
||||
}
|
||||
break;
|
||||
case "endTime":
|
||||
State endTimeState = getDateTimeState(value);
|
||||
logger.debug("endTimeState '{}' for device '{}' received", endTimeState, getThing().getUID());
|
||||
if (endTimeState != null) {
|
||||
updateState(CHANNEL_ENDTIME, endTimeState);
|
||||
updateState(CHANNEL_END_TIME, endTimeState);
|
||||
}
|
||||
break;
|
||||
case "nightModeBrightness":
|
||||
|
@ -402,7 +402,7 @@ public class WemoDimmerHandler extends WemoBaseThingHandler {
|
|||
State nightModeBrightnessState = new PercentType(nightModeBrightnessValue);
|
||||
logger.debug("nightModeBrightnessState '{}' for device '{}' received", nightModeBrightnessState,
|
||||
getThing().getUID());
|
||||
updateState(CHANNEL_NIGHTMODEBRIGHTNESS, nightModeBrightnessState);
|
||||
updateState(CHANNEL_NIGHT_MODE_BRIGHTNESS, nightModeBrightnessState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.wemo.internal.http.WemoHttpCall;
|
||||
import org.openhab.core.config.core.Configuration;
|
||||
import org.openhab.core.io.transport.upnp.UpnpIOService;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.thing.ChannelUID;
|
||||
|
@ -62,21 +61,13 @@ public abstract class WemoHandler extends WemoBaseThingHandler {
|
|||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
Configuration configuration = getConfig();
|
||||
|
||||
if (configuration.get(UDN) != null) {
|
||||
logger.debug("Initializing WemoHandler for UDN '{}'", configuration.get(UDN));
|
||||
addSubscription(BASICEVENT);
|
||||
if (THING_TYPE_INSIGHT.equals(thing.getThingTypeUID())) {
|
||||
addSubscription(INSIGHTEVENT);
|
||||
}
|
||||
pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, DEFAULT_REFRESH_INTERVAL_SECONDS,
|
||||
TimeUnit.SECONDS);
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
} else {
|
||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
|
||||
"@text/config-status.error.missing-udn");
|
||||
addSubscription(BASICEVENT);
|
||||
if (THING_TYPE_INSIGHT.equals(thing.getThingTypeUID())) {
|
||||
addSubscription(INSIGHTEVENT);
|
||||
}
|
||||
pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, DEFAULT_REFRESH_INTERVAL_SECONDS,
|
||||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -143,7 +143,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
|
||||
if (command instanceof RefreshType) {
|
||||
updateWemoState();
|
||||
} else if (CHANNEL_PURIFIERMODE.equals(channelUID.getId())) {
|
||||
} else if (CHANNEL_PURIFIER_MODE.equals(channelUID.getId())) {
|
||||
attribute = "Mode";
|
||||
String commandString = command.toString();
|
||||
switch (commandString) {
|
||||
|
@ -170,7 +170,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
} else if (OnOffType.OFF.equals(command)) {
|
||||
value = "0";
|
||||
}
|
||||
} else if (CHANNEL_HUMIDIFIERMODE.equals(channelUID.getId())) {
|
||||
} else if (CHANNEL_HUMIDIFIER_MODE.equals(channelUID.getId())) {
|
||||
attribute = "FanMode";
|
||||
String commandString = command.toString();
|
||||
switch (commandString) {
|
||||
|
@ -193,7 +193,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
value = "5";
|
||||
break;
|
||||
}
|
||||
} else if (CHANNEL_DESIREDHUMIDITY.equals(channelUID.getId())) {
|
||||
} else if (CHANNEL_DESIRED_HUMIDITY.equals(channelUID.getId())) {
|
||||
attribute = "DesiredHumidity";
|
||||
String commandString = command.toString();
|
||||
switch (commandString) {
|
||||
|
@ -213,7 +213,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
value = "4";
|
||||
break;
|
||||
}
|
||||
} else if (CHANNEL_HEATERMODE.equals(channelUID.getId())) {
|
||||
} else if (CHANNEL_HEATER_MODE.equals(channelUID.getId())) {
|
||||
attribute = "Mode";
|
||||
String commandString = command.toString();
|
||||
switch (commandString) {
|
||||
|
@ -233,7 +233,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
value = "4";
|
||||
break;
|
||||
}
|
||||
} else if (CHANNEL_TARGETTEMP.equals(channelUID.getId())) {
|
||||
} else if (CHANNEL_TARGET_TEMPERATURE.equals(channelUID.getId())) {
|
||||
attribute = "SetTemperature";
|
||||
value = command.toString();
|
||||
}
|
||||
|
@ -341,7 +341,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
newMode = new StringType("AUTO");
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_PURIFIERMODE, newMode);
|
||||
updateState(CHANNEL_PURIFIER_MODE, newMode);
|
||||
} else {
|
||||
switch (attributeValue) {
|
||||
case "0":
|
||||
|
@ -360,7 +360,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
newMode = new StringType("ECO");
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_HEATERMODE, newMode);
|
||||
updateState(CHANNEL_HEATER_MODE, newMode);
|
||||
}
|
||||
break;
|
||||
case "Ionizer":
|
||||
|
@ -386,7 +386,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
newMode = new StringType("GOOD");
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_AIRQUALITY, newMode);
|
||||
updateState(CHANNEL_AIR_QUALITY, newMode);
|
||||
break;
|
||||
case "FilterLife":
|
||||
int filterLife = Integer.valueOf(attributeValue);
|
||||
|
@ -395,7 +395,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
} else {
|
||||
filterLife = Math.round((filterLife / 60480) * 100);
|
||||
}
|
||||
updateState(CHANNEL_FILTERLIFE, new PercentType(String.valueOf(filterLife)));
|
||||
updateState(CHANNEL_FILTER_LIFE, new PercentType(String.valueOf(filterLife)));
|
||||
break;
|
||||
case "ExpiredFilterTime":
|
||||
switch (attributeValue) {
|
||||
|
@ -406,7 +406,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
newMode = OnOffType.ON;
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_EXPIREDFILTERTIME, newMode);
|
||||
updateState(CHANNEL_EXPIRED_FILTER_TIME, newMode);
|
||||
break;
|
||||
case "FilterPresent":
|
||||
switch (attributeValue) {
|
||||
|
@ -417,7 +417,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
newMode = OnOffType.ON;
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_FILTERPRESENT, newMode);
|
||||
updateState(CHANNEL_FILTER_PRESENT, newMode);
|
||||
break;
|
||||
case "FANMode":
|
||||
switch (attributeValue) {
|
||||
|
@ -437,7 +437,7 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
newMode = new StringType("AUTO");
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_PURIFIERMODE, newMode);
|
||||
updateState(CHANNEL_PURIFIER_MODE, newMode);
|
||||
break;
|
||||
case "DesiredHumidity":
|
||||
switch (attributeValue) {
|
||||
|
@ -457,27 +457,27 @@ public class WemoHolmesHandler extends WemoBaseThingHandler {
|
|||
newMode = new PercentType("100");
|
||||
break;
|
||||
}
|
||||
updateState(CHANNEL_DESIREDHUMIDITY, newMode);
|
||||
updateState(CHANNEL_DESIRED_HUMIDITY, newMode);
|
||||
break;
|
||||
case "CurrentHumidity":
|
||||
newMode = new StringType(attributeValue);
|
||||
updateState(CHANNEL_CURRENTHUMIDITY, newMode);
|
||||
updateState(CHANNEL_CURRENT_HUMIDITY, newMode);
|
||||
break;
|
||||
case "Temperature":
|
||||
newMode = new StringType(attributeValue);
|
||||
updateState(CHANNEL_CURRENTTEMP, newMode);
|
||||
updateState(CHANNEL_CURRENT_TEMPERATURE, newMode);
|
||||
break;
|
||||
case "SetTemperature":
|
||||
newMode = new StringType(attributeValue);
|
||||
updateState(CHANNEL_TARGETTEMP, newMode);
|
||||
updateState(CHANNEL_TARGET_TEMPERATURE, newMode);
|
||||
break;
|
||||
case "AutoOffTime":
|
||||
newMode = new StringType(attributeValue);
|
||||
updateState(CHANNEL_AUTOOFFTIME, newMode);
|
||||
updateState(CHANNEL_AUTO_OFF_TIME, newMode);
|
||||
break;
|
||||
case "TimeRemaining":
|
||||
newMode = new StringType(attributeValue);
|
||||
updateState(CHANNEL_HEATINGREMAINING, newMode);
|
||||
updateState(CHANNEL_HEATING_REMAINING, newMode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,17 +12,23 @@
|
|||
*/
|
||||
package org.openhab.binding.wemo.internal.handler;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.openhab.binding.wemo.internal.InsightParser;
|
||||
import org.openhab.binding.wemo.internal.WemoBindingConstants;
|
||||
import org.openhab.binding.wemo.internal.WemoPowerBank;
|
||||
import org.openhab.binding.wemo.internal.config.WemoInsightConfiguration;
|
||||
import org.openhab.binding.wemo.internal.http.WemoHttpCall;
|
||||
import org.openhab.core.io.transport.upnp.UpnpIOService;
|
||||
import org.openhab.core.library.types.OnOffType;
|
||||
import org.openhab.core.library.types.QuantityType;
|
||||
import org.openhab.core.library.unit.Units;
|
||||
import org.openhab.core.thing.Thing;
|
||||
import org.openhab.core.thing.ThingStatus;
|
||||
import org.openhab.core.types.State;
|
||||
|
@ -41,10 +47,33 @@ public class WemoInsightHandler extends WemoHandler {
|
|||
private final Logger logger = LoggerFactory.getLogger(WemoInsightHandler.class);
|
||||
private final Map<String, String> stateMap = new ConcurrentHashMap<String, String>();
|
||||
|
||||
private WemoPowerBank wemoPowerBank = new WemoPowerBank();
|
||||
private int currentPowerSlidingSeconds;
|
||||
private int currentPowerDeltaTrigger;
|
||||
|
||||
public WemoInsightHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
|
||||
super(thing, upnpIOService, wemoHttpCaller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing WemoInsightHandler for thing '{}'", thing.getUID());
|
||||
|
||||
WemoInsightConfiguration configuration = getConfigAs(WemoInsightConfiguration.class);
|
||||
currentPowerSlidingSeconds = configuration.currentPowerSlidingSeconds;
|
||||
currentPowerDeltaTrigger = configuration.currentPowerDeltaTrigger;
|
||||
wemoPowerBank = new WemoPowerBank(currentPowerSlidingSeconds);
|
||||
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
wemoPowerBank.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
|
||||
logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'",
|
||||
|
@ -66,22 +95,79 @@ public class WemoInsightHandler extends WemoHandler {
|
|||
if (insightParams != null) {
|
||||
InsightParser parser = new InsightParser(insightParams);
|
||||
Map<String, State> results = parser.parse();
|
||||
results.forEach((channel, state) -> {
|
||||
for (Entry<String, State> entry : results.entrySet()) {
|
||||
String channel = entry.getKey();
|
||||
State state = entry.getValue();
|
||||
|
||||
logger.trace("New InsightParam {} '{}' for device '{}' received", channel, state,
|
||||
getThing().getUID());
|
||||
updateState(channel, state);
|
||||
});
|
||||
if (channel.equals(WemoBindingConstants.CHANNEL_CURRENT_POWER_RAW)
|
||||
&& state instanceof QuantityType) {
|
||||
QuantityType<?> power = state.as(QuantityType.class);
|
||||
if (power != null) {
|
||||
updateCurrentPower(power);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update helper channel onStandBy by checking if currentPower > standByLimit.
|
||||
var standByLimit = (QuantityType<?>) results.get(WemoBindingConstants.CHANNEL_STANDBYLIMIT);
|
||||
var standByLimit = (QuantityType<?>) results.get(WemoBindingConstants.CHANNEL_STAND_BY_LIMIT);
|
||||
if (standByLimit != null) {
|
||||
var currentPower = (QuantityType<?>) results.get(WemoBindingConstants.CHANNEL_CURRENTPOWER);
|
||||
QuantityType<?> currentPower = wemoPowerBank.getPreviousCurrentPower();
|
||||
if (currentPower != null) {
|
||||
updateState(WemoBindingConstants.CHANNEL_ONSTANDBY,
|
||||
updateState(WemoBindingConstants.CHANNEL_ON_STAND_BY,
|
||||
OnOffType.from(currentPower.intValue() <= standByLimit.intValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean updateCurrentPower(QuantityType<?> power) {
|
||||
double value = power.doubleValue();
|
||||
var roundedValueState = new QuantityType<>(new BigDecimal(value).setScale(0, RoundingMode.HALF_UP),
|
||||
power.getUnit());
|
||||
if (currentPowerSlidingSeconds == 0 || currentPowerDeltaTrigger == 0) {
|
||||
updateState(WemoBindingConstants.CHANNEL_CURRENT_POWER, roundedValueState);
|
||||
return true;
|
||||
}
|
||||
|
||||
wemoPowerBank.apply(value);
|
||||
double averageValue = wemoPowerBank.getCalculatedAverage(value);
|
||||
|
||||
var roundedAverageValueState = new QuantityType<>(
|
||||
new BigDecimal(averageValue).setScale(0, RoundingMode.HALF_UP), power.getUnit());
|
||||
|
||||
if (roundedValueState.equals(wemoPowerBank.getPreviousCurrentPower())) {
|
||||
// No change, skip.
|
||||
return false;
|
||||
}
|
||||
|
||||
double roundedValue = roundedValueState.doubleValue();
|
||||
QuantityType<?> previousCurrentPower = wemoPowerBank.getPreviousCurrentPower();
|
||||
|
||||
if (previousCurrentPower == null) {
|
||||
// Always update initially.
|
||||
return updateCurrentPowerBalanced(roundedValue);
|
||||
}
|
||||
double previousRoundedValue = previousCurrentPower.doubleValue();
|
||||
if (roundedValue < previousRoundedValue - currentPowerDeltaTrigger
|
||||
|| roundedValue > previousRoundedValue + currentPowerDeltaTrigger) {
|
||||
// Update immediately when delta is > 1 W.
|
||||
return updateCurrentPowerBalanced(roundedValue);
|
||||
}
|
||||
if (roundedValueState.equals(roundedAverageValueState)) {
|
||||
// Update when rounded value has stabilized.
|
||||
return updateCurrentPowerBalanced(roundedValue);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean updateCurrentPowerBalanced(double power) {
|
||||
var state = new QuantityType<>(power, Units.WATT);
|
||||
updateState(WemoBindingConstants.CHANNEL_CURRENT_POWER, state);
|
||||
wemoPowerBank.setPreviousCurrentPower(state);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,13 @@ public class WemoMotionHandler extends WemoHandler {
|
|||
super(thing, upnpIOService, wemoHttpCaller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing WemoMotionHandler for thing '{}'", thing.getUID());
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
|
||||
logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'",
|
||||
|
@ -66,10 +73,10 @@ public class WemoMotionHandler extends WemoHandler {
|
|||
if (oldValue == null || !oldValue.equals(binaryState)) {
|
||||
State state = "0".equals(binaryState) ? OnOffType.OFF : OnOffType.ON;
|
||||
logger.debug("State '{}' for device '{}' received", state, getThing().getUID());
|
||||
updateState(WemoBindingConstants.CHANNEL_MOTIONDETECTION, state);
|
||||
updateState(WemoBindingConstants.CHANNEL_MOTION_DETECTION, state);
|
||||
if (OnOffType.ON.equals(state)) {
|
||||
State lastMotionDetected = new DateTimeType();
|
||||
updateState(WemoBindingConstants.CHANNEL_LASTMOTIONDETECTED, lastMotionDetected);
|
||||
updateState(WemoBindingConstants.CHANNEL_LAST_MOTION_DETECTED, lastMotionDetected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,13 @@ public class WemoSwitchHandler extends WemoHandler {
|
|||
super(thing, upnpIOService, wemoHttpCaller);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
logger.debug("Initializing WemoSwitchHandler for thing '{}'", thing.getUID());
|
||||
updateStatus(ThingStatus.UNKNOWN);
|
||||
super.initialize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
|
||||
logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'",
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<config-description:config-descriptions
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:config-description="https://openhab.org/schemas/config-description/v1.0.0"
|
||||
xsi:schemaLocation="https://openhab.org/schemas/config-description/v1.0.0
|
||||
https://openhab.org/schemas/config-description-1.0.0.xsd">
|
||||
|
||||
<config-description uri="thing-type:wemo:insight">
|
||||
<parameter name="udn" type="text" required="true">
|
||||
<label>Unique Device Name</label>
|
||||
<description>The UDN identifies the WeMo Insight Switch</description>
|
||||
</parameter>
|
||||
<parameter name="currentPowerSlidingSeconds" type="integer" min="0" unit="s">
|
||||
<label>Current Power sliding window</label>
|
||||
<description>Sliding window in seconds for which moving average power is calculated (0 = disabled)</description>
|
||||
<unitLabel>seconds</unitLabel>
|
||||
<default>60</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
<parameter name="currentPowerDeltaTrigger" type="integer" min="0" unit="W">
|
||||
<label>Current Power delta trigger</label>
|
||||
<description>Delta triggering immediate channel update (in Watt)</description>
|
||||
<unitLabel>Watt</unitLabel>
|
||||
<default>1</default>
|
||||
<advanced>true</advanced>
|
||||
</parameter>
|
||||
</config-description>
|
||||
|
||||
</config-description:config-descriptions>
|
|
@ -44,6 +44,12 @@ thing-type.config.wemo.bridge.udn.label = Unique Device Name
|
|||
thing-type.config.wemo.bridge.udn.description = The UDN identifies the WeMo Link Device
|
||||
thing-type.config.wemo.device.udn.label = Unique Device Name
|
||||
thing-type.config.wemo.device.udn.description = The UDN identifies the WeMo Device
|
||||
thing-type.config.wemo.insight.currentPowerDeltaTrigger.label = Current Power delta trigger
|
||||
thing-type.config.wemo.insight.currentPowerDeltaTrigger.description = Delta triggering immediate channel update (in Watt)
|
||||
thing-type.config.wemo.insight.currentPowerSlidingSeconds.label = Current Power sliding window
|
||||
thing-type.config.wemo.insight.currentPowerSlidingSeconds.description = Sliding window in seconds for which moving average power is calculated (0 = disabled)
|
||||
thing-type.config.wemo.insight.udn.label = Unique Device Name
|
||||
thing-type.config.wemo.insight.udn.description = The UDN identifies the WeMo Insight Switch
|
||||
|
||||
# channel types
|
||||
|
||||
|
@ -81,8 +87,10 @@ channel-type.wemo.cookedTime.label = CookedTime
|
|||
channel-type.wemo.cookedTime.description = Shows the elapsed cooking time
|
||||
channel-type.wemo.currentHumidity.label = Current Humidity
|
||||
channel-type.wemo.currentHumidity.description = Shows the current humidity of a WeMo enabled Holmes Humidifier
|
||||
channel-type.wemo.currentPower.label = Power
|
||||
channel-type.wemo.currentPower.label = Current Power
|
||||
channel-type.wemo.currentPower.description = The current power consumption
|
||||
channel-type.wemo.currentPowerRaw.label = Current Power Raw
|
||||
channel-type.wemo.currentPowerRaw.description = The current power consumption with full precision
|
||||
channel-type.wemo.currentTemperature.label = Current Temperature
|
||||
channel-type.wemo.currentTemperature.description = Shows the current temperature measured by a WeMo enabled Heater
|
||||
channel-type.wemo.desiredHumidity.label = Target Humidity
|
||||
|
|
|
@ -74,12 +74,20 @@
|
|||
|
||||
<channel-type id="currentPower">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>Power</label>
|
||||
<label>Current Power</label>
|
||||
<description>The current power consumption</description>
|
||||
<category>Energy</category>
|
||||
<state pattern="%.0f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="currentPowerRaw" advanced="true">
|
||||
<item-type>Number:Power</item-type>
|
||||
<label>Current Power Raw</label>
|
||||
<description>The current power consumption with full precision</description>
|
||||
<category>Energy</category>
|
||||
<state pattern="%.3f %unit%"/>
|
||||
</channel-type>
|
||||
|
||||
<channel-type id="energyToday" advanced="true">
|
||||
<item-type>Number:Energy</item-type>
|
||||
<label>Energy Today</label>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<channel id="timespan" typeId="timespan"/>
|
||||
<channel id="averagePower" typeId="averagePower"/>
|
||||
<channel id="currentPower" typeId="currentPower"/>
|
||||
<channel id="currentPowerRaw" typeId="currentPowerRaw"/>
|
||||
<channel id="energyToday" typeId="energyToday"/>
|
||||
<channel id="energyTotal" typeId="energyTotal"/>
|
||||
<channel id="standByLimit" typeId="standByLimit"/>
|
||||
|
@ -25,7 +26,7 @@
|
|||
|
||||
<representation-property>udn</representation-property>
|
||||
|
||||
<config-description-ref uri="thing-type:wemo:device"/>
|
||||
<config-description-ref uri="thing-type:wemo:insight"/>
|
||||
</thing-type>
|
||||
|
||||
</thing:thing-descriptions>
|
||||
|
|
|
@ -48,16 +48,16 @@ public class InsightParserTest {
|
|||
Map<String, State> result = parser.parse();
|
||||
assertEquals(OnOffType.ON, result.get(WemoBindingConstants.CHANNEL_STATE));
|
||||
assertEquals(DateTimeType.valueOf("2022-02-25T15:50:47.000+0100").toZone(ZoneId.systemDefault()),
|
||||
result.get(WemoBindingConstants.CHANNEL_LASTCHANGEDAT));
|
||||
assertEquals(new DecimalType(109_676), result.get(WemoBindingConstants.CHANNEL_LASTONFOR));
|
||||
assertEquals(new DecimalType(80_323), result.get(WemoBindingConstants.CHANNEL_ONTODAY));
|
||||
assertEquals(new DecimalType(1_196_960), result.get(WemoBindingConstants.CHANNEL_ONTOTAL));
|
||||
result.get(WemoBindingConstants.CHANNEL_LAST_CHANGED_AT));
|
||||
assertEquals(new DecimalType(109_676), result.get(WemoBindingConstants.CHANNEL_LAST_ON_FOR));
|
||||
assertEquals(new DecimalType(80_323), result.get(WemoBindingConstants.CHANNEL_ON_TODAY));
|
||||
assertEquals(new DecimalType(1_196_960), result.get(WemoBindingConstants.CHANNEL_ON_TOTAL));
|
||||
assertEquals(new DecimalType(1_209_600), result.get(WemoBindingConstants.CHANNEL_TIMESPAN));
|
||||
assertEquals(new QuantityType<>(44, Units.WATT), result.get(WemoBindingConstants.CHANNEL_AVERAGEPOWER));
|
||||
assertEquals(new QuantityType<>(41, Units.WATT), result.get(WemoBindingConstants.CHANNEL_CURRENTPOWER));
|
||||
assertEquals(new QuantityType<>(505, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGYTODAY));
|
||||
assertEquals(new QuantityType<>(8056, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGYTOTAL));
|
||||
assertEquals(new QuantityType<>(8, Units.WATT), result.get(WemoBindingConstants.CHANNEL_STANDBYLIMIT));
|
||||
assertEquals(new QuantityType<>(44, Units.WATT), result.get(WemoBindingConstants.CHANNEL_AVERAGE_POWER));
|
||||
assertEquals(new QuantityType<>(41.4, Units.WATT), result.get(WemoBindingConstants.CHANNEL_CURRENT_POWER_RAW));
|
||||
assertEquals(new QuantityType<>(505, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGY_TODAY));
|
||||
assertEquals(new QuantityType<>(8056, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGY_TOTAL));
|
||||
assertEquals(new QuantityType<>(8, Units.WATT), result.get(WemoBindingConstants.CHANNEL_STAND_BY_LIMIT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,16 +70,16 @@ public class InsightParserTest {
|
|||
Map<String, State> result = parser.parse();
|
||||
assertEquals(OnOffType.ON, result.get(WemoBindingConstants.CHANNEL_STATE));
|
||||
assertEquals(DateTimeType.valueOf("2022-02-27T14:13:47.000+0100").toZone(ZoneId.systemDefault()),
|
||||
result.get(WemoBindingConstants.CHANNEL_LASTCHANGEDAT));
|
||||
assertEquals(new DecimalType(0), result.get(WemoBindingConstants.CHANNEL_LASTONFOR));
|
||||
assertEquals(new DecimalType(0), result.get(WemoBindingConstants.CHANNEL_ONTODAY));
|
||||
assertEquals(new DecimalType(0), result.get(WemoBindingConstants.CHANNEL_ONTOTAL));
|
||||
result.get(WemoBindingConstants.CHANNEL_LAST_CHANGED_AT));
|
||||
assertEquals(new DecimalType(0), result.get(WemoBindingConstants.CHANNEL_LAST_ON_FOR));
|
||||
assertEquals(new DecimalType(0), result.get(WemoBindingConstants.CHANNEL_ON_TODAY));
|
||||
assertEquals(new DecimalType(0), result.get(WemoBindingConstants.CHANNEL_ON_TOTAL));
|
||||
assertEquals(new DecimalType(1_209_600), result.get(WemoBindingConstants.CHANNEL_TIMESPAN));
|
||||
assertEquals(new QuantityType<>(13, Units.WATT), result.get(WemoBindingConstants.CHANNEL_AVERAGEPOWER));
|
||||
assertEquals(new QuantityType<>(0, Units.WATT), result.get(WemoBindingConstants.CHANNEL_CURRENTPOWER));
|
||||
assertEquals(new QuantityType<>(0, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGYTODAY));
|
||||
assertEquals(new QuantityType<>(0, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGYTOTAL));
|
||||
assertEquals(new QuantityType<>(8, Units.WATT), result.get(WemoBindingConstants.CHANNEL_STANDBYLIMIT));
|
||||
assertEquals(new QuantityType<>(13, Units.WATT), result.get(WemoBindingConstants.CHANNEL_AVERAGE_POWER));
|
||||
assertEquals(new QuantityType<>(0, Units.WATT), result.get(WemoBindingConstants.CHANNEL_CURRENT_POWER_RAW));
|
||||
assertEquals(new QuantityType<>(0, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGY_TODAY));
|
||||
assertEquals(new QuantityType<>(0, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGY_TOTAL));
|
||||
assertEquals(new QuantityType<>(8, Units.WATT), result.get(WemoBindingConstants.CHANNEL_STAND_BY_LIMIT));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,29 +93,29 @@ public class InsightParserTest {
|
|||
Map<String, State> result = parser.parse();
|
||||
assertEquals(OnOffType.ON, result.get(WemoBindingConstants.CHANNEL_STATE));
|
||||
assertEquals(DateTimeType.valueOf("2022-02-25T15:50:47.000+0100").toZone(ZoneId.systemDefault()),
|
||||
result.get(WemoBindingConstants.CHANNEL_LASTCHANGEDAT));
|
||||
assertEquals(new DecimalType(109_676), result.get(WemoBindingConstants.CHANNEL_LASTONFOR));
|
||||
assertEquals(new DecimalType(80_323), result.get(WemoBindingConstants.CHANNEL_ONTODAY));
|
||||
assertEquals(new DecimalType(1_196_960), result.get(WemoBindingConstants.CHANNEL_ONTOTAL));
|
||||
result.get(WemoBindingConstants.CHANNEL_LAST_CHANGED_AT));
|
||||
assertEquals(new DecimalType(109_676), result.get(WemoBindingConstants.CHANNEL_LAST_ON_FOR));
|
||||
assertEquals(new DecimalType(80_323), result.get(WemoBindingConstants.CHANNEL_ON_TODAY));
|
||||
assertEquals(new DecimalType(1_196_960), result.get(WemoBindingConstants.CHANNEL_ON_TOTAL));
|
||||
assertEquals(new DecimalType(1_209_600), result.get(WemoBindingConstants.CHANNEL_TIMESPAN));
|
||||
assertEquals(new QuantityType<>(44, Units.WATT), result.get(WemoBindingConstants.CHANNEL_AVERAGEPOWER));
|
||||
assertEquals(new QuantityType<>(41, Units.WATT), result.get(WemoBindingConstants.CHANNEL_CURRENTPOWER));
|
||||
assertEquals(new QuantityType<>(505, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGYTODAY));
|
||||
assertEquals(new QuantityType<>(8056, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGYTOTAL));
|
||||
assertNull(result.get(WemoBindingConstants.CHANNEL_STANDBYLIMIT));
|
||||
assertEquals(new QuantityType<>(44, Units.WATT), result.get(WemoBindingConstants.CHANNEL_AVERAGE_POWER));
|
||||
assertEquals(new QuantityType<>(41.4, Units.WATT), result.get(WemoBindingConstants.CHANNEL_CURRENT_POWER_RAW));
|
||||
assertEquals(new QuantityType<>(505, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGY_TODAY));
|
||||
assertEquals(new QuantityType<>(8056, Units.WATT_HOUR), result.get(WemoBindingConstants.CHANNEL_ENERGY_TOTAL));
|
||||
assertNull(result.get(WemoBindingConstants.CHANNEL_STAND_BY_LIMIT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseInvalidLastChangedAt() {
|
||||
InsightParser parser = new InsightParser("1|A");
|
||||
Map<String, State> result = parser.parse();
|
||||
assertEquals(UnDefType.UNDEF, result.get(WemoBindingConstants.CHANNEL_LASTCHANGEDAT));
|
||||
assertEquals(UnDefType.UNDEF, result.get(WemoBindingConstants.CHANNEL_LAST_CHANGED_AT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseInvalidLastOnFor() {
|
||||
InsightParser parser = new InsightParser("1|1645800647|A");
|
||||
Map<String, State> result = parser.parse();
|
||||
assertEquals(UnDefType.UNDEF, result.get(WemoBindingConstants.CHANNEL_LASTONFOR));
|
||||
assertEquals(UnDefType.UNDEF, result.get(WemoBindingConstants.CHANNEL_LAST_ON_FOR));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/**
|
||||
* Copyright (c) 2010-2022 Contributors to the openHAB project
|
||||
*
|
||||
* See the NOTICE file(s) distributed with this work for additional
|
||||
* information.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License 2.0 which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0
|
||||
*/
|
||||
package org.openhab.binding.wemo;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
|
||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openhab.binding.wemo.internal.WemoPowerBank;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link WemoPowerBank}.
|
||||
*
|
||||
* @author Jacob Laursen - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public class WemoPowerBankTest {
|
||||
|
||||
@Test
|
||||
public void getCalculatedAverageOneMinuteEvenLoad() {
|
||||
var bank = new WemoPowerBank();
|
||||
|
||||
bank.apply(22, getInstantOf("2022-03-08T22:00:00Z"));
|
||||
bank.apply(23, getInstantOf("2022-03-08T22:00:30Z"));
|
||||
bank.apply(99, getInstantOf("2022-03-08T22:01:00Z"));
|
||||
|
||||
assertEquals(22.5, bank.getCalculatedAverage(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCalculatedAverageOlderValuesAreIgnored() {
|
||||
var bank = new WemoPowerBank();
|
||||
|
||||
bank.apply(99, getInstantOf("2022-03-08T21:59:59Z"));
|
||||
bank.apply(22, getInstantOf("2022-03-08T22:00:00Z"));
|
||||
bank.apply(23, getInstantOf("2022-03-08T22:00:30Z"));
|
||||
bank.apply(99, getInstantOf("2022-03-08T22:01:00Z"));
|
||||
|
||||
assertEquals(22.5, bank.getCalculatedAverage(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCalculatedAveragePreviousValueBeforeWindowIsConsidered() {
|
||||
var bank = new WemoPowerBank();
|
||||
|
||||
bank.apply(22, getInstantOf("2022-03-08T21:59:59Z"));
|
||||
bank.apply(23, getInstantOf("2022-03-08T22:00:30Z"));
|
||||
bank.apply(99, getInstantOf("2022-03-08T22:01:00Z"));
|
||||
|
||||
assertEquals(22.5, bank.getCalculatedAverage(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCalculatedAverageOneMinuteUnevenLoad() {
|
||||
var bank = new WemoPowerBank();
|
||||
|
||||
bank.apply(20, getInstantOf("2022-03-08T22:00:00Z"));
|
||||
bank.apply(26, getInstantOf("2022-03-08T22:00:20Z"));
|
||||
bank.apply(99, getInstantOf("2022-03-08T22:01:00Z"));
|
||||
|
||||
assertEquals(24, bank.getCalculatedAverage(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCalculatedAverageSingleValue() {
|
||||
var bank = new WemoPowerBank();
|
||||
|
||||
bank.apply(20, getInstantOf("2022-03-08T22:00:00Z"));
|
||||
|
||||
assertEquals(50, bank.getCalculatedAverage(50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCalculatedAverageDuplicateInstants() {
|
||||
var bank = new WemoPowerBank();
|
||||
|
||||
bank.apply(22, getInstantOf("2022-03-08T22:00:00Z"));
|
||||
bank.apply(99, getInstantOf("2022-03-08T22:00:30Z"));
|
||||
bank.apply(23, getInstantOf("2022-03-08T22:00:30Z"));
|
||||
bank.apply(99, getInstantOf("2022-03-08T22:01:00Z"));
|
||||
|
||||
assertEquals(22.5, bank.getCalculatedAverage(0));
|
||||
}
|
||||
|
||||
private Instant getInstantOf(String time) {
|
||||
Clock clock = Clock.fixed(Instant.parse(time), ZoneId.of("UTC"));
|
||||
return Instant.now(clock);
|
||||
}
|
||||
}
|
|
@ -89,7 +89,7 @@ public class WemoInsightHandlerTest {
|
|||
public void assertThatChannelLASTONFORIsUpdatedOnReceivedValue() {
|
||||
insightParams.lastOnFor = TIME_PARAM;
|
||||
State expectedStateType = new DecimalType(TIME_PARAM);
|
||||
String expectedChannel = CHANNEL_LASTONFOR;
|
||||
String expectedChannel = CHANNEL_LAST_ON_FOR;
|
||||
|
||||
testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ public class WemoInsightHandlerTest {
|
|||
public void assertThatChannelONTODAYIsUpdatedOnReceivedValue() {
|
||||
insightParams.onToday = TIME_PARAM;
|
||||
State expectedStateType = new DecimalType(TIME_PARAM);
|
||||
String expectedChannel = CHANNEL_ONTODAY;
|
||||
String expectedChannel = CHANNEL_ON_TODAY;
|
||||
|
||||
testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ public class WemoInsightHandlerTest {
|
|||
public void assertThatChannelONTOTALIsUpdatedOnReceivedValue() {
|
||||
insightParams.onTotal = TIME_PARAM;
|
||||
State expectedStateType = new DecimalType(TIME_PARAM);
|
||||
String expectedChannel = CHANNEL_ONTOTAL;
|
||||
String expectedChannel = CHANNEL_ON_TOTAL;
|
||||
|
||||
testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ public class WemoInsightHandlerTest {
|
|||
public void assertThatChannelAVERAGEPOWERIsUpdatedOnReceivedValue() {
|
||||
insightParams.avgPower = POWER_PARAM;
|
||||
State expectedStateType = new QuantityType<>(POWER_PARAM, Units.WATT);
|
||||
String expectedChannel = CHANNEL_AVERAGEPOWER;
|
||||
String expectedChannel = CHANNEL_AVERAGE_POWER;
|
||||
|
||||
testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue