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