diff --git a/bundles/org.openhab.binding.unifi/README.md b/bundles/org.openhab.binding.unifi/README.md index ac97f78db57cf..f904862013872 100644 --- a/bundles/org.openhab.binding.unifi/README.md +++ b/bundles/org.openhab.binding.unifi/README.md @@ -239,16 +239,18 @@ The default mode value is `auto`. The `accessPoint` information that is retrieved is available as these channels: -| Channel ID | Item Type | Description | Permissions | -|------------|----------------------|----------------------------------------------------------------------|-------------| -| online | Switch | Online status of the device | Read | -| enable | Switch | Enable or disable the access point | Read, Write | -| name | String | Name of device (from the controller web UI) | Read | -| site | String | Site name (from the controller web UI) the device is associated with | Read | -| ipAddress | String | IP address of the device | Read | -| uptime | Number:Time | Uptime of the device (in seconds) | Read | -| lastSeen | DateTime | Date and Time the device was last seen | Read | -| experience | Number:Dimensionless | The average health indication of the connected clients | Read | +| Channel ID | Item Type | Description | Permissions | +|-------------|----------------------|----------------------------------------------------------------------|-------------| +| online | Switch | Online status of the device | Read | +| enable | Switch | Enable or disable the access point | Read, Write | +| name | String | Name of device (from the controller web UI) | Read | +| site | String | Site name (from the controller web UI) the device is associated with | Read | +| ipAddress | String | IP address of the device | Read | +| uptime | Number:Time | Uptime of the device (in seconds) | Read | +| lastSeen | DateTime | Date and Time the device was last seen | Read | +| experience | Number:Dimensionless | The average health indication of the connected clients | Read | +| ledOverride | Switch | Override the LED. If disabled, the site-wide setting is used | Read, Write | +| ledColor | Color | Controls the color and brightness of the LED (when overridden) | Read, Write | ## Rule Actions 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 35910b6fabd65..1f4186ede12cd 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 @@ -100,6 +100,8 @@ public final class UniFiBindingConstants { // List of access point device channels public static final String CHANNEL_AP_ENABLE = "enable"; public static final String CHANNEL_AP_STATE = "state"; + 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 05ae21170609f..15533ec84005c 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 @@ -69,6 +69,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; } @@ -138,6 +144,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( 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 a5b63aa2ae118..3e32bbf6fdd04 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 @@ -14,6 +14,7 @@ import static org.openhab.binding.unifi.internal.UniFiBindingConstants.*; +import java.awt.Color; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Map; @@ -27,7 +28,10 @@ import org.openhab.binding.unifi.internal.api.dto.UniFiDevice; import org.openhab.binding.unifi.internal.api.dto.UniFiSite; import org.openhab.core.library.types.DateTimeType; +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.library.types.QuantityType; import org.openhab.core.library.types.StringType; import org.openhab.core.library.unit.Units; @@ -38,6 +42,9 @@ 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. @@ -47,6 +54,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) { @@ -152,10 +163,30 @@ protected State getChannelState(final UniFiDevice device, final String channelId state = new QuantityType<>(device.getExperience(), Units.PERCENT); } 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( // @@ -171,6 +202,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; } @@ -181,4 +216,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/i18n/unifi.properties b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties index ade8ed542954b..70bdf20c32bf5 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 @@ -10,6 +10,7 @@ thing-type.unifi.accessPoint.description = An access point managed by a UniFi co thing-type.unifi.accessPoint.channel.experience.description = The average experience of the connected clients thing-type.unifi.accessPoint.channel.ipAddress.description = IP address of the device thing-type.unifi.accessPoint.channel.lastSeen.description = Timestamp of when the device was last seen +thing-type.unifi.accessPoint.channel.ledColor.description = Controls the color and brightness of the LED thing-type.unifi.accessPoint.channel.name.description = Name of the device thing-type.unifi.accessPoint.channel.online.description = Online status of the device thing-type.unifi.accessPoint.channel.uptime.description = Uptime of the device (in seconds) @@ -65,6 +66,8 @@ channel-type.unifi.ap.label = Access Point channel-type.unifi.ap.description = Access Point the wireless client is connected to channel-type.unifi.apEnable.label = Enabled channel-type.unifi.apEnable.description = If the access point is enabled +channel-type.unifi.apLedOverride.label = LED Override +channel-type.unifi.apLedOverride.description = If the LED is overridden channel-type.unifi.blocked.label = Blocked channel-type.unifi.blocked.description = Is device blocked channel-type.unifi.devState.label = Device State 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 2586fa5095331..4b03fb37e5901 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 @@ -171,11 +171,15 @@ The average experience of the connected clients + + + Controls the color and brightness of the LED + Ubiquiti Networks - 1 + 2 @@ -487,4 +491,10 @@ + + Switch + + If the LED is overridden + + diff --git a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/update/thing-updates.xml b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/update/thing-updates.xml index ed791001bbe4c..bd705999dcd83 100644 --- a/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/update/thing-updates.xml +++ b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/update/thing-updates.xml @@ -36,6 +36,15 @@ The average experience of the connected clients + + + unifi:ledOverride + + + system:color + Controls the color and brightness of the LED + +