Skip to content

Commit 5ef6840

Browse files
authored
[unifi] Add network thing (#18335)
Signed-off-by: Thomas Lauterbach <[email protected]>
1 parent cde8814 commit 5ef6840

15 files changed

+490
-3
lines changed

bundles/org.openhab.binding.unifi/README.md

+20
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This binding integrates with [Ubiquiti UniFi Networks](https://www.ubnt.com/prod
1111
- `wiredClient` - A wired client connected to the UniFi network
1212
- `poePort` - A PoE (Power over Ethernet) port on a UniFi switch
1313
- `accessPoint` - An access point managed by the UniFi controller software
14+
- `network` - A network managed by the UniFi controller software.
1415

1516
## Discovery
1617

@@ -114,6 +115,14 @@ The following table describes the `accessPoint` configuration parameters:
114115
| mac | The MAC address of the access point | Required | - |
115116
| site | The site where the access point should be found | Optional | - |
116117

118+
### `network`
119+
120+
The following table describes the `network` configuration parameters:
121+
122+
| Parameter | Description | Config | Default |
123+
| ------------ | -------------------------------------------------------------|--------- | ------- |
124+
| nid | The id of the network | Required | - |
125+
117126
## Channels
118127

119128
### `site`
@@ -252,6 +261,17 @@ The `accessPoint` information that is retrieved is available as these channels:
252261
| experience | Number:Dimensionless | The average health indication of the connected clients | Read |
253262
| led | Switch | Switch the LED on or off | Read, Write |
254263

264+
### `network`
265+
266+
The `network` information that is retrieved is available as these channels:
267+
268+
| Channel ID | Item Type | Description | Permissions |
269+
|-----------------|-----------|---------------------------------------------------------------------------------|-------------|
270+
| enable | Switch | Enable status of the network | Read, Write |
271+
| totalClients | Number | Total number of clients connected | Read |
272+
| site | String | UniFi Site the client is associated with | Read |
273+
| purpose | String | Purpose of the network (e.g. Corporate, Guest, WAN, VPN, VLAN Only) | Read |
274+
255275
## Rule Actions
256276

257277
As an alternative to using the `guestVoucher` and `guestVouchersGenerate` channels on the `site` thing, it is possible to use rule actions on the thing to generate, revoke and list guest vouchers.

bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,18 @@ public final class UniFiBindingConstants {
3434
// List of all Thing Types
3535
public static final ThingTypeUID THING_TYPE_CONTROLLER = new ThingTypeUID(BINDING_ID, "controller");
3636
public static final ThingTypeUID THING_TYPE_SITE = new ThingTypeUID(BINDING_ID, "site");
37+
public static final ThingTypeUID THING_TYPE_NETWORK = new ThingTypeUID(BINDING_ID, "network");
3738
public static final ThingTypeUID THING_TYPE_WLAN = new ThingTypeUID(BINDING_ID, "wlan");
3839
public static final ThingTypeUID THING_TYPE_WIRED_CLIENT = new ThingTypeUID(BINDING_ID, "wiredClient");
3940
public static final ThingTypeUID THING_TYPE_WIRELESS_CLIENT = new ThingTypeUID(BINDING_ID, "wirelessClient");
4041
public static final ThingTypeUID THING_TYPE_POE_PORT = new ThingTypeUID(BINDING_ID, "poePort");
4142
public static final ThingTypeUID THING_TYPE_ACCESS_POINT = new ThingTypeUID(BINDING_ID, "accessPoint");
4243
public static final Set<ThingTypeUID> ALL_THING_TYPE_SUPPORTED = Set.of(THING_TYPE_CONTROLLER, THING_TYPE_SITE,
44+
THING_TYPE_NETWORK, THING_TYPE_WLAN, THING_TYPE_WIRED_CLIENT, THING_TYPE_WIRELESS_CLIENT,
45+
THING_TYPE_POE_PORT, THING_TYPE_ACCESS_POINT);
46+
public static final Set<ThingTypeUID> THING_TYPE_SUPPORTED = Set.of(THING_TYPE_SITE, THING_TYPE_NETWORK,
4347
THING_TYPE_WLAN, THING_TYPE_WIRED_CLIENT, THING_TYPE_WIRELESS_CLIENT, THING_TYPE_POE_PORT,
4448
THING_TYPE_ACCESS_POINT);
45-
public static final Set<ThingTypeUID> THING_TYPE_SUPPORTED = Set.of(THING_TYPE_SITE, THING_TYPE_WLAN,
46-
THING_TYPE_WIRED_CLIENT, THING_TYPE_WIRELESS_CLIENT, THING_TYPE_POE_PORT, THING_TYPE_ACCESS_POINT);
4749

4850
// List of site channels
4951
public static final String CHANNEL_TOTAL_CLIENTS = "totalClients";
@@ -53,6 +55,9 @@ public final class UniFiBindingConstants {
5355
public static final String CHANNEL_GUEST_VOUCHER = "guestVoucher";
5456
public static final String CHANNEL_GUEST_VOUCHERS_GENERATE = "guestVouchersGenerate";
5557

58+
// List of network channels
59+
public static final String CHANNEL_PURPOSE = "purpose";
60+
5661
// List of wlan channels
5762
public static final String CHANNEL_SECURITY = "security";
5863
public static final String CHANNEL_WLANBAND = "wlanBand";
@@ -112,6 +117,7 @@ public final class UniFiBindingConstants {
112117
public static final String PARAMETER_CID = "cid";
113118
public static final String PARAMETER_SID = "sid";
114119
public static final String PARAMETER_WID = "wid";
120+
public static final String PARAMETER_NID = "nid";
115121
public static final String PARAMETER_VOUCHER_COUNT = "voucherCount";
116122
public static final String PARAMETER_VOUCHER_EXPIRATION = "voucherExpiration";
117123
public static final String PARAMETER_VOUCHER_USERS = "voucherUsers";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2010-2025 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;
14+
15+
import org.eclipse.jdt.annotation.NonNullByDefault;
16+
import org.openhab.binding.unifi.internal.handler.UniFiNetworkThingHandler;
17+
18+
/**
19+
* The {@link UniFiNetworkThingConfig} encapsulates all the configuration options for an instance of the
20+
* {@link UniFiNetworkThingHandler}.
21+
*
22+
* @author Thomas Lauterbach - Initial contribution
23+
*/
24+
@NonNullByDefault
25+
@SuppressWarnings("unused")
26+
public class UniFiNetworkThingConfig {
27+
28+
private String nid = "";
29+
30+
public String getNetworkId() {
31+
return nid;
32+
}
33+
34+
private void setNetworkId(final String nid) {
35+
// method to avoid auto format mark the field as final
36+
this.nid = nid;
37+
}
38+
39+
public boolean isValid() {
40+
return !nid.isBlank();
41+
}
42+
43+
@Override
44+
public String toString() {
45+
return String.format("UniFiNetworkThingConfig{nid: '%s'}", nid);
46+
}
47+
}

bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiThingHandlerFactory.java

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.openhab.binding.unifi.internal.handler.UniFiAccessPointThingHandler;
2222
import org.openhab.binding.unifi.internal.handler.UniFiClientThingHandler;
2323
import org.openhab.binding.unifi.internal.handler.UniFiControllerThingHandler;
24+
import org.openhab.binding.unifi.internal.handler.UniFiNetworkThingHandler;
2425
import org.openhab.binding.unifi.internal.handler.UniFiPoePortThingHandler;
2526
import org.openhab.binding.unifi.internal.handler.UniFiSiteThingHandler;
2627
import org.openhab.binding.unifi.internal.handler.UniFiWlanThingHandler;
@@ -82,6 +83,8 @@ public boolean supportsThingType(final ThingTypeUID thingTypeUID) {
8283
return new UniFiControllerThingHandler((Bridge) thing, httpClient);
8384
} else if (THING_TYPE_SITE.equals(thingTypeUID)) {
8485
return new UniFiSiteThingHandler(thing);
86+
} else if (THING_TYPE_NETWORK.equals(thingTypeUID)) {
87+
return new UniFiNetworkThingHandler(thing);
8588
} else if (THING_TYPE_WLAN.equals(thingTypeUID)) {
8689
return new UniFiWlanThingHandler(thing);
8790
} else if (THING_TYPE_WIRELESS_CLIENT.equals(thingTypeUID) || THING_TYPE_WIRED_CLIENT.equals(thingTypeUID)) {

bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiController.java

+28-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import java.util.Collection;
1616
import java.util.List;
17+
import java.util.Map;
1718

1819
import org.eclipse.jdt.annotation.NonNullByDefault;
1920
import org.eclipse.jdt.annotation.Nullable;
@@ -23,6 +24,7 @@
2324
import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonObject;
2425
import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
2526
import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
27+
import org.openhab.binding.unifi.internal.api.dto.UniFiNetwork;
2628
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
2729
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
2830
import org.openhab.binding.unifi.internal.api.dto.UniFiUnknownClient;
@@ -34,6 +36,7 @@
3436
import org.openhab.binding.unifi.internal.api.util.UniFiClientDeserializer;
3537
import org.openhab.binding.unifi.internal.api.util.UniFiClientInstanceCreator;
3638
import org.openhab.binding.unifi.internal.api.util.UniFiDeviceInstanceCreator;
39+
import org.openhab.binding.unifi.internal.api.util.UniFiNetworkInstanceCreator;
3740
import org.openhab.binding.unifi.internal.api.util.UniFiSiteInstanceCreator;
3841
import org.openhab.binding.unifi.internal.api.util.UniFiVoucherInstanceCreator;
3942
import org.openhab.binding.unifi.internal.api.util.UniFiWlanInstanceCreator;
@@ -87,12 +90,14 @@ public UniFiController(final HttpClient httpClient, final String host, final int
8790
this.timeoutSeconds = timeoutSeconds;
8891
this.csrfToken = "";
8992
final UniFiSiteInstanceCreator siteInstanceCreator = new UniFiSiteInstanceCreator(cache);
93+
final UniFiNetworkInstanceCreator networkInstanceCreator = new UniFiNetworkInstanceCreator(cache);
9094
final UniFiWlanInstanceCreator wlanInstanceCreator = new UniFiWlanInstanceCreator(cache);
9195
final UniFiDeviceInstanceCreator deviceInstanceCreator = new UniFiDeviceInstanceCreator(cache);
9296
final UniFiClientInstanceCreator clientInstanceCreator = new UniFiClientInstanceCreator(cache);
9397
final UniFiVoucherInstanceCreator voucherInstanceCreator = new UniFiVoucherInstanceCreator(cache);
9498
this.gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
9599
.registerTypeAdapter(UniFiSite.class, siteInstanceCreator)
100+
.registerTypeAdapter(UniFiNetwork.class, networkInstanceCreator)
96101
.registerTypeAdapter(UniFiWlan.class, wlanInstanceCreator)
97102
.registerTypeAdapter(UniFiDevice.class, deviceInstanceCreator)
98103
.registerTypeAdapter(UniFiClient.class, new UniFiClientDeserializer())
@@ -149,6 +154,7 @@ public void refresh() throws UniFiException {
149154
synchronized (this) {
150155
cache.clear();
151156
final Collection<UniFiSite> sites = refreshSites();
157+
refreshNetworks(sites);
152158
refreshWlans(sites);
153159
refreshDevices(sites);
154160
refreshClients(sites);
@@ -208,8 +214,17 @@ public void poePowerCycle(final UniFiDevice device, final Integer portIdx) throw
208214
refresh();
209215
}
210216

217+
public void enableNetwork(final UniFiNetwork network, final boolean enable) throws UniFiException {
218+
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.PUT, gson);
219+
req.setAPIPath(String.format("/api/s/%s/group/networkconf", network.getSite().getName()));
220+
req.setBodyParameter("data", Map.of("enabled", enable));
221+
req.setBodyParameter("id", new String[] { network.getId() });
222+
executeRequest(req);
223+
refresh();
224+
}
225+
211226
public void enableWifi(final UniFiWlan wlan, final boolean enable) throws UniFiException {
212-
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.PUT, poeGson);
227+
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.PUT, gson);
213228
req.setAPIPath(String.format("/api/s/%s/rest/wlanconf/%s", wlan.getSite().getName(), wlan.getId()));
214229
req.setBodyParameter("_id", wlan.getId());
215230
req.setBodyParameter("enabled", enable ? "true" : "false");
@@ -309,6 +324,18 @@ private List<UniFiSite> refreshSites() throws UniFiException {
309324
return cache.setSites(executeRequest(req));
310325
}
311326

327+
private void refreshNetworks(final Collection<UniFiSite> sites) throws UniFiException {
328+
for (final UniFiSite site : sites) {
329+
cache.putNetworks(getNetworks(site));
330+
}
331+
}
332+
333+
private UniFiNetwork @Nullable [] getNetworks(final UniFiSite site) throws UniFiException {
334+
final UniFiControllerRequest<UniFiNetwork[]> req = newRequest(UniFiNetwork[].class, HttpMethod.GET, gson);
335+
req.setAPIPath(String.format("/api/s/%s/rest/networkconf", site.getName()));
336+
return executeRequest(req);
337+
}
338+
312339
private void refreshWlans(final Collection<UniFiSite> sites) throws UniFiException {
313340
for (final UniFiSite site : sites) {
314341
cache.putWlans(getWlans(site));

bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/cache/UniFiControllerCache.java

+17
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.eclipse.jdt.annotation.Nullable;
2626
import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
2727
import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
28+
import org.openhab.binding.unifi.internal.api.dto.UniFiNetwork;
2829
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
2930
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
3031
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
@@ -46,6 +47,7 @@ public class UniFiControllerCache {
4647
private final Logger logger = LoggerFactory.getLogger(UniFiControllerCache.class);
4748

4849
private final UniFiSiteCache sitesCache = new UniFiSiteCache();
50+
private final UniFiNetworkCache networksCache = new UniFiNetworkCache();
4951
private final UniFiWlanCache wlansCache = new UniFiWlanCache();
5052
private final UniFiDeviceCache devicesCache = new UniFiDeviceCache();
5153
private final UniFiClientCache clientsCache = new UniFiClientCache();
@@ -55,6 +57,7 @@ public class UniFiControllerCache {
5557

5658
public void clear() {
5759
sitesCache.clear();
60+
networksCache.clear();
5861
wlansCache.clear();
5962
devicesCache.clear();
6063
clientsCache.clear();
@@ -77,6 +80,20 @@ public Collection<UniFiSite> getSites() {
7780
return sitesCache.values();
7881
}
7982

83+
// Networks Cache
84+
85+
public void putNetworks(final UniFiNetwork @Nullable [] networks) {
86+
networksCache.putAll(networks);
87+
}
88+
89+
public @Nullable UniFiNetwork getNetwork(@Nullable final String id) {
90+
return networksCache.get(id);
91+
}
92+
93+
public Collection<UniFiNetwork> getNetworks() {
94+
return networksCache.values();
95+
}
96+
8097
// Wlans Cache
8198

8299
public void putWlans(final UniFiWlan @Nullable [] wlans) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2010-2025 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.cache;
14+
15+
import static org.openhab.binding.unifi.internal.api.cache.UniFiCache.Prefix.ID;
16+
import static org.openhab.binding.unifi.internal.api.cache.UniFiCache.Prefix.NAME;
17+
18+
import org.eclipse.jdt.annotation.NonNullByDefault;
19+
import org.eclipse.jdt.annotation.Nullable;
20+
import org.openhab.binding.unifi.internal.api.dto.UniFiNetwork;
21+
22+
/**
23+
* The {@link UniFiNetworkCache} is a specific implementation of {@link UniFiCache} for the purpose of caching
24+
* {@link UniFiNetwork} instances.
25+
*
26+
* The cache uses the following prefixes: <code>id</code>, <code>name</code>
27+
*
28+
* @author Thomas Lauterbach - Initial contribution
29+
*/
30+
@NonNullByDefault
31+
class UniFiNetworkCache extends UniFiCache<UniFiNetwork> {
32+
33+
public UniFiNetworkCache() {
34+
super(ID, NAME);
35+
}
36+
37+
@Override
38+
protected @Nullable String getSuffix(final UniFiNetwork network, final Prefix prefix) {
39+
switch (prefix) {
40+
case ID:
41+
return network.getId();
42+
case NAME:
43+
return network.getName();
44+
default:
45+
return null;
46+
}
47+
}
48+
}

bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiClient.java

+6
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ public abstract class UniFiClient implements HasId {
6161
@SerializedName("satisfaction")
6262
private Integer experience;
6363

64+
private String networkId;
65+
6466
protected UniFiClient(final UniFiControllerCache cache) {
6567
this.cache = cache;
6668
}
@@ -122,6 +124,10 @@ public Integer getExperience() {
122124
return experience;
123125
}
124126

127+
public UniFiNetwork getNetwork() {
128+
return cache.getNetwork(networkId);
129+
}
130+
125131
@Override
126132
public String toString() {
127133
return String.format(

0 commit comments

Comments
 (0)