2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.wemo.internal.handler;
15 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
16 import static org.openhab.binding.wemo.internal.WemoUtil.*;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
24 import org.openhab.core.config.core.Configuration;
25 import org.openhab.core.io.transport.upnp.UpnpIOService;
26 import org.openhab.core.library.types.OnOffType;
27 import org.openhab.core.thing.ChannelUID;
28 import org.openhab.core.thing.Thing;
29 import org.openhab.core.thing.ThingStatus;
30 import org.openhab.core.thing.ThingStatusDetail;
31 import org.openhab.core.types.Command;
32 import org.openhab.core.types.RefreshType;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
37 * The {@link WemoHandler} is responsible for handling commands, which are
38 * sent to one of the channels and to update their states.
40 * @author Hans-Jörg Merk - Initial contribution
41 * @author Kai Kreuzer - some refactoring for performance and simplification
42 * @author Stefan Bußweiler - Added new thing status handling
43 * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType
44 * @author Mihir Patil - Added standby switch
45 * @author Jacob Laursen - Refactoring
48 public abstract class WemoHandler extends WemoBaseThingHandler {
50 private final Logger logger = LoggerFactory.getLogger(WemoHandler.class);
52 private final Object jobLock = new Object();
54 private @Nullable ScheduledFuture<?> pollingJob;
56 public WemoHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
57 super(thing, upnpIOService, wemoHttpCaller);
59 logger.debug("Creating a WemoHandler for thing '{}'", getThing().getUID());
63 public void initialize() {
65 Configuration configuration = getConfig();
67 if (configuration.get(UDN) != null) {
68 logger.debug("Initializing WemoHandler for UDN '{}'", configuration.get(UDN));
69 addSubscription(BASICEVENT);
70 if (THING_TYPE_INSIGHT.equals(thing.getThingTypeUID())) {
71 addSubscription(INSIGHTEVENT);
73 pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, DEFAULT_REFRESH_INTERVAL_SECONDS,
75 updateStatus(ThingStatus.UNKNOWN);
77 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
78 "@text/config-status.error.missing-udn");
83 public void dispose() {
84 logger.debug("WemoHandler disposed for thing {}", getThing().getUID());
86 ScheduledFuture<?> job = this.pollingJob;
90 this.pollingJob = null;
95 synchronized (jobLock) {
96 if (pollingJob == null) {
100 logger.debug("Polling job");
101 // Check if the Wemo device is set in the UPnP service registry
102 if (!isUpnpDeviceRegistered()) {
103 logger.debug("UPnP device {} not yet registered", getUDN());
104 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
105 "@text/config-status.pending.device-not-registered [\"" + getUDN() + "\"]");
109 } catch (Exception e) {
110 logger.debug("Exception during poll: {}", e.getMessage(), e);
116 public void handleCommand(ChannelUID channelUID, Command command) {
117 String wemoURL = getWemoURL(BASICACTION);
118 if (wemoURL == null) {
119 logger.debug("Failed to send command '{}' for device '{}': URL cannot be created", command,
120 getThing().getUID());
123 if (command instanceof RefreshType) {
126 } catch (Exception e) {
127 logger.debug("Exception during poll", e);
129 } else if (CHANNEL_STATE.equals(channelUID.getId())) {
130 if (command instanceof OnOffType) {
132 boolean binaryState = OnOffType.ON.equals(command) ? true : false;
133 String soapHeader = "\"urn:Belkin:service:basicevent:1#SetBinaryState\"";
134 String content = createBinaryStateContent(binaryState);
135 wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
136 updateStatus(ThingStatus.ONLINE);
137 } catch (Exception e) {
138 logger.warn("Failed to send command '{}' for device '{}': {}", command, getThing().getUID(),
140 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
147 * The {@link updateWemoState} polls the actual state of a WeMo device and
148 * calls {@link onValueReceived} to update the statemap and channels..
151 protected void updateWemoState() {
152 String actionService = BASICACTION;
153 String action = "GetBinaryState";
154 String variable = "BinaryState";
156 if ("insight".equals(getThing().getThingTypeUID().getId())) {
157 action = "GetInsightParams";
158 variable = "InsightParams";
159 actionService = INSIGHTACTION;
161 String wemoURL = getWemoURL(actionService);
162 if (wemoURL == null) {
163 logger.debug("Failed to get actual state for device '{}': URL cannot be created", getThing().getUID());
166 String soapHeader = "\"urn:Belkin:service:" + actionService + ":1#" + action + "\"";
167 String content = createStateRequestContent(action, actionService);
169 String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
170 if ("InsightParams".equals(variable)) {
171 value = substringBetween(wemoCallResponse, "<InsightParams>", "</InsightParams>");
173 value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
175 if (value.length() != 0) {
176 logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
177 this.onValueReceived(variable, value, actionService + "1");
179 updateStatus(ThingStatus.ONLINE);
180 } catch (Exception e) {
181 logger.warn("Failed to get actual state for device '{}': {}", getThing().getUID(), e.getMessage());
182 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());