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