2 * Copyright (c) 2010-2024 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.osgi.service.component.annotations.Component;
34 import org.osgi.service.component.annotations.ServiceScope;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 import com.google.gson.Gson;
41 * The {@link UniFiSiteActions} class defines rule actions for creating guest hotspot vouchers
43 * @author Mark Herwege - Initial contribution
45 @Component(scope = ServiceScope.PROTOTYPE, service = UniFiSiteActions.class)
46 @ThingActionsScope(name = "unifi")
48 public class UniFiSiteActions implements ThingActions {
50 private static final int DEFAULT_COUNT = 1;
51 private static final int DEFAULT_EXPIRE_MIN = 1440;
52 private static final int DEFAULT_USERS = 1;
54 private static final Pattern NON_DIGITS_PATTERN = Pattern.compile("\\D+");
56 private final Logger logger = LoggerFactory.getLogger(UniFiSiteActions.class);
58 private @Nullable UniFiSiteThingHandler handler;
59 private final Gson gson = new Gson();
61 @RuleAction(label = "@text/action.unifi.generateVouchers.label", description = "@text/action.unifi.generateVouchers.description")
62 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean generateVoucher(
64 @ActionInput(name = "expire",
65 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.label",
66 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.description") @Nullable Integer expire,
67 @ActionInput(name = "users",
68 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.label",
69 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.description") @Nullable Integer users,
70 @ActionInput(name = "upLimit",
71 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.label",
72 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.description") @Nullable Integer upLimit,
73 @ActionInput(name = "downLimit",
74 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.label",
75 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.description") @Nullable Integer downLimit,
76 @ActionInput(name = "dataQuota",
77 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.label",
78 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.description") @Nullable Integer dataQuota) {
80 return generateVouchers(1, expire, users, upLimit, downLimit, dataQuota);
83 @RuleAction(label = "@text/action.unifi.generateVouchers.label", description = "@text/action.unifi.generateVouchers.description")
84 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean generateVouchers(
86 @ActionInput(name = "count",
87 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherCount.label",
88 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherCount.description") @Nullable Integer count,
89 @ActionInput(name = "expire",
90 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.label",
91 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherExpiration.description") @Nullable Integer expire,
92 @ActionInput(name = "users",
93 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.label",
94 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUsers.description") @Nullable Integer users,
95 @ActionInput(name = "upLimit",
96 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.label",
97 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherUpLimit.description") @Nullable Integer upLimit,
98 @ActionInput(name = "downLimit",
99 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.label",
100 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDownLimit.description") @Nullable Integer downLimit,
101 @ActionInput(name = "dataQuota",
102 label = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.label",
103 description = "@text/channel-type.config.unifi.guestVouchersGenerate.voucherDataQuota.description") @Nullable Integer dataQuota) {
105 UniFiSiteThingHandler handler = this.handler;
106 if (handler == null) {
107 logger.debug("Could not create guest vouchers, site thing handler not set");
110 final @Nullable UniFiSite entity = handler.getEntity();
111 final UniFiController controller = handler.getController();
112 if (entity == null || controller == null) {
113 logger.debug("Could not create guest vouchers, site thing error");
117 controller.generateVouchers(entity, ((count != null) && (count != 0)) ? count : DEFAULT_COUNT,
118 (expire != null) ? expire : DEFAULT_EXPIRE_MIN, (users != null) ? users : DEFAULT_USERS, upLimit,
119 downLimit, dataQuota);
120 } catch (UniFiException e) {
121 logger.debug("Could not create guest vouchers, uniFi exception", e);
127 public static boolean generateVoucher(ThingActions actions) {
128 return UniFiSiteActions.generateVoucher(actions, DEFAULT_EXPIRE_MIN);
131 public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire) {
132 return UniFiSiteActions.generateVoucher(actions, expire, DEFAULT_USERS);
135 public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire, @Nullable Integer users) {
136 return UniFiSiteActions.generateVoucher(actions, expire, users, null, null, null);
139 public static boolean generateVoucher(ThingActions actions, @Nullable Integer expire, @Nullable Integer users,
140 @Nullable Integer upLimit, @Nullable Integer downLimit, @Nullable Integer dataQuota) {
141 return ((UniFiSiteActions) actions).generateVoucher(expire, users, upLimit, downLimit, dataQuota);
144 public static boolean generateVouchers(ThingActions actions) {
145 return UniFiSiteActions.generateVouchers(actions, DEFAULT_COUNT);
148 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count) {
149 return UniFiSiteActions.generateVouchers(actions, count, DEFAULT_EXPIRE_MIN);
152 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire) {
153 return UniFiSiteActions.generateVouchers(actions, count, expire, DEFAULT_USERS);
156 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire,
157 @Nullable Integer users) {
158 return UniFiSiteActions.generateVouchers(actions, count, expire, users, null, null, null);
161 public static boolean generateVouchers(ThingActions actions, @Nullable Integer count, @Nullable Integer expire,
162 @Nullable Integer users, @Nullable Integer upLimit, @Nullable Integer downLimit,
163 @Nullable Integer dataQuota) {
164 return ((UniFiSiteActions) actions).generateVouchers(count, expire, users, upLimit, downLimit, dataQuota);
167 @RuleAction(label = "@text/action.unifi.revokeVouchers.label", description = "@text/action.unifi.revokeVouchers.description")
168 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeVoucher(
170 @ActionInput(name = "voucherCodes", label = "@text/action.unifi.vouchersInputVoucherCodes.label",
171 description = "@text/action.unifi.vouchersInputVoucherCodes.description") String voucherCode) {
173 return revokeVouchers(List.of(voucherCode));
176 @RuleAction(label = "@text/action.unifi.revokeVouchers.label", description = "@text/action.unifi.revokeVouchers.description")
177 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeVouchers(
179 @ActionInput(name = "voucherCodes", label = "@text/action.unifi.vouchersInputVoucherCodes.label",
180 description = "@text/action.unifi.vouchersInputVoucherCodes.description") List<String> voucherCodes) {
182 UniFiSiteThingHandler handler = this.handler;
183 if (handler == null) {
184 logger.debug("Could not revoke guest vouchers, site thing handler not set");
187 final @Nullable UniFiSite entity = handler.getEntity();
188 final UniFiController controller = handler.getController();
189 if (entity == null || controller == null) {
190 logger.debug("Could not revoke guest vouchers, site thing error");
194 // Only keep digits in provided codes, so matching is done correctly. This makes blanks and dashes in the input
195 // possible, as shown in the UniFi voucher UI.
196 List<String> cleanCodes = voucherCodes.stream().map(c -> NON_DIGITS_PATTERN.matcher(c).replaceAll(""))
197 .filter(c -> !c.isEmpty()).toList();
198 Stream<UniFiVoucher> voucherStream = entity.getCache().getVoucherStreamForSite(entity);
199 // If no codes provided, revoke all codes
200 List<UniFiVoucher> vouchers = (voucherCodes.isEmpty() ? voucherStream
201 : voucherStream.filter(v -> cleanCodes.contains(v.getCode()))).toList();
203 controller.revokeVouchers(entity, vouchers);
204 } catch (UniFiException e) {
205 logger.debug("Could not revoke guest vouchers, uniFi exception", e);
211 @RuleAction(label = "@text/action.unifi.revokeAllVouchers.label", description = "@text/action.unifi.revokeAllVouchers.description")
212 public @ActionOutput(name = "success", type = "java.lang.Boolean") Boolean revokeAllVouchers() {
213 return revokeVouchers(List.of());
216 public static boolean revokeVoucher(ThingActions actions, String voucherCode) {
217 return revokeVouchers(actions, List.of(voucherCode));
220 public static boolean revokeVouchers(ThingActions actions, List<String> voucherCodes) {
221 return ((UniFiSiteActions) actions).revokeVouchers(voucherCodes);
224 public static boolean revokeAllVouchers(ThingActions actions) {
225 return revokeVouchers(actions);
228 public static boolean revokeVouchers(ThingActions actions) {
229 return revokeVouchers(actions, List.of());
232 @RuleAction(label = "@text/action.unifi.listVouchers.label", description = "@text/action.unifi.listVouchers.description")
233 public @ActionOutput(name = "vouchers", type = "java.lang.String") String listVouchers() {
234 UniFiSiteThingHandler handler = this.handler;
235 if (handler == null) {
236 logger.debug("Could not list guest vouchers, site thing handler not set");
239 final @Nullable UniFiSite entity = handler.getEntity();
240 if (entity == null) {
241 logger.debug("Could not list guest vouchers, site thing error");
245 record Voucher(String code, String createTime, Integer duration, Integer quota, Integer used,
246 Integer qosUsageQuota, Integer qosRateMaxUp, Integer qosRateMaxDown, Boolean qosOverwrite, String note,
251 .toJson(entity.getCache().getVoucherStreamForSite(entity)
252 .collect(Collectors.mapping(
253 v -> new Voucher(v.getCode(), v.getCreateTime().toString(), v.getDuration(),
254 v.getQuota(), v.getUsed(), v.getQosUsageQuota(), v.getQosRateMaxUp(),
255 v.getQosRateMaxDown(), v.isQosOverwrite(), v.getNote(), v.getStatus()),
256 Collectors.toList())));
259 public static String listVouchers(ThingActions actions) {
260 return ((UniFiSiteActions) actions).listVouchers();
264 public void setThingHandler(ThingHandler handler) {
265 if (handler instanceof UniFiSiteThingHandler siteThingHandler) {
266 this.handler = siteThingHandler;
271 public @Nullable ThingHandler getThingHandler() {