]> git.basschouten.com Git - openhab-addons.git/blob
6dbdc35c869262c488bbf4db20897f2ee5981b4e
[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.unifi.internal.api.model;
14
15 import java.util.Collection;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jdt.annotation.Nullable;
19 import org.eclipse.jetty.client.HttpClient;
20 import org.openhab.binding.unifi.internal.api.UniFiException;
21 import org.openhab.binding.unifi.internal.api.UniFiExpiredSessionException;
22 import org.openhab.binding.unifi.internal.api.UniFiNotAuthorizedException;
23 import org.openhab.binding.unifi.internal.api.cache.UniFiClientCache;
24 import org.openhab.binding.unifi.internal.api.cache.UniFiDeviceCache;
25 import org.openhab.binding.unifi.internal.api.cache.UniFiSiteCache;
26 import org.openhab.binding.unifi.internal.api.util.UniFiClientDeserializer;
27 import org.openhab.binding.unifi.internal.api.util.UniFiClientInstanceCreator;
28 import org.openhab.binding.unifi.internal.api.util.UniFiDeviceInstanceCreator;
29 import org.openhab.binding.unifi.internal.api.util.UniFiSiteInstanceCreator;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import com.google.gson.FieldNamingPolicy;
34 import com.google.gson.Gson;
35 import com.google.gson.GsonBuilder;
36
37 /**
38  * The {@link UniFiController} is the main communication point with an external instance of the Ubiquiti Networks
39  * Controller Software.
40  *
41  * @author Matthew Bowman - Initial contribution
42  * @author Patrik Wimnell - Blocking / Unblocking client support
43  */
44 @NonNullByDefault
45 public class UniFiController {
46
47     private final Logger logger = LoggerFactory.getLogger(UniFiController.class);
48
49     private UniFiSiteCache sitesCache = new UniFiSiteCache();
50
51     private UniFiDeviceCache devicesCache = new UniFiDeviceCache();
52
53     private UniFiClientCache clientsCache = new UniFiClientCache();
54
55     private UniFiClientCache insightsCache = new UniFiClientCache();
56
57     private final HttpClient httpClient;
58
59     private final String host;
60
61     private final int port;
62
63     private final String username;
64
65     private final String password;
66
67     private final boolean unifios;
68
69     private String csrfToken;
70
71     private final Gson gson;
72
73     public UniFiController(HttpClient httpClient, String host, int port, String username, String password,
74             boolean unifios) {
75         this.httpClient = httpClient;
76         this.host = host;
77         this.port = port;
78         this.username = username;
79         this.password = password;
80         this.unifios = unifios;
81         this.csrfToken = "";
82         UniFiSiteInstanceCreator siteInstanceCreator = new UniFiSiteInstanceCreator(this);
83         UniFiDeviceInstanceCreator deviceInstanceCreator = new UniFiDeviceInstanceCreator(this);
84         UniFiClientInstanceCreator clientInstanceCreator = new UniFiClientInstanceCreator(this);
85         this.gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
86                 .registerTypeAdapter(UniFiSite.class, siteInstanceCreator)
87                 .registerTypeAdapter(UniFiDevice.class, deviceInstanceCreator)
88                 .registerTypeAdapter(UniFiClient.class, new UniFiClientDeserializer())
89                 .registerTypeAdapter(UniFiUnknownClient.class, clientInstanceCreator)
90                 .registerTypeAdapter(UniFiWiredClient.class, clientInstanceCreator)
91                 .registerTypeAdapter(UniFiWirelessClient.class, clientInstanceCreator).create();
92     }
93
94     // Public API
95
96     public void start() throws UniFiException {
97         login();
98     }
99
100     public void stop() throws UniFiException {
101         logout();
102     }
103
104     public void login() throws UniFiException {
105         csrfToken = "";
106
107         UniFiControllerRequest<Void> req = newRequest(Void.class);
108         req.setPath(unifios ? "/api/auth/login" : "/api/login");
109         req.setBodyParameter("username", username);
110         req.setBodyParameter("password", password);
111         // scurb: Changed strict = false to make blocking feature work
112         req.setBodyParameter("strict", false);
113         req.setBodyParameter("remember", false);
114         executeRequest(req);
115     }
116
117     public void logout() throws UniFiException {
118         csrfToken = "";
119         UniFiControllerRequest<Void> req = newRequest(Void.class);
120         req.setPath(unifios ? "/api/auth/logout" : "/logout");
121         executeRequest(req);
122     }
123
124     public void refresh() throws UniFiException {
125         synchronized (this) {
126             sitesCache = getSites();
127             devicesCache = getDevices();
128             clientsCache = getClients();
129             insightsCache = getInsights();
130         }
131     }
132
133     // Site API
134
135     public @Nullable UniFiSite getSite(@Nullable String id) {
136         UniFiSite site = null;
137         if (id != null && !id.isBlank()) {
138             synchronized (this) {
139                 site = sitesCache.get(id);
140             }
141             if (site == null) {
142                 logger.debug("Could not find a matching site for id = '{}'", id);
143             }
144         }
145         return site;
146     }
147
148     // Device API
149
150     public @Nullable UniFiDevice getDevice(@Nullable String id) {
151         UniFiDevice device = null;
152         if (id != null && !id.isBlank()) {
153             synchronized (this) {
154                 device = devicesCache.get(id);
155             }
156             if (device == null) {
157                 logger.debug("Could not find a matching device for id = '{}'", id);
158             }
159         }
160         return device;
161     }
162
163     // Client API
164
165     public @Nullable UniFiClient getClient(@Nullable String id) {
166         UniFiClient client = null;
167         if (id != null && !id.isBlank()) {
168             synchronized (this) {
169                 // mgb: first check active clients and fallback to insights if not found
170                 client = clientsCache.get(id);
171                 if (client == null) {
172                     client = insightsCache.get(id);
173                 }
174             }
175             if (client == null) {
176                 logger.debug("Could not find a matching client for id = {}", id);
177             }
178         }
179         return client;
180     }
181
182     protected void block(UniFiClient client, boolean blocked) throws UniFiException {
183         UniFiControllerRequest<Void> req = newRequest(Void.class);
184         req.setAPIPath("/api/s/" + client.getSite().getName() + "/cmd/stamgr");
185         req.setBodyParameter("cmd", blocked ? "block-sta" : "unblock-sta");
186         req.setBodyParameter("mac", client.getMac());
187         executeRequest(req);
188     }
189
190     protected void reconnect(UniFiClient client) throws UniFiException {
191         UniFiControllerRequest<Void> req = newRequest(Void.class);
192         req.setAPIPath("/api/s/" + client.getSite().getName() + "/cmd/stamgr");
193         req.setBodyParameter("cmd", "kick-sta");
194         req.setBodyParameter("mac", client.getMac());
195         executeRequest(req);
196     }
197
198     // Internal API
199
200     private <T> UniFiControllerRequest<T> newRequest(Class<T> responseType) {
201         return new UniFiControllerRequest<>(responseType, gson, httpClient, host, port, csrfToken, unifios);
202     }
203
204     private <T> @Nullable T executeRequest(UniFiControllerRequest<T> request) throws UniFiException {
205         T result;
206         try {
207             result = request.execute();
208             csrfToken = request.getCsrfToken();
209         } catch (UniFiExpiredSessionException e) {
210             login();
211             result = executeRequest(request);
212         } catch (UniFiNotAuthorizedException e) {
213             logger.warn("Not Authorized! Please make sure your controller credentials have administrator rights");
214             result = null;
215         }
216         return result;
217     }
218
219     private UniFiSiteCache getSites() throws UniFiException {
220         UniFiControllerRequest<UniFiSite[]> req = newRequest(UniFiSite[].class);
221         req.setAPIPath("/api/self/sites");
222         UniFiSite[] sites = executeRequest(req);
223         UniFiSiteCache cache = new UniFiSiteCache();
224         if (sites != null) {
225             logger.debug("Found {} UniFi Site(s): {}", sites.length, lazyFormatAsList(sites));
226             for (UniFiSite site : sites) {
227                 cache.put(site);
228             }
229         }
230         return cache;
231     }
232
233     private UniFiDeviceCache getDevices() throws UniFiException {
234         UniFiDeviceCache cache = new UniFiDeviceCache();
235         Collection<UniFiSite> sites = sitesCache.values();
236         for (UniFiSite site : sites) {
237             cache.putAll(getDevices(site));
238         }
239         return cache;
240     }
241
242     private UniFiDeviceCache getDevices(UniFiSite site) throws UniFiException {
243         UniFiControllerRequest<UniFiDevice[]> req = newRequest(UniFiDevice[].class);
244         req.setAPIPath("/api/s/" + site.getName() + "/stat/device");
245         UniFiDevice[] devices = executeRequest(req);
246         UniFiDeviceCache cache = new UniFiDeviceCache();
247         if (devices != null) {
248             logger.debug("Found {} UniFi Device(s): {}", devices.length, lazyFormatAsList(devices));
249             for (UniFiDevice device : devices) {
250                 cache.put(device);
251             }
252         }
253         return cache;
254     }
255
256     private UniFiClientCache getClients() throws UniFiException {
257         UniFiClientCache cache = new UniFiClientCache();
258         Collection<UniFiSite> sites = sitesCache.values();
259         for (UniFiSite site : sites) {
260             cache.putAll(getClients(site));
261         }
262         return cache;
263     }
264
265     private UniFiClientCache getClients(UniFiSite site) throws UniFiException {
266         UniFiControllerRequest<UniFiClient[]> req = newRequest(UniFiClient[].class);
267         req.setAPIPath("/api/s/" + site.getName() + "/stat/sta");
268         UniFiClient[] clients = executeRequest(req);
269         UniFiClientCache cache = new UniFiClientCache();
270         if (clients != null) {
271             logger.debug("Found {} UniFi Client(s): {}", clients.length, lazyFormatAsList(clients));
272             for (UniFiClient client : clients) {
273                 cache.put(client);
274             }
275         }
276         return cache;
277     }
278
279     private UniFiClientCache getInsights() throws UniFiException {
280         UniFiClientCache cache = new UniFiClientCache();
281         Collection<UniFiSite> sites = sitesCache.values();
282         for (UniFiSite site : sites) {
283             cache.putAll(getInsights(site));
284         }
285         return cache;
286     }
287
288     private UniFiClientCache getInsights(UniFiSite site) throws UniFiException {
289         UniFiControllerRequest<UniFiClient[]> req = newRequest(UniFiClient[].class);
290         req.setAPIPath("/api/s/" + site.getName() + "/stat/alluser");
291         req.setQueryParameter("within", 168); // scurb: Changed to 7 days.
292         UniFiClient[] clients = executeRequest(req);
293         UniFiClientCache cache = new UniFiClientCache();
294         if (clients != null) {
295             logger.debug("Found {} UniFi Insights(s): {}", clients.length, lazyFormatAsList(clients));
296             for (UniFiClient client : clients) {
297                 cache.put(client);
298             }
299         }
300         return cache;
301     }
302
303     private static Object lazyFormatAsList(Object[] arr) {
304         return new Object() {
305
306             @Override
307             public String toString() {
308                 String value = "";
309                 for (Object o : arr) {
310                     value += "\n - " + o.toString();
311                 }
312                 return value;
313             }
314         };
315     }
316 }