]> git.basschouten.com Git - openhab-addons.git/blob
0953fe6287a3c5d60827fcd0fd3d3ccda01bf599
[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.ONLINE);
76         } else {
77             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
78                     "@text/config-status.error.missing-udn");
79             logger.debug("Cannot initalize WemoHandler. UDN not set.");
80         }
81     }
82
83     @Override
84     public void dispose() {
85         logger.debug("WemoHandler disposed for thing {}", getThing().getUID());
86
87         ScheduledFuture<?> job = this.pollingJob;
88         if (job != null) {
89             job.cancel(true);
90         }
91         this.pollingJob = null;
92         super.dispose();
93     }
94
95     private void poll() {
96         synchronized (jobLock) {
97             if (pollingJob == null) {
98                 return;
99             }
100             try {
101                 logger.debug("Polling job");
102                 // Check if the Wemo device is set in the UPnP service registry
103                 // If not, set the thing state to ONLINE/CONFIG-PENDING and wait for the next poll
104                 if (!isUpnpDeviceRegistered()) {
105                     logger.debug("UPnP device {} not yet registered", getUDN());
106                     updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
107                             "@text/config-status.pending.device-not-registered [\"" + getUDN() + "\"]");
108                     return;
109                 }
110                 updateWemoState();
111             } catch (Exception e) {
112                 logger.debug("Exception during poll: {}", e.getMessage(), e);
113             }
114         }
115     }
116
117     @Override
118     public void handleCommand(ChannelUID channelUID, Command command) {
119         String wemoURL = getWemoURL(BASICACTION);
120         if (wemoURL == null) {
121             logger.debug("Failed to send command '{}' for device '{}': URL cannot be created", command,
122                     getThing().getUID());
123             return;
124         }
125         if (command instanceof RefreshType) {
126             try {
127                 updateWemoState();
128             } catch (Exception e) {
129                 logger.debug("Exception during poll", e);
130             }
131         } else if (CHANNEL_STATE.equals(channelUID.getId())) {
132             if (command instanceof OnOffType) {
133                 try {
134                     boolean binaryState = OnOffType.ON.equals(command) ? true : false;
135                     String soapHeader = "\"urn:Belkin:service:basicevent:1#SetBinaryState\"";
136                     String content = createBinaryStateContent(binaryState);
137                     wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
138                     updateStatus(ThingStatus.ONLINE);
139                 } catch (Exception e) {
140                     logger.warn("Failed to send command '{}' for device '{}': {}", command, getThing().getUID(),
141                             e.getMessage());
142                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
143                 }
144             }
145         }
146     }
147
148     /**
149      * The {@link updateWemoState} polls the actual state of a WeMo device and
150      * calls {@link onValueReceived} to update the statemap and channels..
151      *
152      */
153     protected void updateWemoState() {
154         String actionService = BASICACTION;
155         String action = "GetBinaryState";
156         String variable = "BinaryState";
157         String value = null;
158         if ("insight".equals(getThing().getThingTypeUID().getId())) {
159             action = "GetInsightParams";
160             variable = "InsightParams";
161             actionService = INSIGHTACTION;
162         }
163         String wemoURL = getWemoURL(actionService);
164         if (wemoURL == null) {
165             logger.debug("Failed to get actual state for device '{}': URL cannot be created", getThing().getUID());
166             return;
167         }
168         String soapHeader = "\"urn:Belkin:service:" + actionService + ":1#" + action + "\"";
169         String content = createStateRequestContent(action, actionService);
170         try {
171             String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
172             if ("InsightParams".equals(variable)) {
173                 value = substringBetween(wemoCallResponse, "<InsightParams>", "</InsightParams>");
174             } else {
175                 value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
176             }
177             if (value.length() != 0) {
178                 logger.trace("New state '{}' for device '{}' received", value, getThing().getUID());
179                 this.onValueReceived(variable, value, actionService + "1");
180             }
181         } catch (Exception e) {
182             logger.warn("Failed to get actual state for device '{}': {}", getThing().getUID(), e.getMessage());
183         }
184     }
185 }