2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.unifi.internal.action;
15 import java.util.List;
16 import java.util.regex.Pattern;
17 import java.util.stream.Collectors;
18 import java.util.stream.Stream;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.openhab.binding.unifi.internal.api.UniFiController;
23 import org.openhab.binding.unifi.internal.api.UniFiException;
24 import org.openhab.binding.unifi.internal.api.dto.UniFiSite;
25 import org.openhab.binding.unifi.internal.api.dto.UniFiVoucher;
26 import org.openhab.binding.unifi.internal.handler.UniFiSiteThingHandler;
27 import org.openhab.core.automation.annotation.ActionInput;
28 import org.openhab.core.automation.annotation.ActionOutput;
29 import org.openhab.core.automation.annotation.RuleAction;
30 import org.openhab.core.thing.binding.ThingActions;
31 import org.openhab.core.thing.binding.ThingActionsScope;
32 import org.openhab.core.thing.binding.ThingHandler;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 import com.google.gson.Gson;
39 * The {@link UniFiSiteActions} class defines rule actions for creating guest hotspot vouchers
41 * @author Mark Herwege - Initial contribution
43 @ThingActionsScope(name = "unifi")
45 public class UniFiSiteActions implements ThingActions {
47 private static final int DEFAULT_COUNT = 1;
48 private static final int DEFAULT_EXPIRE_MIN = 1440;
49 private static final int DEFAULT_USERS = 1;
51 private static final Pattern NON_DIGITS_PATTERN = Pattern.compile("\\D+");
53 private final Logger logger = LoggerFactory.getLogger(UniFiSiteActions.class);
55 private @Nullable UniFiSiteThingHandler handler;
56 private final Gson gson = new Gson();
58 @RuleAction(label = "@text/action.unifi.generateVouchers.label", description = "@text/action.unifi.generateVouchers.description")
59 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean generateVoucher(
61 @ActionInput(name = "expire",
62 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.label",
63 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.description") @Nullable Integer expire,
64 @ActionInput(name = "users",
65 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.label",
66 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.description") @Nullable Integer users,
67 @ActionInput(name = "upLimit",
68 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.label",
69 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.description") @Nullable Integer upLimit,
70 @ActionInput(name = "downLimit",
71 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.label",
72 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.description") @Nullable Integer downLimit,
73 @ActionInput(name = "dataQuota",
74 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.label",
75 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.description") @Nullable Integer dataQuota) {
77 return generateVouchers(1, expire, users, upLimit, downLimit, dataQuota);
80 @RuleAction(label = "@text/action.unifi.generateVouchers.label", description = "@text/action.unifi.generateVouchers.description")
81 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean generateVouchers(
83 @ActionInput(name = "count",
84 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherCount.label",
85 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherCount.description") @Nullable Integer count,
86 @ActionInput(name = "expire",
87 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.label",
88 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.description") @Nullable Integer expire,
89 @ActionInput(name = "users",
90 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.label",
91 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.description") @Nullable Integer users,
92 @ActionInput(name = "upLimit",
93 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.label",
94 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.description") @Nullable Integer upLimit,
95 @ActionInput(name = "downLimit",
96 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.label",
97 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.description") @Nullable Integer downLimit,
98 @ActionInput(name = "dataQuota",
99 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.label",
100 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.description") @Nullable Integer dataQuota) {
102 UniFiSiteThingHandler handler = this.handler;
103 if (handler == null) {
104 logger.debug("Could not create guest vouchers, site thing handler not set");
107 final @Nullable UniFiSite entity = handler.getEntity();
108 final UniFiController controller = handler.getController();
109 if (entity == null || controller == null) {
110 logger.debug("Could not create guest vouchers, site thing error");
114 controller.generateVouchers(entity, ((count != null) && (count != 0)) ? count : DEFAULT_COUNT,
115 (expire != null) ? expire : DEFAULT_EXPIRE_MIN, (users != null) ? users : DEFAULT_USERS, upLimit,
116 downLimit, dataQuota);
117 } catch (UniFiException e) {
118 logger.debug("Could not create guest vouchers, uniFi exception", e);
124 public static boolean generateVoucher(ThingActions actions) {
125 return UniFiSiteActions.generateVoucher(actions, DEFAULT_EXPIRE_MIN);
128 public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire) {
129 return UniFiSiteActions.generateVoucher(actions, expire, DEFAULT_USERS);
132 public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire, @Nullable Integer users) {
133 return UniFiSiteActions.generateVoucher(actions, expire, users, null, null, null);
136 public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire, @Nullable Integer users,
137 @Nullable Integer upLimit, @Nullable Integer downLimit, @Nullable Integer dataQuota) {
138 return ((UniFiSiteActions) actions).generateVoucher(expire, users, upLimit, downLimit, dataQuota);
141 public static boolean generateVouchers(ThingActions actions) {
142 return UniFiSiteActions.generateVouchers(actions, DEFAULT_COUNT);
145 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count) {
146 return UniFiSiteActions.generateVouchers(actions, count, DEFAULT_EXPIRE_MIN);
149 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire) {
150 return UniFiSiteActions.generateVouchers(actions, count, expire, DEFAULT_USERS);
153 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire,
154 @Nullable Integer users) {
155 return UniFiSiteActions.generateVouchers(actions, count, expire, users, null, null, null);
158 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire,
159 @Nullable Integer users, @Nullable Integer upLimit, @Nullable Integer downLimit,
160 @Nullable Integer dataQuota) {
161 return ((UniFiSiteActions) actions).generateVouchers(count, expire, users, upLimit, downLimit, dataQuota);
164 @RuleAction(label = "@text/action.unifi.revokeVouchers.label", description = "@text/action.unifi.revokeVouchers.description")
165 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeVoucher(
167 @ActionInput(name = "voucherCodes", label = "@text/action.unifi.vouchersInputVoucherCodes.label",
168 description = "@text/action.unifi.vouchersInputVoucherCodes.description") String voucherCode) {
170 return revokeVouchers(List.of(voucherCode));
173 @RuleAction(label = "@text/action.unifi.revokeVouchers.label", description = "@text/action.unifi.revokeVouchers.description")
174 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeVouchers(
176 @ActionInput(name = "voucherCodes", label = "@text/action.unifi.vouchersInputVoucherCodes.label",
177 description = "@text/action.unifi.vouchersInputVoucherCodes.description") List<String> voucherCodes) {
179 UniFiSiteThingHandler handler = this.handler;
180 if (handler == null) {
181 logger.debug("Could not revoke guest vouchers, site thing handler not set");
184 final @Nullable UniFiSite entity = handler.getEntity();
185 final UniFiController controller = handler.getController();
186 if (entity == null || controller == null) {
187 logger.debug("Could not revoke guest vouchers, site thing error");
191 // Only keep digits in provided codes, so matching is done correctly. This makes blanks and dashes in the input
192 // possible, as shown in the UniFi voucher UI.
193 List<String> cleanCodes = voucherCodes.stream().map(c -> NON_DIGITS_PATTERN.matcher(c).replaceAll(""))
194 .filter(c -> !c.isEmpty()).toList();
195 Stream<UniFiVoucher> voucherStream = entity.getCache().getVoucherStreamForSite(entity);
196 // If no codes provided, revoke all codes
197 List<UniFiVoucher> vouchers = (voucherCodes.isEmpty() ? voucherStream
198 : voucherStream.filter(v -> cleanCodes.contains(v.getCode()))).toList();
200 controller.revokeVouchers(entity, vouchers);
201 } catch (UniFiException e) {
202 logger.debug("Could not revoke guest vouchers, uniFi exception", e);
208 @RuleAction(label = "@text/action.unifi.revokeAllVouchers.label", description = "@text/action.unifi.revokeAllVouchers.description")
209 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeAllVouchers() {
210 return revokeVouchers(List.of());
213 public static boolean revokeVoucher(ThingActions actions, String voucherCode) {
214 return revokeVouchers(actions, List.of(voucherCode));
217 public static boolean revokeVouchers(ThingActions actions, List<String> voucherCodes) {
218 return ((UniFiSiteActions) actions).revokeVouchers(voucherCodes);
221 public static boolean revokeAllVouchers(ThingActions actions) {
222 return revokeVouchers(actions);
225 public static boolean revokeVouchers(ThingActions actions) {
226 return revokeVouchers(actions, List.of());
229 @RuleAction(label = "@text/action.unifi.listVouchers.label", description = "@text/action.unifi.listVouchers.description")
230 public @ActionOutput(name = "vouchers", type = "java.lang.String") String listVouchers() {
231 UniFiSiteThingHandler handler = this.handler;
232 if (handler == null) {
233 logger.debug("Could not list guest vouchers, site thing handler not set");
236 final @Nullable UniFiSite entity = handler.getEntity();
237 if (entity == null) {
238 logger.debug("Could not list guest vouchers, site thing error");
242 record Voucher(String code, String createTime, Integer duration, Integer quota, Integer used,
243 Integer qosUsageQuota, Integer qosRateMaxUp, Integer qosRateMaxDown, Boolean qosOverwrite, String note,
248 .toJson(entity.getCache().getVoucherStreamForSite(entity)
249 .collect(Collectors.mapping(
250 v -> new Voucher(v.getCode(), v.getCreateTime().toString(), v.getDuration(),
251 v.getQuota(), v.getUsed(), v.getQosUsageQuota(), v.getQosRateMaxUp(),
252 v.getQosRateMaxDown(), v.isQosOverwrite(), v.getNote(), v.getStatus()),
253 Collectors.toList())));
256 public static String listVouchers(ThingActions actions) {
257 return ((UniFiSiteActions) actions).listVouchers();
261 public void setThingHandler(ThingHandler handler) {
262 if (handler instanceof UniFiSiteThingHandler siteThingHandler) {
263 this.handler = siteThingHandler;
268 public @Nullable ThingHandler getThingHandler() {