From 1239dda691bb851e4eb374f247c5a0b445602ba0 Mon Sep 17 00:00:00 2001 From: Jacob Laursen Date: Sat, 2 Apr 2022 12:46:26 +0200 Subject: [PATCH] [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 --- bundles/org.openhab.binding.wemo/README.md | 58 ++++++--- .../binding/wemo/internal/InsightParser.java | 20 +-- .../wemo/internal/WemoBindingConstants.java | 91 ++++++------- .../binding/wemo/internal/WemoPowerBank.java | 122 ++++++++++++++++++ .../config/WemoInsightConfiguration.java | 33 +++++ .../internal/handler/WemoCoffeeHandler.java | 32 ++--- .../internal/handler/WemoCrockpotHandler.java | 10 +- .../internal/handler/WemoDimmerHandler.java | 28 ++-- .../wemo/internal/handler/WemoHandler.java | 19 +-- .../internal/handler/WemoHolmesHandler.java | 36 +++--- .../internal/handler/WemoInsightHandler.java | 96 +++++++++++++- .../internal/handler/WemoMotionHandler.java | 11 +- .../internal/handler/WemoSwitchHandler.java | 7 + .../main/resources/OH-INF/config/insight.xml | 29 +++++ .../resources/OH-INF/i18n/wemo.properties | 10 +- .../main/resources/OH-INF/thing/channels.xml | 10 +- .../main/resources/OH-INF/thing/insight.xml | 3 +- .../binding/wemo/InsightParserTest.java | 58 ++++----- .../binding/wemo/WemoPowerBankTest.java | 103 +++++++++++++++ .../handler/test/WemoInsightHandlerTest.java | 8 +- 20 files changed, 602 insertions(+), 182 deletions(-) create mode 100644 bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoPowerBank.java create mode 100644 bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/config/WemoInsightConfiguration.java create mode 100644 bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/config/insight.xml create mode 100644 bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/WemoPowerBankTest.java diff --git a/bundles/org.openhab.binding.wemo/README.md b/bundles/org.openhab.binding.wemo/README.md index 0bb98e837..8ebc22ce1 100644 --- a/bundles/org.openhab.binding.wemo/README.md +++ b/bundles/org.openhab.binding.wemo/README.md @@ -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 - - } } ``` diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/InsightParser.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/InsightParser.java index c80f74d7c..ca89abfac 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/InsightParser.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/InsightParser.java @@ -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); } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoBindingConstants.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoBindingConstants.java index 48f300068..64706014c 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoBindingConstants.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoBindingConstants.java @@ -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; diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoPowerBank.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoPowerBank.java new file mode 100644 index 000000000..e4d2796fd --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoPowerBank.java @@ -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 slidingCache = new ConcurrentLinkedDeque(); + + @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 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; + } +} diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/config/WemoInsightConfiguration.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/config/WemoInsightConfiguration.java new file mode 100644 index 000000000..3cd949a65 --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/config/WemoInsightConfiguration.java @@ -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; +} diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCoffeeHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCoffeeHandler.java index 7714ac2c7..bd16e5bf4 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCoffeeHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCoffeeHandler.java @@ -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; } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCrockpotHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCrockpotHandler.java index 435d54418..a2e76beea 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCrockpotHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoCrockpotHandler.java @@ -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); diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoDimmerHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoDimmerHandler.java index 4d43e87d9..846fecb9f 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoDimmerHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoDimmerHandler.java @@ -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 = "" + "" + "" @@ -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; } } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java index 4e16cce21..ae84e0806 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHandler.java @@ -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 diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHolmesHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHolmesHandler.java index 041707008..5802c6c55 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHolmesHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoHolmesHandler.java @@ -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; } } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoInsightHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoInsightHandler.java index e028e7568..19ad6e253 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoInsightHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoInsightHandler.java @@ -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 stateMap = new ConcurrentHashMap(); + 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 results = parser.parse(); - results.forEach((channel, state) -> { + for (Entry 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; + } } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMotionHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMotionHandler.java index 032bab278..f51bd09af 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMotionHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMotionHandler.java @@ -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); } } } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoSwitchHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoSwitchHandler.java index 79df99db7..99c6668ef 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoSwitchHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoSwitchHandler.java @@ -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 '{}'", diff --git a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/config/insight.xml b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/config/insight.xml new file mode 100644 index 000000000..1a6efd1f6 --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/config/insight.xml @@ -0,0 +1,29 @@ + + + + + + + The UDN identifies the WeMo Insight Switch + + + + Sliding window in seconds for which moving average power is calculated (0 = disabled) + seconds + 60 + true + + + + Delta triggering immediate channel update (in Watt) + Watt + 1 + true + + + + diff --git a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties index e69a1e555..0ee306b6e 100644 --- a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties +++ b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/i18n/wemo.properties @@ -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 diff --git a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/channels.xml b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/channels.xml index 62aeed076..ffb2bab9d 100644 --- a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/channels.xml +++ b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/channels.xml @@ -74,12 +74,20 @@ Number:Power - + The current power consumption Energy + + Number:Power + + The current power consumption with full precision + Energy + + + Number:Energy diff --git a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/insight.xml b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/insight.xml index 6485462d7..6d3fa3e74 100644 --- a/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/insight.xml +++ b/bundles/org.openhab.binding.wemo/src/main/resources/OH-INF/thing/insight.xml @@ -17,6 +17,7 @@ + @@ -25,7 +26,7 @@ udn - + diff --git a/bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/InsightParserTest.java b/bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/InsightParserTest.java index fe5c0dc6e..1937a43bc 100644 --- a/bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/InsightParserTest.java +++ b/bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/InsightParserTest.java @@ -48,16 +48,16 @@ public class InsightParserTest { Map 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 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 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 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 result = parser.parse(); - assertEquals(UnDefType.UNDEF, result.get(WemoBindingConstants.CHANNEL_LASTONFOR)); + assertEquals(UnDefType.UNDEF, result.get(WemoBindingConstants.CHANNEL_LAST_ON_FOR)); } } diff --git a/bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/WemoPowerBankTest.java b/bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/WemoPowerBankTest.java new file mode 100644 index 000000000..53ca008c7 --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/test/java/org/openhab/binding/wemo/WemoPowerBankTest.java @@ -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); + } +} diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoInsightHandlerTest.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoInsightHandlerTest.java index cf04469b9..a54265398 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoInsightHandlerTest.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoInsightHandlerTest.java @@ -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()); }