[unifi] Guest wifi vouchers (#14284)
* guest voucher support Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
This commit is contained in:
parent
aa7580965e
commit
16f3a3e854
|
@ -114,11 +114,25 @@ The following table describes the `poePort` configuration parameters:
|
||||||
The `site` information that is retrieved is available as these channels:
|
The `site` information that is retrieved is available as these channels:
|
||||||
|
|
||||||
| Channel ID | Item Type | Description | Permissions |
|
| Channel ID | Item Type | Description | Permissions |
|
||||||
|-----------------|-----------|--------------------------------------|-------------|
|
|-----------------------|-----------|------------------------------------------------------------------------|-------------|
|
||||||
| totalClients | Number | Total number of clients connected | Read |
|
| totalClients | Number | Total number of clients connected | Read |
|
||||||
| wirelessClients | Number | Number of wireless clients connected | Read |
|
| wirelessClients | Number | Number of wireless clients connected | Read |
|
||||||
| wiredClients | Number | Number of wired clients connected | Read |
|
| wiredClients | Number | Number of wired clients connected | Read |
|
||||||
| guestClients | Number | Number of guest clients connected | Read |
|
| guestClients | Number | Number of guest clients connected | Read |
|
||||||
|
| guestVoucher | String | Guest voucher for access through the guest portal | Read |
|
||||||
|
| guestVouchersGenerate | String | Generate additional guest vouchers for access through the guest portal | Write |
|
||||||
|
|
||||||
|
The `guestVouchersGenerate` string channel is a command only channel that will trigger voucher creation.
|
||||||
|
It has configuration parameters to tailor the vouchers created:
|
||||||
|
|
||||||
|
| Parameter | Description | Config | Default |
|
||||||
|
| ------------------------ | --------------------------------------------------------------------------- |--------- | ------- |
|
||||||
|
| voucherCount | Number of vouchers to create | Optional | 1 |
|
||||||
|
| voucherExpiration | Minutes a voucher is valid after activation (default is 1 day) | Optional | 1440 |
|
||||||
|
| voucherUsers | Number of users for voucher, 0 for no limit | Optional | 1 |
|
||||||
|
| voucherUpLimit | Upload speed limit in kbps, no limit if not set | Optional | |
|
||||||
|
| voucherDownLimit | Download speed limit in kbps, no limit if not set | Optional | |
|
||||||
|
| voucherDataQuota | Data transfer quota in MB per user, no limit if not set | Optional | |
|
||||||
|
|
||||||
### `wlan`
|
### `wlan`
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.openhab.core.thing.ThingTypeUID;
|
||||||
* @author Matthew Bowman - Initial contribution
|
* @author Matthew Bowman - Initial contribution
|
||||||
* @author Patrik Wimnell - Blocking / Unblocking client support
|
* @author Patrik Wimnell - Blocking / Unblocking client support
|
||||||
* @author Hilbrand Bouwkamp - Added poePort
|
* @author Hilbrand Bouwkamp - Added poePort
|
||||||
|
* @author Mark Herwege - Added guest vouchers
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public final class UniFiBindingConstants {
|
public final class UniFiBindingConstants {
|
||||||
|
@ -47,6 +48,8 @@ public final class UniFiBindingConstants {
|
||||||
public static final String CHANNEL_WIRELESS_CLIENTS = "wirelessClients";
|
public static final String CHANNEL_WIRELESS_CLIENTS = "wirelessClients";
|
||||||
public static final String CHANNEL_WIRED_CLIENTS = "wiredClients";
|
public static final String CHANNEL_WIRED_CLIENTS = "wiredClients";
|
||||||
public static final String CHANNEL_GUEST_CLIENTS = "guestClients";
|
public static final String CHANNEL_GUEST_CLIENTS = "guestClients";
|
||||||
|
public static final String CHANNEL_GUEST_VOUCHER = "guestVoucher";
|
||||||
|
public static final String CHANNEL_GUEST_VOUCHERS_GENERATE = "guestVouchersGenerate";
|
||||||
|
|
||||||
// List of wlan channels
|
// List of wlan channels
|
||||||
public static final String CHANNEL_SECURITY = "security";
|
public static final String CHANNEL_SECURITY = "security";
|
||||||
|
@ -98,6 +101,12 @@ public final class UniFiBindingConstants {
|
||||||
public static final String PARAMETER_CID = "cid";
|
public static final String PARAMETER_CID = "cid";
|
||||||
public static final String PARAMETER_SID = "sid";
|
public static final String PARAMETER_SID = "sid";
|
||||||
public static final String PARAMETER_WID = "wid";
|
public static final String PARAMETER_WID = "wid";
|
||||||
|
public static final String PARAMETER_VOUCHER_COUNT = "voucherCount";
|
||||||
|
public static final String PARAMETER_VOUCHER_EXPIRATION = "voucherExpiration";
|
||||||
|
public static final String PARAMETER_VOUCHER_USERS = "voucherUsers";
|
||||||
|
public static final String PARAMETER_VOUCHER_UP_LIMIT = "voucherUpLimit";
|
||||||
|
public static final String PARAMETER_VOUCHER_DOWN_LIMIT = "voucherDownLimit";
|
||||||
|
public static final String PARAMETER_VOUCHER_DATA_QUOTA = "voucherDataQuota";
|
||||||
public static final String PARAMETER_PORT_NUMBER = "portNumber";
|
public static final String PARAMETER_PORT_NUMBER = "portNumber";
|
||||||
public static final String PARAMETER_MAC_ADDRESS = "macAddress";
|
public static final String PARAMETER_MAC_ADDRESS = "macAddress";
|
||||||
public static final String PARAMETER_WIFI_NAME = "wifi";
|
public static final String PARAMETER_WIFI_NAME = "wifi";
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.unifi.internal;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link UniFiVoucherChannelConfig} encapsulates all the configuration options for the guestVouchersGenerate
|
||||||
|
* channel on the UniFi Site thing.
|
||||||
|
*
|
||||||
|
* @author Mark Herwege - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class UniFiVoucherChannelConfig {
|
||||||
|
|
||||||
|
private int voucherCount;
|
||||||
|
private int voucherExpiration;
|
||||||
|
private int voucherUsers;
|
||||||
|
private @Nullable Integer voucherUpLimit;
|
||||||
|
private @Nullable Integer voucherDownLimit;
|
||||||
|
private @Nullable Integer voucherDataQuota;
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return voucherCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExpiration() {
|
||||||
|
return voucherExpiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getVoucherUsers() {
|
||||||
|
return voucherUsers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getUpLimit() {
|
||||||
|
return voucherUpLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getDownLimit() {
|
||||||
|
return voucherDownLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Integer getDataQuota() {
|
||||||
|
return voucherDataQuota;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiUnknownClient;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiUnknownClient;
|
||||||
|
import org.openhab.binding.unifi.internal.api.dto.UniFiVoucher;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWiredClient;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiWiredClient;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWirelessClient;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiWirelessClient;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
|
||||||
|
@ -34,6 +35,7 @@ import org.openhab.binding.unifi.internal.api.util.UniFiClientDeserializer;
|
||||||
import org.openhab.binding.unifi.internal.api.util.UniFiClientInstanceCreator;
|
import org.openhab.binding.unifi.internal.api.util.UniFiClientInstanceCreator;
|
||||||
import org.openhab.binding.unifi.internal.api.util.UniFiDeviceInstanceCreator;
|
import org.openhab.binding.unifi.internal.api.util.UniFiDeviceInstanceCreator;
|
||||||
import org.openhab.binding.unifi.internal.api.util.UniFiSiteInstanceCreator;
|
import org.openhab.binding.unifi.internal.api.util.UniFiSiteInstanceCreator;
|
||||||
|
import org.openhab.binding.unifi.internal.api.util.UniFiVoucherInstanceCreator;
|
||||||
import org.openhab.binding.unifi.internal.api.util.UniFiWlanInstanceCreator;
|
import org.openhab.binding.unifi.internal.api.util.UniFiWlanInstanceCreator;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -51,6 +53,7 @@ import com.google.gson.JsonObject;
|
||||||
* @author Patrik Wimnell - Blocking / Unblocking client support
|
* @author Patrik Wimnell - Blocking / Unblocking client support
|
||||||
* @author Jacob Laursen - Fix online/blocked channels (broken by UniFi Controller 5.12.35)
|
* @author Jacob Laursen - Fix online/blocked channels (broken by UniFi Controller 5.12.35)
|
||||||
* @author Hilbrand Bouwkamp - Added POEPort support, moved generic cache related code to cache object
|
* @author Hilbrand Bouwkamp - Added POEPort support, moved generic cache related code to cache object
|
||||||
|
* @author Mark Herwege - Added guest vouchers
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class UniFiController {
|
public class UniFiController {
|
||||||
|
@ -85,6 +88,7 @@ public class UniFiController {
|
||||||
final UniFiWlanInstanceCreator wlanInstanceCreator = new UniFiWlanInstanceCreator(cache);
|
final UniFiWlanInstanceCreator wlanInstanceCreator = new UniFiWlanInstanceCreator(cache);
|
||||||
final UniFiDeviceInstanceCreator deviceInstanceCreator = new UniFiDeviceInstanceCreator(cache);
|
final UniFiDeviceInstanceCreator deviceInstanceCreator = new UniFiDeviceInstanceCreator(cache);
|
||||||
final UniFiClientInstanceCreator clientInstanceCreator = new UniFiClientInstanceCreator(cache);
|
final UniFiClientInstanceCreator clientInstanceCreator = new UniFiClientInstanceCreator(cache);
|
||||||
|
final UniFiVoucherInstanceCreator voucherInstanceCreator = new UniFiVoucherInstanceCreator(cache);
|
||||||
this.gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
this.gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||||
.registerTypeAdapter(UniFiSite.class, siteInstanceCreator)
|
.registerTypeAdapter(UniFiSite.class, siteInstanceCreator)
|
||||||
.registerTypeAdapter(UniFiWlan.class, wlanInstanceCreator)
|
.registerTypeAdapter(UniFiWlan.class, wlanInstanceCreator)
|
||||||
|
@ -92,7 +96,8 @@ public class UniFiController {
|
||||||
.registerTypeAdapter(UniFiClient.class, new UniFiClientDeserializer())
|
.registerTypeAdapter(UniFiClient.class, new UniFiClientDeserializer())
|
||||||
.registerTypeAdapter(UniFiUnknownClient.class, clientInstanceCreator)
|
.registerTypeAdapter(UniFiUnknownClient.class, clientInstanceCreator)
|
||||||
.registerTypeAdapter(UniFiWiredClient.class, clientInstanceCreator)
|
.registerTypeAdapter(UniFiWiredClient.class, clientInstanceCreator)
|
||||||
.registerTypeAdapter(UniFiWirelessClient.class, clientInstanceCreator).create();
|
.registerTypeAdapter(UniFiWirelessClient.class, clientInstanceCreator)
|
||||||
|
.registerTypeAdapter(UniFiVoucher.class, voucherInstanceCreator).create();
|
||||||
this.poeGson = new GsonBuilder()
|
this.poeGson = new GsonBuilder()
|
||||||
.registerTypeAdapter(UnfiPortOverrideJsonObject.class, new UnfiPortOverrideJsonElementDeserializer())
|
.registerTypeAdapter(UnfiPortOverrideJsonObject.class, new UnfiPortOverrideJsonElementDeserializer())
|
||||||
.create();
|
.create();
|
||||||
|
@ -146,6 +151,7 @@ public class UniFiController {
|
||||||
refreshDevices(sites);
|
refreshDevices(sites);
|
||||||
refreshClients(sites);
|
refreshClients(sites);
|
||||||
refreshInsights(sites);
|
refreshInsights(sites);
|
||||||
|
refreshVouchers(sites);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,6 +215,27 @@ public class UniFiController {
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void generateGuestVouchers(final UniFiSite site, final int count, final int expiration, final int users,
|
||||||
|
@Nullable Integer upLimit, @Nullable Integer downLimit, @Nullable Integer dataQuota) throws UniFiException {
|
||||||
|
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.POST, gson);
|
||||||
|
req.setAPIPath(String.format("/api/s/%s/cmd/hotspot", site.getName()));
|
||||||
|
req.setBodyParameter("cmd", "create-voucher");
|
||||||
|
req.setBodyParameter("expire", expiration);
|
||||||
|
req.setBodyParameter("n", count);
|
||||||
|
req.setBodyParameter("quota", users);
|
||||||
|
if (upLimit != null) {
|
||||||
|
req.setBodyParameter("up", upLimit);
|
||||||
|
}
|
||||||
|
if (downLimit != null) {
|
||||||
|
req.setBodyParameter("down", downLimit);
|
||||||
|
}
|
||||||
|
if (dataQuota != null) {
|
||||||
|
req.setBodyParameter("bytes", dataQuota);
|
||||||
|
}
|
||||||
|
executeRequest(req);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
// Internal API
|
// Internal API
|
||||||
|
|
||||||
private <T> UniFiControllerRequest<T> newRequest(final Class<T> responseType, final HttpMethod method,
|
private <T> UniFiControllerRequest<T> newRequest(final Class<T> responseType, final HttpMethod method,
|
||||||
|
@ -284,6 +311,18 @@ public class UniFiController {
|
||||||
return executeRequest(req);
|
return executeRequest(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void refreshVouchers(final Collection<UniFiSite> sites) throws UniFiException {
|
||||||
|
for (final UniFiSite site : sites) {
|
||||||
|
cache.putVouchers(getVouchers(site));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private UniFiVoucher @Nullable [] getVouchers(final UniFiSite site) throws UniFiException {
|
||||||
|
final UniFiControllerRequest<UniFiVoucher[]> req = newRequest(UniFiVoucher[].class, HttpMethod.GET, gson);
|
||||||
|
req.setAPIPath(String.format("/api/s/%s/stat/voucher", site.getName()));
|
||||||
|
return executeRequest(req);
|
||||||
|
}
|
||||||
|
|
||||||
private void refreshInsights(final Collection<UniFiSite> sites) throws UniFiException {
|
private void refreshInsights(final Collection<UniFiSite> sites) throws UniFiException {
|
||||||
for (final UniFiSite site : sites) {
|
for (final UniFiSite site : sites) {
|
||||||
cache.putInsights(getInsights(site));
|
cache.putInsights(getInsights(site));
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
package org.openhab.binding.unifi.internal.api.cache;
|
package org.openhab.binding.unifi.internal.api.cache;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
@ -27,6 +28,7 @@ import org.openhab.binding.unifi.internal.api.dto.UniFiDevice;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiSwitchPorts;
|
||||||
|
import org.openhab.binding.unifi.internal.api.dto.UniFiVoucher;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiWlan;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -36,6 +38,7 @@ import org.slf4j.LoggerFactory;
|
||||||
*
|
*
|
||||||
* @author Matthew Bowman - Initial contribution
|
* @author Matthew Bowman - Initial contribution
|
||||||
* @author Hilbrand Bouwkamp - Moved cache to this dedicated class.
|
* @author Hilbrand Bouwkamp - Moved cache to this dedicated class.
|
||||||
|
* @author Mark Herwege - Added guest vouchers
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class UniFiControllerCache {
|
public class UniFiControllerCache {
|
||||||
|
@ -47,6 +50,7 @@ public class UniFiControllerCache {
|
||||||
private final UniFiDeviceCache devicesCache = new UniFiDeviceCache();
|
private final UniFiDeviceCache devicesCache = new UniFiDeviceCache();
|
||||||
private final UniFiClientCache clientsCache = new UniFiClientCache();
|
private final UniFiClientCache clientsCache = new UniFiClientCache();
|
||||||
private final UniFiClientCache insightsCache = new UniFiClientCache();
|
private final UniFiClientCache insightsCache = new UniFiClientCache();
|
||||||
|
private final UniFiVoucherCache vouchersCache = new UniFiVoucherCache();
|
||||||
private final Map<String, UniFiSwitchPorts> devicesToPortTables = new ConcurrentHashMap<>();
|
private final Map<String, UniFiSwitchPorts> devicesToPortTables = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
@ -55,6 +59,7 @@ public class UniFiControllerCache {
|
||||||
devicesCache.clear();
|
devicesCache.clear();
|
||||||
clientsCache.clear();
|
clientsCache.clear();
|
||||||
insightsCache.clear();
|
insightsCache.clear();
|
||||||
|
vouchersCache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sites Cache
|
// Sites Cache
|
||||||
|
@ -170,4 +175,19 @@ public class UniFiControllerCache {
|
||||||
public void putInsights(final UniFiClient @Nullable [] insights) {
|
public void putInsights(final UniFiClient @Nullable [] insights) {
|
||||||
insightsCache.putAll(insights);
|
insightsCache.putAll(insights);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vouchers Cache
|
||||||
|
|
||||||
|
public void putVouchers(final UniFiVoucher @Nullable [] vouchers) {
|
||||||
|
vouchersCache.putAll(vouchers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Stream<UniFiVoucher> getVoucherStreamForSite(final UniFiSite site) {
|
||||||
|
return vouchersCache.values().stream().filter(voucher -> voucher.getSite().equals(site));
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable UniFiVoucher getVoucher(final UniFiSite site) {
|
||||||
|
// Use one of the oldest vouchers first
|
||||||
|
return getVoucherStreamForSite(site).min(Comparator.comparing(UniFiVoucher::getCreateTime)).orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.unifi.internal.api.cache;
|
||||||
|
|
||||||
|
import static org.openhab.binding.unifi.internal.api.cache.UniFiCache.Prefix.ID;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.unifi.internal.api.dto.UniFiVoucher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link UniFiVoucherCache} is a specific implementation of {@link UniFiCache} for the purpose of caching
|
||||||
|
* {@link UniFiVoucher} instances.
|
||||||
|
*
|
||||||
|
* The cache uses the following prefixes: <code>id</code>
|
||||||
|
*
|
||||||
|
* @author Mark Herwege - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
class UniFiVoucherCache extends UniFiCache<UniFiVoucher> {
|
||||||
|
|
||||||
|
public UniFiVoucherCache() {
|
||||||
|
super(ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected @Nullable String getSuffix(final UniFiVoucher voucher, final Prefix prefix) {
|
||||||
|
switch (prefix) {
|
||||||
|
case ID:
|
||||||
|
return voucher.getId();
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ import com.google.gson.annotations.SerializedName;
|
||||||
* The {@link UniFiSite} represents the data model of a UniFi site.
|
* The {@link UniFiSite} represents the data model of a UniFi site.
|
||||||
*
|
*
|
||||||
* @author Matthew Bowman - Initial contribution
|
* @author Matthew Bowman - Initial contribution
|
||||||
|
* @author Mark Herwege - Added guest vouchers
|
||||||
*/
|
*/
|
||||||
public class UniFiSite implements HasId {
|
public class UniFiSite implements HasId {
|
||||||
|
|
||||||
|
@ -53,6 +54,14 @@ public class UniFiSite implements HasId {
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getVoucher() {
|
||||||
|
UniFiVoucher voucher = cache.getVoucher(this);
|
||||||
|
if (voucher == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return voucher.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isSite(final UniFiSite site) {
|
public boolean isSite(final UniFiSite site) {
|
||||||
return site != null && id.equals(site.getId());
|
return site != null && id.equals(site.getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.unifi.internal.api.dto;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
||||||
|
import org.openhab.binding.unifi.internal.api.util.UniFiTimestampDeserializer;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link UniFiVoucher} is the base data model for a guest network voucher
|
||||||
|
*
|
||||||
|
* @author Mark Herwege - Initial contribution
|
||||||
|
*/
|
||||||
|
public class UniFiVoucher implements HasId {
|
||||||
|
|
||||||
|
private final transient UniFiControllerCache cache;
|
||||||
|
|
||||||
|
@SerializedName("_id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
private String siteId;
|
||||||
|
|
||||||
|
private String code;
|
||||||
|
@JsonAdapter(UniFiTimestampDeserializer.class)
|
||||||
|
private Instant createTime;
|
||||||
|
private Integer duration;
|
||||||
|
private Integer quota;
|
||||||
|
private Integer used;
|
||||||
|
private boolean qosOverwrite;
|
||||||
|
private Integer qosUsageQuota;
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
public UniFiVoucher(final UniFiControllerCache cache) {
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getCreateTime() {
|
||||||
|
return createTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQuota() {
|
||||||
|
return quota;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getUsed() {
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isQosOverwrite() {
|
||||||
|
return qosOverwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQosUsageQuota() {
|
||||||
|
return qosUsageQuota;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniFiSite getSite() {
|
||||||
|
return cache.getSite(siteId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"UniFiVoucher{id: '%s', code: '%s', created: '%s', duration: '%s', quota: '%s', used: '%s', qosUsageQuota: '%s', status: '%s', site: %s}",
|
||||||
|
id, code, createTime, duration, quota, used, qosUsageQuota, status, getSite());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2010-2023 Contributors to the openHAB project
|
||||||
|
*
|
||||||
|
* See the NOTICE file(s) distributed with this work for additional
|
||||||
|
* information.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.openhab.binding.unifi.internal.api.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
||||||
|
import org.openhab.binding.unifi.internal.api.dto.UniFiVoucher;
|
||||||
|
|
||||||
|
import com.google.gson.InstanceCreator;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link UniFiVoucherInstanceCreator} creates instances of {@link UniFiVoucher}s during the JSON unmarshalling of
|
||||||
|
* controller responses.
|
||||||
|
*
|
||||||
|
* @author Mark Herwege - Initial contribution
|
||||||
|
*/
|
||||||
|
@NonNullByDefault
|
||||||
|
public class UniFiVoucherInstanceCreator implements InstanceCreator<UniFiVoucher> {
|
||||||
|
|
||||||
|
private final UniFiControllerCache cache;
|
||||||
|
|
||||||
|
public UniFiVoucherInstanceCreator(final UniFiControllerCache cache) {
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UniFiVoucher createInstance(final @Nullable Type type) {
|
||||||
|
if (UniFiVoucher.class.equals(type)) {
|
||||||
|
return new UniFiVoucher(cache);
|
||||||
|
} else {
|
||||||
|
throw new JsonSyntaxException("Expected a UniFi Voucher type, but got " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,19 +12,23 @@
|
||||||
*/
|
*/
|
||||||
package org.openhab.binding.unifi.internal.handler;
|
package org.openhab.binding.unifi.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_GUEST_CLIENTS;
|
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.*;
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_TOTAL_CLIENTS;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WIRED_CLIENTS;
|
import java.util.function.Predicate;
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WIRELESS_CLIENTS;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.binding.unifi.internal.UniFiSiteThingConfig;
|
import org.openhab.binding.unifi.internal.UniFiSiteThingConfig;
|
||||||
|
import org.openhab.binding.unifi.internal.UniFiVoucherChannelConfig;
|
||||||
import org.openhab.binding.unifi.internal.api.UniFiController;
|
import org.openhab.binding.unifi.internal.api.UniFiController;
|
||||||
import org.openhab.binding.unifi.internal.api.UniFiException;
|
import org.openhab.binding.unifi.internal.api.UniFiException;
|
||||||
import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache;
|
||||||
|
import org.openhab.binding.unifi.internal.api.dto.UniFiClient;
|
||||||
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
||||||
import org.openhab.core.library.types.DecimalType;
|
import org.openhab.core.library.types.DecimalType;
|
||||||
|
import org.openhab.core.library.types.OnOffType;
|
||||||
|
import org.openhab.core.library.types.StringType;
|
||||||
|
import org.openhab.core.thing.Channel;
|
||||||
import org.openhab.core.thing.ChannelUID;
|
import org.openhab.core.thing.ChannelUID;
|
||||||
import org.openhab.core.thing.Thing;
|
import org.openhab.core.thing.Thing;
|
||||||
import org.openhab.core.thing.ThingStatus;
|
import org.openhab.core.thing.ThingStatus;
|
||||||
|
@ -39,6 +43,7 @@ import org.openhab.core.types.UnDefType;
|
||||||
*
|
*
|
||||||
* @author Matthew Bowman - Initial contribution
|
* @author Matthew Bowman - Initial contribution
|
||||||
* @author Hilbrand Bouwkamp - Initial contribution
|
* @author Hilbrand Bouwkamp - Initial contribution
|
||||||
|
* @author Mark Herwege - Added guest vouchers
|
||||||
*/
|
*/
|
||||||
@NonNullByDefault
|
@NonNullByDefault
|
||||||
public class UniFiSiteThingHandler extends UniFiBaseThingHandler<UniFiSite, UniFiSiteThingConfig> {
|
public class UniFiSiteThingHandler extends UniFiBaseThingHandler<UniFiSite, UniFiSiteThingConfig> {
|
||||||
|
@ -67,32 +72,59 @@ public class UniFiSiteThingHandler extends UniFiBaseThingHandler<UniFiSite, UniF
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected State getChannelState(final UniFiSite site, final String channelId) {
|
protected State getChannelState(final UniFiSite site, final String channelId) {
|
||||||
final UniFiControllerCache cache = site.getCache();
|
final State state;
|
||||||
final long count;
|
|
||||||
|
|
||||||
switch (channelId) {
|
switch (channelId) {
|
||||||
case CHANNEL_TOTAL_CLIENTS:
|
case CHANNEL_TOTAL_CLIENTS:
|
||||||
count = cache.countClients(site, c -> true);
|
state = countClients(site, c -> true);
|
||||||
break;
|
break;
|
||||||
case CHANNEL_WIRELESS_CLIENTS:
|
case CHANNEL_WIRELESS_CLIENTS:
|
||||||
count = cache.countClients(site, c -> c.isWireless());
|
state = countClients(site, c -> c.isWireless());
|
||||||
break;
|
break;
|
||||||
case CHANNEL_WIRED_CLIENTS:
|
case CHANNEL_WIRED_CLIENTS:
|
||||||
count = cache.countClients(site, c -> c.isWired());
|
state = countClients(site, c -> c.isWired());
|
||||||
break;
|
break;
|
||||||
case CHANNEL_GUEST_CLIENTS:
|
case CHANNEL_GUEST_CLIENTS:
|
||||||
count = cache.countClients(site, c -> c.isGuest());
|
state = countClients(site, c -> c.isGuest());
|
||||||
|
break;
|
||||||
|
case CHANNEL_GUEST_VOUCHER:
|
||||||
|
String voucher = site.getVoucher();
|
||||||
|
state = (voucher != null) ? StringType.valueOf(voucher) : UnDefType.UNDEF;
|
||||||
|
break;
|
||||||
|
case CHANNEL_GUEST_VOUCHERS_GENERATE:
|
||||||
|
state = OnOffType.OFF;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Unsupported channel; nothing to update
|
// Unsupported channel; nothing to update
|
||||||
return UnDefType.NULL;
|
return UnDefType.NULL;
|
||||||
}
|
}
|
||||||
return new DecimalType(count);
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static State countClients(final UniFiSite site, final Predicate<UniFiClient> filter) {
|
||||||
|
return new DecimalType(site.getCache().countClients(site, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean handleCommand(final UniFiController controller, final UniFiSite entity,
|
protected boolean handleCommand(final UniFiController controller, final UniFiSite entity,
|
||||||
final ChannelUID channelUID, final Command command) throws UniFiException {
|
final ChannelUID channelUID, final Command command) throws UniFiException {
|
||||||
|
final String channelID = channelUID.getId();
|
||||||
|
|
||||||
|
if (CHANNEL_GUEST_VOUCHERS_GENERATE.equals(channelID)) {
|
||||||
|
Channel channel = getThing().getChannel(CHANNEL_GUEST_VOUCHERS_GENERATE);
|
||||||
|
if (channel == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UniFiVoucherChannelConfig config = channel.getConfiguration().as(UniFiVoucherChannelConfig.class);
|
||||||
|
final int count = config.getCount();
|
||||||
|
final int expire = config.getExpiration();
|
||||||
|
final int users = config.getVoucherUsers();
|
||||||
|
final Integer upLimit = config.getUpLimit();
|
||||||
|
final Integer downLimit = config.getDownLimit();
|
||||||
|
final Integer dataQuota = config.getDataQuota();
|
||||||
|
controller.generateGuestVouchers(entity, count, expire, users, upLimit, downLimit, dataQuota);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,36 @@
|
||||||
</parameter>
|
</parameter>
|
||||||
</config-description>
|
</config-description>
|
||||||
|
|
||||||
|
<config-description uri="channel-type:unifi:guestVouchersGenerate">
|
||||||
|
<parameter name="voucherCount" type="integer">
|
||||||
|
<label>Number</label>
|
||||||
|
<description>Number of vouchers to create</description>
|
||||||
|
<default>1</default>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="voucherExpiration" type="integer" unit="min">
|
||||||
|
<label>Expiration Time</label>
|
||||||
|
<description>Minutes a voucher is valid after activation</description>
|
||||||
|
<default>1440</default>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="voucherUsers" type="integer">
|
||||||
|
<label>Users</label>
|
||||||
|
<description>Number of users for voucher, 0 if no limit</description>
|
||||||
|
<default>1</default>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="voucherUpLimit" type="integer">
|
||||||
|
<label>Upload Speed Limit</label>
|
||||||
|
<description>Upload speed limit in kbps, no limit if not set</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="voucherDownLimit" type="integer">
|
||||||
|
<label>Download Speed Limit</label>
|
||||||
|
<description>Download speed limit in kbps, no limit if not set</description>
|
||||||
|
</parameter>
|
||||||
|
<parameter name="voucherDataQuota" type="integer">
|
||||||
|
<label>Data Transfer Quota</label>
|
||||||
|
<description>Data transfer quota in MB per user, no limit if not set</description>
|
||||||
|
</parameter>
|
||||||
|
</config-description>
|
||||||
|
|
||||||
<config-description uri="thing-type:unifi:poePort">
|
<config-description uri="thing-type:unifi:poePort">
|
||||||
<parameter name="portNumber" type="integer" required="true">
|
<parameter name="portNumber" type="integer" required="true">
|
||||||
<label>Port Number</label>
|
<label>Port Number</label>
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
<channel id="wirelessClients" typeId="wirelessClients"/>
|
<channel id="wirelessClients" typeId="wirelessClients"/>
|
||||||
<channel id="wiredClients" typeId="wiredClients"/>
|
<channel id="wiredClients" typeId="wiredClients"/>
|
||||||
<channel id="guestClients" typeId="guestClients"/>
|
<channel id="guestClients" typeId="guestClients"/>
|
||||||
|
<channel id="guestVoucher" typeId="guestVoucher"/>
|
||||||
|
<channel id="guestVouchersGenerate" typeId="guestVouchersGenerate"/>
|
||||||
</channels>
|
</channels>
|
||||||
|
|
||||||
<representation-property>sid</representation-property>
|
<representation-property>sid</representation-property>
|
||||||
|
@ -165,6 +167,25 @@
|
||||||
<state readOnly="true"></state>
|
<state readOnly="true"></state>
|
||||||
</channel-type>
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="guestVoucher">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Guest Voucher</label>
|
||||||
|
<description>Guest voucher for access through the guest portal</description>
|
||||||
|
<state readOnly="true"></state>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
|
<channel-type id="guestVouchersGenerate">
|
||||||
|
<item-type>String</item-type>
|
||||||
|
<label>Generate Guest Vouchers</label>
|
||||||
|
<description>Generate additional guest vouchers for access through the guest portal</description>
|
||||||
|
<command>
|
||||||
|
<options>
|
||||||
|
<option value="GENERATE">Generate</option>
|
||||||
|
</options>
|
||||||
|
</command>
|
||||||
|
<config-description-ref uri="channel-type:unifi:guestVouchersGenerate"/>
|
||||||
|
</channel-type>
|
||||||
|
|
||||||
<channel-type id="wlanEnable">
|
<channel-type id="wlanEnable">
|
||||||
<item-type>Switch</item-type>
|
<item-type>Switch</item-type>
|
||||||
<label>Enable</label>
|
<label>Enable</label>
|
||||||
|
|
Loading…
Reference in New Issue