[unifi] guest voucher actions (#14303)
* guest voucher actions Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
This commit is contained in:
parent
bc6a027f9e
commit
fbbce11cf2
@ -230,21 +230,89 @@ The `poePort` information that is retrieved is available as these channels:
|
|||||||
The `enable` switch channel has a configuration parameter `mode` which is the value used to switch PoE on when the channel is switched to ON.
|
The `enable` switch channel has a configuration parameter `mode` which is the value used to switch PoE on when the channel is switched to ON.
|
||||||
The default mode value is `auto`.
|
The default mode value is `auto`.
|
||||||
|
|
||||||
|
## Rule Actions
|
||||||
|
|
||||||
|
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.
|
||||||
|
The following actions are available:
|
||||||
|
|
||||||
|
- `boolean success = generateVoucher(Integer expire, Integer users, Integer upLimit, Integer downLimit, Integer dataQuota)`
|
||||||
|
- `boolean success = generateVouchers(Integer count, Integer expire, Integer users, Integer upLimit, Integer downLimit, Integer dataQuota)`
|
||||||
|
- `boolean success = revokeVoucher(String voucherCode)`
|
||||||
|
- `boolean success = revokeVouchers(List<String> voucherCodes)`
|
||||||
|
- `boolean success = revokeAllVouchers()`
|
||||||
|
- `String vouchers = listVouchers()`
|
||||||
|
|
||||||
|
Since there is a separate rule action instance for each `site` thing, this needs to be retrieved through `getActions(scope, thingUID)`.
|
||||||
|
The first parameter always has to be `unifi` and the second is the full Thing UID of the site that should be used.
|
||||||
|
Once this action instance is retrieved, you can invoke the action method on it.
|
||||||
|
|
||||||
|
Boolean return values for the actions indicate success or failure.
|
||||||
|
|
||||||
|
The `generateVoucher(s)` actions parameters match the configuration parameters for the `guestVouchersGenerate` channel.
|
||||||
|
With the actions, these parameters can be controlled in a rule or script.
|
||||||
|
`null` values for the parameters are allowed, and will set the parameter to the default value.
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
| ------------- | --------------------------------------------------------------------------- | ------- |
|
||||||
|
| count | Number of vouchers to create | 1 |
|
||||||
|
| expire | Minutes a voucher is valid after activation (default is 1 day) | 1440 |
|
||||||
|
| users | Number of users for voucher, 0 for no limit | 1 |
|
||||||
|
| upLimit | Upload speed limit in kbps, no limit if not set | |
|
||||||
|
| downLimit | Download speed limit in kbps, no limit if not set | |
|
||||||
|
| dataQuota | Data transfer quota in MB per user, no limit if not set | |
|
||||||
|
|
||||||
|
The `revoke...` actions allow you to revoke previously created vouchers.
|
||||||
|
The parameter is the voucher code or a list of voucher codes to be revoked.
|
||||||
|
|
||||||
|
The `listVouchers` action will return a json string representing the currently available vouchers for the site.
|
||||||
|
The json contains all parameters for the voucher, therefore it is possible to filter on these in a rule or script.
|
||||||
|
For example, one could retrieve all vouchers created before a certain time and use the `revokeVouchers` action to delete these.
|
||||||
|
The structure of the returned json is (depending on content, some fields may be missing):
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"code": "3867791284",
|
||||||
|
"createTime": "2023-01-31T14:40:47Z",
|
||||||
|
"duration": 1440,
|
||||||
|
"quota": 2,
|
||||||
|
"used": 0,
|
||||||
|
"qosUsageQuota": 300,
|
||||||
|
"qosRateMaxUp": 200,
|
||||||
|
"qosRateMaxDown": 100,
|
||||||
|
"qosOverwrite": true,
|
||||||
|
"note": "I added a note when creating vouchers in the UniFi hotspot UI",
|
||||||
|
"status": "VALID_MULTI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "0021952641",
|
||||||
|
"createTime": "2023-01-31T14:38:47Z",
|
||||||
|
"duration": 1440,
|
||||||
|
"quota": 1,
|
||||||
|
"used": 0,
|
||||||
|
"qosOverwrite": false,
|
||||||
|
"status": "VALID_ONE"
|
||||||
|
},
|
||||||
|
{ ... }
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
## Full Example
|
## Full Example
|
||||||
|
|
||||||
things/unifi.things
|
### `things/unifi.things`
|
||||||
|
|
||||||
```
|
```
|
||||||
Bridge unifi:controller:home "UniFi Controller" [ host="unifi", port=8443, unifios=false, username="$username", password="$password", refresh=10 ] {
|
Bridge unifi:controller:home "UniFi Controller" [ host="unifi", port=8443, unifios=false, username="$username", password="$password", refresh=10 ] {
|
||||||
Thing wirelessClient matthewsPhone "Matthew's iPhone" [ cid="$cid", site="default", considerHome=180 ]
|
Thing wirelessClient matthewsPhone "Matthew's iPhone" [ cid="$cid", site="default", considerHome=180 ]
|
||||||
|
Thing site mysite "My Site" [ sid="$sid" ]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
_Note: Usually on Unifi OS, the default port is 443_
|
_Note: Usually on Unifi OS, the default port is 443_
|
||||||
|
|
||||||
Replace `$user`, `$password` and `$cid` accordingly.
|
Replace `$user`, `$password`, `$cid` and `$sid` accordingly.
|
||||||
|
|
||||||
items/unifi.items
|
### `items/unifi.items`
|
||||||
|
|
||||||
```
|
```
|
||||||
Switch MatthewsPhone "Matthew's iPhone [MAP(unifi.map):%s]" { channel="unifi:wirelessClient:home:matthewsPhone:online" }
|
Switch MatthewsPhone "Matthew's iPhone [MAP(unifi.map):%s]" { channel="unifi:wirelessClient:home:matthewsPhone:online" }
|
||||||
@ -260,14 +328,14 @@ Switch MatthewsPhoneBlocked "Matthew's iPhone: Blocked"
|
|||||||
Switch MatthewsPhoneReconnect "Matthew's iPhone: Reconnect" { channel="unifi:wirelessClient:home:matthewsPhone:reconnect" }
|
Switch MatthewsPhoneReconnect "Matthew's iPhone: Reconnect" { channel="unifi:wirelessClient:home:matthewsPhone:reconnect" }
|
||||||
```
|
```
|
||||||
|
|
||||||
transform/unifi.map
|
### `transform/unifi.map`
|
||||||
|
|
||||||
```
|
```
|
||||||
ON=Home
|
ON=Home
|
||||||
OFF=Away
|
OFF=Away
|
||||||
```
|
```
|
||||||
|
|
||||||
sitemaps/unifi.sitemap
|
### `sitemaps/unifi.sitemap`
|
||||||
|
|
||||||
```
|
```
|
||||||
sitemap unifi label="UniFi Binding"
|
sitemap unifi label="UniFi Binding"
|
||||||
@ -287,3 +355,23 @@ sitemap unifi label="UniFi Binding"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### `rule actions` for `site` thing
|
||||||
|
|
||||||
|
```java
|
||||||
|
val uniFiActions = getActions("unifi","unifi:site:home:mysite")
|
||||||
|
val success = uniFiActions.generateVoucher(null, null, null, 100, 500, 250)
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
val uniFiActions = getActions("unifi","unifi:site:home:mysite")
|
||||||
|
val vouchersJson = uniFiActions.listVouchers()
|
||||||
|
```
|
||||||
|
|
||||||
|
```java
|
||||||
|
import java.util.List
|
||||||
|
|
||||||
|
val List<String> voucherList = newArrayList("38677-91284", "46415-36104")
|
||||||
|
val uniFiActions = getActions("unifi","unifi:site:home:mysite")
|
||||||
|
val success = uniFiActions.revokeVouchers(voucherList)
|
||||||
|
```
|
||||||
|
|||||||
@ -12,13 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.unifi.internal;
|
package org.openhab.binding.unifi.internal;
|
||||||
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.ALL_THING_TYPE_SUPPORTED;
|
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.*;
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.THING_TYPE_CONTROLLER;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.THING_TYPE_POE_PORT;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.THING_TYPE_SITE;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.THING_TYPE_WIRED_CLIENT;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.THING_TYPE_WIRELESS_CLIENT;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.THING_TYPE_WLAN;
|
|
||||||
|
|
||||||
import org.eclipse.jdt.annotation.NonNullByDefault;
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
|||||||
@ -0,0 +1,271 @@
|
|||||||
|
/**
|
||||||
|
* 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.action;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||||
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
|
import org.openhab.binding.unifi.internal.api.UniFiController;
|
||||||
|
import org.openhab.binding.unifi.internal.api.UniFiException;
|
||||||
|
import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
|
||||||
|
import org.openhab.binding.unifi.internal.api.dto.UniFiVoucher;
|
||||||
|
import org.openhab.binding.unifi.internal.handler.UniFiSiteThingHandler;
|
||||||
|
import org.openhab.core.automation.annotation.ActionInput;
|
||||||
|
import org.openhab.core.automation.annotation.ActionOutput;
|
||||||
|
import org.openhab.core.automation.annotation.RuleAction;
|
||||||
|
import org.openhab.core.thing.binding.ThingActions;
|
||||||
|
import org.openhab.core.thing.binding.ThingActionsScope;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandler;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link UniFiSiteActions} class defines rule actions for creating guest hotspot vouchers
|
||||||
|
*
|
||||||
|
* @author Mark Herwege - Initial contribution
|
||||||
|
*/
|
||||||
|
@ThingActionsScope(name = "unifi")
|
||||||
|
@NonNullByDefault
|
||||||
|
public class UniFiSiteActions implements ThingActions {
|
||||||
|
|
||||||
|
private static final int DEFAULT_COUNT = 1;
|
||||||
|
private static final int DEFAULT_EXPIRE_MIN = 1440;
|
||||||
|
private static final int DEFAULT_USERS = 1;
|
||||||
|
|
||||||
|
private static final Pattern NON_DIGITS_PATTERN = Pattern.compile("\\D+");
|
||||||
|
|
||||||
|
private final Logger logger = LoggerFactory.getLogger(UniFiSiteActions.class);
|
||||||
|
|
||||||
|
private @Nullable UniFiSiteThingHandler handler;
|
||||||
|
private final Gson gson = new Gson();
|
||||||
|
|
||||||
|
@RuleAction(label = "@text/action.unifi.generateVouchers.label", description = "@text/action.unifi.generateVouchers.description")
|
||||||
|
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean generateVoucher(
|
||||||
|
/* @formatter:off */
|
||||||
|
@ActionInput(name = "expire",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.description") @Nullable Integer expire,
|
||||||
|
@ActionInput(name = "users",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.description") @Nullable Integer users,
|
||||||
|
@ActionInput(name = "upLimit",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.description") @Nullable Integer upLimit,
|
||||||
|
@ActionInput(name = "downLimit",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.description") @Nullable Integer downLimit,
|
||||||
|
@ActionInput(name = "dataQuota",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.description") @Nullable Integer dataQuota) {
|
||||||
|
/* @formatter:on */
|
||||||
|
return generateVouchers(1, expire, users, upLimit, downLimit, dataQuota);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RuleAction(label = "@text/action.unifi.generateVouchers.label", description = "@text/action.unifi.generateVouchers.description")
|
||||||
|
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean generateVouchers(
|
||||||
|
/* @formatter:off */
|
||||||
|
@ActionInput(name = "count",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherCount.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherCount.description") @Nullable Integer count,
|
||||||
|
@ActionInput(name = "expire",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.description") @Nullable Integer expire,
|
||||||
|
@ActionInput(name = "users",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.description") @Nullable Integer users,
|
||||||
|
@ActionInput(name = "upLimit",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.description") @Nullable Integer upLimit,
|
||||||
|
@ActionInput(name = "downLimit",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.description") @Nullable Integer downLimit,
|
||||||
|
@ActionInput(name = "dataQuota",
|
||||||
|
label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.label",
|
||||||
|
description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.description") @Nullable Integer dataQuota) {
|
||||||
|
/* @formatter:on */
|
||||||
|
UniFiSiteThingHandler handler = this.handler;
|
||||||
|
if (handler == null) {
|
||||||
|
logger.debug("Could not create guest vouchers, site thing handler not set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final @Nullable UniFiSite entity = handler.getEntity();
|
||||||
|
final UniFiController controller = handler.getController();
|
||||||
|
if (entity == null || controller == null) {
|
||||||
|
logger.debug("Could not create guest vouchers, site thing error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
controller.generateVouchers(entity, ((count != null) && (count != 0)) ? count : DEFAULT_COUNT,
|
||||||
|
(expire != null) ? expire : DEFAULT_EXPIRE_MIN, (users != null) ? users : DEFAULT_USERS, upLimit,
|
||||||
|
downLimit, dataQuota);
|
||||||
|
} catch (UniFiException e) {
|
||||||
|
logger.debug("Could not create guest vouchers, uniFi exception", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVoucher(ThingActions actions) {
|
||||||
|
return UniFiSiteActions.generateVoucher(actions, DEFAULT_EXPIRE_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire) {
|
||||||
|
return UniFiSiteActions.generateVoucher(actions, expire, DEFAULT_USERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire, @Nullable Integer users) {
|
||||||
|
return UniFiSiteActions.generateVoucher(actions, expire, users, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire, @Nullable Integer users,
|
||||||
|
@Nullable Integer upLimit, @Nullable Integer downLimit, @Nullable Integer dataQuota) {
|
||||||
|
return ((UniFiSiteActions) actions).generateVoucher(expire, users, upLimit, downLimit, dataQuota);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVouchers(ThingActions actions) {
|
||||||
|
return UniFiSiteActions.generateVouchers(actions, DEFAULT_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVouchers(ThingActions actions, @Nullable Integer count) {
|
||||||
|
return UniFiSiteActions.generateVouchers(actions, count, DEFAULT_EXPIRE_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire) {
|
||||||
|
return UniFiSiteActions.generateVouchers(actions, count, expire, DEFAULT_USERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire,
|
||||||
|
@Nullable Integer users) {
|
||||||
|
return UniFiSiteActions.generateVouchers(actions, count, expire, users, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire,
|
||||||
|
@Nullable Integer users, @Nullable Integer upLimit, @Nullable Integer downLimit,
|
||||||
|
@Nullable Integer dataQuota) {
|
||||||
|
return ((UniFiSiteActions) actions).generateVouchers(count, expire, users, upLimit, downLimit, dataQuota);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RuleAction(label = "@text/action.unifi.revokeVouchers.label", description = "@text/action.unifi.revokeVouchers.description")
|
||||||
|
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeVoucher(
|
||||||
|
/* @formatter:off */
|
||||||
|
@ActionInput(name = "voucherCodes", label = "@text/action.unifi.vouchersInputVoucherCodes.label",
|
||||||
|
description = "@text/action.unifi.vouchersInputVoucherCodes.description") String voucherCode) {
|
||||||
|
/* @formatter:on */
|
||||||
|
return revokeVouchers(List.of(voucherCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
@RuleAction(label = "@text/action.unifi.revokeVouchers.label", description = "@text/action.unifi.revokeVouchers.description")
|
||||||
|
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeVouchers(
|
||||||
|
/* @formatter:off */
|
||||||
|
@ActionInput(name = "voucherCodes", label = "@text/action.unifi.vouchersInputVoucherCodes.label",
|
||||||
|
description = "@text/action.unifi.vouchersInputVoucherCodes.description") List<String> voucherCodes) {
|
||||||
|
/* @formatter:on */
|
||||||
|
UniFiSiteThingHandler handler = this.handler;
|
||||||
|
if (handler == null) {
|
||||||
|
logger.debug("Could not revoke guest vouchers, site thing handler not set");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final @Nullable UniFiSite entity = handler.getEntity();
|
||||||
|
final UniFiController controller = handler.getController();
|
||||||
|
if (entity == null || controller == null) {
|
||||||
|
logger.debug("Could not revoke guest vouchers, site thing error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only keep digits in provided codes, so matching is done correctly. This makes blanks and dashes in the input
|
||||||
|
// possible, as shown in the UniFi voucher UI.
|
||||||
|
List<String> cleanCodes = voucherCodes.stream().map(c -> NON_DIGITS_PATTERN.matcher(c).replaceAll(""))
|
||||||
|
.filter(c -> !c.isEmpty()).toList();
|
||||||
|
Stream<UniFiVoucher> voucherStream = entity.getCache().getVoucherStreamForSite(entity);
|
||||||
|
// If no codes provided, revoke all codes
|
||||||
|
List<UniFiVoucher> vouchers = (voucherCodes.isEmpty() ? voucherStream
|
||||||
|
: voucherStream.filter(v -> cleanCodes.contains(v.getCode()))).toList();
|
||||||
|
try {
|
||||||
|
controller.revokeVouchers(entity, vouchers);
|
||||||
|
} catch (UniFiException e) {
|
||||||
|
logger.debug("Could not revoke guest vouchers, uniFi exception", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RuleAction(label = "@text/action.unifi.revokeAllVouchers.label", description = "@text/action.unifi.revokeAllVouchers.description")
|
||||||
|
public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeAllVouchers() {
|
||||||
|
return revokeVouchers(List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean revokeVoucher(ThingActions actions, String voucherCode) {
|
||||||
|
return revokeVouchers(actions, List.of(voucherCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean revokeVouchers(ThingActions actions, List<String> voucherCodes) {
|
||||||
|
return ((UniFiSiteActions) actions).revokeVouchers(voucherCodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean revokeAllVouchers(ThingActions actions) {
|
||||||
|
return revokeVouchers(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean revokeVouchers(ThingActions actions) {
|
||||||
|
return revokeVouchers(actions, List.of());
|
||||||
|
}
|
||||||
|
|
||||||
|
@RuleAction(label = "@text/action.unifi.listVouchers.label", description = "@text/action.unifi.listVouchers.description")
|
||||||
|
public @ActionOutput(name = "vouchers", type = "java.lang.String") String listVouchers() {
|
||||||
|
UniFiSiteThingHandler handler = this.handler;
|
||||||
|
if (handler == null) {
|
||||||
|
logger.debug("Could not list guest vouchers, site thing handler not set");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
final @Nullable UniFiSite entity = handler.getEntity();
|
||||||
|
if (entity == null) {
|
||||||
|
logger.debug("Could not list guest vouchers, site thing error");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
record Voucher(String code, String createTime, Integer duration, Integer quota, Integer used,
|
||||||
|
Integer qosUsageQuota, Integer qosRateMaxUp, Integer qosRateMaxDown, Boolean qosOverwrite, String note,
|
||||||
|
String status) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return gson
|
||||||
|
.toJson(entity.getCache().getVoucherStreamForSite(entity)
|
||||||
|
.collect(Collectors.mapping(
|
||||||
|
v -> new Voucher(v.getCode(), v.getCreateTime().toString(), v.getDuration(),
|
||||||
|
v.getQuota(), v.getUsed(), v.getQosUsageQuota(), v.getQosRateMaxUp(),
|
||||||
|
v.getQosRateMaxDown(), v.isQosOverwrite(), v.getNote(), v.getStatus()),
|
||||||
|
Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String listVouchers(ThingActions actions) {
|
||||||
|
return ((UniFiSiteActions) actions).listVouchers();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setThingHandler(ThingHandler handler) {
|
||||||
|
if (handler instanceof UniFiSiteThingHandler) {
|
||||||
|
this.handler = (UniFiSiteThingHandler) handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ThingHandler getThingHandler() {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -215,7 +215,7 @@ public class UniFiController {
|
|||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generateGuestVouchers(final UniFiSite site, final int count, final int expiration, final int users,
|
public void generateVouchers(final UniFiSite site, final int count, final int expiration, final int users,
|
||||||
@Nullable Integer upLimit, @Nullable Integer downLimit, @Nullable Integer dataQuota) throws UniFiException {
|
@Nullable Integer upLimit, @Nullable Integer downLimit, @Nullable Integer dataQuota) throws UniFiException {
|
||||||
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.POST, gson);
|
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.POST, gson);
|
||||||
req.setAPIPath(String.format("/api/s/%s/cmd/hotspot", site.getName()));
|
req.setAPIPath(String.format("/api/s/%s/cmd/hotspot", site.getName()));
|
||||||
@ -236,6 +236,17 @@ public class UniFiController {
|
|||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void revokeVouchers(final UniFiSite site, final List<UniFiVoucher> vouchers) throws UniFiException {
|
||||||
|
for (UniFiVoucher voucher : vouchers) {
|
||||||
|
final UniFiControllerRequest<Void> req = newRequest(Void.class, HttpMethod.POST, gson);
|
||||||
|
req.setAPIPath(String.format("/api/s/%s/cmd/hotspot", site.getName()));
|
||||||
|
req.setBodyParameter("cmd", "delete-voucher");
|
||||||
|
req.setBodyParameter("_id", voucher.getId());
|
||||||
|
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,
|
||||||
|
|||||||
@ -40,8 +40,11 @@ public class UniFiVoucher implements HasId {
|
|||||||
private Integer duration;
|
private Integer duration;
|
||||||
private Integer quota;
|
private Integer quota;
|
||||||
private Integer used;
|
private Integer used;
|
||||||
private boolean qosOverwrite;
|
|
||||||
private Integer qosUsageQuota;
|
private Integer qosUsageQuota;
|
||||||
|
private Integer qosRateMaxUp;
|
||||||
|
private Integer qosRateMaxDown;
|
||||||
|
private boolean qosOverwrite;
|
||||||
|
private String note;
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
public UniFiVoucher(final UniFiControllerCache cache) {
|
public UniFiVoucher(final UniFiControllerCache cache) {
|
||||||
@ -73,12 +76,24 @@ public class UniFiVoucher implements HasId {
|
|||||||
return used;
|
return used;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getQosUsageQuota() {
|
||||||
|
return qosUsageQuota;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQosRateMaxUp() {
|
||||||
|
return qosRateMaxUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getQosRateMaxDown() {
|
||||||
|
return qosRateMaxDown;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isQosOverwrite() {
|
public boolean isQosOverwrite() {
|
||||||
return qosOverwrite;
|
return qosOverwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getQosUsageQuota() {
|
public String getNote() {
|
||||||
return qosUsageQuota;
|
return note;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getStatus() {
|
public String getStatus() {
|
||||||
@ -92,7 +107,9 @@ public class UniFiVoucher implements HasId {
|
|||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format(
|
return String.format(
|
||||||
"UniFiVoucher{id: '%s', code: '%s', created: '%s', duration: '%s', quota: '%s', used: '%s', qosUsageQuota: '%s', status: '%s', site: %s}",
|
"UniFiVoucher{id: '%s', code: '%s', created: '%s', duration: '%s', quota: '%s', used: '%s', qosUsageQuota: '%s', "
|
||||||
id, code, createTime, duration, quota, used, qosUsageQuota, status, getSite());
|
+ "qosRateMaxUp: '%s', qosRateMaxDown: '%s', qosOverwrite: '%s', note: '%s', status: '%s', site: %s}",
|
||||||
|
id, code, createTime, duration, quota, used, qosUsageQuota, qosRateMaxUp, qosRateMaxDown, qosOverwrite,
|
||||||
|
note, status, getSite());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,8 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.openhab.binding.unifi.internal.handler;
|
package org.openhab.binding.unifi.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.core.thing.ThingStatus.OFFLINE;
|
import static org.openhab.core.thing.ThingStatus.*;
|
||||||
import static org.openhab.core.thing.ThingStatus.ONLINE;
|
|
||||||
import static org.openhab.core.types.RefreshType.REFRESH;
|
import static org.openhab.core.types.RefreshType.REFRESH;
|
||||||
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
@ -81,7 +80,7 @@ public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("null")
|
@SuppressWarnings("null")
|
||||||
private final @Nullable UniFiController getController() {
|
public final @Nullable UniFiController getController() {
|
||||||
final Bridge bridge = getBridge();
|
final Bridge bridge = getBridge();
|
||||||
if (bridge != null && bridge.getHandler() != null
|
if (bridge != null && bridge.getHandler() != null
|
||||||
&& (bridge.getHandler() instanceof UniFiControllerThingHandler)) {
|
&& (bridge.getHandler() instanceof UniFiControllerThingHandler)) {
|
||||||
@ -90,7 +89,8 @@ public abstract class UniFiBaseThingHandler<E, C> extends BaseThingHandler {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable E getEntity() {
|
@Nullable
|
||||||
|
public E getEntity() {
|
||||||
final UniFiController controller = getController();
|
final UniFiController controller = getController();
|
||||||
return controller == null ? null : getEntity(controller.getCache());
|
return controller == null ? null : getEntity(controller.getCache());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,19 +12,17 @@
|
|||||||
*/
|
*/
|
||||||
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_GUEST_VOUCHER;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_GUEST_VOUCHERS_GENERATE;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_TOTAL_CLIENTS;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WIRED_CLIENTS;
|
|
||||||
import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_WIRELESS_CLIENTS;
|
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
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.UniFiVoucherChannelConfig;
|
||||||
|
import org.openhab.binding.unifi.internal.action.UniFiSiteActions;
|
||||||
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;
|
||||||
@ -38,6 +36,7 @@ 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;
|
||||||
import org.openhab.core.thing.ThingStatusDetail;
|
import org.openhab.core.thing.ThingStatusDetail;
|
||||||
|
import org.openhab.core.thing.binding.ThingHandlerService;
|
||||||
import org.openhab.core.types.Command;
|
import org.openhab.core.types.Command;
|
||||||
import org.openhab.core.types.State;
|
import org.openhab.core.types.State;
|
||||||
import org.openhab.core.types.UnDefType;
|
import org.openhab.core.types.UnDefType;
|
||||||
@ -127,9 +126,14 @@ public class UniFiSiteThingHandler extends UniFiBaseThingHandler<UniFiSite, UniF
|
|||||||
final Integer upLimit = config.getUpLimit();
|
final Integer upLimit = config.getUpLimit();
|
||||||
final Integer downLimit = config.getDownLimit();
|
final Integer downLimit = config.getDownLimit();
|
||||||
final Integer dataQuota = config.getDataQuota();
|
final Integer dataQuota = config.getDataQuota();
|
||||||
controller.generateGuestVouchers(entity, count, expire, users, upLimit, downLimit, dataQuota);
|
controller.generateVouchers(entity, count, expire, users, upLimit, downLimit, dataQuota);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Class<? extends ThingHandlerService>> getServices() {
|
||||||
|
return Collections.singleton(UniFiSiteActions.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -150,6 +150,19 @@ channel-type.config.unifi.poeEnable.mode.description = The value to set when set
|
|||||||
channel-type.config.unifi.poeEnable.mode.option.auto = Auto
|
channel-type.config.unifi.poeEnable.mode.option.auto = Auto
|
||||||
channel-type.config.unifi.poeEnable.mode.option.pasv24 = 24V
|
channel-type.config.unifi.poeEnable.mode.option.pasv24 = 24V
|
||||||
channel-type.config.unifi.poeEnable.mode.option.passthrough = Passthrough
|
channel-type.config.unifi.poeEnable.mode.option.passthrough = Passthrough
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherCount.label = Number
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherCount.description = Number of vouchers to create
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.label = Expiration Time
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.description = Minutes a voucher is valid after activation
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherUsers.label = Users
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherUsers.description = Number of users for voucher, 0 if no limit
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.label = Upload Speed Limit
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.description = Upload speed limit in kbps, no limit if not set
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.label = Download Speed Limit
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.description = Download speed limit in kbps, no limit if not set
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.label = Data Transfer Quota
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.description = Data transfer quota in MB per user, no limit if not set
|
||||||
|
channel-type.config.unifi.guestVouchersGenerate.option.GENERATE = Generate
|
||||||
|
|
||||||
# status messages
|
# status messages
|
||||||
|
|
||||||
@ -164,3 +177,16 @@ error.thing.offline.configuration_error = You must choose a UniFi Controller for
|
|||||||
error.thing.poe.offline.configuration_error = The configuration parameter macAddress must be set and not be empty.
|
error.thing.poe.offline.configuration_error = The configuration parameter macAddress must be set and not be empty.
|
||||||
error.thing.poe.offline.nodata_error = No data for the PoE port could be found in the UniFi API data. See TRACE log for actual API data.
|
error.thing.poe.offline.nodata_error = No data for the PoE port could be found in the UniFi API data. See TRACE log for actual API data.
|
||||||
error.thing.site.offline.configuration_error = The configuration parameter sid must be set and not be empty.
|
error.thing.site.offline.configuration_error = The configuration parameter sid must be set and not be empty.
|
||||||
|
|
||||||
|
# actions
|
||||||
|
|
||||||
|
action.unifi.generateVouchers.label = Generate
|
||||||
|
action.unifi.generateVouchers.description = Generate guest voucher(s)
|
||||||
|
action.unifi.revokeAllVouchers.label = Revoke All
|
||||||
|
action.unifi.revokeAllVouchers.description = Revoke all guest vouchers
|
||||||
|
action.unifi.revokeVouchers.label = Revoke
|
||||||
|
action.unifi.revokeVouchers.description = Revoke guest voucher(s)
|
||||||
|
action.unifi.vouchersInputVoucherCodes.label = Voucher Code(s)
|
||||||
|
action.unifi.vouchersInputVoucherCodes.description = Code(s) of voucher(s) to revoke
|
||||||
|
action.unifi.listVouchers.label = List Vouchers
|
||||||
|
action.unifi.listVouchers.description = List available vouchers with their parameters and status
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user