]> git.basschouten.com Git - openhab-addons.git/blob
da3d31f046786cb35d0fc4fadb7b1c99b57fde67
[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.Predicate;
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  * The {@link UniFiWlanThingHandler} is responsible for handling commands and status updates for a wireless network.
52  *
53  * @author Hilbrand Bouwkamp - Initial contribution
54  */
55 @NonNullByDefault
56 public class UniFiWlanThingHandler extends UniFiBaseThingHandler<UniFiWlan, UniFiWlanThingConfig> {
57
58     private UniFiWlanThingConfig config = new UniFiWlanThingConfig();
59
60     public UniFiWlanThingHandler(final Thing thing) {
61         super(thing);
62     }
63
64     @Override
65     protected boolean initialize(final UniFiWlanThingConfig config) {
66         this.config = config;
67
68         if (!config.isValid()) {
69             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
70                     "@text/error.thing.wlan.offline.configuration_error");
71             return false;
72         }
73         return true;
74     }
75
76     @Override
77     protected @Nullable UniFiWlan getEntity(final UniFiControllerCache cache) {
78         return cache.getWlan(config.getWlanId());
79     }
80
81     @Override
82     protected State getChannelState(final UniFiWlan wlan, final String channelId) {
83         final State state;
84
85         switch (channelId) {
86             case CHANNEL_ENABLE:
87                 state = OnOffType.from(wlan.isEnabled());
88                 break;
89             case CHANNEL_ESSID:
90                 state = StringType.valueOf(wlan.getName());
91                 break;
92             case CHANNEL_SITE:
93                 final UniFiSite site = wlan.getSite();
94                 if (site != null && site.getDescription() != null && !site.getDescription().isBlank()) {
95                     state = StringType.valueOf(site.getDescription());
96                 } else {
97                     state = UnDefType.UNDEF;
98                 }
99                 break;
100             case CHANNEL_WIRELESS_CLIENTS:
101                 state = countClients(wlan, c -> true);
102                 break;
103             case CHANNEL_GUEST_CLIENTS:
104                 state = countClients(wlan, c -> c.isGuest());
105                 break;
106             case CHANNEL_SECURITY:
107                 state = StringType.valueOf(wlan.getSecurity());
108                 break;
109             case CHANNEL_WLANBAND:
110                 state = StringType.valueOf(wlan.getWlanBand());
111                 break;
112             case CHANNEL_WPAENC:
113                 state = StringType.valueOf(wlan.getWpaEnc());
114                 break;
115             case CHANNEL_WPAMODE:
116                 state = StringType.valueOf(wlan.getWpaMode());
117                 break;
118             case CHANNEL_PASSPHRASE:
119                 state = StringType.valueOf(wlan.getXPassphrase());
120                 break;
121             case CHANNEL_QRCODE_ENCODING:
122                 state = qrcodeEncoding(wlan);
123                 break;
124             default:
125                 // Unsupported channel; nothing to update
126                 state = UnDefType.NULL;
127         }
128         return state;
129     }
130
131     private static State countClients(final UniFiWlan wlan, final Predicate<UniFiClient> filter) {
132         final UniFiSite site = wlan.getSite();
133
134         if (site == null) {
135             return UnDefType.UNDEF;
136         } else {
137             return new DecimalType(site.getCache().countClients(site,
138                     c -> c instanceof UniFiWirelessClient wirelessClient
139                             && (wlan.getName() != null && wlan.getName().equals(wirelessClient.getEssid()))
140                             && filter.test(c)));
141         }
142     }
143
144     /**
145      * Returns a MERCARD like notation of the Wi-Fi access code. Format:
146      * <code>WIFI:S:&lt;SSID>;T:WPA|blank;P:&lt;password>;;</code>
147      *
148      * @param wlan wlan UniFi entity object containing the data
149      * @return MERCARD like Wi-Fi access format
150      * @see https://github.com/zxing/zxing/wiki/Barcode-Contents#wi-fi-network-config-android-ios-11
151      */
152     private static State qrcodeEncoding(final UniFiWlan wlan) {
153         final String name = encode(wlan.getName());
154         final String xPassphrase = wlan.getXPassphrase();
155         final boolean nopass = xPassphrase == null || xPassphrase.isBlank();
156         final String mode = nopass ? "nopass" : "WPA";
157         final String hidden = wlan.isHideSsid() ? "H:true" : "";
158         final String passcode = nopass ? "" : "P:" + encode(xPassphrase);
159
160         return StringType.valueOf(String.format("WIFI:S:%s;T:%s;%s;%s;", name, mode, passcode, hidden));
161     }
162
163     private static String encode(final @Nullable String value) {
164         return value == null ? "" : value.replaceAll("([\\;,\":])", "\\\\$1");
165     }
166
167     @Override
168     protected boolean handleCommand(final UniFiController controller, final UniFiWlan entity,
169             final ChannelUID channelUID, final Command command) throws UniFiException {
170         final String channelID = channelUID.getId();
171
172         if (CHANNEL_ENABLE.equals(channelID) && command instanceof OnOffType && entity.getSite() != null) {
173             controller.enableWifi(entity, OnOffType.ON == command);
174             return true;
175         }
176         return false;
177     }
178 }