]> git.basschouten.com Git - openhab-addons.git/blob
f0a48f8baffd85cea497c7e9e83b4aba08461553
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 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(this::authorize, 1, TimeUnit.SECONDS);
162             }
163         } else {
164             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
165                     "Freebox Server FQDN not set in the thing configuration");
166         }
167     }
168
169     private void pollServerState() {
170         logger.debug("Polling server state...");
171
172         boolean commOk = true;
173         commOk &= fetchSystemConfig();
174         commOk &= fetchLCDConfig();
175         commOk &= fetchWifiConfig();
176         commOk &= (fetchxDslStatus() || fetchFtthPresent());
177         commOk &= fetchConnectionStatus();
178         commOk &= fetchFtpConfig();
179         commOk &= fetchAirMediaConfig();
180         commOk &= fetchUPnPAVConfig();
181         commOk &= fetchSambaConfig();
182         List<FreeboxLanHost> lanHosts = fetchLanHosts();
183         commOk &= (lanHosts != null);
184         List<FreeboxAirMediaReceiver> airPlayDevices = fetchAirPlayDevices();
185         commOk &= (airPlayDevices != null);
186
187         // Trigger a new discovery of things
188         for (FreeboxDataListener dataListener : dataListeners) {
189             dataListener.onDataFetched(getThing().getUID(), lanHosts, airPlayDevices);
190         }
191
192         if (commOk) {
193             updateStatus(ThingStatus.ONLINE);
194         } else {
195             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
196         }
197     }
198
199     private void authorize() {
200         logger.debug("Authorize job...");
201
202         String fqdn = configuration.fqdn;
203         FreeboxDiscoveryResponse result = null;
204         boolean httpsRequestOk = false;
205         if (!Boolean.TRUE.equals(configuration.useOnlyHttp)) {
206             result = apiManager.checkApi(fqdn, true);
207             httpsRequestOk = (result != null);
208         }
209         if (!httpsRequestOk) {
210             result = apiManager.checkApi(fqdn, false);
211         }
212         String apiBaseUrl = result == null ? null : result.getApiBaseUrl();
213         String apiVersion = result == null ? null : result.getApiVersion();
214         String deviceType = result == null ? null : result.getDeviceType();
215         String apiDomain = result == null ? null : result.getApiDomain();
216         Integer httpsPort = result == null ? null : result.getHttpsPort();
217         boolean useHttps = false;
218         String errorMsg = null;
219         if (result == null) {
220             errorMsg = "Can't connect to " + fqdn;
221         } else if (apiBaseUrl == null || apiBaseUrl.isEmpty()) {
222             errorMsg = fqdn + " does not deliver any API base URL";
223         } else if (apiVersion == null || apiVersion.isEmpty()) {
224             errorMsg = fqdn + " does not deliver any API version";
225         } else if (Boolean.TRUE.equals(result.isHttpsAvailable()) && !Boolean.TRUE.equals(configuration.useOnlyHttp)) {
226             if (httpsPort == null || apiDomain == null || apiDomain.isEmpty()) {
227                 if (httpsRequestOk) {
228                     useHttps = true;
229                 } else {
230                     logger.debug("{} does not deliver API domain or HTTPS port; use HTTP API", fqdn);
231                 }
232             } else if (apiManager.checkApi(String.format("%s:%d", apiDomain, httpsPort), true) != null) {
233                 useHttps = true;
234                 fqdn = String.format("%s:%d", apiDomain, httpsPort);
235             }
236         }
237
238         if (errorMsg != null) {
239             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
240         } else if (!apiManager.authorize(useHttps, fqdn, apiBaseUrl, apiVersion, configuration.appToken)) {
241             if (configuration.appToken == null || configuration.appToken.isEmpty()) {
242                 errorMsg = "Pairing request rejected or timeout";
243             } else {
244                 errorMsg = "Check your app token in the thing configuration; opening session with " + fqdn + " using "
245                         + (useHttps ? "HTTPS" : "HTTP") + " API version " + apiVersion + " failed";
246             }
247             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, errorMsg);
248         } else {
249             logger.debug("Thing {}: session opened with {} using {} API version {}", getThing().getUID(), fqdn,
250                     (useHttps ? "HTTPS" : "HTTP"), apiVersion);
251             String appToken = apiManager.getAppToken();
252             if ((configuration.appToken == null || configuration.appToken.isEmpty()) && appToken != null) {
253                 logger.debug("Store new app token in the thing configuration");
254                 configuration.appToken = appToken;
255                 Configuration thingConfig = editConfiguration();
256                 thingConfig.put(FreeboxServerConfiguration.APP_TOKEN, appToken);
257                 updateConfiguration(thingConfig);
258             }
259             updateStatus(ThingStatus.ONLINE);
260             if (globalJob == null || globalJob.isCancelled()) {
261                 long pollingInterval = configuration.refreshInterval;
262                 logger.debug("Scheduling server state update every {} seconds...", pollingInterval);
263                 globalJob = scheduler.scheduleWithFixedDelay(() -> {
264                     try {
265                         pollServerState();
266                     } catch (Exception e) {
267                         logger.debug("Server state job failed: {}", e.getMessage(), e);
268                         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
269                     }
270                 }, 1, pollingInterval, TimeUnit.SECONDS);
271             }
272         }
273
274         Map<String, String> properties = editProperties();
275         if (apiBaseUrl != null && !apiBaseUrl.isEmpty()) {
276             properties.put(API_BASE_URL, apiBaseUrl);
277         }
278         if (apiVersion != null && !apiVersion.isEmpty()) {
279             properties.put(API_VERSION, apiVersion);
280         }
281         if (deviceType != null && !deviceType.isEmpty()) {
282             properties.put(Thing.PROPERTY_HARDWARE_VERSION, deviceType);
283         }
284         updateProperties(properties);
285     }
286
287     @Override
288     public void dispose() {
289         logger.debug("Disposing Freebox Server handler for thing {}", getThing().getUID());
290         if (authorizeJob != null && !authorizeJob.isCancelled()) {
291             authorizeJob.cancel(true);
292             authorizeJob = null;
293         }
294         if (globalJob != null && !globalJob.isCancelled()) {
295             globalJob.cancel(true);
296             globalJob = null;
297         }
298         apiManager.closeSession();
299         super.dispose();
300     }
301
302     public FreeboxApiManager getApiManager() {
303         return apiManager;
304     }
305
306     public String getAppToken() {
307         return configuration == null ? null : configuration.appToken;
308     }
309
310     public boolean registerDataListener(FreeboxDataListener dataListener) {
311         if (dataListener == null) {
312             throw new IllegalArgumentException("It's not allowed to pass a null dataListener.");
313         }
314         return dataListeners.add(dataListener);
315     }
316
317     public boolean unregisterDataListener(FreeboxDataListener dataListener) {
318         if (dataListener == null) {
319             throw new IllegalArgumentException("It's not allowed to pass a null dataListener.");
320         }
321         return dataListeners.remove(dataListener);
322     }
323
324     private boolean fetchConnectionStatus() {
325         try {
326             FreeboxConnectionStatus connectionStatus = apiManager.getConnectionStatus();
327             String state = connectionStatus.getState();
328             if (state != null && !state.isEmpty()) {
329                 updateChannelStringState(LINESTATUS, state);
330             }
331             String ipv4 = connectionStatus.getIpv4();
332             if (ipv4 != null && !ipv4.isEmpty()) {
333                 updateChannelStringState(IPV4, ipv4);
334             }
335             updateChannelDecimalState(RATEUP, connectionStatus.getRateUp());
336             updateChannelDecimalState(RATEDOWN, connectionStatus.getRateDown());
337             updateChannelDecimalState(BYTESUP, connectionStatus.getBytesUp());
338             updateChannelDecimalState(BYTESDOWN, connectionStatus.getBytesDown());
339             return true;
340         } catch (FreeboxException e) {
341             logger.debug("Thing {}: exception in fetchConnectionStatus: {}", getThing().getUID(), e.getMessage(), e);
342             return false;
343         }
344     }
345
346     private boolean fetchxDslStatus() {
347         try {
348             String status = apiManager.getxDslStatus();
349             if (status != null && !status.isEmpty()) {
350                 updateChannelStringState(XDSLSTATUS, status);
351             }
352             return true;
353         } catch (FreeboxException e) {
354             logger.debug("Thing {}: exception in fetchxDslStatus: {}", getThing().getUID(), e.getMessage(), e);
355             return false;
356         }
357     }
358
359     private boolean fetchFtthPresent() {
360         try {
361             boolean status = apiManager.getFtthPresent();
362             updateChannelSwitchState(FTTHSTATUS, status);
363             return status;
364         } catch (FreeboxException e) {
365             logger.debug("Thing {}: exception in fetchxFtthStatus: {}", getThing().getUID(), e.getMessage(), e);
366             return false;
367         }
368     }
369
370     private boolean fetchWifiConfig() {
371         try {
372             updateChannelSwitchState(WIFISTATUS, apiManager.isWifiEnabled());
373             return true;
374         } catch (FreeboxException e) {
375             logger.debug("Thing {}: exception in fetchWifiConfig: {}", getThing().getUID(), e.getMessage(), e);
376             return false;
377         }
378     }
379
380     private boolean fetchFtpConfig() {
381         try {
382             updateChannelSwitchState(FTPSTATUS, apiManager.isFtpEnabled());
383             return true;
384         } catch (FreeboxException e) {
385             logger.debug("Thing {}: exception in fetchFtpConfig: {}", getThing().getUID(), e.getMessage(), e);
386             return false;
387         }
388     }
389
390     private boolean fetchAirMediaConfig() {
391         try {
392             if (!apiManager.isInLanBridgeMode()) {
393                 updateChannelSwitchState(AIRMEDIASTATUS, apiManager.isAirMediaEnabled());
394             }
395             return true;
396         } catch (FreeboxException e) {
397             logger.debug("Thing {}: exception in fetchAirMediaConfig: {}", getThing().getUID(), e.getMessage(), e);
398             return false;
399         }
400     }
401
402     private boolean fetchUPnPAVConfig() {
403         try {
404             if (!apiManager.isInLanBridgeMode()) {
405                 updateChannelSwitchState(UPNPAVSTATUS, apiManager.isUPnPAVEnabled());
406             }
407             return true;
408         } catch (FreeboxException e) {
409             logger.debug("Thing {}: exception in fetchUPnPAVConfig: {}", getThing().getUID(), e.getMessage(), e);
410             return false;
411         }
412     }
413
414     private boolean fetchSambaConfig() {
415         try {
416             FreeboxSambaConfig config = apiManager.getSambaConfig();
417             updateChannelSwitchState(SAMBAFILESTATUS, config.isFileShareEnabled());
418             updateChannelSwitchState(SAMBAPRINTERSTATUS, config.isPrintShareEnabled());
419             return true;
420         } catch (FreeboxException e) {
421             logger.debug("Thing {}: exception in fetchSambaConfig: {}", getThing().getUID(), e.getMessage(), e);
422             return false;
423         }
424     }
425
426     private boolean fetchLCDConfig() {
427         try {
428             FreeboxLcdConfig config = apiManager.getLcdConfig();
429             updateChannelDecimalState(LCDBRIGHTNESS, config.getBrightness());
430             updateChannelDecimalState(LCDORIENTATION, config.getOrientation());
431             updateChannelSwitchState(LCDFORCED, config.isOrientationForced());
432             return true;
433         } catch (FreeboxException e) {
434             logger.debug("Thing {}: exception in fetchLCDConfig: {}", getThing().getUID(), e.getMessage(), e);
435             return false;
436         }
437     }
438
439     private boolean fetchSystemConfig() {
440         try {
441             FreeboxSystemConfig config = apiManager.getSystemConfig();
442             Map<String, String> properties = editProperties();
443             String value = config.getSerial();
444             if (value != null && !value.isEmpty()) {
445                 properties.put(Thing.PROPERTY_SERIAL_NUMBER, value);
446             }
447             value = config.getBoardName();
448             if (value != null && !value.isEmpty()) {
449                 properties.put(Thing.PROPERTY_HARDWARE_VERSION, value);
450             }
451             value = config.getFirmwareVersion();
452             if (value != null && !value.isEmpty()) {
453                 properties.put(Thing.PROPERTY_FIRMWARE_VERSION, value);
454                 updateChannelStringState(FWVERSION, value);
455             }
456             value = config.getMac();
457             if (value != null && !value.isEmpty()) {
458                 properties.put(Thing.PROPERTY_MAC_ADDRESS, value);
459             }
460             updateProperties(properties);
461
462             long newUptime = config.getUptimeVal();
463             updateChannelSwitchState(RESTARTED, newUptime < uptime);
464             uptime = newUptime;
465
466             updateChannelDecimalState(UPTIME, uptime);
467             updateChannelDecimalState(TEMPCPUM, config.getTempCpum());
468             updateChannelDecimalState(TEMPCPUB, config.getTempCpub());
469             updateChannelDecimalState(TEMPSWITCH, config.getTempSw());
470             updateChannelDecimalState(FANSPEED, config.getFanRpm());
471             return true;
472         } catch (FreeboxException e) {
473             logger.debug("Thing {}: exception in fetchSystemConfig: {}", getThing().getUID(), e.getMessage(), e);
474             return false;
475         }
476     }
477
478     private synchronized List<FreeboxLanHost> fetchLanHosts() {
479         try {
480             List<FreeboxLanHost> hosts = apiManager.getLanHosts();
481             if (hosts == null) {
482                 hosts = new ArrayList<>();
483             }
484
485             // The update of channels is delegated to each thing handler
486             for (Thing thing : getThing().getThings()) {
487                 ThingHandler handler = thing.getHandler();
488                 if (handler instanceof FreeboxThingHandler) {
489                     ((FreeboxThingHandler) handler).updateNetInfo(hosts);
490                 }
491             }
492
493             return hosts;
494         } catch (FreeboxException e) {
495             logger.debug("Thing {}: exception in fetchLanHosts: {}", getThing().getUID(), e.getMessage(), e);
496             return null;
497         }
498     }
499
500     private synchronized List<FreeboxAirMediaReceiver> fetchAirPlayDevices() {
501         try {
502             List<FreeboxAirMediaReceiver> devices = apiManager.getAirMediaReceivers();
503             if (devices == null) {
504                 devices = new ArrayList<>();
505             }
506
507             // The update of channels is delegated to each thing handler
508             for (Thing thing : getThing().getThings()) {
509                 ThingHandler handler = thing.getHandler();
510                 if (handler instanceof FreeboxThingHandler) {
511                     ((FreeboxThingHandler) handler).updateAirPlayDevice(devices);
512                 }
513             }
514
515             return devices;
516         } catch (FreeboxException e) {
517             logger.debug("Thing {}: exception in fetchAirPlayDevices: {}", getThing().getUID(), e.getMessage(), e);
518             return null;
519         }
520     }
521
522     private void setBrightness(ChannelUID channelUID, Command command) {
523         try {
524             if (command instanceof IncreaseDecreaseType) {
525                 if (command == IncreaseDecreaseType.INCREASE) {
526                     updateChannelDecimalState(LCDBRIGHTNESS, apiManager.increaseLcdBrightness());
527                 } else {
528                     updateChannelDecimalState(LCDBRIGHTNESS, apiManager.decreaseLcdBrightness());
529                 }
530             } else if (command instanceof OnOffType) {
531                 updateChannelDecimalState(LCDBRIGHTNESS,
532                         apiManager.setLcdBrightness((command == OnOffType.ON) ? 100 : 0));
533             } else if (command instanceof DecimalType) {
534                 updateChannelDecimalState(LCDBRIGHTNESS,
535                         apiManager.setLcdBrightness(((DecimalType) command).intValue()));
536             } else if (command instanceof PercentType) {
537                 updateChannelDecimalState(LCDBRIGHTNESS,
538                         apiManager.setLcdBrightness(((PercentType) command).intValue()));
539             } else {
540                 logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
541                         channelUID.getId());
542             }
543         } catch (FreeboxException e) {
544             logCommandException(e, channelUID, command);
545             fetchLCDConfig();
546         }
547     }
548
549     private void setOrientation(ChannelUID channelUID, Command command) {
550         if (command instanceof DecimalType) {
551             try {
552                 FreeboxLcdConfig config = apiManager.setLcdOrientation(((DecimalType) command).intValue());
553                 updateChannelDecimalState(LCDORIENTATION, config.getOrientation());
554                 updateChannelSwitchState(LCDFORCED, config.isOrientationForced());
555             } catch (FreeboxException e) {
556                 logCommandException(e, channelUID, command);
557                 fetchLCDConfig();
558             }
559         } else {
560             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
561                     channelUID.getId());
562         }
563     }
564
565     private void setForced(ChannelUID channelUID, Command command) {
566         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
567             try {
568                 updateChannelSwitchState(LCDFORCED, apiManager.setLcdOrientationForced(command.equals(OnOffType.ON)
569                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
570             } catch (FreeboxException e) {
571                 logCommandException(e, channelUID, command);
572                 fetchLCDConfig();
573             }
574         } else {
575             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
576                     channelUID.getId());
577         }
578     }
579
580     private void setWifiStatus(ChannelUID channelUID, Command command) {
581         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
582             try {
583                 updateChannelSwitchState(WIFISTATUS, apiManager.enableWifi(command.equals(OnOffType.ON)
584                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
585             } catch (FreeboxException e) {
586                 logCommandException(e, channelUID, command);
587                 fetchWifiConfig();
588             }
589         } else {
590             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
591                     channelUID.getId());
592         }
593     }
594
595     private void setFtpStatus(ChannelUID channelUID, Command command) {
596         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
597             try {
598                 updateChannelSwitchState(FTPSTATUS, apiManager.enableFtp(command.equals(OnOffType.ON)
599                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
600             } catch (FreeboxException e) {
601                 logCommandException(e, channelUID, command);
602                 fetchFtpConfig();
603             }
604         } else {
605             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
606                     channelUID.getId());
607         }
608     }
609
610     private void setAirMediaStatus(ChannelUID channelUID, Command command) {
611         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
612             try {
613                 if (!apiManager.isInLanBridgeMode()) {
614                     updateChannelSwitchState(AIRMEDIASTATUS, apiManager.enableAirMedia(command.equals(OnOffType.ON)
615                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
616                 } else {
617                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
618                             getThing().getUID(), command, channelUID.getId());
619                 }
620             } catch (FreeboxException e) {
621                 logCommandException(e, channelUID, command);
622                 fetchAirMediaConfig();
623             }
624         } else {
625             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
626                     channelUID.getId());
627         }
628     }
629
630     private void setUPnPAVStatus(ChannelUID channelUID, Command command) {
631         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
632             try {
633                 if (!apiManager.isInLanBridgeMode()) {
634                     updateChannelSwitchState(UPNPAVSTATUS, apiManager.enableUPnPAV(command.equals(OnOffType.ON)
635                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
636                 } else {
637                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
638                             getThing().getUID(), command, channelUID.getId());
639                 }
640             } catch (FreeboxException e) {
641                 logCommandException(e, channelUID, command);
642                 fetchUPnPAVConfig();
643             }
644         } else {
645             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
646                     channelUID.getId());
647         }
648     }
649
650     private void setSambaFileStatus(ChannelUID channelUID, Command command) {
651         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
652             try {
653                 updateChannelSwitchState(SAMBAFILESTATUS, apiManager.enableSambaFileShare(command.equals(OnOffType.ON)
654                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
655             } catch (FreeboxException e) {
656                 logCommandException(e, channelUID, command);
657                 fetchSambaConfig();
658             }
659         } else {
660             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
661                     channelUID.getId());
662         }
663     }
664
665     private void setSambaPrinterStatus(ChannelUID channelUID, Command command) {
666         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
667             try {
668                 updateChannelSwitchState(SAMBAPRINTERSTATUS,
669                         apiManager.enableSambaPrintShare(command.equals(OnOffType.ON) || command.equals(UpDownType.UP)
670                                 || command.equals(OpenClosedType.OPEN)));
671             } catch (FreeboxException e) {
672                 logCommandException(e, channelUID, command);
673                 fetchSambaConfig();
674             }
675         } else {
676             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
677                     channelUID.getId());
678         }
679     }
680
681     private void reboot(ChannelUID channelUID, Command command) {
682         if (command.equals(OnOffType.ON) || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)) {
683             try {
684                 apiManager.reboot();
685             } catch (FreeboxException e) {
686                 logCommandException(e, channelUID, command);
687             }
688         } else {
689             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
690                     channelUID.getId());
691         }
692     }
693
694     private void updateChannelStringState(String channel, String state) {
695         updateState(new ChannelUID(getThing().getUID(), channel), new StringType(state));
696     }
697
698     private void updateChannelSwitchState(String channel, boolean state) {
699         updateState(new ChannelUID(getThing().getUID(), channel), state ? OnOffType.ON : OnOffType.OFF);
700     }
701
702     private void updateChannelDecimalState(String channel, int state) {
703         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
704     }
705
706     private void updateChannelDecimalState(String channel, long state) {
707         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
708     }
709
710     public void logCommandException(FreeboxException e, ChannelUID channelUID, Command command) {
711         if (e.isMissingRights()) {
712             logger.debug("Thing {}: missing right {} while handling command {} from channel {}", getThing().getUID(),
713                     e.getResponse().getMissingRight(), command, channelUID.getId());
714         } else {
715             logger.debug("Thing {}: error while handling command {} from channel {}", getThing().getUID(), command,
716                     channelUID.getId(), e);
717         }
718     }
719 }