]> git.basschouten.com Git - openhab-addons.git/blob
4e16cce218771f416badc77d72c28c4478185153
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.wemo.internal.handler;
14
15 import static org.openhab.binding.wemo.internal.WemoBindingConstants.*;
16 import static org.openhab.binding.wemo.internal.WemoUtil.*;
17
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
20
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;
35
36 /**
37  * The {@link WemoHandler} is responsible for handling commands, which are
38  * sent to one of the channels and to update their states.
39  *
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
46  */
47 @NonNullByDefault
48 public abstract class WemoHandler extends WemoBaseThingHandler {
49
50     private final Logger logger = LoggerFactory.getLogger(WemoHandler.class);
51
52     private final Object jobLock = new Object();
53
54     private @Nullable ScheduledFuture<?> pollingJob;
55
56     public WemoHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
57         super(thing, upnpIOService, wemoHttpCaller);
58
59         logger.debug("Creating a WemoHandler for thing '{}'", getThing().getUID());
60     }
61
62     @Override
63     public void initialize() {
64         super.initialize();
65         Configuration configuration = getConfig();
66
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);
72             }
73             pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, DEFAULT_REFRESH_INTERVAL_SECONDS,
74                     TimeUnit.SECONDS);
75             updateStatus(ThingStatus.UNKNOWN);
76         } else {
77             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
78                     "@text/config-status.error.missing-udn");
79         }
80     }
81
82     @Override
83     public void dispose() {
84         logger.debug("WemoHandler disposed for thing {}", getThing().getUID());
85
86         ScheduledFuture<?> job = this.pollingJob;
87         if (job != null) {
88             job.cancel(true);
89         }
90         this.pollingJob = null;
91         super.dispose();
92     }
93
94     private void poll() {
95         synchronized (jobLock) {
96             if (pollingJob == null) {
97                 return;
98             }
99             try {
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() + "\"]");
106                     return;
107                 }
108                 updateWemoState();
109             } catch (Exception e) {
110                 logger.debug("Exception during poll: {}", e.getMessage(), e);
111             }
112         }
113     }
114
115     @Override
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());
121             return;
122         }
123         if (command instanceof RefreshType) {
124             try {
125                 updateWemoState();
126             } catch (Exception e) {
127                 logger.debug("Exception during poll", e);
128             }
129         } else if (CHANNEL_STATE.equals(channelUID.getId())) {
130             if (command instanceof OnOffType) {
131                 try {
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(),
139                             e.getMessage());
140                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
141                 }
142             }
143         }
144     }
145
146     /**
147      * The {@link updateWemoState} polls the actual state of a WeMo device and
148      * calls {@link onValueReceived} to update the statemap and channels..
149      *
150      */
151     protected void updateWemoState() {
152         String actionService = BASICACTION;
153         String action = "GetBinaryState";
154         String variable = "BinaryState";
155         String value = null;
156         if ("insight".equals(getThing().getThingTypeUID().getId())) {
157             action = "GetInsightParams";
158             variable = "InsightParams";
159             actionService = INSIGHTACTION;
160         }
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());
164             return;
165         }
166         String soapHeader = "\"urn:Belkin:service:" + actionService + ":1#" + action + "\"";
167         String content = createStateRequestContent(action, actionService);
168         try {
169             String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
170             if ("InsightParams".equals(variable)) {
171                 value = substringBetween(wemoCallResponse, "<InsightParams>", "</InsightParams>");
172             } else {
173                 value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
174             }
175             if (value.length() != 0) {
176                 logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
177                 this.onValueReceived(variable, value, actionService + "1");
178             }
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());
183         }
184     }
185 }