diff --git a/bundles/org.openhab.binding.unifi/README.md b/bundles/org.openhab.binding.unifi/README.md index b2c70edf7..6ac989449 100644 --- a/bundles/org.openhab.binding.unifi/README.md +++ b/bundles/org.openhab.binding.unifi/README.md @@ -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 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 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 -things/unifi.things +### `things/unifi.things` ``` 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 site mysite "My Site" [ sid="$sid" ] } ``` _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" } @@ -260,14 +328,14 @@ Switch MatthewsPhoneBlocked "Matthew's iPhone: Blocked" Switch MatthewsPhoneReconnect "Matthew's iPhone: Reconnect" { channel="unifi:wirelessClient:home:matthewsPhone:reconnect" } ``` -transform/unifi.map +### `transform/unifi.map` ``` ON=Home OFF=Away ``` -sitemaps/unifi.sitemap +### `sitemaps/unifi.sitemap` ``` 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 voucherList = newArrayList("38677-91284", "46415-36104") +val uniFiActions = getActions("unifi","unifi:site:home:mysite") +val success = uniFiActions.revokeVouchers(voucherList) +``` diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiThingHandlerFactory.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiThingHandlerFactory.java index ddca4f06d..032189c58 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiThingHandlerFactory.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiThingHandlerFactory.java @@ -12,13 +12,7 @@ */ 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.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 static org.openhab.binding.unifi.internal.UniFiBindingConstants.*; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/action/UniFiSiteActions.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/action/UniFiSiteActions.java new file mode 100644 index 000000000..59b7cfb37 --- /dev/null +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/action/UniFiSiteActions.java @@ -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 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 cleanCodes = voucherCodes.stream().map(c -> NON_DIGITS_PATTERN.matcher(c).replaceAll("")) + .filter(c -> !c.isEmpty()).toList(); + Stream voucherStream = entity.getCache().getVoucherStreamForSite(entity); + // If no codes provided, revoke all codes + List 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 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; + } +} diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiController.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiController.java index 18467f9e6..01995f487 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiController.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiController.java @@ -215,7 +215,7 @@ public class UniFiController { 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 { final UniFiControllerRequest req = newRequest(Void.class, HttpMethod.POST, gson); req.setAPIPath(String.format("/api/s/%s/cmd/hotspot", site.getName())); @@ -236,6 +236,17 @@ public class UniFiController { refresh(); } + public void revokeVouchers(final UniFiSite site, final List vouchers) throws UniFiException { + for (UniFiVoucher voucher : vouchers) { + final UniFiControllerRequest 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 private UniFiControllerRequest newRequest(final Class responseType, final HttpMethod method, diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiVoucher.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiVoucher.java index 5a62f6e2b..55d581fd3 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiVoucher.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiVoucher.java @@ -40,8 +40,11 @@ public class UniFiVoucher implements HasId { private Integer duration; private Integer quota; private Integer used; - private boolean qosOverwrite; private Integer qosUsageQuota; + private Integer qosRateMaxUp; + private Integer qosRateMaxDown; + private boolean qosOverwrite; + private String note; private String status; public UniFiVoucher(final UniFiControllerCache cache) { @@ -73,12 +76,24 @@ public class UniFiVoucher implements HasId { return used; } + public Integer getQosUsageQuota() { + return qosUsageQuota; + } + + public Integer getQosRateMaxUp() { + return qosRateMaxUp; + } + + public Integer getQosRateMaxDown() { + return qosRateMaxDown; + } + public boolean isQosOverwrite() { return qosOverwrite; } - public Integer getQosUsageQuota() { - return qosUsageQuota; + public String getNote() { + return note; } public String getStatus() { @@ -92,7 +107,9 @@ public class UniFiVoucher implements HasId { @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()); + "UniFiVoucher{id: '%s', code: '%s', created: '%s', duration: '%s', quota: '%s', used: '%s', qosUsageQuota: '%s', " + + "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()); } } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiBaseThingHandler.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiBaseThingHandler.java index 6d089732c..ba63f3e5f 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiBaseThingHandler.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiBaseThingHandler.java @@ -12,8 +12,7 @@ */ package org.openhab.binding.unifi.internal.handler; -import static org.openhab.core.thing.ThingStatus.OFFLINE; -import static org.openhab.core.thing.ThingStatus.ONLINE; +import static org.openhab.core.thing.ThingStatus.*; import static org.openhab.core.types.RefreshType.REFRESH; import java.lang.reflect.ParameterizedType; @@ -81,7 +80,7 @@ public abstract class UniFiBaseThingHandler extends BaseThingHandler { * @return */ @SuppressWarnings("null") - private final @Nullable UniFiController getController() { + public final @Nullable UniFiController getController() { final Bridge bridge = getBridge(); if (bridge != null && bridge.getHandler() != null && (bridge.getHandler() instanceof UniFiControllerThingHandler)) { @@ -90,7 +89,8 @@ public abstract class UniFiBaseThingHandler extends BaseThingHandler { return null; } - private @Nullable E getEntity() { + @Nullable + public E getEntity() { final UniFiController controller = getController(); return controller == null ? null : getEntity(controller.getCache()); } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiSiteThingHandler.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiSiteThingHandler.java index 5234fc491..7ec1c0d1f 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiSiteThingHandler.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiSiteThingHandler.java @@ -12,19 +12,17 @@ */ 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.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 static org.openhab.binding.unifi.internal.UniFiBindingConstants.*; +import java.util.Collection; +import java.util.Collections; import java.util.function.Predicate; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.unifi.internal.UniFiSiteThingConfig; 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.UniFiException; 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.ThingStatus; import org.openhab.core.thing.ThingStatusDetail; +import org.openhab.core.thing.binding.ThingHandlerService; import org.openhab.core.types.Command; import org.openhab.core.types.State; import org.openhab.core.types.UnDefType; @@ -127,9 +126,14 @@ public class UniFiSiteThingHandler extends UniFiBaseThingHandler> getServices() { + return Collections.singleton(UniFiSiteActions.class); + } } diff --git a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties index ee1b74eda..d4829cc3a 100644 --- a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties +++ b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties @@ -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.pasv24 = 24V 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 @@ -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.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. + +# 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