diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java index 69d8fdce8c678..db9c7581b90a6 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/UniFiBindingConstants.java @@ -97,6 +97,8 @@ public final class UniFiBindingConstants { // List of access point channels public static final String CHANNEL_AP_ENABLE = "enable"; + public static final String CHANNEL_AP_LED_OVERRIDE = "ledOverride"; + public static final String CHANNEL_AP_LED_COLOR = "ledColor"; // List of all Parameters public static final String PARAMETER_HOST = "host"; 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 fa93d7bde8752..4e9f7c4f9e738 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 @@ -224,6 +224,24 @@ public void disableAccessPoint(final UniFiDevice device, final boolean disable) refresh(); } + public void setLedOverride(final UniFiDevice device, final String override, final String color, + final @Nullable Integer brightness) throws UniFiException { + final UniFiControllerRequest req = newRequest(Void.class, HttpMethod.PUT, gson); + req.setAPIPath(String.format("/api/s/%s/rest/device/%s", device.getSite().getName(), device.getId())); + req.setBodyParameter("_id", device.getId()); + if (!override.isEmpty()) { + req.setBodyParameter("led_override", override); + } + if (!color.isEmpty()) { + req.setBodyParameter("led_override_color", color); + } + if (brightness != null) { + req.setBodyParameter("led_override_color_brightness", brightness); + } + executeRequest(req); + refresh(); + } + 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); diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiDevice.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiDevice.java index 8449fd515c0b3..93763b828f57c 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiDevice.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiDevice.java @@ -54,6 +54,12 @@ public class UniFiDevice implements HasId { private boolean disabled; + private String ledOverride; + + private String ledOverrideColor; + + private Integer ledOverrideColorBrightness; + public UniFiDevice(final UniFiControllerCache cache) { this.cache = cache; } @@ -103,6 +109,18 @@ public boolean isDisabled() { return disabled; } + public String getLedOverride() { + return ledOverride; + } + + public String getLedOverrideColor() { + return ledOverrideColor; + } + + public Integer getLedOverrideColorBrightness() { + return ledOverrideColorBrightness; + } + @Override public String toString() { return String.format("UniFiDevice{mac: '%s', name: '%s', type: %s, model: '%s', disabled: %b, site: %s}", mac, diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiAccessPointThingHandler.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiAccessPointThingHandler.java index eacf3fae80be1..56cabe2de247a 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiAccessPointThingHandler.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiAccessPointThingHandler.java @@ -12,9 +12,9 @@ */ package org.openhab.binding.unifi.internal.handler; -import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_AP_ENABLE; -import static org.openhab.binding.unifi.internal.UniFiBindingConstants.DEVICE_TYPE_UAP; +import static org.openhab.binding.unifi.internal.UniFiBindingConstants.*; +import java.awt.Color; import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -25,13 +25,20 @@ import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache; import org.openhab.binding.unifi.internal.api.dto.UniFiDevice; import org.openhab.binding.unifi.internal.api.dto.UniFiSite; +import org.openhab.core.library.types.HSBType; +import org.openhab.core.library.types.IncreaseDecreaseType; import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.PercentType; 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.types.Command; import org.openhab.core.types.State; +import org.openhab.core.types.UnDefType; +import org.openhab.core.util.ColorUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * An access point managed by the UniFi controller software. @@ -41,6 +48,10 @@ @NonNullByDefault public class UniFiAccessPointThingHandler extends UniFiBaseThingHandler { + private static final int LED_BRIGHTNESS_STEP_PERCENT = 5; + + private final Logger logger = LoggerFactory.getLogger(UniFiAccessPointThingHandler.class); + private UniFiAccessPointThingConfig config = new UniFiAccessPointThingConfig(); public UniFiAccessPointThingHandler(final Thing thing) { @@ -86,10 +97,30 @@ protected State getChannelState(final UniFiDevice device, final String channelId case CHANNEL_AP_ENABLE: state = OnOffType.from(!device.isDisabled()); break; + case CHANNEL_AP_LED_OVERRIDE: + state = OnOffType.from(!"default".equals(device.getLedOverride())); + break; + case CHANNEL_AP_LED_COLOR: + state = getLedColorState(device); + break; } return state; } + private State getLedColorState(final UniFiDevice device) { + if (device.getLedOverride().equals("off")) { + return HSBType.BLACK; + } + String overrideColor = device.getLedOverrideColor(); + Integer overrideBrightness = device.getLedOverrideColorBrightness(); + if (overrideColor == null || overrideBrightness == null) { + return UnDefType.UNDEF; + } + Color color = Color.decode(overrideColor); + HSBType hsb = HSBType.fromRGB(color.getRed(), color.getGreen(), color.getBlue()); + return new HSBType(hsb.getHue(), hsb.getSaturation(), new PercentType(overrideBrightness)); + } + @Override protected void updateProperties(final UniFiDevice device) { updateProperties(Map.of( // @@ -105,6 +136,10 @@ protected boolean handleCommand(final UniFiController controller, final UniFiDev if (CHANNEL_AP_ENABLE.equals(channelID) && command instanceof OnOffType onOffCommand) { return handleEnableCommand(controller, device, channelUID, onOffCommand); + } else if (CHANNEL_AP_LED_OVERRIDE.equals(channelID) && command instanceof OnOffType onOffCommand) { + return handleLedOverrideCommand(controller, device, channelUID, onOffCommand); + } else if (CHANNEL_AP_LED_COLOR.equals(channelID)) { + return handleLedColorCommand(controller, device, channelUID, command); } return false; } @@ -115,4 +150,59 @@ private boolean handleEnableCommand(final UniFiController controller, final UniF refresh(); return true; } + + private boolean handleLedOverrideCommand(final UniFiController controller, final UniFiDevice device, + final ChannelUID channelUID, final OnOffType command) throws UniFiException { + controller.setLedOverride(device, command == OnOffType.ON ? "on" : "default", "", null); + refresh(); + return true; + } + + private boolean handleLedColorCommand(final UniFiController controller, final UniFiDevice device, + final ChannelUID channelUID, final Command command) throws UniFiException { + String newOverride = "", newColor = ""; + Integer newBrightness = null; + + if (command instanceof HSBType hsbCommand) { + int brightness = hsbCommand.getBrightness().intValue(); + HSBType fullColor = new HSBType(hsbCommand.getHue(), hsbCommand.getSaturation(), PercentType.HUNDRED); + Color color = new Color(ColorUtil.hsbTosRgb(fullColor)); + newOverride = brightness == 0 ? "off" : "on"; + newBrightness = brightness; + newColor = "#%02x%02x%02x".formatted(color.getRed(), color.getGreen(), color.getBlue()); + } else if (command instanceof PercentType brightnessCommand) { + int brightness = brightnessCommand.intValue(); + newOverride = brightness == 0 ? "off" : "on"; + newBrightness = brightness; + } else { + Integer currentOverrideBrightness = device.getLedOverrideColorBrightness(); + if (currentOverrideBrightness == null) { + logger.warn("Failed to handle command {} since current state is missing", command); + return false; + } + int currentBrightness = currentOverrideBrightness.intValue(); + + if (command instanceof IncreaseDecreaseType increaseDecreaseCommand) { + int brightness = switch (increaseDecreaseCommand) { + case INCREASE -> currentBrightness + LED_BRIGHTNESS_STEP_PERCENT; + case DECREASE -> currentBrightness - LED_BRIGHTNESS_STEP_PERCENT; + }; + brightness = brightness < 0 ? 0 : brightness > 100 ? 100 : brightness; + newOverride = brightness == 0 ? "off" : "on"; + newBrightness = brightness; + } else if (command instanceof OnOffType) { + newOverride = command == OnOffType.ON ? "on" : "off"; + newBrightness = command == OnOffType.ON && currentBrightness == 0 ? 100 : null; + } + } + + boolean isOverridden = !"default".equals(device.getLedOverride()); + if ((!newOverride.isEmpty() && isOverridden) || !newColor.isEmpty() || newBrightness != null) { + controller.setLedOverride(device, isOverridden ? newOverride : "", newColor, newBrightness); + refresh(); + return true; + } else { + return false; + } + } } diff --git a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml index 5d096e14c4da9..7e214fe693d5e 100644 --- a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml +++ b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/thing/thing-types.xml @@ -151,6 +151,10 @@ + + + Controls the color and brightness of the LED + @@ -442,4 +446,10 @@ If the access point is enabled + + Switch + + If the LED is overridden + +