From fdada9a155f6bbbe6ddb195a2cd661eca5e314d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hans-J=C3=B6rg=20Merk?= Date: Thu, 8 Apr 2021 22:46:46 +0200 Subject: [PATCH] [wemo] add annotations and remove usage of apache.commons.* (#9829) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [wemo] add annotations and remove usage of apache.commons.* Also-by: Wouter Born Signed-off-by: Hans-Jörg Merk --- .../wemo/internal/WemoBindingConstants.java | 6 +- .../wemo/internal/WemoHandlerFactory.java | 136 ++++--- .../wemo/internal/WemoHttpCallFactory.java | 27 ++ .../binding/wemo/internal/WemoUtil.java | 158 ++++++++ .../discovery/WemoDiscoveryParticipant.java | 6 +- .../discovery/WemoDiscoveryService.java | 5 +- .../discovery/WemoLinkDiscoveryService.java | 40 +- .../internal/handler/AbstractWemoHandler.java | 13 +- .../internal/handler/WemoBridgeHandler.java | 2 + .../internal/handler/WemoCoffeeHandler.java | 171 ++++---- .../internal/handler/WemoCrockpotHandler.java | 144 ++++--- .../internal/handler/WemoDimmerHandler.java | 375 +++++++++--------- .../wemo/internal/handler/WemoHandler.java | 225 ++++------- .../internal/handler/WemoHolmesHandler.java | 95 ++--- .../internal/handler/WemoLightHandler.java | 138 +++---- .../internal/handler/WemoMakerHandler.java | 104 ++--- .../wemo/internal/http/WemoHttpCall.java | 6 +- .../test/WemoDiscoveryParticipantTest.java | 4 +- .../handler/test/WemoHandlerOSGiTest.java | 20 +- .../handler/test/WemoHandlerTest.java | 14 +- .../test/WemoLightHandlerOSGiTest.java | 5 +- .../test/WemoMakerHandlerOSGiTest.java | 20 +- .../test/GenericWemoLightOSGiTestParent.java | 25 +- .../internal/test/GenericWemoOSGiTest.java | 49 +-- 24 files changed, 905 insertions(+), 883 deletions(-) create mode 100644 bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHttpCallFactory.java create mode 100644 bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoUtil.java 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 81374f34a19..c094db7e592 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 @@ -17,6 +17,7 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.thing.ThingTypeUID; /** @@ -26,6 +27,7 @@ import org.openhab.core.thing.ThingTypeUID; * @author Hans-Jörg Merk - Initial contribution * @author Mihir Patil - Added standby switch */ +@NonNullByDefault public class WemoBindingConstants { public static final String BINDING_ID = "wemo"; @@ -109,8 +111,8 @@ public class WemoBindingConstants { public static final String UDN = "udn"; public static final String DEVICE_ID = "deviceID"; public static final String POLLINGINTERVALL = "pollingInterval"; - - public static final int SUBSCRIPTION_DURATION = 600; + public static final int DEFAULT_REFRESH_INTERVALL_SECONDS = 60; + public static final int SUBSCRIPTION_DURATION_SECONDS = 600; public static final int LINK_DISCOVERY_SERVICE_INITIAL_DELAY = 5; public static final String HTTP_CALL_CONTENT_HEADER = "text/xml; charset=utf-8"; 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 4dbef6902af..0b25b1e0ac7 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 @@ -19,6 +19,8 @@ import java.util.Hashtable; import java.util.Map; import java.util.Set; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.wemo.internal.discovery.WemoLinkDiscoveryService; import org.openhab.binding.wemo.internal.handler.WemoBridgeHandler; import org.openhab.binding.wemo.internal.handler.WemoCoffeeHandler; @@ -39,8 +41,11 @@ import org.openhab.core.thing.binding.BaseThingHandlerFactory; import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.ThingHandlerFactory; import org.osgi.framework.ServiceRegistration; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,15 +56,17 @@ import org.slf4j.LoggerFactory; * @author Hans-Jörg Merk - Initial contribution * @author Kai Kreuzer - some refactoring for performance and simplification */ +@NonNullByDefault @Component(service = ThingHandlerFactory.class, configurationPid = "binding.wemo") public class WemoHandlerFactory extends BaseThingHandlerFactory { private final Logger logger = LoggerFactory.getLogger(WemoHandlerFactory.class); - private UpnpIOService upnpIOService; - public static final Set SUPPORTED_THING_TYPES = WemoBindingConstants.SUPPORTED_THING_TYPES; + private UpnpIOService upnpIOService; + private @Nullable WemoHttpCallFactory wemoHttpCallFactory; + @Override public boolean supportsThingType(ThingTypeUID thingTypeUID) { return SUPPORTED_THING_TYPES.contains(thingTypeUID); @@ -67,70 +74,73 @@ public class WemoHandlerFactory extends BaseThingHandlerFactory { private final Map> discoveryServiceRegs = new HashMap<>(); - @SuppressWarnings({ "null", "unused" }) - @Override - protected ThingHandler createHandler(Thing thing) { - ThingTypeUID thingTypeUID = thing.getThingTypeUID(); - if (thingTypeUID != null) { - logger.debug("Trying to create a handler for ThingType '{}", thingTypeUID); - - WemoHttpCall wemoHttpcaller = new WemoHttpCall(); - - if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_BRIDGE)) { - logger.debug("Creating a WemoBridgeHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get(UDN)); - WemoBridgeHandler handler = new WemoBridgeHandler((Bridge) thing); - registerDeviceDiscoveryService(handler, wemoHttpcaller); - return handler; - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MAKER)) { - logger.debug("Creating a WemoMakerHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get(UDN)); - return new WemoMakerHandler(thing, upnpIOService, wemoHttpcaller); - } else if (WemoBindingConstants.SUPPORTED_DEVICE_THING_TYPES.contains(thing.getThingTypeUID())) { - logger.debug("Creating a WemoHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get(UDN)); - return new WemoHandler(thing, upnpIOService, wemoHttpcaller); - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_COFFEE)) { - logger.debug("Creating a WemoCoffeeHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get(UDN)); - return new WemoCoffeeHandler(thing, upnpIOService, wemoHttpcaller); - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_DIMMER)) { - logger.debug("Creating a WemoDimmerHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get("udn")); - return new WemoDimmerHandler(thing, upnpIOService, wemoHttpcaller); - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_CROCKPOT)) { - logger.debug("Creating a WemoCockpotHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get("udn")); - return new WemoCrockpotHandler(thing, upnpIOService, wemoHttpcaller); - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_PURIFIER)) { - logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get("udn")); - return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller); - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HUMIDIFIER)) { - logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get("udn")); - return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller); - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HEATER)) { - logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(), - thing.getConfiguration().get("udn")); - return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller); - } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MZ100)) { - return new WemoLightHandler(thing, upnpIOService, wemoHttpcaller); - } else { - logger.warn("ThingHandler not found for {}", thingTypeUID); - return null; - } - } - return null; - } - - @Reference - protected void setUpnpIOService(UpnpIOService upnpIOService) { + @Activate + public WemoHandlerFactory(final @Reference UpnpIOService upnpIOService) { this.upnpIOService = upnpIOService; } - protected void unsetUpnpIOService(UpnpIOService upnpIOService) { - this.upnpIOService = null; + @Reference(cardinality = ReferenceCardinality.OPTIONAL, policy = ReferencePolicy.DYNAMIC) + public void setWemoHttpCallFactory(WemoHttpCallFactory wemoHttpCallFactory) { + this.wemoHttpCallFactory = wemoHttpCallFactory; + } + + public void unsetWemoHttpCallFactory(WemoHttpCallFactory wemoHttpCallFactory) { + this.wemoHttpCallFactory = null; + } + + @Override + protected @Nullable ThingHandler createHandler(Thing thing) { + ThingTypeUID thingTypeUID = thing.getThingTypeUID(); + logger.debug("Trying to create a handler for ThingType '{}", thingTypeUID); + + WemoHttpCallFactory wemoHttpCallFactory = this.wemoHttpCallFactory; + WemoHttpCall wemoHttpcaller = wemoHttpCallFactory == null ? new WemoHttpCall() + : wemoHttpCallFactory.createHttpCall(); + + if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_BRIDGE)) { + logger.debug("Creating a WemoBridgeHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get(UDN)); + WemoBridgeHandler handler = new WemoBridgeHandler((Bridge) thing); + registerDeviceDiscoveryService(handler, wemoHttpcaller); + return handler; + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MAKER)) { + logger.debug("Creating a WemoMakerHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get(UDN)); + return new WemoMakerHandler(thing, upnpIOService, wemoHttpcaller); + } else if (WemoBindingConstants.SUPPORTED_DEVICE_THING_TYPES.contains(thing.getThingTypeUID())) { + logger.debug("Creating a WemoHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get(UDN)); + return new WemoHandler(thing, upnpIOService, wemoHttpcaller); + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_COFFEE)) { + logger.debug("Creating a WemoCoffeeHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get(UDN)); + return new WemoCoffeeHandler(thing, upnpIOService, wemoHttpcaller); + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_DIMMER)) { + logger.debug("Creating a WemoDimmerHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get("udn")); + return new WemoDimmerHandler(thing, upnpIOService, wemoHttpcaller); + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_CROCKPOT)) { + logger.debug("Creating a WemoCockpotHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get("udn")); + return new WemoCrockpotHandler(thing, upnpIOService, wemoHttpcaller); + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_PURIFIER)) { + logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get("udn")); + return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller); + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HUMIDIFIER)) { + logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get("udn")); + return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller); + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_HEATER)) { + logger.debug("Creating a WemoHolmesHandler for thing '{}' with UDN '{}'", thing.getUID(), + thing.getConfiguration().get("udn")); + return new WemoHolmesHandler(thing, upnpIOService, wemoHttpcaller); + } else if (thingTypeUID.equals(WemoBindingConstants.THING_TYPE_MZ100)) { + return new WemoLightHandler(thing, upnpIOService, wemoHttpcaller); + } else { + logger.warn("ThingHandler not found for {}", thingTypeUID); + return null; + } } @Override diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHttpCallFactory.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHttpCallFactory.java new file mode 100644 index 00000000000..45ef5424623 --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoHttpCallFactory.java @@ -0,0 +1,27 @@ +/** + * Copyright (c) 2010-2021 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 org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.wemo.internal.http.WemoHttpCall; + +/** + * {@link WemoHttpCallFactory} creates {@WemoHttpCall}s. + * + * @author Wouter Born - Initial contribution + */ +@NonNullByDefault +public interface WemoHttpCallFactory { + + WemoHttpCall createHttpCall(); +} diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoUtil.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoUtil.java new file mode 100644 index 00000000000..a89a55b53c4 --- /dev/null +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/WemoUtil.java @@ -0,0 +1,158 @@ +/** + * Copyright (c) 2010-2021 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.io.IOException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; +import org.openhab.core.io.net.http.HttpUtil; + +/** + * {@link WemoUtil} implements some helper functions. + * + * @author Hans-Jörg Merk - Initial contribution + */ +@NonNullByDefault +public class WemoUtil { + + public static BiFunction serviceAvailableFunction = WemoUtil::servicePing; + + public static String substringBefore(@Nullable String string, String pattern) { + if (string != null) { + int pos = string.indexOf(pattern); + if (pos > 0) { + return string.substring(0, pos); + } + } + return ""; + } + + public static String substringBetween(@Nullable String string, String begin, String end) { + if (string != null) { + int s = string.indexOf(begin); + if (s != -1) { + String result = string.substring(s + begin.length()); + return substringBefore(result, end); + } + } + return ""; + } + + public static String unescape(final String text) { + StringBuilder result = new StringBuilder(text.length()); + int i = 0; + int n = text.length(); + while (i < n) { + char charAt = text.charAt(i); + if (charAt != '&') { + result.append(charAt); + i++; + } else { + if (text.startsWith("&", i)) { + result.append('&'); + i += 5; + } else if (text.startsWith("'", i)) { + result.append('\''); + i += 6; + } else if (text.startsWith(""", i)) { + result.append('"'); + i += 6; + } else if (text.startsWith("<", i)) { + result.append('<'); + i += 4; + } else if (text.startsWith(">", i)) { + result.append('>'); + i += 4; + } else { + i++; + } + } + } + return result.toString(); + } + + public static String unescapeXml(final String xml) { + Pattern xmlEntityRegex = Pattern.compile("&(#?)([^;]+);"); + // Unfortunately, Matcher requires a StringBuffer instead of a StringBuilder + StringBuffer unescapedOutput = new StringBuffer(xml.length()); + + Matcher m = xmlEntityRegex.matcher(xml); + Map builtinEntities = null; + String entity; + String hashmark; + String ent; + int code; + while (m.find()) { + ent = m.group(2); + hashmark = m.group(1); + if ((hashmark != null) && (hashmark.length() > 0)) { + code = Integer.parseInt(ent); + entity = Character.toString((char) code); + } else { + // must be a non-numerical entity + if (builtinEntities == null) { + builtinEntities = buildBuiltinXMLEntityMap(); + } + entity = builtinEntities.get(ent); + if (entity == null) { + // not a known entity - ignore it + entity = "&" + ent + ';'; + } + } + m.appendReplacement(unescapedOutput, entity); + } + m.appendTail(unescapedOutput); + + return unescapedOutput.toString(); + } + + public static @Nullable String getWemoURL(URL descriptorURL, String actionService) { + int portCheckStart = 49151; + int portCheckStop = 49157; + String port = null; + String host = substringBetween(descriptorURL.toString(), "://", ":"); + for (int i = portCheckStart; i < portCheckStop; i++) { + if (serviceAvailableFunction.apply(host, i)) { + port = String.valueOf(i); + break; + } + } + return port == null ? null : "http://" + host + ":" + port + "/upnp/control/" + actionService + "1"; + } + + private static boolean servicePing(String host, int port) { + try { + HttpUtil.executeUrl("GET", "http://" + host + ":" + port, 250); + return true; + } catch (IOException e) { + return false; + } + } + + private static Map buildBuiltinXMLEntityMap() { + Map entities = new HashMap(10); + entities.put("lt", "<"); + entities.put("gt", ">"); + entities.put("amp", "&"); + entities.put("apos", "'"); + entities.put("quot", "\""); + return entities; + } +} diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryParticipant.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryParticipant.java index 09767ff1a16..940946c7b63 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryParticipant.java @@ -18,6 +18,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.jupnp.model.meta.RemoteDevice; import org.openhab.binding.wemo.internal.WemoBindingConstants; @@ -39,6 +40,7 @@ import org.slf4j.LoggerFactory; * @author Kai Kreuzer - some refactoring for performance and simplification * */ +@NonNullByDefault @Component(service = UpnpDiscoveryParticipant.class) public class WemoDiscoveryParticipant implements UpnpDiscoveryParticipant { @@ -50,7 +52,7 @@ public class WemoDiscoveryParticipant implements UpnpDiscoveryParticipant { } @Override - public DiscoveryResult createResult(RemoteDevice device) { + public @Nullable DiscoveryResult createResult(RemoteDevice device) { ThingUID uid = getThingUID(device); if (uid != null) { Map properties = new HashMap<>(2); @@ -75,7 +77,7 @@ public class WemoDiscoveryParticipant implements UpnpDiscoveryParticipant { } @Override - public ThingUID getThingUID(@Nullable RemoteDevice device) { + public @Nullable ThingUID getThingUID(@Nullable RemoteDevice device) { if (device != null) { if (device.getDetails().getManufacturerDetails().getManufacturer() != null) { if (device.getDetails().getManufacturerDetails().getManufacturer().toUpperCase().contains("BELKIN")) { diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryService.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryService.java index 0442dd606e3..531fa6c457a 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryService.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoDiscoveryService.java @@ -12,6 +12,8 @@ */ package org.openhab.binding.wemo.internal.discovery; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.jupnp.UpnpService; import org.jupnp.model.message.header.RootDeviceHeader; import org.openhab.core.config.discovery.AbstractDiscoveryService; @@ -28,6 +30,7 @@ import org.slf4j.LoggerFactory; * @author Hans-Jörg Merk - Initial contribution * */ +@NonNullByDefault @Component(service = DiscoveryService.class, configurationPid = "discovery.wemo") public class WemoDiscoveryService extends AbstractDiscoveryService { @@ -37,7 +40,7 @@ public class WemoDiscoveryService extends AbstractDiscoveryService { super(5); } - private UpnpService upnpService; + private @Nullable UpnpService upnpService; @Reference protected void setUpnpService(UpnpService upnpService) { diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoLinkDiscoveryService.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoLinkDiscoveryService.java index 368bb103cc2..40d7d03cf02 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoLinkDiscoveryService.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/discovery/WemoLinkDiscoveryService.java @@ -13,6 +13,7 @@ package org.openhab.binding.wemo.internal.discovery; import static org.openhab.binding.wemo.internal.WemoBindingConstants.*; +import static org.openhab.binding.wemo.internal.WemoUtil.*; import java.io.StringReader; import java.net.URL; @@ -26,8 +27,8 @@ import java.util.concurrent.TimeUnit; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.wemo.internal.handler.WemoBridgeHandler; import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.core.config.discovery.AbstractDiscoveryService; @@ -53,6 +54,7 @@ import org.xml.sax.InputSource; * @author Hans-Jörg Merk - Initial contribution * */ +@NonNullByDefault public class WemoLinkDiscoveryService extends AbstractDiscoveryService implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoLinkDiscoveryService.class); @@ -84,7 +86,7 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement /** * Schedule for scanning */ - private ScheduledFuture scanningJob; + private @Nullable ScheduledFuture scanningJob; /** * The Upnp service @@ -96,20 +98,12 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement public WemoLinkDiscoveryService(WemoBridgeHandler wemoBridgeHandler, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { super(SEARCH_TIME); + this.service = upnpIOService; this.wemoBridgeHandler = wemoBridgeHandler; this.wemoHttpCaller = wemoHttpCaller; - if (upnpIOService != null) { - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } - this.scanningRunnable = new WemoLinkScan(); - if (wemoBridgeHandler == null) { - logger.warn("no bridge handler for scan given"); - } this.activate(null); } @@ -134,7 +128,7 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement URL descriptorURL = service.getDescriptorURL(this); if (descriptorURL != null) { - String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml"); + String deviceURL = substringBefore(descriptorURL.toString(), "/setup.xml"); String wemoURL = deviceURL + "/upnp/control/bridge1"; String endDeviceRequest = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); @@ -143,10 +137,9 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement logger.trace("endDeviceRequest answered '{}'", endDeviceRequest); try { - String stringParser = StringUtils.substringBetween(endDeviceRequest, "", - ""); + String stringParser = substringBetween(endDeviceRequest, "", ""); - stringParser = StringEscapeUtils.unescapeXml(stringParser); + stringParser = unescapeXml(stringParser); // check if there are already paired devices with WeMo Link if ("0".equals(stringParser)) { @@ -245,7 +238,9 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement protected void startBackgroundDiscovery() { logger.trace("Start WeMo device background discovery"); - if (scanningJob == null || scanningJob.isCancelled()) { + ScheduledFuture job = scanningJob; + + if (job == null || job.isCancelled()) { this.scanningJob = scheduler.scheduleWithFixedDelay(this.scanningRunnable, LINK_DISCOVERY_SERVICE_INITIAL_DELAY, SCAN_INTERVAL, TimeUnit.SECONDS); } else { @@ -257,10 +252,11 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement protected void stopBackgroundDiscovery() { logger.debug("Stop WeMo device background discovery"); - if (scanningJob != null && !scanningJob.isCancelled()) { - scanningJob.cancel(true); - scanningJob = null; + ScheduledFuture job = scanningJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + scanningJob = null; } @Override @@ -269,11 +265,11 @@ public class WemoLinkDiscoveryService extends AbstractDiscoveryService implement } @Override - public void onServiceSubscribed(String service, boolean succeeded) { + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { } @Override - public void onValueReceived(String variable, String value, String service) { + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { } @Override diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/AbstractWemoHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/AbstractWemoHandler.java index dce551b1d4f..1702b3e28e3 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/AbstractWemoHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/AbstractWemoHandler.java @@ -12,24 +12,21 @@ */ package org.openhab.binding.wemo.internal.handler; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.core.thing.Thing; import org.openhab.core.thing.binding.BaseThingHandler; /** - * - * @author Stefan Triller - * + * @author Stefan Triller - Initial contribution */ +@NonNullByDefault public abstract class AbstractWemoHandler extends BaseThingHandler { - public AbstractWemoHandler(Thing thing) { - super(thing); - } - protected WemoHttpCall wemoHttpCaller; - public void setWemoHttpCaller(WemoHttpCall wemoHttpCaller) { + public AbstractWemoHandler(Thing thing, WemoHttpCall wemoHttpCaller) { + super(thing); this.wemoHttpCaller = wemoHttpCaller; } } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBridgeHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBridgeHandler.java index d115fb74184..abdda3d2890 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBridgeHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoBridgeHandler.java @@ -17,6 +17,7 @@ import static org.openhab.binding.wemo.internal.WemoBindingConstants.*; import java.util.Collections; import java.util.Set; +import org.eclipse.jdt.annotation.NonNullByDefault; import org.openhab.core.config.core.Configuration; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.ChannelUID; @@ -34,6 +35,7 @@ import org.slf4j.LoggerFactory; * * @author Hans-Jörg Merk - Initial contribution */ +@NonNullByDefault public class WemoBridgeHandler extends BaseBridgeHandler { public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_BRIDGE); 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 2e5ebbe1c19..a39d63f2f81 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 @@ -13,6 +13,7 @@ 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.io.StringReader; import java.math.BigDecimal; @@ -30,8 +31,8 @@ import java.util.concurrent.TimeUnit; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; +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.UpnpIOParticipant; @@ -64,7 +65,7 @@ import org.xml.sax.InputSource; * @author Hans-Jörg Merk - Initial contribution * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType */ - +@NonNullByDefault public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoCoffeeHandler.class); @@ -73,16 +74,11 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart private Map subscriptionState = new HashMap<>(); - protected static final int SUBSCRIPTION_DURATION = 600; - private UpnpIOService service; - /** - * The default refresh interval in Seconds. - */ - private final int REFRESH_INTERVAL = 60; + private WemoHttpCall wemoCall; - private ScheduledFuture refreshJob; + private @Nullable ScheduledFuture refreshJob; private final Runnable refreshRunnable = new Runnable() { @@ -102,18 +98,13 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart } }; - public WemoCoffeeHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpcaller) { - super(thing); + public WemoCoffeeHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, wemoHttpCaller); - this.wemoHttpCaller = wemoHttpcaller; + this.wemoCall = wemoHttpCaller; + this.service = upnpIOService; logger.debug("Creating a WemoCoffeeHandler V0.4 for thing '{}'", getThing().getUID()); - - if (upnpIOService != null) { - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } } @Override @@ -134,12 +125,12 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart public void dispose() { logger.debug("WeMoCoffeeHandler disposed."); - removeSubscription(); - - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; + removeSubscription(); } @Override @@ -171,10 +162,11 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart + "<attribute><name>Cleaning</name><value>NULL</value></attribute>" + "" + "" + ""; - String wemoURL = getWemoURL("deviceevent"); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { updateState(CHANNEL_STATE, OnOffType.ON); State newMode = new StringType("Brewing"); @@ -195,13 +187,16 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart } @Override - public void onServiceSubscribed(String service, boolean succeeded) { - logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed"); - subscriptionState.put(service, succeeded); + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { + if (service != null) { + logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, + succeeded ? "succeeded" : "failed"); + subscriptionState.put(service, succeeded); + } } @Override - public void onValueReceived(String variable, String value, String service) { + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { // We can subscribe to GENA events, but there is no usefull response right now. } @@ -210,9 +205,9 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart logger.debug("Checking WeMo GENA subscription for '{}'", this); String subscription = "deviceevent1"; - if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) == null) { logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription); - service.addSubscription(this, subscription, SUBSCRIPTION_DURATION); + service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS); subscriptionState.put(subscription, true); } } else { @@ -226,7 +221,7 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart if (service.isRegistered(this)) { String subscription = "deviceevent1"; - if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) != null) { logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription); service.removeSubscription(this, subscription); } @@ -237,9 +232,10 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart } private synchronized void onUpdate() { - if (refreshJob == null || refreshJob.isCancelled()) { + ScheduledFuture job = refreshJob; + if (job == null || job.isCancelled()) { Configuration config = getThing().getConfiguration(); - int refreshInterval = REFRESH_INTERVAL; + int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS; Object refreshConfig = config.get("pollingInterval"); if (refreshConfig != null) { refreshInterval = ((BigDecimal) refreshConfig).intValue(); @@ -272,17 +268,18 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart + action + ">" + "" + ""; try { - String wemoURL = getWemoURL(actionService); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, actionService); + if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { try { - String stringParser = StringUtils.substringBetween(wemoCallResponse, "", - ""); + String stringParser = substringBetween(wemoCallResponse, "", ""); // Due to Belkins bad response formatting, we need to run this twice. - stringParser = StringEscapeUtils.unescapeXml(stringParser); - stringParser = StringEscapeUtils.unescapeXml(stringParser); + stringParser = unescapeXml(stringParser); + stringParser = unescapeXml(stringParser); logger.trace("CoffeeMaker response '{}' for device '{}' received", stringParser, getThing().getUID()); @@ -321,6 +318,8 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart switch (attributeName) { case "Mode": State newMode = new StringType("Brewing"); + State newAttributeValue; + switch (attributeValue) { case "0": updateState(CHANNEL_STATE, OnOffType.ON); @@ -370,51 +369,35 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart } break; case "ModeTime": - if (attributeValue != null) { - State newAttributeValue = new DecimalType(attributeValue); - updateState(CHANNEL_MODETIME, newAttributeValue); - } + newAttributeValue = new DecimalType(attributeValue); + updateState(CHANNEL_MODETIME, newAttributeValue); break; case "TimeRemaining": - if (attributeValue != null) { - State newAttributeValue = new DecimalType(attributeValue); - updateState(CHANNEL_TIMEREMAINING, newAttributeValue); - } + newAttributeValue = new DecimalType(attributeValue); + updateState(CHANNEL_TIMEREMAINING, newAttributeValue); break; case "WaterLevelReached": - if (attributeValue != null) { - State newAttributeValue = new DecimalType(attributeValue); - updateState(CHANNEL_WATERLEVELREACHED, newAttributeValue); - } + newAttributeValue = new DecimalType(attributeValue); + updateState(CHANNEL_WATERLEVELREACHED, newAttributeValue); break; case "CleanAdvise": - if (attributeValue != null) { - State newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF - : OnOffType.ON; - updateState(CHANNEL_CLEANADVISE, newAttributeValue); - } + newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF : OnOffType.ON; + updateState(CHANNEL_CLEANADVISE, newAttributeValue); break; case "FilterAdvise": - if (attributeValue != null) { - State newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF - : OnOffType.ON; - updateState(CHANNEL_FILTERADVISE, newAttributeValue); - } + newAttributeValue = attributeValue.equals("0") ? OnOffType.OFF : OnOffType.ON; + updateState(CHANNEL_FILTERADVISE, newAttributeValue); break; case "Brewed": - if (attributeValue != null) { - State newAttributeValue = getDateTimeState(attributeValue); - if (newAttributeValue != null) { - updateState(CHANNEL_BREWED, newAttributeValue); - } + newAttributeValue = getDateTimeState(attributeValue); + if (newAttributeValue != null) { + updateState(CHANNEL_BREWED, newAttributeValue); } break; case "LastCleaned": - if (attributeValue != null) { - State newAttributeValue = getDateTimeState(attributeValue); - if (newAttributeValue != null) { - updateState(CHANNEL_LASTCLEANED, newAttributeValue); - } + newAttributeValue = getDateTimeState(attributeValue); + if (newAttributeValue != null) { + updateState(CHANNEL_LASTCLEANED, newAttributeValue); } break; } @@ -430,37 +413,19 @@ public class WemoCoffeeHandler extends AbstractWemoHandler implements UpnpIOPart } } - @SuppressWarnings("null") - public State getDateTimeState(String attributeValue) { - if (attributeValue != null) { - long value = 0; - try { - value = Long.parseLong(attributeValue) * 1000; // convert s to ms - } catch (NumberFormatException e) { - logger.error("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue, - getThing().getUID()); - return null; - } - ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(value), - TimeZone.getDefault().toZoneId()); - State dateTimeState = new DateTimeType(zoned); - if (dateTimeState != null) { - logger.trace("New attribute brewed '{}' received", dateTimeState); - return dateTimeState; - } + public @Nullable State getDateTimeState(String attributeValue) { + long value = 0; + try { + value = Long.parseLong(attributeValue); + } catch (NumberFormatException e) { + logger.error("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue, + getThing().getUID()); + return null; } - return null; - } - - public String getWemoURL(String actionService) { - URL descriptorURL = service.getDescriptorURL(this); - String wemoURL = null; - if (descriptorURL != null) { - String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml"); - wemoURL = deviceURL + "/upnp/control/" + actionService + "1"; - return wemoURL; - } - return null; + ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochSecond(value), TimeZone.getDefault().toZoneId()); + State dateTimeState = new DateTimeType(zoned); + logger.trace("New attribute brewed '{}' received", dateTimeState); + return dateTimeState; } public static String getCharacterDataFromElement(Element e) { 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 4ca69f11012..b76e2e7d071 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 @@ -13,6 +13,7 @@ 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.net.URL; @@ -23,7 +24,8 @@ import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.StringUtils; +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.UpnpIOParticipant; @@ -47,22 +49,21 @@ import org.slf4j.LoggerFactory; * * @author Hans-Jörg Merk - Initial contribution; */ - +@NonNullByDefault public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoCrockpotHandler.class); public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_CROCKPOT); - /** - * The default refresh interval in Seconds. - */ - private static final int DEFAULT_REFRESH_INTERVAL_SECONDS = 120; + private final Map subscriptionState = new HashMap<>(); private final Map stateMap = Collections.synchronizedMap(new HashMap<>()); private UpnpIOService service; - private ScheduledFuture refreshJob; + private WemoHttpCall wemoCall; + + private @Nullable ScheduledFuture refreshJob; private final Runnable refreshRunnable = () -> { updateWemoState(); @@ -73,18 +74,13 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa } }; - public WemoCrockpotHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) { - super(thing); + public WemoCrockpotHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, wemoHttpCaller); - this.wemoHttpCaller = wemohttpCaller; + this.wemoCall = wemoHttpCaller; + this.service = upnpIOService; logger.debug("Creating a WemoCrockpotHandler for thing '{}'", getThing().getUID()); - - if (upnpIOService != null) { - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } } @Override @@ -106,12 +102,12 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa public void dispose() { logger.debug("WeMoCrockpotHandler disposed."); - removeSubscription(); - - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; + removeSubscription(); } @Override @@ -146,10 +142,12 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa + "" + "" + "" + mode + "" + "" + "" + "" + ""; - String wemoURL = getWemoURL("basicevent"); + + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); if (wemoURL != null) { - wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + wemoCall.executeCall(wemoURL, soapHeader, content); } } catch (RuntimeException e) { logger.debug("Failed to send command '{}' for device '{}':", command, getThing().getUID(), e); @@ -160,18 +158,23 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa } @Override - public void onServiceSubscribed(String service, boolean succeeded) { - logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed"); - subscriptionState.put(service, succeeded); + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { + if (service != null) { + logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, + succeeded ? "succeeded" : "failed"); + subscriptionState.put(service, succeeded); + } } @Override - public void onValueReceived(String variable, String value, String service) { + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", variable, value, service, this.getThing().getUID()); updateStatus(ThingStatus.ONLINE); - this.stateMap.put(variable, value); + if (variable != null && value != null) { + this.stateMap.put(variable, value); + } } private synchronized void onSubscription() { @@ -180,9 +183,9 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) == null) { logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription); - service.addSubscription(this, subscription, SUBSCRIPTION_DURATION); + service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS); subscriptionState.put(subscription, true); } @@ -198,7 +201,7 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa if (service.isRegistered(this)) { String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) != null) { logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription); service.removeSubscription(this, subscription); } @@ -209,11 +212,12 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa } private synchronized void onUpdate() { - if (refreshJob == null || refreshJob.isCancelled()) { + ScheduledFuture job = refreshJob; + if (job == null || job.isCancelled()) { Configuration config = getThing().getConfiguration(); - int refreshInterval = DEFAULT_REFRESH_INTERVAL_SECONDS; + int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS; Object refreshConfig = config.get("refresh"); - refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVAL_SECONDS + refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVALL_SECONDS : ((BigDecimal) refreshConfig).intValue(); refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS); } @@ -244,42 +248,41 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa + action + ">" + "" + ""; try { - String wemoURL = getWemoURL(actionService); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, actionService); + if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID()); - String mode = StringUtils.substringBetween(wemoCallResponse, "", ""); - String time = StringUtils.substringBetween(wemoCallResponse, ""); - String coockedTime = StringUtils.substringBetween(wemoCallResponse, "", - ""); + String mode = substringBetween(wemoCallResponse, "", ""); + String time = substringBetween(wemoCallResponse, ""); + String coockedTime = substringBetween(wemoCallResponse, "", ""); - if (mode != null && time != null && coockedTime != null) { - State newMode = new StringType(mode); - State newCoockedTime = DecimalType.valueOf(coockedTime); - switch (mode) { - case "0": - newMode = new StringType("OFF"); - break; - case "50": - newMode = new StringType("WARM"); - State warmTime = DecimalType.valueOf(time); - updateState(CHANNEL_WARMCOOKTIME, warmTime); - break; - case "51": - newMode = new StringType("LOW"); - State lowTime = DecimalType.valueOf(time); - updateState(CHANNEL_LOWCOOKTIME, lowTime); - break; - case "52": - newMode = new StringType("HIGH"); - State highTime = DecimalType.valueOf(time); - updateState(CHANNEL_HIGHCOOKTIME, highTime); - break; - } - updateState(CHANNEL_COOKMODE, newMode); - updateState(CHANNEL_COOKEDTIME, newCoockedTime); + State newMode = new StringType(mode); + State newCoockedTime = DecimalType.valueOf(coockedTime); + switch (mode) { + case "0": + newMode = new StringType("OFF"); + break; + case "50": + newMode = new StringType("WARM"); + State warmTime = DecimalType.valueOf(time); + updateState(CHANNEL_WARMCOOKTIME, warmTime); + break; + case "51": + newMode = new StringType("LOW"); + State lowTime = DecimalType.valueOf(time); + updateState(CHANNEL_LOWCOOKTIME, lowTime); + break; + case "52": + newMode = new StringType("HIGH"); + State highTime = DecimalType.valueOf(time); + updateState(CHANNEL_HIGHCOOKTIME, highTime); + break; } + updateState(CHANNEL_COOKMODE, newMode); + updateState(CHANNEL_COOKEDTIME, newCoockedTime); } } } catch (RuntimeException e) { @@ -289,17 +292,6 @@ public class WemoCrockpotHandler extends AbstractWemoHandler implements UpnpIOPa updateStatus(ThingStatus.ONLINE); } - public String getWemoURL(String actionService) { - URL descriptorURL = service.getDescriptorURL(this); - String wemoURL = null; - if (descriptorURL != null) { - String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml"); - wemoURL = deviceURL + "/upnp/control/" + actionService + "1"; - return wemoURL; - } - return null; - } - @Override public void onStatusChanged(boolean status) { } 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 cfd6fa622ab..3496ae3e3fb 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 @@ -13,6 +13,7 @@ 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.net.URL; @@ -26,7 +27,8 @@ import java.util.TimeZone; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.StringUtils; +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.UpnpIOParticipant; @@ -53,27 +55,28 @@ import org.slf4j.LoggerFactory; * * @author Hans-Jörg Merk - Initial contribution */ - +@NonNullByDefault public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoDimmerHandler.class); + public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DIMMER); + private Map subscriptionState = new HashMap<>(); private Map stateMap = Collections.synchronizedMap(new HashMap<>()); - protected static final int SUBSCRIPTION_DURATION = 600; + private UpnpIOService service; + private WemoHttpCall wemoCall; + private int currentBrightness; private int currentNightModeBrightness; - private String currentNightModeState = null; + private @Nullable String currentNightModeState; /** * Set dimming stepsize to 5% */ private static final int DIM_STEPSIZE = 5; - /** - * The default refresh interval in Seconds. - */ - private int DEFAULT_REFRESH_INTERVAL = 60; - private ScheduledFuture refreshJob; + + private @Nullable ScheduledFuture refreshJob; private Runnable refreshRunnable = new Runnable() { @Override @@ -90,15 +93,13 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart } }; - public WemoDimmerHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) { - super(thing); - this.wemoHttpCaller = wemohttpCaller; + public WemoDimmerHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, wemoHttpCaller); + + this.service = upnpIOService; + this.wemoCall = wemoHttpCaller; + logger.debug("Creating a WemoDimmerHandler for thing '{}'", getThing().getUID()); - if (upnpIOService != null) { - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } } @Override @@ -117,11 +118,14 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart @Override public void dispose() { logger.debug("WeMoDimmerHandler disposed."); - removeSubscription(); - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; + + removeSubscription(); } @Override @@ -140,6 +144,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart String timeStamp = null; switch (channelUID.getId()) { case CHANNEL_BRIGHTNESS: + String binaryState = this.stateMap.get("BinaryState"); if (command instanceof OnOffType) { value = command.equals(OnOffType.OFF) ? "0" : "1"; setBinaryState(action, argument, value); @@ -163,7 +168,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart value = "0"; argument = "BinaryState"; setBinaryState(action, argument, "0"); - } else if (this.stateMap.get("BinaryState").equals("0")) { + } else if ("0".equals(binaryState)) { argument = "BinaryState"; setBinaryState(action, argument, "1"); } @@ -197,7 +202,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart value = "0"; argument = "BinaryState"; setBinaryState(action, argument, "0"); - } else if (this.stateMap.get("BinaryState").equals("0")) { + } else if ("0".equals(binaryState)) { argument = "BinaryState"; setBinaryState(action, argument, "1"); } @@ -235,12 +240,15 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart logger.info("timestamp '{}' created", timeStamp); String faderSeconds = null; String faderEnabled = null; - String[] splitFader = this.stateMap.get("fader").split(":"); - if (splitFader[0] != null) { - faderSeconds = splitFader[0]; - } - if (splitFader[0] != null) { - faderEnabled = splitFader[2]; + String fader = this.stateMap.get("fader"); + if (fader != null) { + String[] splitFader = fader.split(":"); + if (splitFader[0] != null) { + faderSeconds = splitFader[0]; + } + if (splitFader[0] != null) { + faderEnabled = splitFader[2]; + } } if (faderSeconds != null && faderEnabled != null) { if (command.equals(OnOffType.ON)) { @@ -311,82 +319,100 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart } @Override - public void onServiceSubscribed(String service, boolean succeeded) { - logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed"); - subscriptionState.put(service, succeeded); + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { + if (service != null) { + logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, + succeeded ? "succeeded" : "failed"); + subscriptionState.put(service, succeeded); + } } @Override - public void onValueReceived(String variable, String value, String service) { + 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); - this.stateMap.put(variable, value); - switch (variable) { - case "BinaryState": - State state = value.equals("0") ? OnOffType.OFF : OnOffType.ON; - logger.debug("State '{}' for device '{}' received", state, getThing().getUID()); - updateState(CHANNEL_BRIGHTNESS, state); - if (state.equals(OnOffType.OFF)) { - updateState(CHANNEL_TIMERSTART, OnOffType.OFF); - } - break; - case "brightness": - logger.debug("brightness '{}' for device '{}' received", value, getThing().getUID()); - int newBrightnessValue = Integer.valueOf(value); - State newBrightnessState = new PercentType(newBrightnessValue); - if (this.stateMap.get("BinaryState").equals("1")) { - updateState(CHANNEL_BRIGHTNESS, newBrightnessState); - } - currentBrightness = newBrightnessValue; - break; - case "fader": - logger.debug("fader '{}' for device '{}' received", value, getThing().getUID()); - String[] splitFader = value.split(":"); - if (splitFader[0] != null) { - int faderSeconds = Integer.valueOf(splitFader[0]); - State faderMinutes = new DecimalType(faderSeconds / 60); - logger.debug("faderTime '{} minutes' for device '{}' received", faderMinutes, getThing().getUID()); - updateState(CHANNEL_FADERCOUNTDOWNTIME, 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); - if (isTimerRunning.equals(OnOffType.ON)) { - updateState(CHANNEL_STATE, OnOffType.ON); + if (variable != null && value != null) { + this.stateMap.put(variable, value); + } + if (variable != null && value != null) { + switch (variable) { + case "BinaryState": + State state = value.equals("0") ? OnOffType.OFF : OnOffType.ON; + logger.debug("State '{}' for device '{}' received", state, getThing().getUID()); + updateState(CHANNEL_BRIGHTNESS, state); + if (state.equals(OnOffType.OFF)) { + updateState(CHANNEL_TIMERSTART, OnOffType.OFF); } - } - if (splitFader[2] != null) { - State isFaderEnabled = splitFader[1].equals("0") ? OnOffType.OFF : OnOffType.ON; - logger.debug("isFaderEnabled '{}' for device '{}' received", isFaderEnabled, getThing().getUID()); - updateState(CHANNEL_FADERENABLED, isFaderEnabled); - } - break; - case "nightMode": - State nightModeState = value.equals("0") ? OnOffType.OFF : OnOffType.ON; - currentNightModeState = value; - logger.debug("nightModeState '{}' for device '{}' received", nightModeState, getThing().getUID()); - updateState(CHANNEL_NIGHTMODE, nightModeState); - break; - case "startTime": - State startTimeState = getDateTimeState(value); - logger.debug("startTimeState '{}' for device '{}' received", startTimeState, getThing().getUID()); - updateState(CHANNEL_STARTTIME, startTimeState); - break; - case "endTime": - State endTimeState = getDateTimeState(value); - logger.debug("endTimeState '{}' for device '{}' received", endTimeState, getThing().getUID()); - updateState(CHANNEL_ENDTIME, endTimeState); - break; - case "nightModeBrightness": - int nightModeBrightnessValue = Integer.valueOf(value); - currentNightModeBrightness = nightModeBrightnessValue; - State nightModeBrightnessState = new PercentType(nightModeBrightnessValue); - logger.debug("nightModeBrightnessState '{}' for device '{}' received", nightModeBrightnessState, - getThing().getUID()); - updateState(CHANNEL_NIGHTMODEBRIGHTNESS, nightModeBrightnessState); - break; + break; + case "brightness": + logger.debug("brightness '{}' for device '{}' received", value, getThing().getUID()); + int newBrightnessValue = Integer.valueOf(value); + State newBrightnessState = new PercentType(newBrightnessValue); + String binaryState = this.stateMap.get("BinaryState"); + if (binaryState != null) { + if (binaryState.equals("1")) { + updateState(CHANNEL_BRIGHTNESS, newBrightnessState); + } + } + currentBrightness = newBrightnessValue; + break; + case "fader": + logger.debug("fader '{}' for device '{}' received", value, getThing().getUID()); + String[] splitFader = value.split(":"); + if (splitFader[0] != null) { + int faderSeconds = Integer.valueOf(splitFader[0]); + State faderMinutes = new DecimalType(faderSeconds / 60); + logger.debug("faderTime '{} minutes' for device '{}' received", faderMinutes, + getThing().getUID()); + updateState(CHANNEL_FADERCOUNTDOWNTIME, 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); + if (isTimerRunning.equals(OnOffType.ON)) { + updateState(CHANNEL_STATE, OnOffType.ON); + } + } + if (splitFader[2] != null) { + State isFaderEnabled = splitFader[1].equals("0") ? OnOffType.OFF : OnOffType.ON; + logger.debug("isFaderEnabled '{}' for device '{}' received", isFaderEnabled, + getThing().getUID()); + updateState(CHANNEL_FADERENABLED, isFaderEnabled); + } + break; + case "nightMode": + State nightModeState = value.equals("0") ? OnOffType.OFF : OnOffType.ON; + currentNightModeState = value; + logger.debug("nightModeState '{}' for device '{}' received", nightModeState, getThing().getUID()); + updateState(CHANNEL_NIGHTMODE, nightModeState); + break; + case "startTime": + State startTimeState = getDateTimeState(value); + logger.debug("startTimeState '{}' for device '{}' received", startTimeState, getThing().getUID()); + if (startTimeState != null) { + updateState(CHANNEL_STARTTIME, startTimeState); + } + break; + case "endTime": + State endTimeState = getDateTimeState(value); + logger.debug("endTimeState '{}' for device '{}' received", endTimeState, getThing().getUID()); + if (endTimeState != null) { + updateState(CHANNEL_ENDTIME, endTimeState); + } + break; + case "nightModeBrightness": + int nightModeBrightnessValue = Integer.valueOf(value); + currentNightModeBrightness = nightModeBrightnessValue; + State nightModeBrightnessState = new PercentType(nightModeBrightnessValue); + logger.debug("nightModeBrightnessState '{}' for device '{}' received", nightModeBrightnessState, + getThing().getUID()); + updateState(CHANNEL_NIGHTMODEBRIGHTNESS, nightModeBrightnessState); + break; + } + } } @@ -394,9 +420,9 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart if (service.isRegistered(this)) { logger.debug("Checking WeMo GENA subscription for '{}'", this); String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) == null) { logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription); - service.addSubscription(this, subscription, SUBSCRIPTION_DURATION); + service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS); subscriptionState.put(subscription, true); } } else { @@ -409,7 +435,7 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart logger.debug("Removing WeMo GENA subscription for '{}'", this); if (service.isRegistered(this)) { String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) != null) { logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription); service.removeSubscription(this, subscription); } @@ -419,9 +445,10 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart } private synchronized void onUpdate() { - if (refreshJob == null || refreshJob.isCancelled()) { + ScheduledFuture job = refreshJob; + if (job == null || job.isCancelled()) { Configuration config = getThing().getConfiguration(); - int refreshInterval = DEFAULT_REFRESH_INTERVAL; + int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS; Object refreshConfig = config.get("refresh"); if (refreshConfig != null) { refreshInterval = ((BigDecimal) refreshConfig).intValue(); @@ -455,29 +482,25 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart + "" + "" + "" + "" + ""; try { - String wemoURL = getWemoURL(actionService); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); + if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID()); - value = StringUtils.substringBetween(wemoCallResponse, "", ""); - if (value != null) { - variable = "BinaryState"; - logger.trace("New state '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); - } - value = StringUtils.substringBetween(wemoCallResponse, "", ""); - if (value != null) { - variable = "brightness"; - logger.trace("New brightness '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); - } - value = StringUtils.substringBetween(wemoCallResponse, "", ""); - if (value != null) { - variable = "fader"; - logger.trace("New fader value '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); - } + value = substringBetween(wemoCallResponse, "", ""); + variable = "BinaryState"; + logger.trace("New state '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); + value = substringBetween(wemoCallResponse, "", ""); + variable = "brightness"; + logger.trace("New brightness '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); + value = substringBetween(wemoCallResponse, "", ""); + variable = "fader"; + logger.trace("New fader value '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); } } } catch (Exception e) { @@ -494,38 +517,30 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart + "" + "" + "" + "" + ""; try { - String wemoURL = getWemoURL(actionService); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); + if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { logger.trace("GetNightModeConfiguration response '{}' for device '{}' received", wemoCallResponse, getThing().getUID()); - value = StringUtils.substringBetween(wemoCallResponse, "", ""); - if (value != null) { - variable = "startTime"; - logger.trace("New startTime '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); - } - value = StringUtils.substringBetween(wemoCallResponse, "", ""); - if (value != null) { - variable = "endTime"; - logger.trace("New endTime '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); - } - value = StringUtils.substringBetween(wemoCallResponse, "", ""); - if (value != null) { - variable = "nightMode"; - logger.trace("New nightMode state '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); - } - value = StringUtils.substringBetween(wemoCallResponse, "", - ""); - if (value != null) { - variable = "nightModeBrightness"; - logger.trace("New nightModeBrightness '{}' for device '{}' received", value, - getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); - } + value = substringBetween(wemoCallResponse, "", ""); + variable = "startTime"; + logger.trace("New startTime '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); + value = substringBetween(wemoCallResponse, "", ""); + variable = "endTime"; + logger.trace("New endTime '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); + value = substringBetween(wemoCallResponse, "", ""); + variable = "nightMode"; + logger.trace("New nightMode state '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); + value = substringBetween(wemoCallResponse, "", ""); + variable = "nightModeBrightness"; + logger.trace("New nightModeBrightness '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); } } } catch (Exception e) { @@ -536,37 +551,19 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart updateStatus(ThingStatus.ONLINE); } - public String getWemoURL(String actionService) { - URL descriptorURL = service.getDescriptorURL(this); - String wemoURL = null; - if (descriptorURL != null) { - String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml"); - wemoURL = deviceURL + "/upnp/control/" + actionService + "1"; - return wemoURL; + public @Nullable State getDateTimeState(String attributeValue) { + long value = 0; + try { + value = Long.parseLong(attributeValue); + } catch (NumberFormatException e) { + logger.error("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue, + getThing().getUID()); + return null; } - return null; - } - - @SuppressWarnings("null") - public State getDateTimeState(String attributeValue) { - if (attributeValue != null) { - long value = 0; - try { - value = Long.parseLong(attributeValue) * 1000; // convert s to ms - } catch (NumberFormatException e) { - logger.warn("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue, - getThing().getUID()); - return null; - } - ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochMilli(value), - TimeZone.getDefault().toZoneId()); - State dateTimeState = new DateTimeType(zoned); - if (dateTimeState != null) { - logger.trace("New attribute '{}' received", dateTimeState); - return dateTimeState; - } - } - return null; + ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochSecond(value), TimeZone.getDefault().toZoneId()); + State dateTimeState = new DateTimeType(zoned); + logger.trace("New attribute brewed '{}' received", dateTimeState); + return dateTimeState; } public void setBinaryState(String action, String argument, String value) { @@ -576,10 +573,12 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart + "" + "" + "" + "<" + argument + ">" + value + "" + "" + "" + ""; - String wemoURL = getWemoURL("basicevent"); + + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); + if (wemoURL != null) { - logger.trace("About to send content to Dimmer {}", content); - wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + wemoCall.executeCall(wemoURL, soapHeader, content); } } catch (Exception e) { logger.debug("Failed to set binaryState '{}' for device '{}': {}", value, getThing().getUID(), @@ -595,10 +594,12 @@ public class WemoDimmerHandler extends AbstractWemoHandler implements UpnpIOPart + "" + "" + "" + value + "" + "" + ""; - String wemoURL = getWemoURL("basicevent"); + + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); + if (wemoURL != null) { - logger.trace("About to send content to Dimmer {}", content); - wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + wemoCall.executeCall(wemoURL, soapHeader, content); } } catch (Exception e) { logger.debug("Failed to set binaryState '{}' for device '{}': {}", value, getThing().getUID(), 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 d1fe489b754..41a53c4deb5 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 @@ -13,8 +13,8 @@ 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.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; import java.net.URL; @@ -30,10 +30,10 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.apache.commons.lang3.StringUtils; +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.net.http.HttpUtil; import org.openhab.core.io.transport.upnp.UpnpIOParticipant; import org.openhab.core.io.transport.upnp.UpnpIOService; import org.openhab.core.library.types.DateTimeType; @@ -54,13 +54,13 @@ import org.slf4j.LoggerFactory; * The {@link WemoHandler} is responsible for handling commands, which are * sent to one of the channels and to update their states. * - * @author Hans-Jörg Merk - Initial contribution; Added support for WeMo Insight energy measurement + * @author Hans-Jörg Merk - Initial contribution * @author Kai Kreuzer - some refactoring for performance and simplification * @author Stefan Bußweiler - Added new thing status handling * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType * @author Mihir Patil - Added standby switch */ - +@NonNullByDefault public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoHandler.class); @@ -73,16 +73,10 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan private final Map stateMap = Collections.synchronizedMap(new HashMap<>()); - // protected static final int SUBSCRIPTION_DURATION = WemoBindingConstants.SUBSCRIPTION_DURATION; + protected UpnpIOService service; + private WemoHttpCall wemoCall; - private UpnpIOService service; - - /** - * The default refresh interval in Seconds. - */ - private final int DEFAULT_REFRESH_INTERVAL = 120; - - private ScheduledFuture refreshJob; + private @Nullable ScheduledFuture refreshJob; private final Runnable refreshRunnable = new Runnable() { @@ -102,18 +96,13 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan } }; - public WemoHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) { - super(thing); + public WemoHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, wemoHttpCaller); - this.wemoHttpCaller = wemohttpCaller; + this.service = upnpIOService; + this.wemoCall = wemoHttpCaller; logger.debug("Creating a WemoHandler for thing '{}'", getThing().getUID()); - - if (upnpIOService != null) { - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } } @Override @@ -135,12 +124,12 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan public void dispose() { logger.debug("WeMoHandler disposed."); - removeSubscription(); - - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; + removeSubscription(); } @Override @@ -172,10 +161,11 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan + "" + binaryState + "" + "" + "" + ""; - String wemoURL = getWemoURL("basicevent"); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); if (wemoURL != null) { - wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + wemoCall.executeCall(wemoURL, soapHeader, content); } } catch (Exception e) { logger.error("Failed to send command '{}' for device '{}': {}", command, getThing().getUID(), @@ -188,20 +178,24 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan } @Override - public void onServiceSubscribed(String service, boolean succeeded) { - logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed"); - subscriptionState.put(service, succeeded); + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { + if (service != null) { + logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, + succeeded ? "succeeded" : "failed"); + subscriptionState.put(service, succeeded); + } } - @SuppressWarnings("null") @Override - public void onValueReceived(String variable, String value, String service) { + 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); - this.stateMap.put(variable, value); + if (variable != null && value != null) { + this.stateMap.put(variable, value); + } if (getThing().getThingTypeUID().getId().equals("insight")) { String insightParams = stateMap.get("InsightParams"); @@ -212,11 +206,9 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan if (splitInsightParams[0] != null) { OnOffType binaryState = null; binaryState = splitInsightParams[0].equals("0") ? OnOffType.OFF : OnOffType.ON; - if (binaryState != null) { - logger.trace("New InsightParam binaryState '{}' for device '{}' received", binaryState, - getThing().getUID()); - updateState(CHANNEL_STATE, binaryState); - } + logger.trace("New InsightParam binaryState '{}' for device '{}' received", binaryState, + getThing().getUID()); + updateState(CHANNEL_STATE, binaryState); } long lastChangedAt = 0; @@ -237,77 +229,57 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan } State lastOnFor = DecimalType.valueOf(splitInsightParams[2]); - if (lastOnFor != null) { - logger.trace("New InsightParam lastOnFor '{}' for device '{}' received", lastOnFor, - getThing().getUID()); - updateState(CHANNEL_LASTONFOR, lastOnFor); - } + logger.trace("New InsightParam lastOnFor '{}' for device '{}' received", lastOnFor, + getThing().getUID()); + updateState(CHANNEL_LASTONFOR, lastOnFor); State onToday = DecimalType.valueOf(splitInsightParams[3]); - if (onToday != null) { - logger.trace("New InsightParam onToday '{}' for device '{}' received", onToday, - getThing().getUID()); - updateState(CHANNEL_ONTODAY, onToday); - } + logger.trace("New InsightParam onToday '{}' for device '{}' received", onToday, getThing().getUID()); + updateState(CHANNEL_ONTODAY, onToday); State onTotal = DecimalType.valueOf(splitInsightParams[4]); - if (onTotal != null) { - logger.trace("New InsightParam onTotal '{}' for device '{}' received", onTotal, - getThing().getUID()); - updateState(CHANNEL_ONTOTAL, onTotal); - } + logger.trace("New InsightParam onTotal '{}' for device '{}' received", onTotal, getThing().getUID()); + updateState(CHANNEL_ONTOTAL, onTotal); State timespan = DecimalType.valueOf(splitInsightParams[5]); - if (timespan != null) { - logger.trace("New InsightParam timespan '{}' for device '{}' received", timespan, - getThing().getUID()); - updateState(CHANNEL_TIMESPAN, timespan); - } + logger.trace("New InsightParam timespan '{}' for device '{}' received", timespan, getThing().getUID()); + updateState(CHANNEL_TIMESPAN, timespan); State averagePower = DecimalType.valueOf(splitInsightParams[6]); // natively given in W - if (averagePower != null) { - logger.trace("New InsightParam averagePower '{}' for device '{}' received", averagePower, - getThing().getUID()); - updateState(CHANNEL_AVERAGEPOWER, averagePower); - } + logger.trace("New InsightParam averagePower '{}' for device '{}' received", averagePower, + getThing().getUID()); + updateState(CHANNEL_AVERAGEPOWER, averagePower); BigDecimal currentMW = new BigDecimal(splitInsightParams[7]); State currentPower = new DecimalType(currentMW.divide(new BigDecimal(1000), RoundingMode.HALF_UP)); // recalculate // mW to W - if (currentPower != null) { - logger.trace("New InsightParam currentPower '{}' for device '{}' received", currentPower, - getThing().getUID()); - updateState(CHANNEL_CURRENTPOWER, currentPower); - } + 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 DecimalType( energyTodayMWMin.divide(new BigDecimal(60000), RoundingMode.HALF_UP)); - if (energyToday != null) { - logger.trace("New InsightParam energyToday '{}' for device '{}' received", energyToday, - getThing().getUID()); - updateState(CHANNEL_ENERGYTODAY, energyToday); - } + 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 DecimalType( energyTotalMWMin.divide(new BigDecimal(60000), RoundingMode.HALF_UP)); - if (energyTotal != null) { - logger.trace("New InsightParam energyTotal '{}' for device '{}' received", energyTotal, - getThing().getUID()); - updateState(CHANNEL_ENERGYTOTAL, energyTotal); - } + logger.trace("New InsightParam energyTotal '{}' for device '{}' received", energyTotal, + getThing().getUID()); + updateState(CHANNEL_ENERGYTOTAL, energyTotal); BigDecimal standByLimitMW = new BigDecimal(splitInsightParams[10]); State standByLimit = new DecimalType(standByLimitMW.divide(new BigDecimal(1000), RoundingMode.HALF_UP)); // recalculate // mW to W - if (standByLimit != null) { - logger.trace("New InsightParam standByLimit '{}' for device '{}' received", standByLimit, - getThing().getUID()); - updateState(CHANNEL_STANDBYLIMIT, standByLimit); - } + logger.trace("New InsightParam standByLimit '{}' for device '{}' received", standByLimit, + getThing().getUID()); + updateState(CHANNEL_STANDBYLIMIT, standByLimit); + if (currentMW.divide(new BigDecimal(1000), RoundingMode.HALF_UP).intValue() > standByLimitMW .divide(new BigDecimal(1000), RoundingMode.HALF_UP).intValue()) { updateState(CHANNEL_ONSTANDBY, OnOffType.OFF); @@ -316,11 +288,10 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan } } } else { - State state = stateMap.get("BinaryState").equals("0") ? OnOffType.OFF : OnOffType.ON; - - logger.debug("State '{}' for device '{}' received", state, getThing().getUID()); - - if (state != null) { + String binaryState = stateMap.get("BinaryState"); + if (binaryState != null) { + State state = binaryState.equals("0") ? OnOffType.OFF : OnOffType.ON; + logger.debug("State '{}' for device '{}' received", state, getThing().getUID()); if (getThing().getThingTypeUID().getId().equals("motion")) { updateState(CHANNEL_MOTIONDETECTION, state); if (state.equals(OnOffType.ON)) { @@ -341,19 +312,18 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan ThingTypeUID thingTypeUID = thing.getThingTypeUID(); String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) == null) { logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription); - service.addSubscription(this, subscription, SUBSCRIPTION_DURATION); + service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS); subscriptionState.put(subscription, true); } if (thingTypeUID.equals(THING_TYPE_INSIGHT)) { subscription = "insight1"; - if ((subscriptionState.get(subscription) == null) - || !subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) == null) { logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription); - service.addSubscription(this, subscription, SUBSCRIPTION_DURATION); + service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS); subscriptionState.put(subscription, true); } } @@ -370,15 +340,14 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan ThingTypeUID thingTypeUID = thing.getThingTypeUID(); String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) != null) { logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription); service.removeSubscription(this, subscription); } if (thingTypeUID.equals(THING_TYPE_INSIGHT)) { subscription = "insight1"; - if ((subscriptionState.get(subscription) != null) - && subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) != null) { logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription); service.removeSubscription(this, subscription); } @@ -389,9 +358,10 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan } private synchronized void onUpdate() { - if (refreshJob == null || refreshJob.isCancelled()) { + ScheduledFuture job = refreshJob; + if (job == null || job.isCancelled()) { Configuration config = getThing().getConfiguration(); - int refreshInterval = DEFAULT_REFRESH_INTERVAL; + int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS; Object refreshConfig = config.get("refresh"); if (refreshConfig != null) { refreshInterval = ((BigDecimal) refreshConfig).intValue(); @@ -433,20 +403,20 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan + action + ">" + "" + ""; try { - String wemoURL = getWemoURL(actionService); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, actionService); + if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID()); if (variable.equals("InsightParams")) { - value = StringUtils.substringBetween(wemoCallResponse, "", ""); + value = substringBetween(wemoCallResponse, "", ""); } else { - value = StringUtils.substringBetween(wemoCallResponse, "", ""); - } - if (value != null) { - logger.trace("New state '{}' for device '{}' received", value, getThing().getUID()); - this.onValueReceived(variable, value, actionService + "1"); + value = substringBetween(wemoCallResponse, "", ""); } + logger.trace("New state '{}' for device '{}' received", value, getThing().getUID()); + this.onValueReceived(variable, value, actionService + "1"); } } } catch (Exception e) { @@ -454,43 +424,6 @@ public class WemoHandler extends AbstractWemoHandler implements UpnpIOParticipan } } - public String getWemoURL(String actionService) { - URL descriptorURL = service.getDescriptorURL(this); - int portCheckStart = 49151; - int portCheckStop = 49157; - String wemoURL = null; - String host = null; - String port = null; - if (descriptorURL != null) { - host = StringUtils.substringBetween(descriptorURL.toString(), "://", ":"); - for (int i = portCheckStart; i < portCheckStop; i++) { - try { - boolean portFound = servicePing(host, i); - if (portFound) { - logger.trace("WeMo device {} responded at Port {}", getUDN(), i); - port = String.valueOf(i); - break; - } - } catch (Exception e) { - } - } - wemoURL = "http://" + host + ":" + port + "/upnp/control/" + actionService + "1"; - logger.trace("WeMo url {}", wemoURL); - return wemoURL; - } - return wemoURL; - } - - public boolean servicePing(String host, int port) { - logger.trace("Ping WeMo device at '{}:{}'", host, port); - try { - HttpUtil.executeUrl("GET", "http://" + host + ":" + port, 250); - } catch (IOException e) { - return false; - } - return true; - } - @Override public void onStatusChanged(boolean status) { } 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 0017e9395a4..52a8f9ca52e 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 @@ -13,6 +13,7 @@ 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.io.IOException; import java.io.StringReader; @@ -29,8 +30,8 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; +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.UpnpIOParticipant; @@ -62,25 +63,22 @@ import org.xml.sax.SAXException; * * @author Hans-Jörg Merk - Initial contribution; */ - +@NonNullByDefault public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoHolmesHandler.class); public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_PURIFIER); - /** - * The default refresh interval in Seconds. - */ - private static final int DEFAULT_REFRESH_INTERVAL_SECONDS = 120; private static final int FILTER_LIFE_DAYS = 330; private static final int FILTER_LIFE_MINS = FILTER_LIFE_DAYS * 24 * 60; private final Map subscriptionState = new HashMap<>(); private final Map stateMap = Collections.synchronizedMap(new HashMap<>()); private UpnpIOService service; + private WemoHttpCall wemoCall; - private ScheduledFuture refreshJob; + private @Nullable ScheduledFuture refreshJob; private final Runnable refreshRunnable = () -> { if (!isUpnpDeviceRegistered()) { @@ -91,18 +89,13 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart } }; - public WemoHolmesHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemohttpCaller) { - super(thing); + public WemoHolmesHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) { + super(thing, wemoHttpCaller); - this.wemoHttpCaller = wemohttpCaller; + this.service = upnpIOService; + this.wemoCall = wemoHttpCaller; logger.debug("Creating a WemoHolmesHandler for thing '{}'", getThing().getUID()); - - if (upnpIOService != null) { - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } } @Override @@ -124,12 +117,12 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart public void dispose() { logger.debug("WemoHolmesHandler disposed."); - removeSubscription(); - - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; + removeSubscription(); } @Override @@ -243,10 +236,12 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart + "<attribute><name>" + attribute + "</name><value>" + value + "</value></attribute>" + "" + "" + ""; - String wemoURL = getWemoURL("deviceevent"); + + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "deviceevent"); if (wemoURL != null) { - wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + wemoCall.executeCall(wemoURL, soapHeader, content); } } catch (RuntimeException e) { logger.debug("Failed to send command '{}' for device '{}':", command, getThing().getUID(), e); @@ -256,18 +251,23 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart } @Override - public void onServiceSubscribed(String service, boolean succeeded) { - logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, succeeded ? "succeeded" : "failed"); - subscriptionState.put(service, succeeded); + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { + if (service != null) { + logger.debug("WeMo {}: Subscription to service {} {}", getUDN(), service, + succeeded ? "succeeded" : "failed"); + subscriptionState.put(service, succeeded); + } } @Override - public void onValueReceived(String variable, String value, String service) { + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'", variable, value, service, this.getThing().getUID()); updateStatus(ThingStatus.ONLINE); - this.stateMap.put(variable, value); + if (variable != null && value != null) { + this.stateMap.put(variable, value); + } } private synchronized void onSubscription() { @@ -276,9 +276,9 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) == null) || !subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) == null) { logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), subscription); - service.addSubscription(this, subscription, SUBSCRIPTION_DURATION); + service.addSubscription(this, subscription, SUBSCRIPTION_DURATION_SECONDS); subscriptionState.put(subscription, true); } @@ -294,7 +294,7 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart if (service.isRegistered(this)) { String subscription = "basicevent1"; - if ((subscriptionState.get(subscription) != null) && subscriptionState.get(subscription).booleanValue()) { + if (subscriptionState.get(subscription) != null) { logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), subscription); service.removeSubscription(this, subscription); } @@ -305,11 +305,12 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart } private synchronized void onUpdate() { - if (refreshJob == null || refreshJob.isCancelled()) { + ScheduledFuture job = refreshJob; + if (job == null || job.isCancelled()) { Configuration config = getThing().getConfiguration(); - int refreshInterval = DEFAULT_REFRESH_INTERVAL_SECONDS; + int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS; Object refreshConfig = config.get("refresh"); - refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVAL_SECONDS + refreshInterval = refreshConfig == null ? DEFAULT_REFRESH_INTERVALL_SECONDS : ((BigDecimal) refreshConfig).intValue(); refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS); } @@ -340,18 +341,19 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart + action + ">" + "" + ""; try { - String wemoURL = getWemoURL(actionService); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, actionService); + if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { logger.trace("State response '{}' for device '{}' received", wemoCallResponse, getThing().getUID()); - String stringParser = StringUtils.substringBetween(wemoCallResponse, "", - ""); + String stringParser = substringBetween(wemoCallResponse, "", ""); // Due to Belkins bad response formatting, we need to run this twice. - stringParser = StringEscapeUtils.unescapeXml(stringParser); - stringParser = StringEscapeUtils.unescapeXml(stringParser); + stringParser = unescapeXml(stringParser); + stringParser = unescapeXml(stringParser); logger.trace("AirPurifier response '{}' for device '{}' received", stringParser, getThing().getUID()); @@ -557,17 +559,6 @@ public class WemoHolmesHandler extends AbstractWemoHandler implements UpnpIOPart updateStatus(ThingStatus.ONLINE); } - public String getWemoURL(String actionService) { - URL descriptorURL = service.getDescriptorURL(this); - String wemoURL = null; - if (descriptorURL != null) { - String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml"); - wemoURL = deviceURL + "/upnp/control/" + actionService + "1"; - return wemoURL; - } - return null; - } - public static String getCharacterDataFromElement(Element e) { Node child = e.getFirstChild(); if (child instanceof CharacterData) { diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoLightHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoLightHandler.java index 59c0969680b..3ed10f1f517 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoLightHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoLightHandler.java @@ -13,6 +13,7 @@ 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.net.URL; @@ -21,8 +22,8 @@ import java.util.Map; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; +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.UpnpIOParticipant; @@ -49,6 +50,7 @@ import org.slf4j.LoggerFactory; * * @author Hans-Jörg Merk - Initial contribution */ +@NonNullByDefault public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoLightHandler.class); @@ -56,10 +58,11 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti private Map subscriptionState = new HashMap<>(); private UpnpIOService service; + private WemoHttpCall wemoCall; - private WemoBridgeHandler wemoBridgeHandler; + private @Nullable WemoBridgeHandler wemoBridgeHandler; - private String wemoLightID; + private @Nullable String wemoLightID; private int currentBrightness; @@ -70,19 +73,12 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti protected static final String SUBSCRIPTION = "bridge1"; - protected static final int SUBSCRIPTION_DURATION = 600; - - /** - * The default refresh interval in Seconds. - */ - private final int DEFAULT_REFRESH_INTERVAL = 60; - /** * The default refresh initial delay in Seconds. */ private static final int DEFAULT_REFRESH_INITIAL_DELAY = 15; - private ScheduledFuture refreshJob; + private @Nullable ScheduledFuture refreshJob; private final Runnable refreshRunnable = new Runnable() { @@ -103,16 +99,10 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti }; public WemoLightHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpcaller) { - super(thing); + super(thing, wemoHttpcaller); - this.wemoHttpCaller = wemoHttpcaller; - - if (upnpIOService != null) { - logger.debug("UPnPIOService '{}'", upnpIOService); - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } + this.service = upnpIOService; + this.wemoCall = wemoHttpcaller; } @Override @@ -120,17 +110,13 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti // initialize() is only called if the required parameter 'deviceID' is available wemoLightID = (String) getConfig().get(DEVICE_ID); - if (getBridge() != null) { - logger.debug("Initializing WemoLightHandler for LightID '{}'", wemoLightID); - if (getBridge().getStatus() == ThingStatus.ONLINE) { - updateStatus(ThingStatus.ONLINE); - onSubscription(); - onUpdate(); - } else { - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.BRIDGE_OFFLINE); - } + final Bridge bridge = getBridge(); + if (bridge != null && bridge.getStatus() == ThingStatus.ONLINE) { + updateStatus(ThingStatus.ONLINE); + onSubscription(); + onUpdate(); } else { - updateStatus(ThingStatus.OFFLINE); + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.BRIDGE_OFFLINE); } } @@ -142,10 +128,11 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti onUpdate(); } else { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.OFFLINE.BRIDGE_OFFLINE); - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; } } @@ -153,28 +140,26 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti public void dispose() { logger.debug("WeMoLightHandler disposed."); - removeSubscription(); - - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; + removeSubscription(); } - private synchronized WemoBridgeHandler getWemoBridgeHandler() { - if (this.wemoBridgeHandler == null) { - Bridge bridge = getBridge(); - if (bridge == null) { - logger.error("Required bridge not defined for device {}.", wemoLightID); - return null; - } - ThingHandler handler = bridge.getHandler(); - if (handler instanceof WemoBridgeHandler) { - this.wemoBridgeHandler = (WemoBridgeHandler) handler; - } else { - logger.debug("No available bridge handler found for {} bridge {} .", wemoLightID, bridge.getUID()); - return null; - } + private synchronized @Nullable WemoBridgeHandler getWemoBridgeHandler() { + Bridge bridge = getBridge(); + if (bridge == null) { + logger.error("Required bridge not defined for device {}.", wemoLightID); + return null; + } + ThingHandler handler = bridge.getHandler(); + if (handler instanceof WemoBridgeHandler) { + this.wemoBridgeHandler = (WemoBridgeHandler) handler; + } else { + logger.debug("No available bridge handler found for {} bridge {} .", wemoLightID, bridge.getUID()); + return null; } return this.wemoBridgeHandler; } @@ -266,10 +251,11 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti + "</CapabilityValue></DeviceStatus>" + "" + "" + "" + ""; - String wemoURL = getWemoURL(); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "bridge"); if (wemoURL != null && capability != null && value != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { if (capability.equals("10008")) { OnOffType binaryState = null; @@ -285,7 +271,7 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti } @Override - public String getUDN() { + public @Nullable String getUDN() { WemoBridgeHandler wemoBridge = getWemoBridgeHandler(); if (wemoBridge == null) { logger.debug("wemoBridgeHandler not found"); @@ -307,14 +293,14 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti + "" + "" + "" + wemoLightID + "" + "" + "" + ""; - String wemoURL = getWemoURL(); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "bridge"); if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { - wemoCallResponse = StringEscapeUtils.unescapeXml(wemoCallResponse); - String response = StringUtils.substringBetween(wemoCallResponse, "", - ""); + wemoCallResponse = unescapeXml(wemoCallResponse); + String response = substringBetween(wemoCallResponse, "", ""); logger.trace("wemoNewLightState = {}", response); String[] splitResponse = response.split(","); if (splitResponse[0] != null) { @@ -341,15 +327,15 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti } @Override - public void onServiceSubscribed(String service, boolean succeeded) { + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { } @Override - public void onValueReceived(String variable, String value, String service) { + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { logger.trace("Received pair '{}':'{}' (service '{}') for thing '{}'", new Object[] { variable, value, service, this.getThing().getUID() }); - String capabilityId = StringUtils.substringBetween(value, "", ""); - String newValue = StringUtils.substringBetween(value, "", ""); + String capabilityId = substringBetween(value, "", ""); + String newValue = substringBetween(value, "", ""); switch (capabilityId) { case "10006": OnOffType binaryState = null; @@ -377,9 +363,9 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti if (service.isRegistered(this)) { logger.debug("Checking WeMo GENA subscription for '{}'", this); - if ((subscriptionState.get(SUBSCRIPTION) == null) || !subscriptionState.get(SUBSCRIPTION).booleanValue()) { + if (subscriptionState.get(SUBSCRIPTION) == null) { logger.debug("Setting up GENA subscription {}: Subscribing to service {}...", getUDN(), SUBSCRIPTION); - service.addSubscription(this, SUBSCRIPTION, SUBSCRIPTION_DURATION); + service.addSubscription(this, SUBSCRIPTION, SUBSCRIPTION_DURATION_SECONDS); subscriptionState.put(SUBSCRIPTION, true); } } else { @@ -392,7 +378,7 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti if (service.isRegistered(this)) { logger.debug("Removing WeMo GENA subscription for '{}'", this); - if ((subscriptionState.get(SUBSCRIPTION) != null) && subscriptionState.get(SUBSCRIPTION).booleanValue()) { + if (subscriptionState.get(SUBSCRIPTION) != null) { logger.debug("WeMo {}: Unsubscribing from service {}...", getUDN(), SUBSCRIPTION); service.removeSubscription(this, SUBSCRIPTION); } @@ -403,9 +389,10 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti } private synchronized void onUpdate() { - if (refreshJob == null || refreshJob.isCancelled()) { + ScheduledFuture job = refreshJob; + if (job == null || job.isCancelled()) { Configuration config = getThing().getConfiguration(); - int refreshInterval = DEFAULT_REFRESH_INTERVAL; + int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS; Object refreshConfig = config.get("refresh"); if (refreshConfig != null) { refreshInterval = ((BigDecimal) refreshConfig).intValue(); @@ -419,15 +406,4 @@ public class WemoLightHandler extends AbstractWemoHandler implements UpnpIOParti private boolean isUpnpDeviceRegistered() { return service.isRegistered(this); } - - public String getWemoURL() { - URL descriptorURL = service.getDescriptorURL(this); - String wemoURL = null; - if (descriptorURL != null) { - String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml"); - wemoURL = deviceURL + "/upnp/control/bridge1"; - return wemoURL; - } - return null; - } } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMakerHandler.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMakerHandler.java index c8ac1f28629..f36314beb50 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMakerHandler.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/handler/WemoMakerHandler.java @@ -13,6 +13,7 @@ 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.io.StringReader; import java.math.BigDecimal; @@ -25,8 +26,8 @@ import java.util.concurrent.TimeUnit; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; +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.UpnpIOParticipant; @@ -55,7 +56,7 @@ import org.xml.sax.InputSource; * * @author Hans-Jörg Merk - Initial contribution */ - +@NonNullByDefault public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParticipant { private final Logger logger = LoggerFactory.getLogger(WemoMakerHandler.class); @@ -63,13 +64,9 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti public static final Set SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_MAKER); private UpnpIOService service; + private WemoHttpCall wemoCall; - /** - * The default refresh interval in Seconds. - */ - private final int DEFAULT_REFRESH_INTERVAL = 15; - - private ScheduledFuture refreshJob; + private @Nullable ScheduledFuture refreshJob; private final Runnable refreshRunnable = new Runnable() { @@ -85,17 +82,12 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti }; public WemoMakerHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpcaller) { - super(thing); + super(thing, wemoHttpcaller); - this.wemoHttpCaller = wemoHttpcaller; + this.service = upnpIOService; + this.wemoCall = wemoHttpcaller; logger.debug("Creating a WemoMakerHandler for thing '{}'", getThing().getUID()); - - if (upnpIOService != null) { - this.service = upnpIOService; - } else { - logger.debug("upnpIOService not set."); - } } @Override @@ -115,10 +107,11 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti public void dispose() { logger.debug("WeMoMakerHandler disposed."); - if (refreshJob != null && !refreshJob.isCancelled()) { - refreshJob.cancel(true); - refreshJob = null; + ScheduledFuture job = refreshJob; + if (job != null && !job.isCancelled()) { + job.cancel(true); } + refreshJob = null; } @Override @@ -150,11 +143,11 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti + "" + binaryState + "" + "" + "" + ""; - String wemoURL = getWemoURL("basicevent"); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, "basicevent"); if (wemoURL != null) { - @SuppressWarnings("unused") - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + wemoCall.executeCall(wemoURL, soapHeader, content); } } catch (Exception e) { logger.error("Failed to send command '{}' for device '{}' ", command, getThing().getUID(), e); @@ -172,16 +165,15 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti } private synchronized void onUpdate() { - if (service.isRegistered(this)) { - if (refreshJob == null || refreshJob.isCancelled()) { - Configuration config = getThing().getConfiguration(); - int refreshInterval = DEFAULT_REFRESH_INTERVAL; - Object refreshConfig = config.get("refresh"); - if (refreshConfig != null) { - refreshInterval = ((BigDecimal) refreshConfig).intValue(); - } - refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS); + ScheduledFuture job = refreshJob; + if (job == null || job.isCancelled()) { + Configuration config = getThing().getConfiguration(); + int refreshInterval = DEFAULT_REFRESH_INTERVALL_SECONDS; + Object refreshConfig = config.get("refresh"); + if (refreshConfig != null) { + refreshInterval = ((BigDecimal) refreshConfig).intValue(); } + refreshJob = scheduler.scheduleWithFixedDelay(refreshRunnable, 0, refreshInterval, TimeUnit.SECONDS); } } @@ -193,7 +185,6 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti /** * The {@link updateWemoState} polls the actual state of a WeMo Maker. */ - @SuppressWarnings("null") protected void updateWemoState() { String action = "GetAttributes"; String actionService = "deviceevent"; @@ -205,18 +196,20 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti + action + ">" + "" + ""; try { - String wemoURL = getWemoURL(actionService); + URL descriptorURL = service.getDescriptorURL(this); + String wemoURL = getWemoURL(descriptorURL, actionService); + if (wemoURL != null) { - String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content); + String wemoCallResponse = wemoCall.executeCall(wemoURL, soapHeader, content); if (wemoCallResponse != null) { try { - String stringParser = StringUtils.substringBetween(wemoCallResponse, "", - ""); + String stringParser = substringBetween(wemoCallResponse, "", ""); + logger.trace("Escaped Maker response for device '{}' :", getThing().getUID()); + logger.trace("'{}'", stringParser); // Due to Belkins bad response formatting, we need to run this twice. - stringParser = StringEscapeUtils.unescapeXml(stringParser); - stringParser = StringEscapeUtils.unescapeXml(stringParser); - + stringParser = unescapeXml(stringParser); + stringParser = unescapeXml(stringParser); logger.trace("Maker response '{}' for device '{}' received", stringParser, getThing().getUID()); stringParser = "" + stringParser + ""; @@ -253,19 +246,15 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti switch (attributeName) { case "Switch": State relayState = attributeValue.equals("0") ? OnOffType.OFF : OnOffType.ON; - if (relayState != null) { - logger.debug("New relayState '{}' for device '{}' received", relayState, - getThing().getUID()); - updateState(CHANNEL_RELAY, relayState); - } + logger.debug("New relayState '{}' for device '{}' received", relayState, + getThing().getUID()); + updateState(CHANNEL_RELAY, relayState); break; case "Sensor": State sensorState = attributeValue.equals("1") ? OnOffType.OFF : OnOffType.ON; - if (sensorState != null) { - logger.debug("New sensorState '{}' for device '{}' received", sensorState, - getThing().getUID()); - updateState(CHANNEL_SENSOR, sensorState); - } + logger.debug("New sensorState '{}' for device '{}' received", sensorState, + getThing().getUID()); + updateState(CHANNEL_SENSOR, sensorState); break; } } @@ -279,17 +268,6 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti } } - public String getWemoURL(String actionService) { - URL descriptorURL = service.getDescriptorURL(this); - String wemoURL = null; - if (descriptorURL != null) { - String deviceURL = StringUtils.substringBefore(descriptorURL.toString(), "/setup.xml"); - wemoURL = deviceURL + "/upnp/control/" + actionService + "1"; - return wemoURL; - } - return null; - } - public static String getCharacterDataFromElement(Element e) { Node child = e.getFirstChild(); if (child instanceof CharacterData) { @@ -304,10 +282,10 @@ public class WemoMakerHandler extends AbstractWemoHandler implements UpnpIOParti } @Override - public void onServiceSubscribed(String service, boolean succeeded) { + public void onServiceSubscribed(@Nullable String service, boolean succeeded) { } @Override - public void onValueReceived(String variable, String value, String service) { + public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) { } } diff --git a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/http/WemoHttpCall.java b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/http/WemoHttpCall.java index 54fe051f104..d7198aa9fb3 100644 --- a/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/http/WemoHttpCall.java +++ b/bundles/org.openhab.binding.wemo/src/main/java/org/openhab/binding/wemo/internal/http/WemoHttpCall.java @@ -18,6 +18,8 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Properties; +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.wemo.internal.WemoBindingConstants; import org.openhab.core.io.net.http.HttpUtil; import org.slf4j.Logger; @@ -28,12 +30,12 @@ import org.slf4j.LoggerFactory; * * @author Hans-Jörg Merk - Initial contribution */ - +@NonNullByDefault public class WemoHttpCall { private final Logger logger = LoggerFactory.getLogger(WemoHttpCall.class); - public String executeCall(String wemoURL, String soapHeader, String content) { + public @Nullable String executeCall(String wemoURL, String soapHeader, String content) { try { Properties wemoHeaders = new Properties(); wemoHeaders.setProperty("CONTENT-TYPE", WemoBindingConstants.HTTP_CALL_CONTENT_HEADER); diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/discovery/test/WemoDiscoveryParticipantTest.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/discovery/test/WemoDiscoveryParticipantTest.java index 945e5c85f38..ce5a2f0375a 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/discovery/test/WemoDiscoveryParticipantTest.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/discovery/test/WemoDiscoveryParticipantTest.java @@ -48,8 +48,8 @@ import org.openhab.core.thing.ThingUID; public class WemoDiscoveryParticipantTest { UpnpDiscoveryParticipant participant = new WemoDiscoveryParticipant(); - private final String DEVICE_UDN = GenericWemoOSGiTest.DEVICE_MANUFACTURER + "_3434xxx"; - private final String DEVICE_FRIENDLY_NAME = "Wemo Test"; + private static final String DEVICE_UDN = GenericWemoOSGiTest.DEVICE_MANUFACTURER + "_3434xxx"; + private static final String DEVICE_FRIENDLY_NAME = "Wemo Test"; RemoteDevice createUpnpDevice(String modelName) throws MalformedURLException, ValidationException, URISyntaxException { diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerOSGiTest.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerOSGiTest.java index 2431d5f6a55..efdd5c4e87b 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerOSGiTest.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoHandlerOSGiTest.java @@ -28,10 +28,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.jupnp.model.ValidationException; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; 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.binding.wemo.internal.test.GenericWemoOSGiTest; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; @@ -50,14 +48,14 @@ import org.openhab.core.types.RefreshType; public class WemoHandlerOSGiTest extends GenericWemoOSGiTest { // Thing information - private final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE; - private final String DEFAULT_TEST_CHANNEL_TYPE = "Switch"; - private final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_SOCKET; + private static final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE; + private static final String DEFAULT_TEST_CHANNEL_TYPE = "Switch"; + private static final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_SOCKET; // UPnP information - private final String MODEL_NAME = WemoBindingConstants.THING_TYPE_SOCKET.getId(); - private final String SERVICE_ID = "basicevent"; - private final String SERVICE_NUMBER = "1"; + private static final String MODEL_NAME = WemoBindingConstants.THING_TYPE_SOCKET.getId(); + private static final String SERVICE_ID = "basicevent"; + private static final String SERVICE_NUMBER = "1"; @BeforeEach public void setUp() throws IOException { @@ -74,8 +72,7 @@ public class WemoHandlerOSGiTest extends GenericWemoOSGiTest { throws MalformedURLException, URISyntaxException, ValidationException { Command command = OnOffType.OFF; - WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall()); - Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller); + Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE); waitForAssert(() -> { assertThat(thing.getStatus(), is(ThingStatus.ONLINE)); @@ -111,8 +108,7 @@ public class WemoHandlerOSGiTest extends GenericWemoOSGiTest { throws MalformedURLException, URISyntaxException, ValidationException { Command command = RefreshType.REFRESH; - WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall()); - Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller); + Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE); waitForAssert(() -> { assertThat(thing.getStatus(), is(ThingStatus.ONLINE)); 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/WemoHandlerTest.java index 8c716a4cdc5..144fa25e623 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/WemoHandlerTest.java @@ -40,23 +40,23 @@ import org.openhab.core.types.State; */ public class WemoHandlerTest { - private final ThingTypeUID THING_TYPE = WemoBindingConstants.THING_TYPE_INSIGHT; - private final String THING_ID = "test"; + private static final ThingTypeUID THING_TYPE = WemoBindingConstants.THING_TYPE_INSIGHT; + private static final String THING_ID = "test"; private MockWemoHandler handler; - private final String SERVICE_ID = "insight"; - private final String PARAMS_NAME = "InsightParams"; + 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 final int TIME_PARAM = 4702; + private static final int TIME_PARAM = 4702; /** Represents a state parameter, where 1 stays for ON and 0 stays for OFF **/ - private final int STATE_PARAM = 1; + private static final int STATE_PARAM = 1; /** Represents power in Wats **/ - private final int POWER_PARAM = 54; + private static final int POWER_PARAM = 54; private final Thing thing = mock(Thing.class); diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoLightHandlerOSGiTest.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoLightHandlerOSGiTest.java index 74c87460434..af7966b8c8d 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoLightHandlerOSGiTest.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoLightHandlerOSGiTest.java @@ -28,10 +28,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.jupnp.model.ValidationException; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; import org.openhab.binding.wemo.internal.WemoBindingConstants; import org.openhab.binding.wemo.internal.handler.WemoLightHandler; -import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.binding.wemo.internal.test.GenericWemoLightOSGiTestParent; import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.OnOffType; @@ -154,8 +152,7 @@ public class WemoLightHandlerOSGiTest extends GenericWemoLightOSGiTestParent { String capitability) throws MalformedURLException, URISyntaxException, ValidationException { Thing bridge = createBridge(BRIDGE_TYPE_UID); - WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall()); - Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller); + Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE); waitForAssert(() -> { assertThat(bridge.getStatus(), is(ThingStatus.ONLINE)); diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoMakerHandlerOSGiTest.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoMakerHandlerOSGiTest.java index aa4668c9801..354c71a8b2f 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoMakerHandlerOSGiTest.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/handler/test/WemoMakerHandlerOSGiTest.java @@ -28,10 +28,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.jupnp.model.ValidationException; import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; import org.openhab.binding.wemo.internal.WemoBindingConstants; import org.openhab.binding.wemo.internal.handler.WemoMakerHandler; -import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.binding.wemo.internal.test.GenericWemoOSGiTest; import org.openhab.core.library.types.OnOffType; import org.openhab.core.thing.ChannelUID; @@ -51,14 +49,14 @@ import org.openhab.core.types.RefreshType; public class WemoMakerHandlerOSGiTest extends GenericWemoOSGiTest { // Specific Thing information - private final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_RELAY; - private final String DEFAULT_TEST_CHANNEL_TYPE = "Switch"; - private final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MAKER; + private static final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_RELAY; + private static final String DEFAULT_TEST_CHANNEL_TYPE = "Switch"; + private static final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MAKER; // Specific UpnP service information - private final String MODEL = THING_TYPE_UID.getId(); - private final String BASIC_EVENT_SERVICE_ID = "basicevent"; - private final String SERVICE_NUMBER = "1"; + private static final String MODEL = THING_TYPE_UID.getId(); + private static final String BASIC_EVENT_SERVICE_ID = "basicevent"; + private static final String SERVICE_NUMBER = "1"; @BeforeEach public void setUp() throws IOException { @@ -75,8 +73,7 @@ public class WemoMakerHandlerOSGiTest extends GenericWemoOSGiTest { throws MalformedURLException, URISyntaxException, ValidationException { Command command = OnOffType.OFF; - WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall()); - Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller); + Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE); waitForAssert(() -> { assertThat(thing.getStatus(), is(ThingStatus.ONLINE)); @@ -111,8 +108,7 @@ public class WemoMakerHandlerOSGiTest extends GenericWemoOSGiTest { throws MalformedURLException, URISyntaxException, ValidationException { Command command = RefreshType.REFRESH; - WemoHttpCall mockCaller = Mockito.spy(new WemoHttpCall()); - Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE, mockCaller); + Thing thing = createThing(THING_TYPE_UID, DEFAULT_TEST_CHANNEL, DEFAULT_TEST_CHANNEL_TYPE); waitForAssert(() -> { assertThat(thing.getStatus(), is(ThingStatus.ONLINE)); diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoLightOSGiTestParent.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoLightOSGiTestParent.java index db6207ed69e..86e5a824cee 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoLightOSGiTestParent.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoLightOSGiTestParent.java @@ -17,7 +17,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import org.openhab.binding.wemo.internal.WemoBindingConstants; import org.openhab.binding.wemo.internal.handler.AbstractWemoHandler; -import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.core.config.core.Configuration; import org.openhab.core.thing.Bridge; import org.openhab.core.thing.Channel; @@ -42,19 +41,19 @@ import org.openhab.core.thing.type.ChannelKind; public class GenericWemoLightOSGiTestParent extends GenericWemoOSGiTest { // Thing information - protected ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MZ100; - protected ThingTypeUID BRIDGE_TYPE_UID = WemoBindingConstants.THING_TYPE_BRIDGE; - protected String WEMO_BRIDGE_ID = BRIDGE_TYPE_UID.getId(); - protected String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE; - protected String DEFAULT_TEST_CHANNEL_TYPE = "Switch"; + protected static final ThingTypeUID THING_TYPE_UID = WemoBindingConstants.THING_TYPE_MZ100; + protected static final ThingTypeUID BRIDGE_TYPE_UID = WemoBindingConstants.THING_TYPE_BRIDGE; + protected static final String WEMO_BRIDGE_ID = BRIDGE_TYPE_UID.getId(); + protected static final String DEFAULT_TEST_CHANNEL = WemoBindingConstants.CHANNEL_STATE; + protected static final String DEFAULT_TEST_CHANNEL_TYPE = "Switch"; - private final String WEMO_LIGHT_ID = THING_TYPE_UID.getId(); + private static final String WEMO_LIGHT_ID = THING_TYPE_UID.getId(); // UPnP service information - protected String DEVICE_MODEL_NAME = WEMO_LIGHT_ID; - protected String SERVICE_ID = "bridge"; - protected String SERVICE_NUMBER = "1"; - protected String SERVLET_URL = DEVICE_CONTROL_PATH + SERVICE_ID + SERVICE_NUMBER; + protected static final String DEVICE_MODEL_NAME = WEMO_LIGHT_ID; + protected static final String SERVICE_ID = "bridge"; + protected static final String SERVICE_NUMBER = "1"; + protected static final String SERVLET_URL = DEVICE_CONTROL_PATH + SERVICE_ID + SERVICE_NUMBER; private Bridge bridge; @@ -71,8 +70,7 @@ public class GenericWemoLightOSGiTestParent extends GenericWemoOSGiTest { } @Override - protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType, - WemoHttpCall wemoHttpCaller) { + protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType) { Configuration configuration = new Configuration(); configuration.put(WemoBindingConstants.DEVICE_ID, WEMO_LIGHT_ID); @@ -91,7 +89,6 @@ public class GenericWemoLightOSGiTestParent extends GenericWemoOSGiTest { ThingHandler handler = thing.getHandler(); if (handler != null) { AbstractWemoHandler h = (AbstractWemoHandler) handler; - h.setWemoHttpCaller(wemoHttpCaller); } return thing; diff --git a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoOSGiTest.java b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoOSGiTest.java index cf87e867b41..82f640c23cf 100644 --- a/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoOSGiTest.java +++ b/itests/org.openhab.binding.wemo.tests/src/main/java/org/openhab/binding/wemo/internal/test/GenericWemoOSGiTest.java @@ -37,8 +37,10 @@ import org.jupnp.model.types.DeviceType; import org.jupnp.model.types.ServiceId; import org.jupnp.model.types.ServiceType; import org.jupnp.model.types.UDN; +import org.mockito.Mockito; import org.openhab.binding.wemo.internal.WemoBindingConstants; -import org.openhab.binding.wemo.internal.handler.AbstractWemoHandler; +import org.openhab.binding.wemo.internal.WemoHttpCallFactory; +import org.openhab.binding.wemo.internal.WemoUtil; import org.openhab.binding.wemo.internal.http.WemoHttpCall; import org.openhab.core.config.core.Configuration; import org.openhab.core.io.transport.upnp.UpnpIOService; @@ -52,7 +54,6 @@ import org.openhab.core.thing.Thing; import org.openhab.core.thing.ThingRegistry; import org.openhab.core.thing.ThingTypeUID; import org.openhab.core.thing.ThingUID; -import org.openhab.core.thing.binding.ThingHandler; import org.openhab.core.thing.binding.builder.ChannelBuilder; import org.openhab.core.thing.binding.builder.ThingBuilder; import org.openhab.core.thing.type.ChannelKind; @@ -69,35 +70,39 @@ import org.openhab.core.thing.type.ChannelTypeUID; */ public abstract class GenericWemoOSGiTest extends JavaOSGiTest { - public static MockUpnpService mockUpnpService; public static final String DEVICE_MANUFACTURER = "Belkin"; // This port is included in the run configuration - private final int ORG_OSGI_SERVICE_HTTP_PORT = 9090; + private static final int ORG_OSGI_SERVICE_HTTP_PORT = 9090; // Thing information - protected String TEST_THING_ID = "TestThing"; + protected static final String TEST_THING_ID = "TestThing"; // UPnP Device information - public static String DEVICE_UDN = "Test-1_0-22124"; + public static final String DEVICE_UDN = "Test-1_0-22124"; - private final String DEVICE_TYPE = "Test"; - private final int DEVICE_VERSION = 1; - private final String DEVICE_URL = "http://127.0.0.1:" + ORG_OSGI_SERVICE_HTTP_PORT; - private final String DEVICE_DESCRIPTION_PATH = "/setup.xml"; + private static final String DEVICE_TYPE = "Test"; + private static final int DEVICE_VERSION = 1; + private static final String DEVICE_URL = "http://127.0.0.1:" + ORG_OSGI_SERVICE_HTTP_PORT; + private static final String DEVICE_DESCRIPTION_PATH = "/setup.xml"; - protected final String DEVICE_FRIENDLY_NAME = "WeMo Test"; - protected final String DEVICE_CONTROL_PATH = "/upnp/control/"; - protected final ChannelTypeUID DEFAULT_CHANNEL_TYPE_UID = new ChannelTypeUID( + protected static final String DEVICE_FRIENDLY_NAME = "WeMo Test"; + protected static final String DEVICE_CONTROL_PATH = "/upnp/control/"; + protected static final ChannelTypeUID DEFAULT_CHANNEL_TYPE_UID = new ChannelTypeUID( WemoBindingConstants.BINDING_ID + ":channelType"); protected ManagedThingProvider managedThingProvider; protected UpnpIOService upnpIOService; protected ThingRegistry thingRegistry; + protected WemoHttpCall mockCaller; + protected MockUpnpService mockUpnpService; + protected Thing thing; protected void setUpServices() throws IOException { + WemoUtil.serviceAvailableFunction = (host, port) -> true; + // StorageService is required from the ManagedThingProvider VolatileStorageService volatileStorageService = new VolatileStorageService(); registerService(volatileStorageService); @@ -117,14 +122,17 @@ public abstract class GenericWemoOSGiTest extends JavaOSGiTest { upnpIOService = getService(UpnpIOService.class); assertThat(upnpIOService, is(notNullValue())); + mockCaller = Mockito.spy(new WemoHttpCall()); + WemoHttpCallFactory wemoHttpCallFactory = () -> mockCaller; + registerService(wemoHttpCallFactory, WemoHttpCallFactory.class.getName()); + ChannelTypeProvider channelTypeProvider = mock(ChannelTypeProvider.class); when(channelTypeProvider.getChannelType(any(ChannelTypeUID.class), any(Locale.class))).thenReturn( ChannelTypeBuilder.state(DEFAULT_CHANNEL_TYPE_UID, "label", CoreItemFactory.SWITCH).build()); registerService(channelTypeProvider); } - protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType, - WemoHttpCall wemoHttpCaller) { + protected Thing createThing(ThingTypeUID thingTypeUID, String channelID, String itemAcceptedType) { Configuration configuration = new Configuration(); configuration.put(WemoBindingConstants.UDN, DEVICE_UDN); @@ -138,13 +146,6 @@ public abstract class GenericWemoOSGiTest extends JavaOSGiTest { .build(); managedThingProvider.add(thing); - - ThingHandler handler = thing.getHandler(); - if (handler != null) { - AbstractWemoHandler h = (AbstractWemoHandler) handler; - h.setWemoHttpCaller(wemoHttpCaller); - } - return thing; } @@ -153,8 +154,8 @@ public abstract class GenericWemoOSGiTest extends JavaOSGiTest { UDN udn = new UDN(DEVICE_UDN); URL deviceURL = new URL(DEVICE_URL + DEVICE_DESCRIPTION_PATH); - RemoteDeviceIdentity identity = new RemoteDeviceIdentity(udn, WemoBindingConstants.SUBSCRIPTION_DURATION, - deviceURL, new byte[1], null); + RemoteDeviceIdentity identity = new RemoteDeviceIdentity(udn, + WemoBindingConstants.SUBSCRIPTION_DURATION_SECONDS, deviceURL, new byte[1], null); DeviceType type = new DeviceType(DEVICE_MANUFACTURER, DEVICE_TYPE, DEVICE_VERSION); ManufacturerDetails manufacturerDetails = new ManufacturerDetails(DEVICE_MANUFACTURER);