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