]> git.basschouten.com Git - openhab-addons.git/blob
560530c24c3b489cfd8fc216ea539b4e7fe4aa8d
[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.PARAMETER_CID;
16 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER_MAC_ADDRESS;
17 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER_PORT_NUMBER;
18 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER_SID;
19 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER_SITE;
20 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER_WID;
21 import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER_WIFI_NAME;
22
23 import java.util.Map;
24 import java.util.concurrent.TimeUnit;
25 import java.util.regex.Pattern;
26
27 import org.eclipse.jdt.annotation.NonNullByDefault;
28 import org.eclipse.jdt.annotation.Nullable;
29 import org.openhab.binding.unifi.internal.UniFiBindingConstants;
30 import org.openhab.binding.unifi.internal.api.UniFiController;
31 import org.openhab.binding.unifi.internal.api.UniFiException;
32 import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
33 import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
34 import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
35 import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
36 import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
37 import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
38 import org.openhab.core.config.discovery.AbstractDiscoveryService;
39 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
40 import org.openhab.core.config.discovery.DiscoveryService;
41 import org.openhab.core.thing.ThingUID;
42 import org.openhab.core.thing.binding.ThingHandler;
43 import org.openhab.core.thing.binding.ThingHandlerService;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * Discovery service for detecting things connected to a UniFi controller.
49  *
50  * @author Hilbrand Bouwkamp - Initial contribution
51  */
52 @NonNullByDefault
53 public class UniFiThingDiscoveryService extends AbstractDiscoveryService
54         implements ThingHandlerService, DiscoveryService {
55
56     /**
57      * Timeout for discovery time.
58      */
59     private static final int UNIFI_DISCOVERY_TIMEOUT_SECONDS = 30;
60     private static final long TTL_SECONDS = TimeUnit.MINUTES.toSeconds(5);
61     private static final int THING_ID_LENGTH = 8;
62     private static final Pattern DEFAULT_PORTNAME = Pattern.compile("Port \\d+");
63
64     private final Logger logger = LoggerFactory.getLogger(UniFiThingDiscoveryService.class);
65
66     private @Nullable UniFiControllerThingHandler bridgeHandler;
67
68     public UniFiThingDiscoveryService() {
69         super(UniFiBindingConstants.THING_TYPE_SUPPORTED, UNIFI_DISCOVERY_TIMEOUT_SECONDS, false);
70     }
71
72     @Override
73     public void deactivate() {
74         super.deactivate();
75     }
76
77     @Override
78     public void setThingHandler(final ThingHandler handler) {
79         if (handler instanceof UniFiControllerThingHandler controllerThingHandler) {
80             bridgeHandler = controllerThingHandler;
81         }
82     }
83
84     @Override
85     public @Nullable ThingHandler getThingHandler() {
86         return bridgeHandler;
87     }
88
89     @Override
90     protected void startScan() {
91         removeOlderResults(getTimestampOfLastScan());
92         final UniFiControllerThingHandler bh = bridgeHandler;
93         if (bh == null) {
94             return;
95         }
96         final UniFiController controller = bh.getController();
97         if (controller == null) {
98             return;
99         }
100         try {
101             controller.refresh();
102             final UniFiControllerCache cache = controller.getCache();
103             final ThingUID bridgeUID = bh.getThing().getUID();
104
105             discoverSites(cache, bridgeUID);
106             discoverWlans(cache, bridgeUID);
107             discoverClients(cache, bridgeUID);
108             discoverPoePorts(cache, bridgeUID);
109         } catch (final UniFiException e) {
110             logger.debug("Exception during discovery of UniFi Things", e);
111         }
112     }
113
114     private void discoverSites(final UniFiControllerCache cache, final ThingUID bridgeUID) {
115         for (final UniFiSite site : cache.getSites()) {
116             final ThingUID thingUID = new ThingUID(UniFiBindingConstants.THING_TYPE_SITE, bridgeUID,
117                     stripIdShort(site.getId()));
118             final Map<String, Object> properties = Map.of(PARAMETER_SID, site.getId());
119
120             thingDiscovered(DiscoveryResultBuilder.create(thingUID).withThingType(UniFiBindingConstants.THING_TYPE_SITE)
121                     .withBridge(bridgeUID).withRepresentationProperty(PARAMETER_SID).withTTL(TTL_SECONDS)
122                     .withProperties(properties).withLabel(site.getName()).build());
123         }
124     }
125
126     private void discoverWlans(final UniFiControllerCache cache, final ThingUID bridgeUID) {
127         for (final UniFiWlan wlan : cache.getWlans()) {
128             final ThingUID thingUID = new ThingUID(UniFiBindingConstants.THING_TYPE_WLAN, bridgeUID,
129                     stripIdShort(wlan.getId()));
130             final String siteName = wlan.getSite() == null ? "" : wlan.getSite().getName();
131             final Map<String, Object> properties = Map.of(PARAMETER_WID, wlan.getId(), PARAMETER_SITE, siteName,
132                     PARAMETER_WIFI_NAME, wlan.getName());
133
134             thingDiscovered(DiscoveryResultBuilder.create(thingUID).withThingType(UniFiBindingConstants.THING_TYPE_WLAN)
135                     .withBridge(bridgeUID).withRepresentationProperty(PARAMETER_WID).withTTL(TTL_SECONDS)
136                     .withProperties(properties).withLabel(wlan.getName()).build());
137         }
138     }
139
140     private void discoverClients(final UniFiControllerCache cache, final ThingUID bridgeUID) {
141         for (final UniFiClient uc : cache.getClients()) {
142             final var thingTypeUID = uc.isWireless() ? UniFiBindingConstants.THING_TYPE_WIRELESS_CLIENT
143                     : UniFiBindingConstants.THING_TYPE_WIRED_CLIENT;
144             final ThingUID thingUID = new ThingUID(thingTypeUID, bridgeUID, stripIdShort(uc.getId()));
145             final Map<String, Object> properties = Map.of(PARAMETER_CID, uc.getMac(), PARAMETER_SITE,
146                     uc.getSite().getName());
147
148             thingDiscovered(DiscoveryResultBuilder.create(thingUID).withThingType(thingTypeUID).withBridge(bridgeUID)
149                     .withRepresentationProperty(PARAMETER_CID).withTTL(TTL_SECONDS).withProperties(properties)
150                     .withLabel(uc.getName()).build());
151         }
152     }
153
154     /**
155      * Shorten the id to make it a bit more comprehensible.
156      *
157      * @param id id to shorten.
158      * @return shortened id or if to short the original id
159      */
160     private static String stripIdShort(final String id) {
161         return id != null && id.length() > THING_ID_LENGTH ? id.substring(id.length() - THING_ID_LENGTH) : id;
162     }
163
164     private void discoverPoePorts(final UniFiControllerCache cache, final ThingUID bridgeUID) {
165         for (final UniFiSwitchPorts uc : cache.getSwitchPorts()) {
166             for (final UniFiPortTuple pt : uc.getPoePorts()) {
167                 final String deviceMac = pt.getDevice().getMac();
168                 final String id = deviceMac.replace(":", "") + "_" + pt.getPortIdx();
169                 final ThingUID thingUID = new ThingUID(UniFiBindingConstants.THING_TYPE_POE_PORT, bridgeUID, id);
170                 final Map<String, Object> properties = Map.of(PARAMETER_PORT_NUMBER, pt.getPortIdx(),
171                         PARAMETER_MAC_ADDRESS, deviceMac);
172
173                 thingDiscovered(DiscoveryResultBuilder.create(thingUID)
174                         .withThingType(UniFiBindingConstants.THING_TYPE_POE_PORT).withBridge(bridgeUID)
175                         .withTTL(TTL_SECONDS).withProperties(properties).withLabel(portName(pt)).build());
176             }
177         }
178     }
179
180     /**
181      * If the PoE port hasn't it's own name, but is named Port with a number the name is prefixed with the device name.
182      *
183      * @param pt port object
184      * @return label for the discovered PoE port
185      */
186     private @Nullable String portName(final UniFiPortTuple pt) {
187         final String portName = pt.getTable().getName();
188
189         return DEFAULT_PORTNAME.matcher(portName).find() ? pt.getDevice().getName() + " " + portName : portName;
190     }
191 }