]> git.basschouten.com Git - openhab-addons.git/blob
554b4edc22079184f9b29800853e18ea2e76777a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 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.freebox.internal.handler;
14
15 import static org.openhab.binding.freebox.internal.FreeboxBindingConstants.*;
16
17 import java.util.ArrayList;
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.concurrent.CopyOnWriteArrayList;
22 import java.util.concurrent.ScheduledFuture;
23 import java.util.concurrent.TimeUnit;
24
25 import org.openhab.binding.freebox.internal.FreeboxDataListener;
26 import org.openhab.binding.freebox.internal.api.FreeboxApiManager;
27 import org.openhab.binding.freebox.internal.api.FreeboxException;
28 import org.openhab.binding.freebox.internal.api.model.FreeboxAirMediaReceiver;
29 import org.openhab.binding.freebox.internal.api.model.FreeboxConnectionStatus;
30 import org.openhab.binding.freebox.internal.api.model.FreeboxDiscoveryResponse;
31 import org.openhab.binding.freebox.internal.api.model.FreeboxLanHost;
32 import org.openhab.binding.freebox.internal.api.model.FreeboxLcdConfig;
33 import org.openhab.binding.freebox.internal.api.model.FreeboxSambaConfig;
34 import org.openhab.binding.freebox.internal.api.model.FreeboxSystemConfig;
35 import org.openhab.binding.freebox.internal.config.FreeboxServerConfiguration;
36 import org.openhab.core.config.core.Configuration;
37 import org.openhab.core.library.types.DecimalType;
38 import org.openhab.core.library.types.IncreaseDecreaseType;
39 import org.openhab.core.library.types.OnOffType;
40 import org.openhab.core.library.types.OpenClosedType;
41 import org.openhab.core.library.types.PercentType;
42 import org.openhab.core.library.types.StringType;
43 import org.openhab.core.library.types.UpDownType;
44 import org.openhab.core.thing.Bridge;
45 import org.openhab.core.thing.ChannelUID;
46 import org.openhab.core.thing.Thing;
47 import org.openhab.core.thing.ThingStatus;
48 import org.openhab.core.thing.ThingStatusDetail;
49 import org.openhab.core.thing.binding.BaseBridgeHandler;
50 import org.openhab.core.thing.binding.ThingHandler;
51 import org.openhab.core.types.Command;
52 import org.openhab.core.types.RefreshType;
53 import org.osgi.framework.Bundle;
54 import org.osgi.framework.FrameworkUtil;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 /**
59  * The {@link FreeboxHandler} is responsible for handling commands, which are
60  * sent to one of the channels.
61  *
62  * @author GaĆ«l L'hopital - Initial contribution
63  * @author Laurent Garnier - updated to a bridge handler and delegate few things to another handler
64  * @author Laurent Garnier - update discovery configuration
65  * @author Laurent Garnier - use new internal API manager
66  */
67 public class FreeboxHandler extends BaseBridgeHandler {
68
69     private final Logger logger = LoggerFactory.getLogger(FreeboxHandler.class);
70
71     private ScheduledFuture<?> authorizeJob;
72     private ScheduledFuture<?> globalJob;
73     private FreeboxApiManager apiManager;
74     private long uptime;
75     private List<FreeboxDataListener> dataListeners = new CopyOnWriteArrayList<>();
76     private FreeboxServerConfiguration configuration;
77
78     public FreeboxHandler(Bridge bridge) {
79         super(bridge);
80
81         Bundle bundle = FrameworkUtil.getBundle(getClass());
82         String appId = bundle.getSymbolicName();
83         String appName = bundle.getHeaders().get("Bundle-Name");
84         String appVersion = String.format("%d.%d", bundle.getVersion().getMajor(), bundle.getVersion().getMinor());
85         String deviceName = bundle.getHeaders().get("Bundle-Vendor");
86         this.apiManager = new FreeboxApiManager(appId, appName, appVersion, deviceName);
87         uptime = -1;
88     }
89
90     @Override
91     public void handleCommand(ChannelUID channelUID, Command command) {
92         if (command instanceof RefreshType) {
93             return;
94         }
95         if (getThing().getStatus() == ThingStatus.UNKNOWN || (getThing().getStatus() == ThingStatus.OFFLINE
96                 && getThing().getStatusInfo().getStatusDetail() == ThingStatusDetail.CONFIGURATION_ERROR)) {
97             return;
98         }
99         switch (channelUID.getId()) {
100             case LCDBRIGHTNESS:
101                 setBrightness(channelUID, command);
102                 break;
103             case LCDORIENTATION:
104                 setOrientation(channelUID, command);
105                 break;
106             case LCDFORCED:
107                 setForced(channelUID, command);
108                 break;
109             case WIFISTATUS:
110                 setWifiStatus(channelUID, command);
111                 break;
112             case FTPSTATUS:
113                 setFtpStatus(channelUID, command);
114                 break;
115             case AIRMEDIASTATUS:
116                 setAirMediaStatus(channelUID, command);
117                 break;
118             case UPNPAVSTATUS:
119                 setUPnPAVStatus(channelUID, command);
120                 break;
121             case SAMBAFILESTATUS:
122                 setSambaFileStatus(channelUID, command);
123                 break;
124             case SAMBAPRINTERSTATUS:
125                 setSambaPrinterStatus(channelUID, command);
126                 break;
127             case REBOOT:
128                 reboot(channelUID, command);
129                 break;
130             default:
131                 logger.debug("Thing {}: unexpected command {} from channel {}", getThing().getUID(), command,
132                         channelUID.getId());
133                 break;
134         }
135     }
136
137     @Override
138     public void initialize() {
139         logger.debug("initializing Freebox Server handler for thing {}", getThing().getUID());
140
141         configuration = getConfigAs(FreeboxServerConfiguration.class);
142
143         // Update the discovery configuration
144         Map<String, Object> configDiscovery = new HashMap<>();
145         configDiscovery.put(FreeboxServerConfiguration.DISCOVER_PHONE, configuration.discoverPhone);
146         configDiscovery.put(FreeboxServerConfiguration.DISCOVER_NET_DEVICE, configuration.discoverNetDevice);
147         configDiscovery.put(FreeboxServerConfiguration.DISCOVER_NET_INTERFACE, configuration.discoverNetInterface);
148         configDiscovery.put(FreeboxServerConfiguration.DISCOVER_AIRPLAY_RECEIVER,
149                 configuration.discoverAirPlayReceiver);
150         for (FreeboxDataListener dataListener : dataListeners) {
151             dataListener.applyConfig(configDiscovery);
152         }
153
154         if (configuration.fqdn != null && !configuration.fqdn.isEmpty()) {
155             if (configuration.appToken == null || configuration.appToken.isEmpty()) {
156                 updateStatus(ThingStatus.UNKNOWN, ThingStatusDetail.CONFIGURATION_PENDING,
157                         "Please accept pairing request directly on your freebox");
158             } else {
159                 updateStatus(ThingStatus.UNKNOWN);
160             }
161
162             logger.debug("Binding will schedule a job to establish a connection...");
163             if (authorizeJob == null || authorizeJob.isCancelled()) {
164                 authorizeJob = scheduler.schedule(this::authorize, 1, TimeUnit.SECONDS);
165             }
166         } else {
167             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
168                     "Freebox Server FQDN not set in the thing configuration");
169         }
170     }
171
172     private void pollServerState() {
173         logger.debug("Polling server state...");
174
175         boolean commOk = true;
176         commOk &= fetchSystemConfig();
177         commOk &= fetchLCDConfig();
178         commOk &= fetchWifiConfig();
179         commOk &= (fetchxDslStatus() || fetchFtthPresent());
180         commOk &= fetchConnectionStatus();
181         commOk &= fetchFtpConfig();
182         commOk &= fetchAirMediaConfig();
183         commOk &= fetchUPnPAVConfig();
184         commOk &= fetchSambaConfig();
185         List<FreeboxLanHost> lanHosts = fetchLanHosts();
186         commOk &= (lanHosts != null);
187         List<FreeboxAirMediaReceiver> airPlayDevices = fetchAirPlayDevices();
188         commOk &= (airPlayDevices != null);
189
190         // Trigger a new discovery of things
191         for (FreeboxDataListener dataListener : dataListeners) {
192             dataListener.onDataFetched(getThing().getUID(), lanHosts, airPlayDevices);
193         }
194
195         if (commOk) {
196             updateStatus(ThingStatus.ONLINE);
197         } else {
198             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
199         }
200     }
201
202     private void authorize() {
203         logger.debug("Authorize job...");
204
205         String fqdn = configuration.fqdn;
206         FreeboxDiscoveryResponse result = null;
207         boolean httpsRequestOk = false;
208         if (!Boolean.TRUE.equals(configuration.useOnlyHttp)) {
209             result = apiManager.checkApi(fqdn, true);
210             httpsRequestOk = (result != null);
211         }
212         if (!httpsRequestOk) {
213             result = apiManager.checkApi(fqdn, false);
214         }
215         String apiBaseUrl = result == null ? null : result.getApiBaseUrl();
216         String apiVersion = result == null ? null : result.getApiVersion();
217         String deviceType = result == null ? null : result.getDeviceType();
218         String apiDomain = result == null ? null : result.getApiDomain();
219         Integer httpsPort = result == null ? null : result.getHttpsPort();
220         boolean useHttps = false;
221         String errorMsg = null;
222         if (result == null) {
223             errorMsg = "Can't connect to " + fqdn;
224         } else if (apiBaseUrl == null || apiBaseUrl.isEmpty()) {
225             errorMsg = fqdn + " does not deliver any API base URL";
226         } else if (apiVersion == null || apiVersion.isEmpty()) {
227             errorMsg = fqdn + " does not deliver any API version";
228         } else if (Boolean.TRUE.equals(result.isHttpsAvailable()) && !Boolean.TRUE.equals(configuration.useOnlyHttp)) {
229             if (httpsPort == null || apiDomain == null || apiDomain.isEmpty()) {
230                 if (httpsRequestOk) {
231                     useHttps = true;
232                 } else {
233                     logger.debug("{} does not deliver API domain or HTTPS port; use HTTP API", fqdn);
234                 }
235             } else if (apiManager.checkApi(String.format("%s:%d", apiDomain, httpsPort), true) != null) {
236                 useHttps = true;
237                 fqdn = String.format("%s:%d", apiDomain, httpsPort);
238             }
239         }
240
241         if (errorMsg != null) {
242             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
243         } else if (!apiManager.authorize(useHttps, fqdn, apiBaseUrl, apiVersion, configuration.appToken)) {
244             if (configuration.appToken == null || configuration.appToken.isEmpty()) {
245                 errorMsg = "Pairing request rejected or timeout";
246             } else {
247                 errorMsg = "Check your app token in the thing configuration; opening session with " + fqdn + " using "
248                         + (useHttps ? "HTTPS" : "HTTP") + " API version " + apiVersion + " failed";
249             }
250             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
251         } else {
252             logger.debug("Thing {}: session opened with {} using {} API version {}", getThing().getUID(), fqdn,
253                     (useHttps ? "HTTPS" : "HTTP"), apiVersion);
254             String appToken = apiManager.getAppToken();
255             if ((configuration.appToken == null || configuration.appToken.isEmpty()) && appToken != null) {
256                 logger.debug("Store new app token in the thing configuration");
257                 configuration.appToken = appToken;
258                 Configuration thingConfig = editConfiguration();
259                 thingConfig.put(FreeboxServerConfiguration.APP_TOKEN, appToken);
260                 updateConfiguration(thingConfig);
261             }
262             updateStatus(ThingStatus.ONLINE);
263             if (globalJob == null || globalJob.isCancelled()) {
264                 long pollingInterval = configuration.refreshInterval;
265                 logger.debug("Scheduling server state update every {} seconds...", pollingInterval);
266                 globalJob = scheduler.scheduleWithFixedDelay(() -> {
267                     try {
268                         pollServerState();
269                     } catch (Exception e) {
270                         logger.debug("Server state job failed: {}", e.getMessage(), e);
271                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
272                     }
273                 }, 1, pollingInterval, TimeUnit.SECONDS);
274             }
275         }
276
277         Map<String, String> properties = editProperties();
278         if (apiBaseUrl != null && !apiBaseUrl.isEmpty()) {
279             properties.put(API_BASE_URL, apiBaseUrl);
280         }
281         if (apiVersion != null && !apiVersion.isEmpty()) {
282             properties.put(API_VERSION, apiVersion);
283         }
284         if (deviceType != null && !deviceType.isEmpty()) {
285             properties.put(Thing.PROPERTY_HARDWARE_VERSION, deviceType);
286         }
287         updateProperties(properties);
288     }
289
290     @Override
291     public void dispose() {
292         logger.debug("Disposing Freebox Server handler for thing {}", getThing().getUID());
293         if (authorizeJob != null && !authorizeJob.isCancelled()) {
294             authorizeJob.cancel(true);
295             authorizeJob = null;
296         }
297         if (globalJob != null && !globalJob.isCancelled()) {
298             globalJob.cancel(true);
299             globalJob = null;
300         }
301         apiManager.closeSession();
302         super.dispose();
303     }
304
305     public FreeboxApiManager getApiManager() {
306         return apiManager;
307     }
308
309     public String getAppToken() {
310         return configuration == null ? null : configuration.appToken;
311     }
312
313     public boolean registerDataListener(FreeboxDataListener dataListener) {
314         if (dataListener == null) {
315             throw new IllegalArgumentException("It's not allowed to pass a null dataListener.");
316         }
317         return dataListeners.add(dataListener);
318     }
319
320     public boolean unregisterDataListener(FreeboxDataListener dataListener) {
321         if (dataListener == null) {
322             throw new IllegalArgumentException("It's not allowed to pass a null dataListener.");
323         }
324         return dataListeners.remove(dataListener);
325     }
326
327     private boolean fetchConnectionStatus() {
328         try {
329             FreeboxConnectionStatus connectionStatus = apiManager.getConnectionStatus();
330             String state = connectionStatus.getState();
331             if (state != null && !state.isEmpty()) {
332                 updateChannelStringState(LINESTATUS, state);
333             }
334             String ipv4 = connectionStatus.getIpv4();
335             if (ipv4 != null && !ipv4.isEmpty()) {
336                 updateChannelStringState(IPV4, ipv4);
337             }
338             updateChannelDecimalState(RATEUP, connectionStatus.getRateUp());
339             updateChannelDecimalState(RATEDOWN, connectionStatus.getRateDown());
340             updateChannelDecimalState(BYTESUP, connectionStatus.getBytesUp());
341             updateChannelDecimalState(BYTESDOWN, connectionStatus.getBytesDown());
342             return true;
343         } catch (FreeboxException e) {
344             logger.debug("Thing {}: exception in fetchConnectionStatus: {}", getThing().getUID(), e.getMessage(), e);
345             return false;
346         }
347     }
348
349     private boolean fetchxDslStatus() {
350         try {
351             String status = apiManager.getxDslStatus();
352             if (status != null && !status.isEmpty()) {
353                 updateChannelStringState(XDSLSTATUS, status);
354             }
355             return true;
356         } catch (FreeboxException e) {
357             logger.debug("Thing {}: exception in fetchxDslStatus: {}", getThing().getUID(), e.getMessage(), e);
358             return false;
359         }
360     }
361
362     private boolean fetchFtthPresent() {
363         try {
364             boolean status = apiManager.getFtthPresent();
365             updateChannelSwitchState(FTTHSTATUS, status);
366             return status;
367         } catch (FreeboxException e) {
368             logger.debug("Thing {}: exception in fetchxFtthStatus: {}", getThing().getUID(), e.getMessage(), e);
369             return false;
370         }
371     }
372
373     private boolean fetchWifiConfig() {
374         try {
375             updateChannelSwitchState(WIFISTATUS, apiManager.isWifiEnabled());
376             return true;
377         } catch (FreeboxException e) {
378             logger.debug("Thing {}: exception in fetchWifiConfig: {}", getThing().getUID(), e.getMessage(), e);
379             return false;
380         }
381     }
382
383     private boolean fetchFtpConfig() {
384         try {
385             updateChannelSwitchState(FTPSTATUS, apiManager.isFtpEnabled());
386             return true;
387         } catch (FreeboxException e) {
388             logger.debug("Thing {}: exception in fetchFtpConfig: {}", getThing().getUID(), e.getMessage(), e);
389             return false;
390         }
391     }
392
393     private boolean fetchAirMediaConfig() {
394         try {
395             if (!apiManager.isInLanBridgeMode()) {
396                 updateChannelSwitchState(AIRMEDIASTATUS, apiManager.isAirMediaEnabled());
397             }
398             return true;
399         } catch (FreeboxException e) {
400             logger.debug("Thing {}: exception in fetchAirMediaConfig: {}", getThing().getUID(), e.getMessage(), e);
401             return false;
402         }
403     }
404
405     private boolean fetchUPnPAVConfig() {
406         try {
407             if (!apiManager.isInLanBridgeMode()) {
408                 updateChannelSwitchState(UPNPAVSTATUS, apiManager.isUPnPAVEnabled());
409             }
410             return true;
411         } catch (FreeboxException e) {
412             logger.debug("Thing {}: exception in fetchUPnPAVConfig: {}", getThing().getUID(), e.getMessage(), e);
413             return false;
414         }
415     }
416
417     private boolean fetchSambaConfig() {
418         try {
419             FreeboxSambaConfig config = apiManager.getSambaConfig();
420             updateChannelSwitchState(SAMBAFILESTATUS, config.isFileShareEnabled());
421             updateChannelSwitchState(SAMBAPRINTERSTATUS, config.isPrintShareEnabled());
422             return true;
423         } catch (FreeboxException e) {
424             logger.debug("Thing {}: exception in fetchSambaConfig: {}", getThing().getUID(), e.getMessage(), e);
425             return false;
426         }
427     }
428
429     private boolean fetchLCDConfig() {
430         try {
431             FreeboxLcdConfig config = apiManager.getLcdConfig();
432             updateChannelDecimalState(LCDBRIGHTNESS, config.getBrightness());
433             updateChannelDecimalState(LCDORIENTATION, config.getOrientation());
434             updateChannelSwitchState(LCDFORCED, config.isOrientationForced());
435             return true;
436         } catch (FreeboxException e) {
437             logger.debug("Thing {}: exception in fetchLCDConfig: {}", getThing().getUID(), e.getMessage(), e);
438             return false;
439         }
440     }
441
442     private boolean fetchSystemConfig() {
443         try {
444             FreeboxSystemConfig config = apiManager.getSystemConfig();
445             Map<String, String> properties = editProperties();
446             String value = config.getSerial();
447             if (value != null && !value.isEmpty()) {
448                 properties.put(Thing.PROPERTY_SERIAL_NUMBER, value);
449             }
450             value = config.getBoardName();
451             if (value != null && !value.isEmpty()) {
452                 properties.put(Thing.PROPERTY_HARDWARE_VERSION, value);
453             }
454             value = config.getFirmwareVersion();
455             if (value != null && !value.isEmpty()) {
456                 properties.put(Thing.PROPERTY_FIRMWARE_VERSION, value);
457                 updateChannelStringState(FWVERSION, value);
458             }
459             value = config.getMac();
460             if (value != null && !value.isEmpty()) {
461                 properties.put(Thing.PROPERTY_MAC_ADDRESS, value);
462             }
463             updateProperties(properties);
464
465             long newUptime = config.getUptimeVal();
466             updateChannelSwitchState(RESTARTED, newUptime < uptime);
467             uptime = newUptime;
468
469             updateChannelDecimalState(UPTIME, uptime);
470             updateChannelDecimalState(TEMPCPUM, config.getTempCpum());
471             updateChannelDecimalState(TEMPCPUB, config.getTempCpub());
472             updateChannelDecimalState(TEMPSWITCH, config.getTempSw());
473             updateChannelDecimalState(FANSPEED, config.getFanRpm());
474             return true;
475         } catch (FreeboxException e) {
476             logger.debug("Thing {}: exception in fetchSystemConfig: {}", getThing().getUID(), e.getMessage(), e);
477             return false;
478         }
479     }
480
481     private synchronized List<FreeboxLanHost> fetchLanHosts() {
482         try {
483             List<FreeboxLanHost> hosts = apiManager.getLanHosts();
484             if (hosts == null) {
485                 hosts = new ArrayList<>();
486             }
487
488             // The update of channels is delegated to each thing handler
489             for (Thing thing : getThing().getThings()) {
490                 ThingHandler handler = thing.getHandler();
491                 if (handler instanceof FreeboxThingHandler) {
492                     ((FreeboxThingHandler) handler).updateNetInfo(hosts);
493                 }
494             }
495
496             return hosts;
497         } catch (FreeboxException e) {
498             logger.debug("Thing {}: exception in fetchLanHosts: {}", getThing().getUID(), e.getMessage(), e);
499             return null;
500         }
501     }
502
503     private synchronized List<FreeboxAirMediaReceiver> fetchAirPlayDevices() {
504         try {
505             List<FreeboxAirMediaReceiver> devices = apiManager.getAirMediaReceivers();
506             if (devices == null) {
507                 devices = new ArrayList<>();
508             }
509
510             // The update of channels is delegated to each thing handler
511             for (Thing thing : getThing().getThings()) {
512                 ThingHandler handler = thing.getHandler();
513                 if (handler instanceof FreeboxThingHandler) {
514                     ((FreeboxThingHandler) handler).updateAirPlayDevice(devices);
515                 }
516             }
517
518             return devices;
519         } catch (FreeboxException e) {
520             logger.debug("Thing {}: exception in fetchAirPlayDevices: {}", getThing().getUID(), e.getMessage(), e);
521             return null;
522         }
523     }
524
525     private void setBrightness(ChannelUID channelUID, Command command) {
526         try {
527             if (command instanceof IncreaseDecreaseType) {
528                 if (command == IncreaseDecreaseType.INCREASE) {
529                     updateChannelDecimalState(LCDBRIGHTNESS, apiManager.increaseLcdBrightness());
530                 } else {
531                     updateChannelDecimalState(LCDBRIGHTNESS, apiManager.decreaseLcdBrightness());
532                 }
533             } else if (command instanceof OnOffType) {
534                 updateChannelDecimalState(LCDBRIGHTNESS,
535                         apiManager.setLcdBrightness((command == OnOffType.ON) ? 100 : 0));
536             } else if (command instanceof DecimalType) {
537                 updateChannelDecimalState(LCDBRIGHTNESS,
538                         apiManager.setLcdBrightness(((DecimalType) command).intValue()));
539             } else if (command instanceof PercentType) {
540                 updateChannelDecimalState(LCDBRIGHTNESS,
541                         apiManager.setLcdBrightness(((PercentType) command).intValue()));
542             } else {
543                 logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
544                         channelUID.getId());
545             }
546         } catch (FreeboxException e) {
547             logCommandException(e, channelUID, command);
548             fetchLCDConfig();
549         }
550     }
551
552     private void setOrientation(ChannelUID channelUID, Command command) {
553         if (command instanceof DecimalType) {
554             try {
555                 FreeboxLcdConfig config = apiManager.setLcdOrientation(((DecimalType) command).intValue());
556                 updateChannelDecimalState(LCDORIENTATION, config.getOrientation());
557                 updateChannelSwitchState(LCDFORCED, config.isOrientationForced());
558             } catch (FreeboxException e) {
559                 logCommandException(e, channelUID, command);
560                 fetchLCDConfig();
561             }
562         } else {
563             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
564                     channelUID.getId());
565         }
566     }
567
568     private void setForced(ChannelUID channelUID, Command command) {
569         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
570             try {
571                 updateChannelSwitchState(LCDFORCED, apiManager.setLcdOrientationForced(command.equals(OnOffType.ON)
572                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
573             } catch (FreeboxException e) {
574                 logCommandException(e, channelUID, command);
575                 fetchLCDConfig();
576             }
577         } else {
578             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
579                     channelUID.getId());
580         }
581     }
582
583     private void setWifiStatus(ChannelUID channelUID, Command command) {
584         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
585             try {
586                 updateChannelSwitchState(WIFISTATUS, apiManager.enableWifi(command.equals(OnOffType.ON)
587                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
588             } catch (FreeboxException e) {
589                 logCommandException(e, channelUID, command);
590                 fetchWifiConfig();
591             }
592         } else {
593             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
594                     channelUID.getId());
595         }
596     }
597
598     private void setFtpStatus(ChannelUID channelUID, Command command) {
599         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
600             try {
601                 updateChannelSwitchState(FTPSTATUS, apiManager.enableFtp(command.equals(OnOffType.ON)
602                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
603             } catch (FreeboxException e) {
604                 logCommandException(e, channelUID, command);
605                 fetchFtpConfig();
606             }
607         } else {
608             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
609                     channelUID.getId());
610         }
611     }
612
613     private void setAirMediaStatus(ChannelUID channelUID, Command command) {
614         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
615             try {
616                 if (!apiManager.isInLanBridgeMode()) {
617                     updateChannelSwitchState(AIRMEDIASTATUS, apiManager.enableAirMedia(command.equals(OnOffType.ON)
618                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
619                 } else {
620                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
621                             getThing().getUID(), command, channelUID.getId());
622                 }
623             } catch (FreeboxException e) {
624                 logCommandException(e, channelUID, command);
625                 fetchAirMediaConfig();
626             }
627         } else {
628             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
629                     channelUID.getId());
630         }
631     }
632
633     private void setUPnPAVStatus(ChannelUID channelUID, Command command) {
634         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
635             try {
636                 if (!apiManager.isInLanBridgeMode()) {
637                     updateChannelSwitchState(UPNPAVSTATUS, apiManager.enableUPnPAV(command.equals(OnOffType.ON)
638                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
639                 } else {
640                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
641                             getThing().getUID(), command, channelUID.getId());
642                 }
643             } catch (FreeboxException e) {
644                 logCommandException(e, channelUID, command);
645                 fetchUPnPAVConfig();
646             }
647         } else {
648             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
649                     channelUID.getId());
650         }
651     }
652
653     private void setSambaFileStatus(ChannelUID channelUID, Command command) {
654         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
655             try {
656                 updateChannelSwitchState(SAMBAFILESTATUS, apiManager.enableSambaFileShare(command.equals(OnOffType.ON)
657                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
658             } catch (FreeboxException e) {
659                 logCommandException(e, channelUID, command);
660                 fetchSambaConfig();
661             }
662         } else {
663             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
664                     channelUID.getId());
665         }
666     }
667
668     private void setSambaPrinterStatus(ChannelUID channelUID, Command command) {
669         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
670             try {
671                 updateChannelSwitchState(SAMBAPRINTERSTATUS,
672                         apiManager.enableSambaPrintShare(command.equals(OnOffType.ON) || command.equals(UpDownType.UP)
673                                 || command.equals(OpenClosedType.OPEN)));
674             } catch (FreeboxException e) {
675                 logCommandException(e, channelUID, command);
676                 fetchSambaConfig();
677             }
678         } else {
679             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
680                     channelUID.getId());
681         }
682     }
683
684     private void reboot(ChannelUID channelUID, Command command) {
685         if (command.equals(OnOffType.ON) || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)) {
686             try {
687                 apiManager.reboot();
688             } catch (FreeboxException e) {
689                 logCommandException(e, channelUID, command);
690             }
691         } else {
692             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
693                     channelUID.getId());
694         }
695     }
696
697     private void updateChannelStringState(String channel, String state) {
698         updateState(new ChannelUID(getThing().getUID(), channel), new StringType(state));
699     }
700
701     private void updateChannelSwitchState(String channel, boolean state) {
702         updateState(new ChannelUID(getThing().getUID(), channel), state ? OnOffType.ON : OnOffType.OFF);
703     }
704
705     private void updateChannelDecimalState(String channel, int state) {
706         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
707     }
708
709     private void updateChannelDecimalState(String channel, long state) {
710         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
711     }
712
713     public void logCommandException(FreeboxException e, ChannelUID channelUID, Command command) {
714         if (e.isMissingRights()) {
715             logger.debug("Thing {}: missing right {} while handling command {} from channel {}", getThing().getUID(),
716                     e.getResponse().getMissingRight(), command, channelUID.getId());
717         } else {
718             logger.debug("Thing {}: error while handling command {} from channel {}", getThing().getUID(), command,
719                     channelUID.getId(), e);
720         }
721     }
722 }