]> git.basschouten.com Git - openhab-addons.git/blob
f79d9fe2b51b69c32bb12e7f9db4db6fd9e5d5fb
[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.orbitbhyve.internal.handler;
14
15 import static org.openhab.binding.orbitbhyve.internal.OrbitBhyveBindingConstants.*;
16
17 import java.io.IOException;
18 import java.net.URI;
19 import java.text.SimpleDateFormat;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.List;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.Future;
28 import java.util.concurrent.ScheduledFuture;
29 import java.util.concurrent.TimeUnit;
30 import java.util.concurrent.TimeoutException;
31
32 import org.eclipse.jdt.annotation.NonNullByDefault;
33 import org.eclipse.jdt.annotation.Nullable;
34 import org.eclipse.jetty.client.HttpClient;
35 import org.eclipse.jetty.client.api.ContentResponse;
36 import org.eclipse.jetty.client.api.Request;
37 import org.eclipse.jetty.client.util.StringContentProvider;
38 import org.eclipse.jetty.http.HttpMethod;
39 import org.eclipse.jetty.websocket.api.Session;
40 import org.eclipse.jetty.websocket.client.WebSocketClient;
41 import org.openhab.binding.orbitbhyve.internal.OrbitBhyveConfiguration;
42 import org.openhab.binding.orbitbhyve.internal.discovery.OrbitBhyveDiscoveryService;
43 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveDevice;
44 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveProgram;
45 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveSessionResponse;
46 import org.openhab.binding.orbitbhyve.internal.model.OrbitBhyveSocketEvent;
47 import org.openhab.binding.orbitbhyve.internal.net.OrbitBhyveSocket;
48 import org.openhab.core.config.core.status.ConfigStatusMessage;
49 import org.openhab.core.library.types.OnOffType;
50 import org.openhab.core.library.types.StringType;
51 import org.openhab.core.thing.Bridge;
52 import org.openhab.core.thing.Channel;
53 import org.openhab.core.thing.ChannelUID;
54 import org.openhab.core.thing.Thing;
55 import org.openhab.core.thing.ThingStatus;
56 import org.openhab.core.thing.ThingStatusDetail;
57 import org.openhab.core.thing.binding.ConfigStatusBridgeHandler;
58 import org.openhab.core.thing.binding.ThingHandlerService;
59 import org.openhab.core.types.Command;
60 import org.slf4j.Logger;
61 import org.slf4j.LoggerFactory;
62
63 import com.google.gson.Gson;
64
65 /**
66  * The {@link OrbitBhyveBridgeHandler} is responsible for handling commands, which are
67  * sent to one of the channels.
68  *
69  * @author Ondrej Pecta - Initial contribution
70  */
71 @NonNullByDefault
72 public class OrbitBhyveBridgeHandler extends ConfigStatusBridgeHandler {
73
74     private final Logger logger = LoggerFactory.getLogger(OrbitBhyveBridgeHandler.class);
75
76     private final HttpClient httpClient;
77
78     private final WebSocketClient webSocketClient;
79
80     private @Nullable ScheduledFuture<?> future = null;
81
82     private @Nullable Session session;
83
84     private @Nullable String sessionToken = null;
85
86     private OrbitBhyveConfiguration config = new OrbitBhyveConfiguration();
87
88     private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
89
90     // Gson & parser
91     private final Gson gson = new Gson();
92
93     public OrbitBhyveBridgeHandler(Bridge thing, HttpClient httpClient, WebSocketClient webSocketClient) {
94         super(thing);
95         this.httpClient = httpClient;
96         this.webSocketClient = webSocketClient;
97     }
98
99     @Override
100     public Collection<ConfigStatusMessage> getConfigStatus() {
101         return Collections.emptyList();
102     }
103
104     @Override
105     public void handleCommand(ChannelUID channelUID, Command command) {
106     }
107
108     @Override
109     public Collection<Class<? extends ThingHandlerService>> getServices() {
110         return Collections.singleton(OrbitBhyveDiscoveryService.class);
111     }
112
113     @Override
114     public void initialize() {
115         config = getConfigAs(OrbitBhyveConfiguration.class);
116         httpClient.setFollowRedirects(false);
117
118         scheduler.execute(() -> {
119             login();
120             future = scheduler.scheduleWithFixedDelay(this::ping, 0, config.refresh, TimeUnit.SECONDS);
121         });
122         logger.debug("Finished initializing!");
123     }
124
125     @Override
126     public void dispose() {
127         ScheduledFuture<?> localFuture = future;
128         if (localFuture != null) {
129             localFuture.cancel(true);
130         }
131         closeSession();
132         super.dispose();
133     }
134
135     private boolean login() {
136         try {
137             String urlParameters = "{\"session\":{\"email\":\"" + config.email + "\",\"password\":\"" + config.password
138                     + "\"}}";
139             ContentResponse response = httpClient.newRequest(BHYVE_SESSION).method(HttpMethod.POST).agent(AGENT)
140                     .content(new StringContentProvider(urlParameters), "application/json; charset=utf-8")
141                     .timeout(BHYVE_TIMEOUT, TimeUnit.SECONDS).send();
142             if (response.getStatus() == 200) {
143                 if (logger.isTraceEnabled()) {
144                     logger.trace("response: {}", response.getContentAsString());
145                 }
146                 OrbitBhyveSessionResponse session = gson.fromJson(response.getContentAsString(),
147                         OrbitBhyveSessionResponse.class);
148                 sessionToken = session.getOrbitSessionToken();
149                 logger.debug("token: {}", sessionToken);
150                 initializeWebSocketSession();
151             } else {
152                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
153                         "Login response status:" + response.getStatus());
154                 return false;
155             }
156         } catch (TimeoutException | ExecutionException e) {
157             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Exception during login");
158             return false;
159         } catch (InterruptedException e) {
160             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Exception during login");
161             Thread.currentThread().interrupt();
162             return false;
163         }
164         updateStatus(ThingStatus.ONLINE);
165         return true;
166     }
167
168     private synchronized void ping() {
169         if (ThingStatus.OFFLINE == thing.getStatus()) {
170             login();
171         }
172
173         if (ThingStatus.ONLINE == thing.getStatus()) {
174             Session localSession = session;
175             if (localSession == null || !localSession.isOpen()) {
176                 initializeWebSocketSession();
177             }
178             localSession = session;
179             if (localSession != null && localSession.isOpen() && localSession.getRemote() != null) {
180                 try {
181                     logger.debug("Sending ping");
182                     localSession.getRemote().sendString("{\"event\":\"ping\"}");
183                     updateAllStatuses();
184                 } catch (IOException e) {
185                     updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
186                             "Error sending ping to a web socket");
187                 }
188             } else {
189                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Web socket creation error");
190             }
191         }
192     }
193
194     public List<OrbitBhyveDevice> getDevices() {
195         try {
196             ContentResponse response = sendRequestBuilder(BHYVE_DEVICES, HttpMethod.GET).send();
197             if (response.getStatus() == 200) {
198                 if (logger.isTraceEnabled()) {
199                     logger.trace("Devices response: {}", response.getContentAsString());
200                 }
201                 OrbitBhyveDevice[] devices = gson.fromJson(response.getContentAsString(), OrbitBhyveDevice[].class);
202                 return Arrays.asList(devices);
203             } else {
204                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
205                         "Get devices returned response status: " + response.getStatus());
206             }
207         } catch (TimeoutException | ExecutionException e) {
208             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during getting devices");
209         } catch (InterruptedException e) {
210             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during getting devices");
211             Thread.currentThread().interrupt();
212         }
213         return new ArrayList<>();
214     }
215
216     Request sendRequestBuilder(String uri, HttpMethod method) {
217         return httpClient.newRequest(uri).method(method).agent(AGENT).header("Orbit-Session-Token", sessionToken)
218                 .timeout(BHYVE_TIMEOUT, TimeUnit.SECONDS);
219     }
220
221     public @Nullable OrbitBhyveDevice getDevice(String deviceId) {
222         try {
223             ContentResponse response = sendRequestBuilder(BHYVE_DEVICES + "/" + deviceId, HttpMethod.GET).send();
224             if (response.getStatus() == 200) {
225                 if (logger.isTraceEnabled()) {
226                     logger.trace("Device response: {}", response.getContentAsString());
227                 }
228                 OrbitBhyveDevice device = gson.fromJson(response.getContentAsString(), OrbitBhyveDevice.class);
229                 return device;
230             } else {
231                 logger.debug("Returned status: {}", response.getStatus());
232                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
233                         "Returned status: " + response.getStatus());
234             }
235         } catch (TimeoutException | ExecutionException e) {
236             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
237                     "Error during getting device info: " + deviceId);
238         } catch (InterruptedException e) {
239             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
240                     "Error during getting device info: " + deviceId);
241             Thread.currentThread().interrupt();
242         }
243         return null;
244     }
245
246     public synchronized void processStatusResponse(String content) {
247         updateStatus(ThingStatus.ONLINE);
248         logger.trace("Got message: {}", content);
249         OrbitBhyveSocketEvent event = gson.fromJson(content, OrbitBhyveSocketEvent.class);
250         if (event != null) {
251             processEvent(event);
252         }
253     }
254
255     private void processEvent(OrbitBhyveSocketEvent event) {
256         switch (event.getEvent()) {
257             case "watering_in_progress_notification":
258                 disableZones(event.getDeviceId());
259                 Channel channel = getThingChannel(event.getDeviceId(), event.getStation());
260                 if (channel != null) {
261                     logger.debug("Watering zone: {}", event.getStation());
262                     updateState(channel.getUID(), OnOffType.ON);
263                     String program = event.getProgram().getAsString();
264                     if (!program.isEmpty() && !"manual".equals(program)) {
265                         channel = getThingChannel(event.getDeviceId(), "program_" + program);
266                         if (channel != null) {
267                             updateState(channel.getUID(), OnOffType.ON);
268                         }
269                     }
270                 }
271                 break;
272             case "watering_complete":
273                 logger.debug("Watering complete");
274                 disableZones(event.getDeviceId());
275                 disablePrograms(event.getDeviceId());
276                 updateDeviceStatus(event.getDeviceId());
277                 break;
278             case "change_mode":
279                 logger.debug("Updating mode to: {}", event.getMode());
280                 Channel ch = getThingChannel(event.getDeviceId(), CHANNEL_MODE);
281                 if (ch != null) {
282                     updateState(ch.getUID(), new StringType(event.getMode()));
283                 }
284                 ch = getThingChannel(event.getDeviceId(), CHANNEL_CONTROL);
285                 if (ch != null) {
286                     updateState(ch.getUID(), "off".equals(event.getMode()) ? OnOffType.OFF : OnOffType.ON);
287                 }
288                 updateDeviceStatus(event.getDeviceId());
289                 break;
290             case "rain_delay":
291                 updateDeviceStatus(event.getDeviceId());
292                 break;
293             case "skip_active_station":
294                 disableZones(event.getDeviceId());
295                 break;
296             case "program_changed":
297                 OrbitBhyveProgram program = gson.fromJson(event.getProgram(), OrbitBhyveProgram.class);
298                 if (program != null) {
299                     updateDeviceProgramStatus(program);
300                     updateDeviceStatus(program.getDeviceId());
301                 }
302                 break;
303             default:
304                 logger.debug("Received event: {}", event.getEvent());
305         }
306     }
307
308     private void updateAllStatuses() {
309         List<OrbitBhyveDevice> devices = getDevices();
310         for (Thing th : getThing().getThings()) {
311             String deviceId = th.getUID().getId();
312             OrbitBhyveSprinklerHandler handler = (OrbitBhyveSprinklerHandler) th.getHandler();
313             for (OrbitBhyveDevice device : devices) {
314                 if (deviceId.equals(th.getUID().getId())) {
315                     updateDeviceStatus(device, handler);
316                 }
317             }
318         }
319     }
320
321     private void updateDeviceStatus(@Nullable OrbitBhyveDevice device, @Nullable OrbitBhyveSprinklerHandler handler) {
322         if (device != null && handler != null) {
323             handler.setDeviceOnline(device.isConnected());
324             handler.updateDeviceStatus(device.getStatus());
325             handler.updateSmartWatering(device.getWaterSenseMode());
326             return;
327         }
328     }
329
330     private void updateDeviceStatus(String deviceId) {
331         for (Thing th : getThing().getThings()) {
332             if (deviceId.equals(th.getUID().getId())) {
333                 OrbitBhyveSprinklerHandler handler = (OrbitBhyveSprinklerHandler) th.getHandler();
334                 OrbitBhyveDevice device = getDevice(deviceId);
335                 updateDeviceStatus(device, handler);
336             }
337         }
338     }
339
340     private void updateDeviceProgramStatus(OrbitBhyveProgram program) {
341         for (Thing th : getThing().getThings()) {
342             if (program.getDeviceId().equals(th.getUID().getId())) {
343                 OrbitBhyveSprinklerHandler handler = (OrbitBhyveSprinklerHandler) th.getHandler();
344                 if (handler != null) {
345                     handler.updateProgram(program);
346                 }
347             }
348         }
349     }
350
351     private void disableZones(String deviceId) {
352         disableChannel(deviceId, "zone_");
353     }
354
355     private void disablePrograms(String deviceId) {
356         disableChannel(deviceId, "program_");
357     }
358
359     private void disableChannel(String deviceId, String name) {
360         for (Thing th : getThing().getThings()) {
361             if (deviceId.equals(th.getUID().getId())) {
362                 for (Channel ch : th.getChannels()) {
363                     if (ch.getUID().getId().startsWith(name)) {
364                         updateState(ch.getUID(), OnOffType.OFF);
365                     }
366                 }
367                 return;
368             }
369         }
370     }
371
372     private @Nullable Channel getThingChannel(String deviceId, int station) {
373         for (Thing th : getThing().getThings()) {
374             if (deviceId.equals(th.getUID().getId())) {
375                 return th.getChannel("zone_" + station);
376             }
377         }
378         logger.debug("Cannot find zone: {} for device: {}", station, deviceId);
379         return null;
380     }
381
382     private @Nullable Channel getThingChannel(String deviceId, String name) {
383         for (Thing th : getThing().getThings()) {
384             if (deviceId.equals(th.getUID().getId())) {
385                 return th.getChannel(name);
386             }
387         }
388         logger.debug("Cannot find channel: {} for device: {}", name, deviceId);
389         return null;
390     }
391
392     private @Nullable Session createSession() {
393         String url = BHYVE_WS_URL;
394         URI uri = URI.create(url);
395
396         try {
397             // The socket that receives events
398             OrbitBhyveSocket socket = new OrbitBhyveSocket(this);
399             // Attempt Connect
400             Future<Session> fut = webSocketClient.connect(socket, uri);
401             // Wait for Connect
402             return fut.get();
403         } catch (IOException e) {
404             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Cannot connect websocket client");
405         } catch (InterruptedException e) {
406             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Cannot create websocket session");
407             Thread.currentThread().interrupt();
408         } catch (ExecutionException e) {
409             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Cannot create websocket session");
410         }
411         return null;
412     }
413
414     private synchronized void initializeWebSocketSession() {
415         logger.debug("Initializing WebSocket session");
416         closeSession();
417         session = createSession();
418         Session localSession = session;
419         if (localSession != null) {
420             logger.debug("WebSocket connected!");
421             try {
422                 String msg = "{\"event\":\"app_connection\",\"orbit_session_token\":\"" + sessionToken + "\"}";
423                 logger.trace("sending message:\n {}", msg);
424                 localSession.getRemote().sendString(msg);
425             } catch (IOException e) {
426                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
427                         "Cannot send hello string to web socket!");
428             }
429         }
430     }
431
432     private void closeSession() {
433         Session localSession = session;
434         if (localSession != null && localSession.isOpen()) {
435             localSession.close();
436         }
437     }
438
439     public void runZone(String deviceId, String zone, int time) {
440         String dateTime = format.format(new Date());
441         try {
442             ping();
443             Session localSession = session;
444             if (localSession != null && localSession.isOpen() && localSession.getRemote() != null) {
445                 localSession.getRemote()
446                         .sendString("{\"event\":\"change_mode\",\"device_id\":\"" + deviceId + "\",\"timestamp\":\""
447                                 + dateTime + "\",\"mode\":\"manual\",\"stations\":[{\"station\":" + zone
448                                 + ",\"run_time\":" + time + "}]}");
449             }
450         } catch (IOException e) {
451             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
452                     "Error during zone watering execution");
453         }
454     }
455
456     public void runProgram(String deviceId, String program) {
457         String dateTime = format.format(new Date());
458         try {
459             ping();
460             Session localSession = session;
461             if (localSession != null && localSession.isOpen() && localSession.getRemote() != null) {
462                 localSession.getRemote().sendString("{\"event\":\"change_mode\",\"mode\":\"manual\",\"program\":\""
463                         + program + "\",\"device_id\":\"" + deviceId + "\",\"timestamp\":\"" + dateTime + "\"}");
464             }
465         } catch (IOException e) {
466             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
467                     "Error during program watering execution");
468         }
469     }
470
471     public void enableProgram(OrbitBhyveProgram program, boolean enable) {
472         try {
473             String payLoad = "{\"sprinkler_timer_program\":{\"id\":\"" + program.getId() + "\",\"device_id\":\""
474                     + program.getDeviceId() + "\",\"program\":\"" + program.getProgram() + "\",\"enabled\":" + enable
475                     + "}}";
476             logger.debug("updating program {} with data {}", program.getProgram(), payLoad);
477             ContentResponse response = sendRequestBuilder(BHYVE_PROGRAMS + "/" + program.getId(), HttpMethod.PUT)
478                     .content(new StringContentProvider(payLoad), "application/json; charset=utf-8").send();
479             if (response.getStatus() == 200) {
480                 if (logger.isTraceEnabled()) {
481                     logger.trace("Enable programs response: {}", response.getContentAsString());
482                 }
483                 return;
484             } else {
485                 logger.debug("Returned status: {}", response.getStatus());
486                 updateStatus(ThingStatus.OFFLINE);
487             }
488         } catch (TimeoutException | ExecutionException e) {
489             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during updating programs");
490         } catch (InterruptedException e) {
491             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during updating programs");
492             Thread.currentThread().interrupt();
493         }
494     }
495
496     public void setRainDelay(String deviceId, int delay) {
497         String dateTime = format.format(new Date());
498         try {
499             ping();
500             Session localSession = session;
501             if (localSession != null && localSession.isOpen() && localSession.getRemote() != null) {
502                 localSession.getRemote().sendString("{\"event\":\"rain_delay\",\"device_id\":\"" + deviceId
503                         + "\",\"delay\":" + delay + ",\"timestamp\":\"" + dateTime + "\"}");
504             }
505         } catch (IOException e) {
506             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during rain delay setting");
507         }
508     }
509
510     public void stopWatering(String deviceId) {
511         String dateTime = format.format(new Date());
512         try {
513             ping();
514             Session localSession = session;
515             if (localSession != null && localSession.isOpen() && localSession.getRemote() != null) {
516                 localSession.getRemote().sendString("{\"event\":\"change_mode\",\"device_id\":\"" + deviceId
517                         + "\",\"timestamp\":\"" + dateTime + "\",\"mode\":\"manual\",\"stations\":[]}");
518             }
519         } catch (IOException e) {
520             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during watering stopping");
521         }
522     }
523
524     public List<OrbitBhyveProgram> getPrograms() {
525         try {
526             ContentResponse response = sendRequestBuilder(BHYVE_PROGRAMS, HttpMethod.GET).send();
527             if (response.getStatus() == 200) {
528                 if (logger.isTraceEnabled()) {
529                     logger.trace("Programs response: {}", response.getContentAsString());
530                 }
531                 OrbitBhyveProgram[] devices = gson.fromJson(response.getContentAsString(), OrbitBhyveProgram[].class);
532                 return Arrays.asList(devices);
533             } else {
534                 logger.debug("Returned status: {}", response.getStatus());
535                 updateStatus(ThingStatus.OFFLINE);
536             }
537         } catch (TimeoutException | ExecutionException e) {
538             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during getting programs");
539         } catch (InterruptedException e) {
540             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during getting programs");
541             Thread.currentThread().interrupt();
542         }
543         return new ArrayList<>();
544     }
545
546     public void changeRunMode(String deviceId, String mode) {
547         String dateTime = format.format(new Date());
548         try {
549             ping();
550             Session localSession = session;
551             if (localSession != null && localSession.isOpen() && localSession.getRemote() != null) {
552                 localSession.getRemote().sendString("{\"event\":\"change_mode\",\"mode\":\"" + mode
553                         + "\",\"device_id\":\"" + deviceId + "\",\"timestamp\":\"" + dateTime + "\"}");
554             }
555         } catch (IOException e) {
556             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during setting run mode");
557         }
558     }
559
560     public void setSmartWatering(String deviceId, boolean enable) {
561         OrbitBhyveDevice device = getDevice(deviceId);
562         if (device != null && device.getId().equals(deviceId)) {
563             device.setWaterSenseMode(enable ? "auto" : "off");
564             updateDevice(deviceId, gson.toJson(device));
565         }
566     }
567
568     private void updateDevice(String deviceId, String deviceString) {
569         String payload = "{\"device\":" + deviceString + "}";
570         logger.trace("New String: {}", payload);
571         try {
572             ContentResponse response = sendRequestBuilder(BHYVE_DEVICES + "/" + deviceId, HttpMethod.PUT)
573                     .content(new StringContentProvider(payload), "application/json;charset=UTF-8").send();
574             if (logger.isTraceEnabled()) {
575                 logger.trace("Device update response: {}", response.getContentAsString());
576             }
577             if (response.getStatus() != 200) {
578                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
579                         "Update device response status: " + response.getStatus());
580             }
581         } catch (TimeoutException | ExecutionException e) {
582             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during updating device");
583         } catch (InterruptedException e) {
584             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Error during updating device");
585             Thread.currentThread().interrupt();
586         }
587     }
588 }