2 * Copyright (c) 2010-2023 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.io.transport.upnp.UpnpIOService;
25 import org.openhab.core.library.types.OnOffType;
26 import org.openhab.core.thing.ChannelUID;
27 import org.openhab.core.thing.Thing;
28 import org.openhab.core.thing.ThingStatus;
29 import org.openhab.core.thing.ThingStatusDetail;
30 import org.openhab.core.types.Command;
31 import org.openhab.core.types.RefreshType;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * The {@link WemoHandler} is responsible for handling commands, which are
37 * sent to one of the channels and to update their states.
39 * @author Hans-Jörg Merk - Initial contribution
40 * @author Kai Kreuzer - some refactoring for performance and simplification
41 * @author Stefan Bußweiler - Added new thing status handling
42 * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType
43 * @author Mihir Patil - Added standby switch
44 * @author Jacob Laursen - Refactoring
47 public abstract class WemoHandler extends WemoBaseThingHandler {
49 private final Logger logger = LoggerFactory.getLogger(WemoHandler.class);
51 private final Object jobLock = new Object();
53 private @Nullable ScheduledFuture<?> pollingJob;
55 public WemoHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
56 super(thing, upnpIOService, wemoHttpCaller);
58 logger.debug("Creating a WemoHandler for thing '{}'", getThing().getUID());
62 public void initialize() {
65 addSubscription(BASICEVENT);
66 if (THING_TYPE_INSIGHT.equals(thing.getThingTypeUID())) {
67 addSubscription(INSIGHTEVENT);
69 pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, DEFAULT_REFRESH_INTERVAL_SECONDS,
74 public void dispose() {
75 logger.debug("WemoHandler disposed for thing {}", getThing().getUID());
77 ScheduledFuture<?> job = this.pollingJob;
81 this.pollingJob = null;
86 synchronized (jobLock) {
87 if (pollingJob == null) {
91 logger.debug("Polling job");
92 // Check if the Wemo device is set in the UPnP service registry
93 if (!isUpnpDeviceRegistered()) {
94 logger.debug("UPnP device {} not yet registered", getUDN());
95 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
96 "@text/config-status.pending.device-not-registered [\"" + getUDN() + "\"]");
100 } catch (Exception e) {
101 logger.debug("Exception during poll: {}", e.getMessage(), e);
107 public void handleCommand(ChannelUID channelUID, Command command) {
108 String wemoURL = getWemoURL(BASICACTION);
109 if (wemoURL == null) {
110 logger.debug("Failed to send command '{}' for device '{}': URL cannot be created", command,
111 getThing().getUID());
114 if (command instanceof RefreshType) {
117 } catch (Exception e) {
118 logger.debug("Exception during poll", e);
120 } else if (CHANNEL_STATE.equals(channelUID.getId())) {
121 if (command instanceof OnOffType) {
123 boolean binaryState = OnOffType.ON.equals(command) ? true : false;
124 String soapHeader = "\"urn:Belkin:service:basicevent:1#SetBinaryState\"";
125 String content = createBinaryStateContent(binaryState);
126 wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
127 updateStatus(ThingStatus.ONLINE);
128 } catch (Exception e) {
129 logger.warn("Failed to send command '{}' for device '{}': {}", command, getThing().getUID(),
131 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
138 * The {@link updateWemoState} polls the actual state of a WeMo device and
139 * calls {@link onValueReceived} to update the statemap and channels..
142 protected void updateWemoState() {
143 String actionService = BASICACTION;
144 String action = "GetBinaryState";
145 String variable = "BinaryState";
147 if ("insight".equals(getThing().getThingTypeUID().getId())) {
148 action = "GetInsightParams";
149 variable = "InsightParams";
150 actionService = INSIGHTACTION;
152 String wemoURL = getWemoURL(actionService);
153 if (wemoURL == null) {
154 logger.debug("Failed to get actual state for device '{}': URL cannot be created", getThing().getUID());
157 String soapHeader = "\"urn:Belkin:service:" + actionService + ":1#" + action + "\"";
158 String content = createStateRequestContent(action, actionService);
160 String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
161 if ("InsightParams".equals(variable)) {
162 value = substringBetween(wemoCallResponse, "<InsightParams>", "</InsightParams>");
164 value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
166 if (value.length() != 0) {
167 logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
168 this.onValueReceived(variable, value, actionService + "1");
170 updateStatus(ThingStatus.ONLINE);
171 } catch (Exception e) {
172 logger.warn("Failed to get actual state for device '{}': {}", getThing().getUID(), e.getMessage());
173 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());