]> git.basschouten.com Git - openhab-addons.git/blob
e7488d75ca224fc2201eaff1b0d1868ee70577ef
[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.time.Instant;
19 import java.time.ZonedDateTime;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.Set;
24 import java.util.TimeZone;
25 import java.util.concurrent.ScheduledFuture;
26 import java.util.concurrent.TimeUnit;
27
28 import org.eclipse.jdt.annotation.NonNullByDefault;
29 import org.eclipse.jdt.annotation.Nullable;
30 import org.openhab.binding.wemo.internal.http.WemoHttpCall;
31 import org.openhab.core.config.core.Configuration;
32 import org.openhab.core.io.transport.upnp.UpnpIOService;
33 import org.openhab.core.library.types.DateTimeType;
34 import org.openhab.core.library.types.DecimalType;
35 import org.openhab.core.library.types.IncreaseDecreaseType;
36 import org.openhab.core.library.types.OnOffType;
37 import org.openhab.core.library.types.PercentType;
38 import org.openhab.core.thing.ChannelUID;
39 import org.openhab.core.thing.Thing;
40 import org.openhab.core.thing.ThingStatus;
41 import org.openhab.core.thing.ThingStatusDetail;
42 import org.openhab.core.thing.ThingTypeUID;
43 import org.openhab.core.types.Command;
44 import org.openhab.core.types.RefreshType;
45 import org.openhab.core.types.State;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /**
50  * The {@link WemoDimmerHandler} is responsible for handling commands, which are
51  * sent to one of the channels and to update their states.
52  *
53  * @author Hans-Jörg Merk - Initial contribution
54  */
55 @NonNullByDefault
56 public class WemoDimmerHandler extends WemoBaseThingHandler {
57
58     private final Logger logger = LoggerFactory.getLogger(WemoDimmerHandler.class);
59
60     public static final Set<ThingTypeUID> SUPPORTED_THING_TYPES = Collections.singleton(THING_TYPE_DIMMER);
61
62     private final Object jobLock = new Object();
63
64     private final Map<String, String> stateMap = Collections.synchronizedMap(new HashMap<>());
65
66     private @Nullable ScheduledFuture<?> pollingJob;
67
68     private int currentBrightness;
69     private int currentNightModeBrightness;
70     private @Nullable String currentNightModeState;
71     /**
72      * Set dimming stepsize to 5%
73      */
74     private static final int DIM_STEPSIZE = 5;
75
76     public WemoDimmerHandler(Thing thing, UpnpIOService upnpIOService, WemoHttpCall wemoHttpCaller) {
77         super(thing, upnpIOService, wemoHttpCaller);
78
79         logger.debug("Creating a WemoDimmerHandler for thing '{}'", getThing().getUID());
80     }
81
82     @Override
83     public void initialize() {
84         super.initialize();
85         Configuration configuration = getConfig();
86
87         if (configuration.get(UDN) != null) {
88             logger.debug("Initializing WemoDimmerHandler for UDN '{}'", configuration.get(UDN));
89             addSubscription(BASICEVENT);
90             pollingJob = scheduler.scheduleWithFixedDelay(this::poll, 0, DEFAULT_REFRESH_INTERVAL_SECONDS,
91                     TimeUnit.SECONDS);
92             updateStatus(ThingStatus.ONLINE);
93         } else {
94             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
95                     "@text/config-status.error.missing-udn");
96             logger.debug("Cannot initalize WemoDimmerHandler. UDN not set.");
97         }
98     }
99
100     @Override
101     public void dispose() {
102         logger.debug("WeMoDimmerHandler disposed.");
103
104         ScheduledFuture<?> job = this.pollingJob;
105         if (job != null && !job.isCancelled()) {
106             job.cancel(true);
107         }
108         this.pollingJob = null;
109         super.dispose();
110     }
111
112     private void poll() {
113         synchronized (jobLock) {
114             if (pollingJob == null) {
115                 return;
116             }
117             try {
118                 logger.debug("Polling job");
119                 // Check if the Wemo device is set in the UPnP service registry
120                 // If not, set the thing state to ONLINE/CONFIG-PENDING and wait for the next poll
121                 if (!isUpnpDeviceRegistered()) {
122                     logger.debug("UPnP device {} not yet registered", getUDN());
123                     updateStatus(ThingStatus.ONLINE, ThingStatusDetail.CONFIGURATION_PENDING,
124                             "@text/config-status.pending.device-not-registered [\"" + getUDN() + "\"]");
125                     return;
126                 }
127                 updateWemoState();
128             } catch (Exception e) {
129                 logger.debug("Exception during poll: {}", e.getMessage(), e);
130             }
131         }
132     }
133
134     @Override
135     public void handleCommand(ChannelUID channelUID, Command command) {
136         logger.trace("Command '{}' received for channel '{}'", command, channelUID);
137         if (command instanceof RefreshType) {
138             try {
139                 updateWemoState();
140             } catch (Exception e) {
141                 logger.debug("Exception during poll", e);
142             }
143         } else {
144             String action = "SetBinaryState";
145             String argument = "BinaryState";
146             String value = "0";
147             String timeStamp = null;
148             switch (channelUID.getId()) {
149                 case CHANNEL_BRIGHTNESS:
150                     String binaryState = this.stateMap.get("BinaryState");
151                     if (command instanceof OnOffType) {
152                         value = command.equals(OnOffType.OFF) ? "0" : "1";
153                         setBinaryState(action, argument, value);
154                         if (command.equals(OnOffType.OFF)) {
155                             State brightnessState = new PercentType("0");
156                             updateState(CHANNEL_BRIGHTNESS, brightnessState);
157                             updateState(CHANNEL_TIMERSTART, OnOffType.OFF);
158                         } else {
159                             State brightnessState = new PercentType(currentBrightness);
160                             updateState(CHANNEL_BRIGHTNESS, brightnessState);
161                         }
162                     } else if (command instanceof PercentType) {
163                         int newBrightness = ((PercentType) command).intValue();
164                         value = String.valueOf(newBrightness);
165                         currentBrightness = newBrightness;
166                         argument = "brightness";
167                         if ("0".equals(value)) {
168                             value = "1";
169                             argument = "brightness";
170                             setBinaryState(action, argument, "1");
171                             value = "0";
172                             argument = "BinaryState";
173                             setBinaryState(action, argument, "0");
174                         } else if ("0".equals(binaryState)) {
175                             argument = "BinaryState";
176                             setBinaryState(action, argument, "1");
177                         }
178                         argument = "brightness";
179                         setBinaryState(action, argument, value);
180                     } else if (command instanceof IncreaseDecreaseType) {
181                         int newBrightness;
182                         switch (command.toString()) {
183                             case "INCREASE":
184                                 newBrightness = currentBrightness + DIM_STEPSIZE;
185                                 if (newBrightness > 100) {
186                                     newBrightness = 100;
187                                 }
188                                 value = String.valueOf(newBrightness);
189                                 currentBrightness = newBrightness;
190                                 break;
191                             case "DECREASE":
192                                 newBrightness = currentBrightness - DIM_STEPSIZE;
193                                 if (newBrightness < 0) {
194                                     newBrightness = 0;
195                                 }
196                                 value = String.valueOf(newBrightness);
197                                 currentBrightness = newBrightness;
198                                 break;
199                         }
200                         argument = "brightness";
201                         if ("0".equals(value)) {
202                             value = "1";
203                             argument = "brightness";
204                             setBinaryState(action, argument, "1");
205                             value = "0";
206                             argument = "BinaryState";
207                             setBinaryState(action, argument, "0");
208                         } else if ("0".equals(binaryState)) {
209                             argument = "BinaryState";
210                             setBinaryState(action, argument, "1");
211                         }
212                         argument = "brightness";
213                         setBinaryState(action, argument, value);
214                     }
215                     break;
216                 case CHANNEL_FADERCOUNTDOWNTIME:
217                     argument = "Fader";
218                     if (command instanceof DecimalType) {
219                         int commandValue = Integer.valueOf(String.valueOf(command));
220                         commandValue = commandValue * 60;
221                         String commandString = String.valueOf(commandValue);
222                         value = "<BinaryState></BinaryState>" + "<Duration></Duration>" + "<EndAction></EndAction>"
223                                 + "<brightness></brightness>" + "<fader>" + commandString + ":-1:1:0:0</fader>"
224                                 + "<UDN></UDN>";
225                         setBinaryState(action, argument, value);
226                     }
227                     break;
228                 case CHANNEL_FADERENABLED:
229                     argument = "Fader";
230                     if (command.equals(OnOffType.ON)) {
231                         value = "<BinaryState></BinaryState>" + "<Duration></Duration>" + "<EndAction></EndAction>"
232                                 + "<brightness></brightness>" + "<fader>600:-1:1:0:0</fader>" + "<UDN></UDN>";
233                     } else if (command.equals(OnOffType.OFF)) {
234                         value = "<BinaryState></BinaryState>" + "<Duration></Duration>" + "<EndAction></EndAction>"
235                                 + "<brightness></brightness>" + "<fader>600:-1:0:0:0</fader>" + "<UDN></UDN>";
236                     }
237                     setBinaryState(action, argument, value);
238                     break;
239                 case CHANNEL_TIMERSTART:
240                     argument = "Fader";
241                     long ts = System.currentTimeMillis() / 1000;
242                     timeStamp = String.valueOf(ts);
243                     logger.info("timestamp '{}' created", timeStamp);
244                     String faderSeconds = null;
245                     String faderEnabled = null;
246                     String fader = this.stateMap.get("fader");
247                     if (fader != null) {
248                         String[] splitFader = fader.split(":");
249                         if (splitFader[0] != null) {
250                             faderSeconds = splitFader[0];
251                         }
252                         if (splitFader[0] != null) {
253                             faderEnabled = splitFader[2];
254                         }
255                     }
256                     if (faderSeconds != null && faderEnabled != null) {
257                         if (OnOffType.ON.equals(command)) {
258                             value = "<BinaryState></BinaryState>" + "<Duration></Duration>" + "<EndAction></EndAction>"
259                                     + "<brightness></brightness>" + "<fader>" + faderSeconds + ":" + timeStamp + ":"
260                                     + faderEnabled + ":0:0</fader>" + "<UDN></UDN>";
261                             updateState(CHANNEL_STATE, OnOffType.ON);
262                         } else if (OnOffType.OFF.equals(command)) {
263                             value = "<BinaryState></BinaryState>" + "<Duration></Duration>" + "<EndAction></EndAction>"
264                                     + "<brightness></brightness>" + "<fader>" + faderSeconds + ":-1:" + faderEnabled
265                                     + ":0:0</fader>" + "<UDN></UDN>";
266                         }
267                     }
268                     setBinaryState(action, argument, value);
269                     break;
270                 case CHANNEL_NIGHTMODE:
271                     action = "ConfigureNightMode";
272                     argument = "NightModeConfiguration";
273                     String nightModeBrightness = String.valueOf(currentNightModeBrightness);
274                     if (OnOffType.ON.equals(command)) {
275                         value = "&lt;startTime&gt;0&lt;/startTime&gt; \\n&lt;nightMode&gt;1&lt;/nightMode&gt; \\n&lt;endTime&gt;23400&lt;/endTime&gt; \\n&lt;nightModeBrightness&gt;"
276                                 + nightModeBrightness + "&lt;/nightModeBrightness&gt; \\n";
277                     } else if (OnOffType.OFF.equals(command)) {
278                         value = "&lt;startTime&gt;0&lt;/startTime&gt; \\n&lt;nightMode&gt;0&lt;/nightMode&gt; \\n&lt;endTime&gt;23400&lt;/endTime&gt; \\n&lt;nightModeBrightness&gt;"
279                                 + nightModeBrightness + "&lt;/nightModeBrightness&gt; \\n";
280                     }
281                     setBinaryState(action, argument, value);
282                     break;
283                 case CHANNEL_NIGHTMODEBRIGHTNESS:
284                     action = "ConfigureNightMode";
285                     argument = "NightModeConfiguration";
286                     if (command instanceof PercentType) {
287                         int newBrightness = ((PercentType) command).intValue();
288                         String newNightModeBrightness = String.valueOf(newBrightness);
289                         value = "&lt;startTime&gt;0&lt;/startTime&gt; \\n&lt;nightMode&gt;" + currentNightModeState
290                                 + "&lt;/nightMode&gt; \\n&lt;endTime&gt;23400&lt;/endTime&gt; \\n&lt;nightModeBrightness&gt;"
291                                 + newNightModeBrightness + "&lt;/nightModeBrightness&gt; \\n";
292                         currentNightModeBrightness = newBrightness;
293                     } else if (command instanceof IncreaseDecreaseType) {
294                         int newBrightness;
295                         String newNightModeBrightness = null;
296                         switch (command.toString()) {
297                             case "INCREASE":
298                                 newBrightness = currentNightModeBrightness + DIM_STEPSIZE;
299                                 if (newBrightness > 100) {
300                                     newBrightness = 100;
301                                 }
302                                 newNightModeBrightness = String.valueOf(newBrightness);
303                                 currentBrightness = newBrightness;
304                                 break;
305                             case "DECREASE":
306                                 newBrightness = currentNightModeBrightness - DIM_STEPSIZE;
307                                 if (newBrightness < 0) {
308                                     newBrightness = 0;
309                                 }
310                                 newNightModeBrightness = String.valueOf(newBrightness);
311                                 currentNightModeBrightness = newBrightness;
312                                 break;
313                         }
314                         value = "&lt;startTime&gt;0&lt;/startTime&gt; \\n&lt;nightMode&gt;" + currentNightModeState
315                                 + "&lt;/nightMode&gt; \\n&lt;endTime&gt;23400&lt;/endTime&gt; \\n&lt;nightModeBrightness&gt;"
316                                 + newNightModeBrightness + "&lt;/nightModeBrightness&gt; \\n";
317                     }
318                     setBinaryState(action, argument, value);
319                     break;
320             }
321         }
322     }
323
324     @Override
325     public void onValueReceived(@Nullable String variable, @Nullable String value, @Nullable String service) {
326         logger.debug("Received pair '{}':'{}' (service '{}') for thing '{}'",
327                 new Object[] { variable, value, service, this.getThing().getUID() });
328         updateStatus(ThingStatus.ONLINE);
329         if (variable != null && value != null) {
330             String oldBinaryState = this.stateMap.get("BinaryState");
331             this.stateMap.put(variable, value);
332             switch (variable) {
333                 case "BinaryState":
334                     if (oldBinaryState == null || !oldBinaryState.equals(value)) {
335                         State state = "0".equals(value) ? OnOffType.OFF : OnOffType.ON;
336                         logger.debug("State '{}' for device '{}' received", state, getThing().getUID());
337                         updateState(CHANNEL_BRIGHTNESS, state);
338                         if (state.equals(OnOffType.OFF)) {
339                             updateState(CHANNEL_TIMERSTART, OnOffType.OFF);
340                         }
341                     }
342                     break;
343                 case "brightness":
344                     logger.debug("brightness '{}' for device '{}' received", value, getThing().getUID());
345                     int newBrightnessValue = Integer.valueOf(value);
346                     State newBrightnessState = new PercentType(newBrightnessValue);
347                     String binaryState = this.stateMap.get("BinaryState");
348                     if (binaryState != null) {
349                         if ("1".equals(binaryState)) {
350                             updateState(CHANNEL_BRIGHTNESS, newBrightnessState);
351                         }
352                     }
353                     currentBrightness = newBrightnessValue;
354                     break;
355                 case "fader":
356                     logger.debug("fader '{}' for device '{}' received", value, getThing().getUID());
357                     String[] splitFader = value.split(":");
358                     if (splitFader[0] != null) {
359                         int faderSeconds = Integer.valueOf(splitFader[0]);
360                         State faderMinutes = new DecimalType(faderSeconds / 60);
361                         logger.debug("faderTime '{} minutes' for device '{}' received", faderMinutes,
362                                 getThing().getUID());
363                         updateState(CHANNEL_FADERCOUNTDOWNTIME, faderMinutes);
364                     }
365                     if (splitFader[1] != null) {
366                         State isTimerRunning = splitFader[1].equals("-1") ? OnOffType.OFF : OnOffType.ON;
367                         logger.debug("isTimerRunning '{}' for device '{}' received", isTimerRunning,
368                                 getThing().getUID());
369                         updateState(CHANNEL_TIMERSTART, isTimerRunning);
370                         if (isTimerRunning.equals(OnOffType.ON)) {
371                             updateState(CHANNEL_STATE, OnOffType.ON);
372                         }
373                     }
374                     if (splitFader[2] != null) {
375                         State isFaderEnabled = splitFader[1].equals("0") ? OnOffType.OFF : OnOffType.ON;
376                         logger.debug("isFaderEnabled '{}' for device '{}' received", isFaderEnabled,
377                                 getThing().getUID());
378                         updateState(CHANNEL_FADERENABLED, isFaderEnabled);
379                     }
380                     break;
381                 case "nightMode":
382                     State nightModeState = "0".equals(value) ? OnOffType.OFF : OnOffType.ON;
383                     currentNightModeState = value;
384                     logger.debug("nightModeState '{}' for device '{}' received", nightModeState, getThing().getUID());
385                     updateState(CHANNEL_NIGHTMODE, nightModeState);
386                     break;
387                 case "startTime":
388                     State startTimeState = getDateTimeState(value);
389                     logger.debug("startTimeState '{}' for device '{}' received", startTimeState, getThing().getUID());
390                     if (startTimeState != null) {
391                         updateState(CHANNEL_STARTTIME, startTimeState);
392                     }
393                     break;
394                 case "endTime":
395                     State endTimeState = getDateTimeState(value);
396                     logger.debug("endTimeState '{}' for device '{}' received", endTimeState, getThing().getUID());
397                     if (endTimeState != null) {
398                         updateState(CHANNEL_ENDTIME, endTimeState);
399                     }
400                     break;
401                 case "nightModeBrightness":
402                     int nightModeBrightnessValue = Integer.valueOf(value);
403                     currentNightModeBrightness = nightModeBrightnessValue;
404                     State nightModeBrightnessState = new PercentType(nightModeBrightnessValue);
405                     logger.debug("nightModeBrightnessState '{}' for device '{}' received", nightModeBrightnessState,
406                             getThing().getUID());
407                     updateState(CHANNEL_NIGHTMODEBRIGHTNESS, nightModeBrightnessState);
408                     break;
409             }
410         }
411     }
412
413     /**
414      * The {@link updateWemoState} polls the actual state of a WeMo device and
415      * calls {@link onValueReceived} to update the statemap and channels..
416      *
417      */
418     protected void updateWemoState() {
419         String wemoURL = getWemoURL(BASICACTION);
420         if (wemoURL == null) {
421             logger.debug("Failed to get actual state for device '{}': URL cannot be created", getThing().getUID());
422             return;
423         }
424         String action = "GetBinaryState";
425         String variable = null;
426         String actionService = BASICACTION;
427         String value = null;
428         String soapHeader = "\"urn:Belkin:service:" + actionService + ":1#" + action + "\"";
429         String content = createStateRequestContent(action, actionService);
430         try {
431             String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
432             value = substringBetween(wemoCallResponse, "<BinaryState>", "</BinaryState>");
433             variable = "BinaryState";
434             this.onValueReceived(variable, value, actionService + "1");
435             value = substringBetween(wemoCallResponse, "<brightness>", "</brightness>");
436             variable = "brightness";
437             this.onValueReceived(variable, value, actionService + "1");
438             value = substringBetween(wemoCallResponse, "<fader>", "</fader>");
439             variable = "fader";
440             this.onValueReceived(variable, value, actionService + "1");
441             updateStatus(ThingStatus.ONLINE);
442         } catch (Exception e) {
443             logger.debug("Failed to get actual state for device '{}': {}", getThing().getUID(), e.getMessage());
444             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
445         }
446         action = "GetNightModeConfiguration";
447         variable = null;
448         value = null;
449         soapHeader = "\"urn:Belkin:service:" + actionService + ":1#" + action + "\"";
450         content = createStateRequestContent(action, actionService);
451         try {
452             String wemoCallResponse = wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
453             value = substringBetween(wemoCallResponse, "<startTime>", "</startTime>");
454             variable = "startTime";
455             this.onValueReceived(variable, value, actionService + "1");
456             value = substringBetween(wemoCallResponse, "<endTime>", "</endTime>");
457             variable = "endTime";
458             this.onValueReceived(variable, value, actionService + "1");
459             value = substringBetween(wemoCallResponse, "<nightMode>", "</nightMode>");
460             variable = "nightMode";
461             this.onValueReceived(variable, value, actionService + "1");
462             value = substringBetween(wemoCallResponse, "<nightModeBrightness>", "</nightModeBrightness>");
463             variable = "nightModeBrightness";
464             this.onValueReceived(variable, value, actionService + "1");
465             updateStatus(ThingStatus.ONLINE);
466         } catch (Exception e) {
467             logger.debug("Failed to get actual NightMode state for device '{}': {}", getThing().getUID(),
468                     e.getMessage());
469             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
470         }
471     }
472
473     public @Nullable State getDateTimeState(String attributeValue) {
474         long value = 0;
475         try {
476             value = Long.parseLong(attributeValue);
477         } catch (NumberFormatException e) {
478             logger.warn("Unable to parse attributeValue '{}' for device '{}'; expected long", attributeValue,
479                     getThing().getUID());
480             return null;
481         }
482         ZonedDateTime zoned = ZonedDateTime.ofInstant(Instant.ofEpochSecond(value), TimeZone.getDefault().toZoneId());
483         State dateTimeState = new DateTimeType(zoned);
484         return dateTimeState;
485     }
486
487     public void setBinaryState(String action, String argument, String value) {
488         String wemoURL = getWemoURL(BASICACTION);
489         if (wemoURL == null) {
490             logger.debug("Failed to set binary state for device '{}': URL cannot be created", getThing().getUID());
491             return;
492         }
493         try {
494             String soapHeader = "\"urn:Belkin:service:basicevent:1#SetBinaryState\"";
495             String content = "<?xml version=\"1.0\"?>"
496                     + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
497                     + "<s:Body>" + "<u:" + action + " xmlns:u=\"urn:Belkin:service:basicevent:1\">" + "<" + argument
498                     + ">" + value + "</" + argument + ">" + "</u:" + action + ">" + "</s:Body>" + "</s:Envelope>";
499
500             wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
501             updateStatus(ThingStatus.ONLINE);
502         } catch (Exception e) {
503             logger.debug("Failed to set binaryState '{}' for device '{}': {}", value, getThing().getUID(),
504                     e.getMessage());
505             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
506         }
507     }
508
509     public void setTimerStart(String action, String argument, String value) {
510         String wemoURL = getWemoURL(BASICACTION);
511         if (wemoURL == null) {
512             logger.warn("Failed to set timerStart for device '{}': URL cannot be created", getThing().getUID());
513             return;
514         }
515         try {
516             String soapHeader = "\"urn:Belkin:service:basicevent:1#SetBinaryState\"";
517             String content = "<?xml version=\"1.0\"?>"
518                     + "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
519                     + "<s:Body>" + "<u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\">" + value
520                     + "</u:SetBinaryState>" + "</s:Body>" + "</s:Envelope>";
521             wemoHttpCaller.executeCall(wemoURL, soapHeader, content);
522             updateStatus(ThingStatus.ONLINE);
523         } catch (Exception e) {
524             logger.debug("Failed to set timerStart '{}' for device '{}': {}", value, getThing().getUID(),
525                     e.getMessage());
526             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
527         }
528     }
529 }