]> git.basschouten.com Git - openhab-addons.git/blob
4cd65f2fa117ffc53299ad47acc997eb2bab224e
[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.unifi.internal.handler;
14
15 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_ENABLE;
16 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_ESSID;
17 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_GUEST_CLIENTS;
18 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PASSPHRASE;
19 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_QRCODE_ENCODING;
20 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_SECURITY;
21 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_SITE;
22 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WIRELESS_CLIENTS;
23 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WLANBAND;
24 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WPAENC;
25 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WPAMODE;
26
27 import java.util.function.Function;
28
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.openhab.binding.unifi.internal.UniFiWlanThingConfig;
32 import org.openhab.binding.unifi.internal.api.UniFiController;
33 import org.openhab.binding.unifi.internal.api.UniFiException;
34 import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
35 import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
36 import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
37 import org.openhab.binding.unifi.internal.api.dto.UniFiWirelessClient;
38 import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
39 import org.openhab.core.library.types.DecimalType;
40 import org.openhab.core.library.types.OnOffType;
41 import org.openhab.core.library.types.StringType;
42 import org.openhab.core.thing.ChannelUID;
43 import org.openhab.core.thing.Thing;
44 import org.openhab.core.thing.ThingStatus;
45 import org.openhab.core.thing.ThingStatusDetail;
46 import org.openhab.core.types.Command;
47 import org.openhab.core.types.State;
48 import org.openhab.core.types.UnDefType;
49
50 /**
51  *
52  * @author Hilbrand Bouwkamp - Initial contribution
53  */
54 @NonNullByDefault
55 public class UniFiWlanThingHandler extends UniFiBaseThingHandler<UniFiWlan, UniFiWlanThingConfig> {
56
57     private UniFiWlanThingConfig config = new UniFiWlanThingConfig();
58
59     public UniFiWlanThingHandler(final Thing thing) {
60         super(thing);
61     }
62
63     @Override
64     protected boolean initialize(final UniFiWlanThingConfig config) {
65         this.config = config;
66
67         if (!config.isValid()) {
68             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
69                     "@text/error.thing.wlan.offline.configuration_error");
70             return false;
71         }
72         return true;
73     }
74
75     @Override
76     protected @Nullable UniFiWlan getEntity(final UniFiControllerCache cache) {
77         return cache.getWlan(config.getWlanId());
78     }
79
80     @Override
81     protected State getChannelState(final UniFiWlan wlan, final String channelId) {
82         final State state;
83
84         switch (channelId) {
85             case CHANNEL_ENABLE:
86                 state = OnOffType.from(wlan.isEnabled());
87                 break;
88             case CHANNEL_ESSID:
89                 state = StringType.valueOf(wlan.getName());
90                 break;
91             case CHANNEL_SITE:
92                 final UniFiSite site = wlan.getSite();
93                 if (site != null && site.getDescription() != null && !site.getDescription().isBlank()) {
94                     state = StringType.valueOf(site.getDescription());
95                 } else {
96                     state = UnDefType.UNDEF;
97                 }
98                 break;
99             case CHANNEL_WIRELESS_CLIENTS:
100                 state = countClients(wlan, c -> true);
101                 break;
102             case CHANNEL_GUEST_CLIENTS:
103                 state = countClients(wlan, c -> c.isGuest());
104                 break;
105             case CHANNEL_SECURITY:
106                 state = StringType.valueOf(wlan.getSecurity());
107                 break;
108             case CHANNEL_WLANBAND:
109                 state = StringType.valueOf(wlan.getWlanBand());
110                 break;
111             case CHANNEL_WPAENC:
112                 state = StringType.valueOf(wlan.getWpaEnc());
113                 break;
114             case CHANNEL_WPAMODE:
115                 state = StringType.valueOf(wlan.getWpaMode());
116                 break;
117             case CHANNEL_PASSPHRASE:
118                 state = StringType.valueOf(wlan.getXPassphrase());
119                 break;
120             case CHANNEL_QRCODE_ENCODING:
121                 state = qrcodeEncoding(wlan);
122                 break;
123             default:
124                 // Unsupported channel; nothing to update
125                 state = UnDefType.NULL;
126         }
127         return state;
128     }
129
130     private static State countClients(final UniFiWlan wlan, final Function<UniFiClient, Boolean> filter) {
131         final UniFiSite site = wlan.getSite();
132         return new DecimalType(site.getCache().countClients(site, c -> c instanceof UniFiWirelessClient
133                 && wlan.getName().equals(((UniFiWirelessClient) c).getEssid()) && filter.apply(c)));
134     }
135
136     /**
137      * Returns a MERCARD like notation of the Wi-Fi access code. Format:
138      * <code>WIFI:S:&lt;SSID>;T:WPA|blank;P:&lt;password>;;</code>
139      *
140      * @param wlan wlan UniFi entity object containing the data
141      * @return MERCARD like Wi-Fi access format
142      * @see https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11
143      */
144     private static State qrcodeEncoding(final UniFiWlan wlan) {
145         final String name = encode(wlan.getName());
146         final String xPassphrase = wlan.getXPassphrase();
147         final boolean nopass = xPassphrase == null || xPassphrase.isBlank();
148         final String mode = nopass ? "nopass" : "WPA";
149         final String hidden = wlan.isHideSsid() ? "H:true" : "";
150         final String passcode = nopass ? "" : "P:" + encode(xPassphrase);
151
152         return StringType.valueOf(String.format("WIFI:S:%s;T:%s;%s;%s;", name, mode, passcode, hidden));
153     }
154
155     private static String encode(final @Nullable String value) {
156         return value == null ? "" : value.replaceAll("([\\;,\":])", "\\\\$1");
157     }
158
159     @Override
160     protected boolean handleCommand(final UniFiController controller, final UniFiWlan entity,
161             final ChannelUID channelUID, final Command command) throws UniFiException {
162         final String channelID = channelUID.getId();
163
164         if (CHANNEL_ENABLE.equals(channelID) && command instanceof OnOffType) {
165             controller.enableWifi(entity, OnOffType.ON == command);
166             return true;
167         }
168         return false;
169     }
170 }