Skip to content

Commit

Permalink
Provide LED channels for access point
Browse files Browse the repository at this point in the history
Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
  • Loading branch information
jlaur committed Oct 14, 2024
1 parent 11f5cb3 commit 104915e
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 11 deletions.
22 changes: 12 additions & 10 deletions bundles/org.openhab.binding.unifi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Void> 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<Void> req = newRequest(Void.class, HttpMethod.POST, gson);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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.
Expand All @@ -47,6 +54,10 @@
@NonNullByDefault
public class UniFiAccessPointThingHandler extends UniFiBaseThingHandler<UniFiDevice, UniFiAccessPointThingConfig> {

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) {
Expand Down Expand Up @@ -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( //
Expand All @@ -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;
}
Expand All @@ -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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,15 @@
<channel id="experience" typeId="experience">
<description>The average experience of the connected clients</description>
</channel>
<channel id="ledOverride" typeId="apLedOverride"/>
<channel id="ledColor" typeId="system.color">
<description>Controls the color and brightness of the LED</description>
</channel>
</channels>

<properties>
<property name="vendor">Ubiquiti Networks</property>
<property name="thingTypeVersion">1</property>
<property name="thingTypeVersion">2</property>
</properties>

<config-description-ref uri="thing-type:unifi:accessPoint"/>
Expand Down Expand Up @@ -487,4 +491,10 @@
</state>
</channel-type>

<channel-type id="apLedOverride">
<item-type>Switch</item-type>
<label>LED Override</label>
<description>If the LED is overridden</description>
</channel-type>

</thing:thing-descriptions>
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@
<description>The average experience of the connected clients</description>
</add-channel>
</instruction-set>
<instruction-set targetVersion="2">
<add-channel id="ledOverride">
<type>unifi:ledOverride</type>
</add-channel>
<add-channel id="ledColor">
<type>system:color</type>
<description>Controls the color and brightness of the LED</description>
</add-channel>
</instruction-set>
</thing-type>

</update:update-descriptions>

0 comments on commit 104915e

Please sign in to comment.