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 5f36ad5707a..48f3000680a 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 @@ -129,10 +129,6 @@ public class WemoBindingConstants { public static final Set SUPPORTED_LIGHT_THING_TYPES = Collections.singleton(THING_TYPE_MZ100); - public static final Set SUPPORTED_DEVICE_THING_TYPES = Collections - .unmodifiableSet(Stream.of(THING_TYPE_SOCKET, THING_TYPE_INSIGHT, THING_TYPE_LIGHTSWITCH, THING_TYPE_MOTION) - .collect(Collectors.toSet())); - public static final Set SUPPORTED_THING_TYPES = Collections .unmodifiableSet(Stream .of(THING_TYPE_SOCKET, THING_TYPE_INSIGHT, THING_TYPE_LIGHTSWITCH, THING_TYPE_MOTION, diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHandlerFactory.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHandlerFactory.java index 56299260c52..75e5dd7f40e 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHandlerFactory.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHandlerFactory.java @@ -26,10 +26,12 @@ import org.openhab.binding.wemo.internal.handler.WemoBridgeHandler; import org.openhab.binding.wemo.internal.handler.WemoCoffeeHandler; import org.openhab.binding.wemo.internal.handler.WemoCrockpotHandler; import org.openhab.binding.wemo.internal.handler.WemoDimmerHandler; -import org.openhab.binding.wemo.internal.handler.WemoHandler; import org.openhab.binding.wemo.internal.handler.WemoHolmesHandler; +import org.openhab.binding.wemo.internal.handler.WemoInsightHandler; import org.openhab.binding.wemo.internal.handler.WemoLightHandler; import org.openhab.binding.wemo.internal.handler.WemoMakerHandler; +import org.openhab.binding.wemo.internal.handler.WemoMotionHandler; +import org.openhab.binding.wemo.internal.handler.WemoSwitchHandler; import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.core.config.discovery.DiscoveryService; import org.openhab.core.io.transport.upnp.UpnpIOService; @@ -103,10 +105,19 @@ public class WemoHandlerFactory extends BaseThingHandlerFactory { WemoBridgeHandler handler = new WemoBridgeHandler((Bridge) thing); registerDeviceDiscoveryService(handler, wemoHttpcaller); return handler; - } else if (WemoBindingConstants.SUPPORTED_DEVICE_THING_TYPES.contains(thing.getThingTypeUID())) { - logger.debug("Creating a WemoHandler for thing '{}' with UDN '{}'", thing.getUID(), + } else if (WemoBindingConstants.THING_TYPE_INSIGHT.equals(thing.getThingTypeUID())) { + logger.debug("Creating a WemoInsightHandler for thing '{}' with UDN '{}'", thing.getUID(), thing.getConfiguration().get(UDN)); - return new WemoHandler(thing, upnpIOService, wemoHttpcaller); + return new WemoInsightHandler(thing, upnpIOService, wemoHttpcaller); + } else if (WemoBindingConstants.THING_TYPE_SOCKET.equals(thing.getThingTypeUID()) + || WemoBindingConstants.THING_TYPE_LIGHTSWITCH.equals(thing.getThingTypeUID())) { + logger.debug("Creating a WemoSwitchHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get(UDN)); + return new WemoSwitchHandler(thing, upnpIOService, wemoHttpcaller); + } else if (WemoBindingConstants.THING_TYPE_MOTION.equals(thing.getThingTypeUID())) { + logger.debug("Creating a WemoMotionHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get(UDN)); + return new WemoMotionHandler(thing, upnpIOService, wemoHttpcaller); } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MAKER)) { logger.debug("Creating a WemoMakerHandler for thing '{}' with UDN '{}'", thing.getUID(), thing.getConfiguration().get(UDN)); diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBaseThingHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBaseThingHandler.java index 2be37f227f5..81b734a8f4d 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBaseThingHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBaseThingHandler.java @@ -32,7 +32,7 @@ import org.openhab.core.types.Command; * @author Jacob Laursen - Initial contribution */ @NonNullByDefault -public class WemoBaseThingHandler extends BaseThingHandler implements UpnpIOParticipant { +public abstract class WemoBaseThingHandler extends BaseThingHandler implements UpnpIOParticipant { protected @Nullable UpnpIOService service; protected WemoHttpCall wemoHttpCaller; 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 fb31f7539fa..4b16e08a744 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 @@ -15,30 +15,17 @@ package org.openhab.binding.wemo.internal.handler; import static org.openhab.binding.wemo.internal.WemoBindingConstants.*; import static org.openhab.binding.wemo.internal.WemoUtil.*; -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.time.Instant; -import java.time.ZonedDateTime; -import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.Set; -import java.util.TimeZone; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.Stream; 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.DateTimeType; -import org.openhab.core.library.types.DecimalType; 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.ChannelUID; import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingStatus; @@ -46,7 +33,6 @@ import org.openhab.core.thing.ThingStatusDetail; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.types.Command; import org.openhab.core.types.RefreshType; -import org.openhab.core.types.State; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -61,19 +47,13 @@ import org.slf4j.LoggerFactory; * @author Mihir Patil - Added standby switch */ @NonNullByDefault -public class WemoHandler extends WemoBaseThingHandler { +public abstract class WemoHandler extends WemoBaseThingHandler { private final Logger logger = LoggerFactory.getLogger(WemoHandler.class); - public static final Set SUPPORTED_THING_TYPES = Stream - .of(THING_TYPE_SOCKET, THING_TYPE_INSIGHT, THING_TYPE_LIGHTSWITCH, THING_TYPE_MOTION) - .collect(Collectors.toSet()); - private final Object upnpLock = new Object(); private final Object jobLock = new Object(); - private final Map stateMap = Collections.synchronizedMap(new HashMap<>()); - private Map subscriptionState = new HashMap<>(); private @Nullable ScheduledFuture pollingJob; @@ -202,137 +182,6 @@ public class WemoHandler extends WemoBaseThingHandler { } } - @Override - public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { - logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", - new Object[] { variable, value, service, this.getThing().getUID() }); - - updateStatus(ThingStatus.ONLINE); - - if (!"BinaryState".equals(variable) && !"InsightParams".equals(variable)) { - return; - } - - String oldValue = this.stateMap.get(variable); - if (variable != null && value != null) { - this.stateMap.put(variable, value); - } - - if (value != null && value.length() > 1) { - String insightParams = stateMap.get(variable); - - if (insightParams != null) { - String[] splitInsightParams = insightParams.split("\\|"); - - if (splitInsightParams[0] != null) { - OnOffType binaryState = "0".equals(splitInsightParams[0]) ? OnOffType.OFF : OnOffType.ON; - logger.trace("New InsightParam binaryState '{}' for device '{}' received", binaryState, - getThing().getUID()); - updateState(CHANNEL_STATE, binaryState); - } - - long lastChangedAt = 0; - try { - lastChangedAt = Long.parseLong(splitInsightParams[1]) * 1000; // convert s to ms - } catch (NumberFormatException e) { - logger.error("Unable to parse lastChangedAt value '{}' for device '{}'; expected long", - splitInsightParams[1], getThing().getUID()); - } - ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(lastChangedAt), - TimeZone.getDefault().toZoneId()); - - State lastChangedAtState = new DateTimeType(zoned); - if (lastChangedAt != 0) { - logger.trace("New InsightParam lastChangedAt '{}' for device '{}' received", lastChangedAtState, - getThing().getUID()); - updateState(CHANNEL_LASTCHANGEDAT, lastChangedAtState); - } - - State lastOnFor = DecimalType.valueOf(splitInsightParams[2]); - logger.trace("New InsightParam lastOnFor '{}' for device '{}' received", lastOnFor, - getThing().getUID()); - updateState(CHANNEL_LASTONFOR, lastOnFor); - - State onToday = DecimalType.valueOf(splitInsightParams[3]); - logger.trace("New InsightParam onToday '{}' for device '{}' received", onToday, getThing().getUID()); - updateState(CHANNEL_ONTODAY, onToday); - - State onTotal = DecimalType.valueOf(splitInsightParams[4]); - logger.trace("New InsightParam onTotal '{}' for device '{}' received", onTotal, getThing().getUID()); - updateState(CHANNEL_ONTOTAL, onTotal); - - State timespan = DecimalType.valueOf(splitInsightParams[5]); - logger.trace("New InsightParam timespan '{}' for device '{}' received", timespan, getThing().getUID()); - updateState(CHANNEL_TIMESPAN, timespan); - - State averagePower = new QuantityType<>(DecimalType.valueOf(splitInsightParams[6]), Units.WATT); // natively - // given - // in W - logger.trace("New InsightParam averagePower '{}' for device '{}' received", averagePower, - getThing().getUID()); - updateState(CHANNEL_AVERAGEPOWER, averagePower); - - BigDecimal currentMW = new BigDecimal(splitInsightParams[7]); - State currentPower = new QuantityType<>(currentMW.divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP), - Units.WATT); // recalculate - // mW to W - logger.trace("New InsightParam currentPower '{}' for device '{}' received", currentPower, - getThing().getUID()); - updateState(CHANNEL_CURRENTPOWER, currentPower); - - BigDecimal energyTodayMWMin = new BigDecimal(splitInsightParams[8]); - // recalculate mW-mins to Wh - State energyToday = new QuantityType<>( - energyTodayMWMin.divide(new BigDecimal(60000), 0, RoundingMode.HALF_UP), Units.WATT_HOUR); - logger.trace("New InsightParam energyToday '{}' for device '{}' received", energyToday, - getThing().getUID()); - updateState(CHANNEL_ENERGYTODAY, energyToday); - - BigDecimal energyTotalMWMin = new BigDecimal(splitInsightParams[9]); - // recalculate mW-mins to Wh - State energyTotal = new QuantityType<>( - energyTotalMWMin.divide(new BigDecimal(60000), 0, RoundingMode.HALF_UP), Units.WATT_HOUR); - logger.trace("New InsightParam energyTotal '{}' for device '{}' received", energyTotal, - getThing().getUID()); - updateState(CHANNEL_ENERGYTOTAL, energyTotal); - - if (splitInsightParams.length > 10 && splitInsightParams[10] != null) { - BigDecimal standByLimitMW = new BigDecimal(splitInsightParams[10]); - State standByLimit = new QuantityType<>( - standByLimitMW.divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP), Units.WATT); // recalculate - // mW to W - logger.trace("New InsightParam standByLimit '{}' for device '{}' received", standByLimit, - getThing().getUID()); - updateState(CHANNEL_STANDBYLIMIT, standByLimit); - - if (currentMW.divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP).intValue() > standByLimitMW - .divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP).intValue()) { - updateState(CHANNEL_ONSTANDBY, OnOffType.OFF); - } else { - updateState(CHANNEL_ONSTANDBY, OnOffType.ON); - } - } - } - } else if (value != null && value.length() == 1) { - String binaryState = stateMap.get("BinaryState"); - if (binaryState != null) { - if (oldValue == null || !oldValue.equals(binaryState)) { - State state = "0".equals(binaryState) ? OnOffType.OFF : OnOffType.ON; - logger.debug("State '{}' for device '{}' received", state, getThing().getUID()); - if ("motion".equals(getThing().getThingTypeUID().getId())) { - updateState(CHANNEL_MOTIONDETECTION, state); - if (OnOffType.ON.equals(state)) { - State lastMotionDetected = new DateTimeType(); - updateState(CHANNEL_LASTMOTIONDETECTED, lastMotionDetected); - } - } else { - updateState(CHANNEL_STATE, state); - } - } - } - } - } - private synchronized void addSubscription() { synchronized (upnpLock) { UpnpIOService localService = service; 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 new file mode 100644 index 00000000000..4383233f091 --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoInsightHandler.java @@ -0,0 +1,167 @@ +/** + * 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.handler; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.util.Map; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.wemo.internal.WemoBindingConstants; +import org.openhab.binding.wemo.internal.http.WemoHttpCall; +import org.openhab.core.io.transport.upnp.UpnpIOService; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.DecimalType; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link WemoInsightHandler} is responsible for handling commands for + * a WeMo Insight Switch. + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class WemoInsightHandler extends WemoHandler { + + private final Logger logger = LoggerFactory.getLogger(WemoInsightHandler.class); + private final Map stateMap = new ConcurrentHashMap(); + + public WemoInsightHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, upnpIOService, wemoHttpCaller); + } + + @Override + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { + logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", + new Object[] { variable, value, service, this.getThing().getUID() }); + + updateStatus(ThingStatus.ONLINE); + + if (!"BinaryState".equals(variable) && !"InsightParams".equals(variable)) { + return; + } + + if (variable != null && value != null) { + this.stateMap.put(variable, value); + } + + if (value != null && value.length() > 1) { + String insightParams = stateMap.get(variable); + + if (insightParams != null) { + String[] splitInsightParams = insightParams.split("\\|"); + + if (splitInsightParams[0] != null) { + OnOffType binaryState = "0".equals(splitInsightParams[0]) ? OnOffType.OFF : OnOffType.ON; + logger.trace("New InsightParam binaryState '{}' for device '{}' received", binaryState, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_STATE, binaryState); + } + + long lastChangedAt = 0; + try { + lastChangedAt = Long.parseLong(splitInsightParams[1]) * 1000; // convert s to ms + } catch (NumberFormatException e) { + logger.error("Unable to parse lastChangedAt value '{}' for device '{}'; expected long", + splitInsightParams[1], getThing().getUID()); + } + ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(lastChangedAt), + TimeZone.getDefault().toZoneId()); + + State lastChangedAtState = new DateTimeType(zoned); + if (lastChangedAt != 0) { + logger.trace("New InsightParam lastChangedAt '{}' for device '{}' received", lastChangedAtState, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_LASTCHANGEDAT, lastChangedAtState); + } + + State lastOnFor = DecimalType.valueOf(splitInsightParams[2]); + logger.trace("New InsightParam lastOnFor '{}' for device '{}' received", lastOnFor, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_LASTONFOR, lastOnFor); + + State onToday = DecimalType.valueOf(splitInsightParams[3]); + logger.trace("New InsightParam onToday '{}' for device '{}' received", onToday, getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_ONTODAY, onToday); + + State onTotal = DecimalType.valueOf(splitInsightParams[4]); + logger.trace("New InsightParam onTotal '{}' for device '{}' received", onTotal, getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_ONTOTAL, onTotal); + + State timespan = DecimalType.valueOf(splitInsightParams[5]); + logger.trace("New InsightParam timespan '{}' for device '{}' received", timespan, getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_TIMESPAN, timespan); + + State averagePower = new QuantityType<>(DecimalType.valueOf(splitInsightParams[6]), Units.WATT); // natively + // given + // in W + logger.trace("New InsightParam averagePower '{}' for device '{}' received", averagePower, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_AVERAGEPOWER, averagePower); + + BigDecimal currentMW = new BigDecimal(splitInsightParams[7]); + State currentPower = new QuantityType<>(currentMW.divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP), + Units.WATT); // recalculate + // mW to W + logger.trace("New InsightParam currentPower '{}' for device '{}' received", currentPower, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_CURRENTPOWER, currentPower); + + BigDecimal energyTodayMWMin = new BigDecimal(splitInsightParams[8]); + // recalculate mW-mins to Wh + State energyToday = new QuantityType<>( + energyTodayMWMin.divide(new BigDecimal(60000), 0, RoundingMode.HALF_UP), Units.WATT_HOUR); + logger.trace("New InsightParam energyToday '{}' for device '{}' received", energyToday, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_ENERGYTODAY, energyToday); + + BigDecimal energyTotalMWMin = new BigDecimal(splitInsightParams[9]); + // recalculate mW-mins to Wh + State energyTotal = new QuantityType<>( + energyTotalMWMin.divide(new BigDecimal(60000), 0, RoundingMode.HALF_UP), Units.WATT_HOUR); + logger.trace("New InsightParam energyTotal '{}' for device '{}' received", energyTotal, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_ENERGYTOTAL, energyTotal); + + if (splitInsightParams.length > 10 && splitInsightParams[10] != null) { + BigDecimal standByLimitMW = new BigDecimal(splitInsightParams[10]); + State standByLimit = new QuantityType<>( + standByLimitMW.divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP), Units.WATT); // recalculate + // mW to W + logger.trace("New InsightParam standByLimit '{}' for device '{}' received", standByLimit, + getThing().getUID()); + updateState(WemoBindingConstants.CHANNEL_STANDBYLIMIT, standByLimit); + + if (currentMW.divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP).intValue() > standByLimitMW + .divide(new BigDecimal(1000), 0, RoundingMode.HALF_UP).intValue()) { + updateState(WemoBindingConstants.CHANNEL_ONSTANDBY, OnOffType.OFF); + } else { + updateState(WemoBindingConstants.CHANNEL_ONSTANDBY, OnOffType.ON); + } + } + } + } + } +} 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 new file mode 100644 index 00000000000..032bab278cc --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMotionHandler.java @@ -0,0 +1,78 @@ +/** + * 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.handler; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.wemo.internal.WemoBindingConstants; +import org.openhab.binding.wemo.internal.http.WemoHttpCall; +import org.openhab.core.io.transport.upnp.UpnpIOService; +import org.openhab.core.library.types.DateTimeType; +import org.openhab.core.library.types.OnOffType; +import org.openhab.core.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link WemoMotionHandler} is responsible for handling commands for + * a WeMo Motion. + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class WemoMotionHandler extends WemoHandler { + + private final Logger logger = LoggerFactory.getLogger(WemoMotionHandler.class); + private final Map stateMap = new ConcurrentHashMap(); + + public WemoMotionHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, upnpIOService, wemoHttpCaller); + } + + @Override + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { + logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", + new Object[] { variable, value, service, this.getThing().getUID() }); + + updateStatus(ThingStatus.ONLINE); + + if (!"BinaryState".equals(variable)) { + return; + } + + String oldValue = this.stateMap.get(variable); + if (variable != null && value != null) { + this.stateMap.put(variable, value); + } + + if (value != null && value.length() == 1) { + String binaryState = stateMap.get("BinaryState"); + if (binaryState != null) { + 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); + if (OnOffType.ON.equals(state)) { + State lastMotionDetected = new DateTimeType(); + updateState(WemoBindingConstants.CHANNEL_LASTMOTIONDETECTED, 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 new file mode 100644 index 00000000000..79df99db7e8 --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoSwitchHandler.java @@ -0,0 +1,73 @@ +/** + * 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.handler; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.wemo.internal.WemoBindingConstants; +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.thing.Thing; +import org.openhab.core.thing.ThingStatus; +import org.openhab.core.types.State; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The {@link WemoSwitchHandler} is responsible for handling commands for + * a WeMo device supporting a binary switch: Socket or Light Switch. + * + * @author Jacob Laursen - Initial contribution + */ +@NonNullByDefault +public class WemoSwitchHandler extends WemoHandler { + + private final Logger logger = LoggerFactory.getLogger(WemoSwitchHandler.class); + private final Map stateMap = new ConcurrentHashMap(); + + public WemoSwitchHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, upnpIOService, wemoHttpCaller); + } + + @Override + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { + logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", + new Object[] { variable, value, service, this.getThing().getUID() }); + + updateStatus(ThingStatus.ONLINE); + + if (!"BinaryState".equals(variable)) { + return; + } + + String oldValue = this.stateMap.get(variable); + if (variable != null && value != null) { + this.stateMap.put(variable, value); + } + + if (value != null && value.length() == 1) { + String binaryState = stateMap.get("BinaryState"); + if (binaryState != null) { + 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_STATE, state); + } + } + } + } +} diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerTest.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoInsightHandlerTest.java similarity index 93% rename from itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerTest.java rename to itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoInsightHandlerTest.java index bd09fdb8b6e..cf04469b96a 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerTest.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoInsightHandlerTest.java @@ -21,7 +21,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.openhab.binding.wemo.internal.WemoBindingConstants; -import org.openhab.binding.wemo.internal.handler.WemoHandler; +import org.openhab.binding.wemo.internal.handler.WemoInsightHandler; import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.core.library.types.DecimalType; import org.openhab.core.library.types.OnOffType; @@ -35,17 +35,17 @@ import org.openhab.core.thing.ThingUID; import org.openhab.core.types.State; /** - * Tests for {@link WemoHandler}. + * Tests for {@link WemoInsightHandler}. * * @author Svilen Valkanov - Initial contribution * @author Stefan Triller - Ported Tests from Groovy to Java */ -public class WemoHandlerTest { +public class WemoInsightHandlerTest { private static final ThingTypeUID THING_TYPE = WemoBindingConstants.THING_TYPE_INSIGHT; private static final String THING_ID = "test"; - private MockWemoHandler handler; + private MockWemoInsightHandler handler; private static final String SERVICE_ID = "insight"; private static final String PARAMS_NAME = "InsightParams"; @@ -131,18 +131,18 @@ public class WemoHandlerTest { } private void testOnValueReceived(String expectedChannel, State expectedState, String insightParams) { - handler = new MockWemoHandler(thing, expectedChannel); + handler = new MockWemoInsightHandler(thing, expectedChannel); handler.onValueReceived(PARAMS_NAME, insightParams, SERVICE_ID); assertThat(handler.channelState, is(notNullValue())); assertThat(handler.channelState, is(expectedState)); } - class MockWemoHandler extends WemoHandler { + class MockWemoInsightHandler extends WemoInsightHandler { State channelState; String channelToWatch; - public MockWemoHandler(Thing thing, String channelToWatch) { + public MockWemoInsightHandler(Thing thing, String channelToWatch) { super(thing, null, new WemoHttpCall()); this.channelToWatch = channelToWatch; }