]> git.basschouten.com Git - openhab-addons.git/blob
a027679a5a9f03678af0c58e072e82e07f7e1e50
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2022 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.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                 ThingHandler handler = thing.getHandler();
494                 if (handler instanceof FreeboxThingHandler) {
495                     ((FreeboxThingHandler) handler).updateNetInfo(hosts);
496                 }
497             }
498
499             return hosts;
500         } catch (FreeboxException e) {
501             logger.debug("Thing {}: exception in fetchLanHosts: {}", getThing().getUID(), e.getMessage(), e);
502             return null;
503         }
504     }
505
506     private synchronized List<FreeboxAirMediaReceiver> fetchAirPlayDevices() {
507         try {
508             List<FreeboxAirMediaReceiver> devices = apiManager.getAirMediaReceivers();
509             if (devices == null) {
510                 devices = new ArrayList<>();
511             }
512
513             // The update of channels is delegated to each thing handler
514             for (Thing thing : getThing().getThings()) {
515                 ThingHandler handler = thing.getHandler();
516                 if (handler instanceof FreeboxThingHandler) {
517                     ((FreeboxThingHandler) handler).updateAirPlayDevice(devices);
518                 }
519             }
520
521             return devices;
522         } catch (FreeboxException e) {
523             logger.debug("Thing {}: exception in fetchAirPlayDevices: {}", getThing().getUID(), e.getMessage(), e);
524             return null;
525         }
526     }
527
528     private void setBrightness(ChannelUID channelUID, Command command) {
529         try {
530             if (command instanceof IncreaseDecreaseType) {
531                 if (command == IncreaseDecreaseType.INCREASE) {
532                     updateChannelDecimalState(LCDBRIGHTNESS, apiManager.increaseLcdBrightness());
533                 } else {
534                     updateChannelDecimalState(LCDBRIGHTNESS, apiManager.decreaseLcdBrightness());
535                 }
536             } else if (command instanceof OnOffType) {
537                 updateChannelDecimalState(LCDBRIGHTNESS,
538                         apiManager.setLcdBrightness((command == OnOffType.ON) ? 100 : 0));
539             } else if (command instanceof DecimalType) {
540                 updateChannelDecimalState(LCDBRIGHTNESS,
541                         apiManager.setLcdBrightness(((DecimalType) command).intValue()));
542             } else if (command instanceof PercentType) {
543                 updateChannelDecimalState(LCDBRIGHTNESS,
544                         apiManager.setLcdBrightness(((PercentType) command).intValue()));
545             } else {
546                 logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
547                         channelUID.getId());
548             }
549         } catch (FreeboxException e) {
550             logCommandException(e, channelUID, command);
551             fetchLCDConfig();
552         }
553     }
554
555     private void setOrientation(ChannelUID channelUID, Command command) {
556         if (command instanceof DecimalType) {
557             try {
558                 FreeboxLcdConfig config = apiManager.setLcdOrientation(((DecimalType) command).intValue());
559                 updateChannelDecimalState(LCDORIENTATION, config.getOrientation());
560                 updateChannelSwitchState(LCDFORCED, config.isOrientationForced());
561             } catch (FreeboxException e) {
562                 logCommandException(e, channelUID, command);
563                 fetchLCDConfig();
564             }
565         } else {
566             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
567                     channelUID.getId());
568         }
569     }
570
571     private void setForced(ChannelUID channelUID, Command command) {
572         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
573             try {
574                 updateChannelSwitchState(LCDFORCED, apiManager.setLcdOrientationForced(command.equals(OnOffType.ON)
575                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
576             } catch (FreeboxException e) {
577                 logCommandException(e, channelUID, command);
578                 fetchLCDConfig();
579             }
580         } else {
581             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
582                     channelUID.getId());
583         }
584     }
585
586     private void setWifiStatus(ChannelUID channelUID, Command command) {
587         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
588             try {
589                 updateChannelSwitchState(WIFISTATUS, apiManager.enableWifi(command.equals(OnOffType.ON)
590                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
591             } catch (FreeboxException e) {
592                 logCommandException(e, channelUID, command);
593                 fetchWifiConfig();
594             }
595         } else {
596             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
597                     channelUID.getId());
598         }
599     }
600
601     private void setFtpStatus(ChannelUID channelUID, Command command) {
602         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
603             try {
604                 updateChannelSwitchState(FTPSTATUS, apiManager.enableFtp(command.equals(OnOffType.ON)
605                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
606             } catch (FreeboxException e) {
607                 logCommandException(e, channelUID, command);
608                 fetchFtpConfig();
609             }
610         } else {
611             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
612                     channelUID.getId());
613         }
614     }
615
616     private void setAirMediaStatus(ChannelUID channelUID, Command command) {
617         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
618             try {
619                 if (!apiManager.isInLanBridgeMode()) {
620                     updateChannelSwitchState(AIRMEDIASTATUS, apiManager.enableAirMedia(command.equals(OnOffType.ON)
621                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
622                 } else {
623                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
624                             getThing().getUID(), command, channelUID.getId());
625                 }
626             } catch (FreeboxException e) {
627                 logCommandException(e, channelUID, command);
628                 fetchAirMediaConfig();
629             }
630         } else {
631             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
632                     channelUID.getId());
633         }
634     }
635
636     private void setUPnPAVStatus(ChannelUID channelUID, Command command) {
637         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
638             try {
639                 if (!apiManager.isInLanBridgeMode()) {
640                     updateChannelSwitchState(UPNPAVSTATUS, apiManager.enableUPnPAV(command.equals(OnOffType.ON)
641                             || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
642                 } else {
643                     logger.debug("Thing {}: command {} from channel {} unavailable when in bridge mode",
644                             getThing().getUID(), command, channelUID.getId());
645                 }
646             } catch (FreeboxException e) {
647                 logCommandException(e, channelUID, command);
648                 fetchUPnPAVConfig();
649             }
650         } else {
651             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
652                     channelUID.getId());
653         }
654     }
655
656     private void setSambaFileStatus(ChannelUID channelUID, Command command) {
657         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
658             try {
659                 updateChannelSwitchState(SAMBAFILESTATUS, apiManager.enableSambaFileShare(command.equals(OnOffType.ON)
660                         || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)));
661             } catch (FreeboxException e) {
662                 logCommandException(e, channelUID, command);
663                 fetchSambaConfig();
664             }
665         } else {
666             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
667                     channelUID.getId());
668         }
669     }
670
671     private void setSambaPrinterStatus(ChannelUID channelUID, Command command) {
672         if (command instanceof OnOffType || command instanceof OpenClosedType || command instanceof UpDownType) {
673             try {
674                 updateChannelSwitchState(SAMBAPRINTERSTATUS,
675                         apiManager.enableSambaPrintShare(command.equals(OnOffType.ON) || command.equals(UpDownType.UP)
676                                 || command.equals(OpenClosedType.OPEN)));
677             } catch (FreeboxException e) {
678                 logCommandException(e, channelUID, command);
679                 fetchSambaConfig();
680             }
681         } else {
682             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
683                     channelUID.getId());
684         }
685     }
686
687     private void reboot(ChannelUID channelUID, Command command) {
688         if (command.equals(OnOffType.ON) || command.equals(UpDownType.UP) || command.equals(OpenClosedType.OPEN)) {
689             try {
690                 apiManager.reboot();
691             } catch (FreeboxException e) {
692                 logCommandException(e, channelUID, command);
693             }
694         } else {
695             logger.debug("Thing {}: invalid command {} from channel {}", getThing().getUID(), command,
696                     channelUID.getId());
697         }
698     }
699
700     private void updateChannelStringState(String channel, String state) {
701         updateState(new ChannelUID(getThing().getUID(), channel), new StringType(state));
702     }
703
704     private void updateChannelSwitchState(String channel, boolean state) {
705         updateState(new ChannelUID(getThing().getUID(), channel), state ? OnOffType.ON : OnOffType.OFF);
706     }
707
708     private void updateChannelDecimalState(String channel, int state) {
709         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
710     }
711
712     private void updateChannelDecimalState(String channel, long state) {
713         updateState(new ChannelUID(getThing().getUID(), channel), new DecimalType(state));
714     }
715
716     public void logCommandException(FreeboxException e, ChannelUID channelUID, Command command) {
717         if (e.isMissingRights()) {
718             logger.debug("Thing {}: missing right {} while handling command {} from channel {}", getThing().getUID(),
719                     e.getResponse().getMissingRight(), command, channelUID.getId());
720         } else {
721             logger.debug("Thing {}: error while handling command {} from channel {}", getThing().getUID(), command,
722                     channelUID.getId(), e);
723         }
724     }
725 }