No logic/code changes yet, just extraction/separation.
Fixes #12105
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
public static final Set<ThingTypeUID> SUPPORTED_LIGHT_THING_TYPES = Collections.singleton(THING_TYPE_MZ100);
- public static final Set<ThingTypeUID> 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<ThingTypeUID> SUPPORTED_THING_TYPES = Collections
.unmodifiableSet(Stream
.of(THING_TYPE_SOCKET, THING_TYPE_INSIGHT, THING_TYPE_LIGHTSWITCH, THING_TYPE_MOTION,
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;
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));
* @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;
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;
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;
* @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<ThingTypeUID> 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<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
-
private Map<String, Boolean> subscriptionState = new HashMap<>();
private @Nullable ScheduledFuture<?> pollingJob;
}
}
- @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;
--- /dev/null
+/**
+ * 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<String, String> stateMap = new ConcurrentHashMap<String, String>();
+
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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<String, String> stateMap = new ConcurrentHashMap<String, String>();
+
+ 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);
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/**
+ * 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<String, String> stateMap = new ConcurrentHashMap<String, String>();
+
+ 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);
+ }
+ }
+ }
+ }
+}
+++ /dev/null
-/**
- * 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.test;
-
-import static org.hamcrest.CoreMatchers.*;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Mockito.*;
-import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
-
-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.http.WemoHttpCall;
-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.thing.ThingStatusDetail;
-import org.openhab.core.thing.ThingTypeUID;
-import org.openhab.core.thing.ThingUID;
-import org.openhab.core.types.State;
-
-/**
- * Tests for {@link WemoHandler}.
- *
- * @author Svilen Valkanov - Initial contribution
- * @author Stefan Triller - Ported Tests from Groovy to Java
- */
-public class WemoHandlerTest {
-
- private static final ThingTypeUID THING_TYPE = WemoBindingConstants.THING_TYPE_INSIGHT;
- private static final String THING_ID = "test";
-
- private MockWemoHandler handler;
-
- private static final String SERVICE_ID = "insight";
- private static final String PARAMS_NAME = "InsightParams";
- private WemoInsightParams insightParams;
-
- /** Used for all tests, where expected value is time in seconds **/
- private static final int TIME_PARAM = 4702;
-
- /** Represents a state parameter, where 1 stays for ON and 0 stays for OFF **/
- private static final int STATE_PARAM = 1;
-
- /** Represents power in Wats **/
- private static final int POWER_PARAM = 54;
-
- private final Thing thing = mock(Thing.class);
-
- @BeforeEach
- public void setUp() {
- insightParams = new WemoInsightParams();
- when(thing.getUID()).thenReturn(new ThingUID(THING_TYPE, THING_ID));
- when(thing.getThingTypeUID()).thenReturn(THING_TYPE);
- when(thing.getStatus()).thenReturn(ThingStatus.ONLINE);
- }
-
- @AfterEach
- public void clear() {
- handler.channelState = null;
- handler.channelToWatch = null;
- }
-
- @Test
- public void assertThatChannelSTATEisUpdatedOnReceivedValue() {
- insightParams.state = STATE_PARAM;
- State expectedStateType = OnOffType.ON;
- String expectedChannel = CHANNEL_STATE;
-
- testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
- }
-
- @Test
- public void assertThatChannelLASTONFORIsUpdatedOnReceivedValue() {
- insightParams.lastOnFor = TIME_PARAM;
- State expectedStateType = new DecimalType(TIME_PARAM);
- String expectedChannel = CHANNEL_LASTONFOR;
-
- testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
- }
-
- @Test
- public void assertThatChannelONTODAYIsUpdatedOnReceivedValue() {
- insightParams.onToday = TIME_PARAM;
- State expectedStateType = new DecimalType(TIME_PARAM);
- String expectedChannel = CHANNEL_ONTODAY;
-
- testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
- }
-
- @Test
- public void assertThatChannelONTOTALIsUpdatedOnReceivedValue() {
- insightParams.onTotal = TIME_PARAM;
- State expectedStateType = new DecimalType(TIME_PARAM);
- String expectedChannel = CHANNEL_ONTOTAL;
-
- testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
- }
-
- @Test
- public void assertThatChannelTIMESPANIsUpdatedOnReceivedValue() {
- insightParams.timespan = TIME_PARAM;
- State expectedStateType = new DecimalType(TIME_PARAM);
- String expectedChannel = CHANNEL_TIMESPAN;
-
- testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
- }
-
- @Test
- public void assertThatChannelAVERAGEPOWERIsUpdatedOnReceivedValue() {
- insightParams.avgPower = POWER_PARAM;
- State expectedStateType = new QuantityType<>(POWER_PARAM, Units.WATT);
- String expectedChannel = CHANNEL_AVERAGEPOWER;
-
- testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
- }
-
- private void testOnValueReceived(String expectedChannel, State expectedState, String insightParams) {
- handler = new MockWemoHandler(thing, expectedChannel);
-
- handler.onValueReceived(PARAMS_NAME, insightParams, SERVICE_ID);
- assertThat(handler.channelState, is(notNullValue()));
- assertThat(handler.channelState, is(expectedState));
- }
-
- class MockWemoHandler extends WemoHandler {
- State channelState;
- String channelToWatch;
-
- public MockWemoHandler(Thing thing, String channelToWatch) {
- super(thing, null, new WemoHttpCall());
- this.channelToWatch = channelToWatch;
- }
-
- @Override
- protected void updateState(String channelID, State channelState) {
- if (channelID.equals(channelToWatch)) {
- this.channelState = channelState;
- }
- }
-
- @Override
- protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, String description) {
- }
-
- @Override
- protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail) {
- }
-
- @Override
- protected void updateStatus(ThingStatus status) {
- }
- }
-
- class WemoInsightParams {
- int state, lastChangedAt, lastOnFor, onToday, onTotal, timespan, avgPower, currPower, todayEnergy, totalEnergy,
- standbyLimit;
-
- @Override
- public String toString() {
- // Example string looks like "1|1427230660|4702|25528|82406|1209600|39|40880|15620649|54450534.000000|8000"
- return state + "|" + lastChangedAt + "|" + lastOnFor + "|" + onToday + "|" + onTotal + "|" + timespan + "|"
- + avgPower + "|" + currPower + "|" + todayEnergy + "|" + totalEnergy + "|" + standbyLimit;
- }
- }
-}
--- /dev/null
+/**
+ * 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.test;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.*;
+import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
+
+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.WemoInsightHandler;
+import org.openhab.binding.wemo.internal.http.WemoHttpCall;
+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.thing.ThingStatusDetail;
+import org.openhab.core.thing.ThingTypeUID;
+import org.openhab.core.thing.ThingUID;
+import org.openhab.core.types.State;
+
+/**
+ * Tests for {@link WemoInsightHandler}.
+ *
+ * @author Svilen Valkanov - Initial contribution
+ * @author Stefan Triller - Ported Tests from Groovy to Java
+ */
+public class WemoInsightHandlerTest {
+
+ private static final ThingTypeUID THING_TYPE = WemoBindingConstants.THING_TYPE_INSIGHT;
+ private static final String THING_ID = "test";
+
+ private MockWemoInsightHandler handler;
+
+ private static final String SERVICE_ID = "insight";
+ private static final String PARAMS_NAME = "InsightParams";
+ private WemoInsightParams insightParams;
+
+ /** Used for all tests, where expected value is time in seconds **/
+ private static final int TIME_PARAM = 4702;
+
+ /** Represents a state parameter, where 1 stays for ON and 0 stays for OFF **/
+ private static final int STATE_PARAM = 1;
+
+ /** Represents power in Wats **/
+ private static final int POWER_PARAM = 54;
+
+ private final Thing thing = mock(Thing.class);
+
+ @BeforeEach
+ public void setUp() {
+ insightParams = new WemoInsightParams();
+ when(thing.getUID()).thenReturn(new ThingUID(THING_TYPE, THING_ID));
+ when(thing.getThingTypeUID()).thenReturn(THING_TYPE);
+ when(thing.getStatus()).thenReturn(ThingStatus.ONLINE);
+ }
+
+ @AfterEach
+ public void clear() {
+ handler.channelState = null;
+ handler.channelToWatch = null;
+ }
+
+ @Test
+ public void assertThatChannelSTATEisUpdatedOnReceivedValue() {
+ insightParams.state = STATE_PARAM;
+ State expectedStateType = OnOffType.ON;
+ String expectedChannel = CHANNEL_STATE;
+
+ testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
+ }
+
+ @Test
+ public void assertThatChannelLASTONFORIsUpdatedOnReceivedValue() {
+ insightParams.lastOnFor = TIME_PARAM;
+ State expectedStateType = new DecimalType(TIME_PARAM);
+ String expectedChannel = CHANNEL_LASTONFOR;
+
+ testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
+ }
+
+ @Test
+ public void assertThatChannelONTODAYIsUpdatedOnReceivedValue() {
+ insightParams.onToday = TIME_PARAM;
+ State expectedStateType = new DecimalType(TIME_PARAM);
+ String expectedChannel = CHANNEL_ONTODAY;
+
+ testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
+ }
+
+ @Test
+ public void assertThatChannelONTOTALIsUpdatedOnReceivedValue() {
+ insightParams.onTotal = TIME_PARAM;
+ State expectedStateType = new DecimalType(TIME_PARAM);
+ String expectedChannel = CHANNEL_ONTOTAL;
+
+ testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
+ }
+
+ @Test
+ public void assertThatChannelTIMESPANIsUpdatedOnReceivedValue() {
+ insightParams.timespan = TIME_PARAM;
+ State expectedStateType = new DecimalType(TIME_PARAM);
+ String expectedChannel = CHANNEL_TIMESPAN;
+
+ testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
+ }
+
+ @Test
+ public void assertThatChannelAVERAGEPOWERIsUpdatedOnReceivedValue() {
+ insightParams.avgPower = POWER_PARAM;
+ State expectedStateType = new QuantityType<>(POWER_PARAM, Units.WATT);
+ String expectedChannel = CHANNEL_AVERAGEPOWER;
+
+ testOnValueReceived(expectedChannel, expectedStateType, insightParams.toString());
+ }
+
+ private void testOnValueReceived(String expectedChannel, State expectedState, String insightParams) {
+ handler = new MockWemoInsightHandler(thing, expectedChannel);
+
+ handler.onValueReceived(PARAMS_NAME, insightParams, SERVICE_ID);
+ assertThat(handler.channelState, is(notNullValue()));
+ assertThat(handler.channelState, is(expectedState));
+ }
+
+ class MockWemoInsightHandler extends WemoInsightHandler {
+ State channelState;
+ String channelToWatch;
+
+ public MockWemoInsightHandler(Thing thing, String channelToWatch) {
+ super(thing, null, new WemoHttpCall());
+ this.channelToWatch = channelToWatch;
+ }
+
+ @Override
+ protected void updateState(String channelID, State channelState) {
+ if (channelID.equals(channelToWatch)) {
+ this.channelState = channelState;
+ }
+ }
+
+ @Override
+ protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail, String description) {
+ }
+
+ @Override
+ protected void updateStatus(ThingStatus status, ThingStatusDetail statusDetail) {
+ }
+
+ @Override
+ protected void updateStatus(ThingStatus status) {
+ }
+ }
+
+ class WemoInsightParams {
+ int state, lastChangedAt, lastOnFor, onToday, onTotal, timespan, avgPower, currPower, todayEnergy, totalEnergy,
+ standbyLimit;
+
+ @Override
+ public String toString() {
+ // Example string looks like "1|1427230660|4702|25528|82406|1209600|39|40880|15620649|54450534.000000|8000"
+ return state + "|" + lastChangedAt + "|" + lastOnFor + "|" + onToday + "|" + onTotal + "|" + timespan + "|"
+ + avgPower + "|" + currPower + "|" + todayEnergy + "|" + totalEnergy + "|" + standbyLimit;
+ }
+ }
+}