From 11f5cb3299aa1092af1575d87769c754170ef3b0 Mon Sep 17 00:00:00 2001 From: Thomas Lauterbach <2452988+DrRSatzteil@users.noreply.github.com> Date: Mon, 14 Oct 2024 22:41:00 +0200 Subject: [PATCH] [unifi] Add some standard channels to access points (#17530) Signed-off-by: Thomas Lauterbach --- bundles/org.openhab.binding.unifi/README.md | 13 +++- .../unifi/internal/UniFiBindingConstants.java | 13 ++-- .../unifi/internal/api/dto/UniFiDevice.java | 44 ++++++++++- .../handler/UniFiAccessPointThingHandler.java | 76 +++++++++++++++++-- .../resources/OH-INF/i18n/unifi.properties | 18 +++++ .../resources/OH-INF/thing/thing-types.xml | 45 +++++++++++ .../resources/OH-INF/update/thing-updates.xml | 41 ++++++++++ 7 files changed, 233 insertions(+), 17 deletions(-) create mode 100644 bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/update/thing-updates.xml diff --git a/bundles/org.openhab.binding.unifi/README.md b/bundles/org.openhab.binding.unifi/README.md index 712d5489d2380..ac97f78db57cf 100644 --- a/bundles/org.openhab.binding.unifi/README.md +++ b/bundles/org.openhab.binding.unifi/README.md @@ -239,9 +239,16 @@ The default mode value is `auto`. The `accessPoint` information that is retrieved is available as these channels: -| Channel ID | Item Type | Description | Permissions | -|------------|-----------|------------------------------------|-------------| -| enable | Switch | Enable or disable the access point | Read, Write | +| 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 | ## 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 69d8fdce8c678..35910b6fabd65 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 @@ -61,21 +61,23 @@ public final class UniFiBindingConstants { public static final String CHANNEL_PASSPHRASE = "passphrase"; public static final String CHANNEL_QRCODE_ENCODING = "qrcodeEncoding"; - // List of common wired + wireless client channels + // List of common wired + wireless client + device channels public static final String CHANNEL_ONLINE = "online"; public static final String CHANNEL_NAME = "name"; - public static final String CHANNEL_HOSTNAME = "hostname"; public static final String CHANNEL_SITE = "site"; - public static final String CHANNEL_MAC_ADDRESS = "macAddress"; public static final String CHANNEL_IP_ADDRESS = "ipAddress"; public static final String CHANNEL_UPTIME = "uptime"; public static final String CHANNEL_LAST_SEEN = "lastSeen"; + public static final String CHANNEL_EXPERIENCE = "experience"; + + // List of common wired + wireless client channels + public static final String CHANNEL_HOSTNAME = "hostname"; + public static final String CHANNEL_MAC_ADDRESS = "macAddress"; public static final String CHANNEL_GUEST = "guest"; public static final String CHANNEL_BLOCKED = "blocked"; public static final String CHANNEL_RECONNECT = "reconnect"; public static final String CHANNEL_CMD = "cmd"; public static final String CHANNEL_CMD_RECONNECT = "reconnect"; - public static final String CHANNEL_EXPERIENCE = "experience"; // List of additional wireless client channels public static final String CHANNEL_AP = "ap"; @@ -95,8 +97,9 @@ public final class UniFiBindingConstants { public static final String CHANNEL_PORT_POE_VOLTAGE = "voltage"; public static final String CHANNEL_PORT_POE_CURRENT = "current"; - // List of access point channels + // List of access point device channels public static final String CHANNEL_AP_ENABLE = "enable"; + public static final String CHANNEL_AP_STATE = "state"; // 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/dto/UniFiDevice.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiDevice.java index 8449fd515c0b3..05ae21170609f 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 @@ -12,8 +12,11 @@ */ package org.openhab.binding.unifi.internal.api.dto; +import java.time.Instant; + import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache; import org.openhab.binding.unifi.internal.api.util.UniFiTidyLowerCaseStringDeserializer; +import org.openhab.binding.unifi.internal.api.util.UniFiTimestampDeserializer; import com.google.gson.JsonObject; import com.google.gson.annotations.JsonAdapter; @@ -36,6 +39,8 @@ public class UniFiDevice implements HasId { @JsonAdapter(UniFiTidyLowerCaseStringDeserializer.class) private String mac; + private String ip; + private String model; private String version; @@ -46,13 +51,23 @@ public class UniFiDevice implements HasId { private String name; + private Integer state; + + private Integer uptime; + + @JsonAdapter(UniFiTimestampDeserializer.class) + private Instant lastSeen; + private String siteId; + @SerializedName("satisfaction") + private Integer experience; + private UniFiPortTable[] portTable; private JsonObject[] portOverrides; - private boolean disabled; + private Boolean disabled; public UniFiDevice(final UniFiControllerCache cache) { this.cache = cache; @@ -79,14 +94,34 @@ public String getSerial() { return serial; } + public Integer getExperience() { + return experience; + } + public String getName() { return name == null || name.isBlank() ? mac : name; } + public Integer getState() { + return state; + } + + public Integer getUptime() { + return uptime; + } + + public Instant getLastSeen() { + return lastSeen; + } + public String getMac() { return mac; } + public String getIp() { + return ip; + } + public UniFiSite getSite() { return cache.getSite(siteId); } @@ -99,13 +134,14 @@ public JsonObject[] getPortOverrides() { return portOverrides; } - public boolean isDisabled() { + public Boolean isDisabled() { return disabled; } @Override public String toString() { - return String.format("UniFiDevice{mac: '%s', name: '%s', type: %s, model: '%s', disabled: %b, site: %s}", mac, - name, type, model, disabled, getSite()); + return String.format( + "UniFiDevice{mac: '%s', name: '%s', type: '%s', model: '%s', version: '%s', experience: %d, disabled: %b, uptime: %d, site: %s}", + mac, name, type, model, version, experience, disabled, uptime, getSite()); } } 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..a5b63aa2ae118 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,10 @@ */ 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.time.ZoneId; +import java.time.ZonedDateTime; import java.util.Map; import org.eclipse.jdt.annotation.NonNullByDefault; @@ -25,13 +26,18 @@ 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.DateTimeType; import org.openhab.core.library.types.OnOffType; +import org.openhab.core.library.types.QuantityType; +import org.openhab.core.library.types.StringType; +import org.openhab.core.library.unit.Units; 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; /** * An access point managed by the UniFi controller software. @@ -47,10 +53,10 @@ public UniFiAccessPointThingHandler(final Thing thing) { super(thing); } - private static boolean belongsToSite(final UniFiDevice client, final String siteName) { + private static boolean belongsToSite(final UniFiDevice device, final String siteName) { boolean result = true; if (!siteName.isEmpty()) { - final UniFiSite site = client.getSite(); + final UniFiSite site = device.getSite(); if (site == null || !site.matchesName(siteName)) { result = false; } @@ -78,13 +84,73 @@ protected boolean initialize(final UniFiAccessPointThingConfig config) { return device; } + @Override + protected State getDefaultState(final String channelID) { + final State state; + switch (channelID) { + case CHANNEL_UPTIME: + state = new QuantityType<>(0, Units.SECOND); + break; + case CHANNEL_EXPERIENCE: + state = new QuantityType<>(0, Units.PERCENT); + break; + default: + state = UnDefType.NULL; + break; + } + return state; + } + @Override protected State getChannelState(final UniFiDevice device, final String channelId) { + final UniFiSite site = device.getSite(); State state = getDefaultState(channelId); switch (channelId) { case CHANNEL_AP_ENABLE: - state = OnOffType.from(!device.isDisabled()); + if (device.isDisabled() != null) { + state = OnOffType.from(!device.isDisabled()); + } + break; + case CHANNEL_ONLINE: + if (device.getState() != null) { + state = OnOffType.from(device.getState() == 1); + } + break; + case CHANNEL_AP_STATE: + if (device.getState() != null) { + state = StringType.valueOf(device.getState().toString()); + } + break; + case CHANNEL_NAME: + if (device.getName() != null) { + state = StringType.valueOf(device.getName()); + } + break; + case CHANNEL_SITE: + if (site != null && site.getDescription() != null && !site.getDescription().isBlank()) { + state = StringType.valueOf(site.getDescription()); + } + break; + case CHANNEL_IP_ADDRESS: + if (device.getIp() != null && !device.getIp().isBlank()) { + state = StringType.valueOf(device.getIp()); + } + break; + case CHANNEL_UPTIME: + if (device.getUptime() != null) { + state = new QuantityType<>(device.getUptime(), Units.SECOND); + } + break; + case CHANNEL_LAST_SEEN: + if (device.getLastSeen() != null) { + state = new DateTimeType(ZonedDateTime.ofInstant(device.getLastSeen(), ZoneId.systemDefault())); + } + break; + case CHANNEL_EXPERIENCE: + if (device.getExperience() != null) { + state = new QuantityType<>(device.getExperience(), Units.PERCENT); + } break; } return state; 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 e6547aa1ccc59..ade8ed542954b 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 @@ -7,6 +7,12 @@ addon.unifi.description = The UniFi binding integrates the UniFi controller from thing-type.unifi.accessPoint.label = UniFi Access Point thing-type.unifi.accessPoint.description = An access point managed by a UniFi controller +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.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) thing-type.unifi.controller.label = UniFi Controller thing-type.unifi.controller.description = A UniFi controller thing-type.unifi.poePort.label = UniFi PoE Port @@ -61,6 +67,18 @@ channel-type.unifi.apEnable.label = Enabled channel-type.unifi.apEnable.description = If the access point is enabled channel-type.unifi.blocked.label = Blocked channel-type.unifi.blocked.description = Is device blocked +channel-type.unifi.devState.label = Device State +channel-type.unifi.devState.description = The state of the device +channel-type.unifi.devState.state.option.0 = Offline +channel-type.unifi.devState.state.option.1 = Connected +channel-type.unifi.devState.state.option.2 = Pending Adoption +channel-type.unifi.devState.state.option.4 = Updating +channel-type.unifi.devState.state.option.5 = Provisioning +channel-type.unifi.devState.state.option.6 = Unreachable +channel-type.unifi.devState.state.option.7 = Adopting +channel-type.unifi.devState.state.option.9 = Adoption Error +channel-type.unifi.devState.state.option.10 = Adoption Failed +channel-type.unifi.devState.state.option.11 = Isolated channel-type.unifi.essid.label = Wireless Network channel-type.unifi.essid.description = Wireless Network (ESSID) the wireless client is connected to channel-type.unifi.experience.label = Experience 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..2586fa5095331 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 @@ -150,9 +150,34 @@ An access point managed by a UniFi controller + + Online status of the device + + + + Name of the device + + + + IP address of the device + + + Uptime of the device (in seconds) + + + Timestamp of when the device was last seen + + + The average experience of the connected clients + + + Ubiquiti Networks + 1 + + @@ -442,4 +467,24 @@ If the access point is enabled + + String + + The state of the device + + + + + + + + + + + + + + + + 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 new file mode 100644 index 0000000000000..ed791001bbe4c --- /dev/null +++ b/bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/update/thing-updates.xml @@ -0,0 +1,41 @@ + + + + + + + unifi:online + Online status of the device + + + unifi:devState + + + unifi:name + Name of the device + + + unifi:site + + + unifi:ipAddress + IP address of the device + + + unifi:uptime + Uptime of the device (in seconds) + + + unifi:lastSeen + Timestamp of when the device was last seen + + + unifi:experience + The average experience of the connected clients + + + + +