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.jupnp.UpnpService;
24 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
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, UpnpService upnpService, WemoHttpCall wemoHttpCaller) {
57 super(thing, upnpIOService, upnpService, wemoHttpCaller);
59 logger.debug("Creating a WemoHandler for thing '{}'", getThing().getUID());
63 public void initialize() {
66 addSubscription(BASICEVENT);
67 if (THING_TYPE_INSIGHT.equals(thing.getThingTypeUID())) {
68 addSubscription(INSIGHTEVENT);
70 pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, DEFAULT_REFRESH_INTERVAL_SECONDS,
75 public void dispose() {
76 logger.debug("WemoHandler disposed for thing {}", getThing().getUID());
78 ScheduledFuture<?> job = this.pollingJob;
82 this.pollingJob = null;
87 synchronized (jobLock) {
88 if (pollingJob == null) {
92 logger.debug("Polling job");
93 // Check if the Wemo device is set in the UPnP service registry
94 if (!isUpnpDeviceRegistered()) {
95 logger.debug("UPnP device {} not yet registered", getUDN());
96 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.NONE,
97 "@text/config-status.pending.device-not-registered [\"" + getUDN() + "\"]");
101 } catch (Exception e) {
102 logger.debug("Exception during poll: {}", e.getMessage(), e);
108 public void handleCommand(ChannelUID channelUID, Command command) {
109 String wemoURL = getWemoURL(BASICACTION);
110 if (wemoURL == null) {
111 logger.debug("Failed to send command '{}' for device '{}': URL cannot be created", command,
112 getThing().getUID());
115 if (command instanceof RefreshType) {
118 } catch (Exception e) {
119 logger.debug("Exception during poll", e);
121 } else if (CHANNEL_STATE.equals(channelUID.getId())) {
122 if (command instanceof OnOffType) {
124 boolean binaryState = OnOffType.ON.equals(command) ? true : false;
125 String soapHeader = "\"urn:Belkin:service:basicevent:1#SetBinaryState\"";
126 String content = createBinaryStateContent(binaryState);
127 wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
128 updateStatus(ThingStatus.ONLINE);
129 } catch (Exception e) {
130 logger.warn("Failed to send command '{}' for device '{}': {}", command, getThing().getUID(),
132 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
139 * The {@link updateWemoState} polls the actual state of a WeMo device and
140 * calls {@link onValueReceived} to update the statemap and channels..
143 protected void updateWemoState() {
144 String actionService = BASICACTION;
145 String action = "GetBinaryState";
146 String variable = "BinaryState";
148 if ("insight".equals(getThing().getThingTypeUID().getId())) {
149 action = "GetInsightParams";
150 variable = "InsightParams";
151 actionService = INSIGHTACTION;
153 String wemoURL = getWemoURL(actionService);
154 if (wemoURL == null) {
155 logger.debug("Failed to get actual state for device '{}': URL cannot be created", getThing().getUID());
158 String soapHeader = "\"urn:Belkin:service:" + actionService + ":1#" + action + "\"";
159 String content = createStateRequestContent(action, actionService);
161 String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
162 if ("InsightParams".equals(variable)) {
163 value = substringBetween(wemoCallResponse, "<InsightParams>", "</InsightParams>");
165 value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
167 if (value.length() != 0) {
168 logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
169 this.onValueReceived(variable, value, actionService + "1");
171 updateStatus(ThingStatus.ONLINE);
172 } catch (Exception e) {
173 logger.warn("Failed to get actual state for device '{}': {}", getThing().getUID(), e.getMessage());
174 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());