]> git.basschouten.com Git - openhab-addons.git/blob
bd769221d9f6216967816fe567fe16c819b10e03
[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.List;
20 import java.util.Map;
21 import java.util.Set;
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 Set.of(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 thingHandler) {
498                     thingHandler.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 thingHandler) {
523                     thingHandler.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 decimalCommand) {
546                 updateChannelDecimalState(LCDBRIGHTNESS, apiManager.setLcdBrightness(decimalCommand.intValue()));
547             } else if (command instanceof PercentType percentCommand) {
548                 updateChannelDecimalState(LCDBRIGHTNESS, apiManager.setLcdBrightness(percentCommand.intValue()));
549             } else {
550                 logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
551                         channelUID.getId());
552             }
553         } catch (FreeboxException e) {
554             logCommandException(e, channelUID, command);
555             fetchLCDConfig();
556         }
557     }
558
559     private void setOrientation(ChannelUID channelUID, Command command) {
560         if (command instanceof DecimalType orientation) {
561             try {
562                 FreeboxLcdConfig config = apiManager.setLcdOrientation(orientation.intValue());
563                 updateChannelDecimalState(LCDORIENTATION, config.getOrientation());
564                 updateChannelSwitchState(LCDFORCED, config.isOrientationForced());
565             } catch (FreeboxException e) {
566                 logCommandException(e, channelUID, command);
567                 fetchLCDConfig();
568             }
569         } else {
570             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
571                     channelUID.getId());
572         }
573     }
574
575     private void setForced(ChannelUID channelUID, Command command) {
576         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
577             try {
578                 updateChannelSwitchState(LCDFORCED, apiManager.setLcdOrientationForced(command.equals(OnOffType.ON)
579                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
580             } catch (FreeboxException e) {
581                 logCommandException(e, channelUID, command);
582                 fetchLCDConfig();
583             }
584         } else {
585             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
586                     channelUID.getId());
587         }
588     }
589
590     private void setWifiStatus(ChannelUID channelUID, Command command) {
591         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
592             try {
593                 updateChannelSwitchState(WIFISTATUS, apiManager.enableWifi(command.equals(OnOffType.ON)
594                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
595             } catch (FreeboxException e) {
596                 logCommandException(e, channelUID, command);
597                 fetchWifiConfig();
598             }
599         } else {
600             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
601                     channelUID.getId());
602         }
603     }
604
605     private void setFtpStatus(ChannelUID channelUID, Command command) {
606         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
607             try {
608                 updateChannelSwitchState(FTPSTATUS, apiManager.enableFtp(command.equals(OnOffType.ON)
609                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
610             } catch (FreeboxException e) {
611                 logCommandException(e, channelUID, command);
612                 fetchFtpConfig();
613             }
614         } else {
615             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
616                     channelUID.getId());
617         }
618     }
619
620     private void setAirMediaStatus(ChannelUID channelUID, Command command) {
621         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
622             try {
623                 if (!apiManager.isInLanBridgeMode()) {
624                     updateChannelSwitchState(AIRMEDIASTATUS, apiManager.enableAirMedia(command.equals(OnOffType.ON)
625                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
626                 } else {
627                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
628                             getThing().getUID(), command, channelUID.getId());
629                 }
630             } catch (FreeboxException e) {
631                 logCommandException(e, channelUID, command);
632                 fetchAirMediaConfig();
633             }
634         } else {
635             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
636                     channelUID.getId());
637         }
638     }
639
640     private void setUPnPAVStatus(ChannelUID channelUID, Command command) {
641         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
642             try {
643                 if (!apiManager.isInLanBridgeMode()) {
644                     updateChannelSwitchState(UPNPAVSTATUS, apiManager.enableUPnPAV(command.equals(OnOffType.ON)
645                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
646                 } else {
647                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
648                             getThing().getUID(), command, channelUID.getId());
649                 }
650             } catch (FreeboxException e) {
651                 logCommandException(e, channelUID, command);
652                 fetchUPnPAVConfig();
653             }
654         } else {
655             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
656                     channelUID.getId());
657         }
658     }
659
660     private void setSambaFileStatus(ChannelUID channelUID, Command command) {
661         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
662             try {
663                 updateChannelSwitchState(SAMBAFILESTATUS, apiManager.enableSambaFileShare(command.equals(OnOffType.ON)
664                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
665             } catch (FreeboxException e) {
666                 logCommandException(e, channelUID, command);
667                 fetchSambaConfig();
668             }
669         } else {
670             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
671                     channelUID.getId());
672         }
673     }
674
675     private void setSambaPrinterStatus(ChannelUID channelUID, Command command) {
676         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
677             try {
678                 updateChannelSwitchState(SAMBAPRINTERSTATUS,
679                         apiManager.enableSambaPrintShare(command.equals(OnOffType.ON) || command.equals(UpDownType.UP)
680                                 || command.equals(OpenClosedType.OPEN)));
681             } catch (FreeboxException e) {
682                 logCommandException(e, channelUID, command);
683                 fetchSambaConfig();
684             }
685         } else {
686             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
687                     channelUID.getId());
688         }
689     }
690
691     private void reboot(ChannelUID channelUID, Command command) {
692         if (command.equals(OnOffType.ON) || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)) {
693             try {
694                 apiManager.reboot();
695             } catch (FreeboxException e) {
696                 logCommandException(e, channelUID, command);
697             }
698         } else {
699             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
700                     channelUID.getId());
701         }
702     }
703
704     private void updateChannelStringState(String channel, String state) {
705         updateState(new ChannelUID(getThing().getUID(), channel), new StringType(state));
706     }
707
708     private void updateChannelSwitchState(String channel, boolean state) {
709         updateState(new ChannelUID(getThing().getUID(), channel), OnOffType.from(state));
710     }
711
712     private void updateChannelDecimalState(String channel, int state) {
713         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
714     }
715
716     private void updateChannelDecimalState(String channel, long state) {
717         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
718     }
719
720     public void logCommandException(FreeboxException e, ChannelUID channelUID, Command command) {
721         if (e.isMissingRights()) {
722             logger.debug("Thing {}: missing right {} while handling command {} from channel {}", getThing().getUID(),
723                     e.getResponse().getMissingRight(), command, channelUID.getId());
724         } else {
725             logger.debug("Thing {}: error while handling command {} from channel {}", getThing().getUID(), command,
726                     channelUID.getId(), e);
727         }
728     }
729 }