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 d0c6678a0b..41f18fd3f3 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 @@ -21,15 +21,16 @@ import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.http.HttpMethod; import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache; -import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverride; +import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement; import org.openhab.binding.unifi.internal.api.dto.UniFiClient; import org.openhab.binding.unifi.internal.api.dto.UniFiDevice; -import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable; +import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple; import org.openhab.binding.unifi.internal.api.dto.UniFiSite; import org.openhab.binding.unifi.internal.api.dto.UniFiUnknownClient; import org.openhab.binding.unifi.internal.api.dto.UniFiWiredClient; import org.openhab.binding.unifi.internal.api.dto.UniFiWirelessClient; import org.openhab.binding.unifi.internal.api.dto.UniFiWlan; +import org.openhab.binding.unifi.internal.api.util.UnfiPortOverrideJsonElementDeserializer; import org.openhab.binding.unifi.internal.api.util.UniFiClientDeserializer; import org.openhab.binding.unifi.internal.api.util.UniFiClientInstanceCreator; import org.openhab.binding.unifi.internal.api.util.UniFiDeviceInstanceCreator; @@ -92,8 +93,9 @@ public class UniFiController { .registerTypeAdapter(UniFiUnknownClient.class, clientInstanceCreator) .registerTypeAdapter(UniFiWiredClient.class, clientInstanceCreator) .registerTypeAdapter(UniFiWirelessClient.class, clientInstanceCreator).create(); - this.poeGson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .excludeFieldsWithoutExposeAnnotation().create(); + this.poeGson = new GsonBuilder() + .registerTypeAdapter(UnfiPortOverrideJsonElement.class, new UnfiPortOverrideJsonElementDeserializer()) + .create(); } // Public API @@ -151,7 +153,7 @@ public class UniFiController { return cache; } - public @Nullable Map getSwitchPorts(@Nullable final String deviceId) { + public @Nullable Map getSwitchPorts(@Nullable final String deviceId) { return cache.getSwitchPorts(deviceId); } @@ -173,12 +175,20 @@ public class UniFiController { refresh(); } - public void poeMode(final UniFiDevice device, final Map data) throws UniFiException { - final UniFiControllerRequest req = newRequest(Void.class, HttpMethod.PUT, poeGson); - req.setAPIPath(String.format("/api/s/%s/rest/device/%s", device.getSite().getName(), device.getId())); - req.setBodyParameter("port_overrides", data.values()); - executeRequest(req); - refresh(); + public boolean poeMode(final UniFiDevice device, final List data) + throws UniFiException { + // Safety check to make sure no empty data is send to avoid corrupting override data on the device. + if (data.isEmpty() || data.stream().anyMatch(p -> p.getJsonObject().entrySet().isEmpty())) { + logger.info("Not overriding port for '{}', because port data contains empty json: {}", device.getName(), + poeGson.toJson(data)); + return false; + } else { + final UniFiControllerRequest req = newRequest(Void.class, HttpMethod.PUT, poeGson); + req.setAPIPath(String.format("/api/s/%s/rest/device/%s", device.getSite().getName(), device.getId())); + req.setBodyParameter("port_overrides", data); + executeRequest(req); + return true; + } } public void poePowerCycle(final UniFiDevice device, final Integer portIdx) throws UniFiException { diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiControllerRequest.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiControllerRequest.java index 4acf1e0b46..2d02158898 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiControllerRequest.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiControllerRequest.java @@ -230,6 +230,7 @@ class UniFiControllerRequest { if (!bodyParameters.isEmpty()) { final String jsonBody = gson.toJson(bodyParameters); + logger.debug("Body parameters for request '{}': {}", request.getPath(), jsonBody); request.content( new StringContentProvider(CONTENT_TYPE_APPLICATION_JSON_UTF_8, jsonBody, StandardCharsets.UTF_8)); } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/cache/UniFiControllerCache.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/cache/UniFiControllerCache.java index 174062cca1..e8189ddaa8 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/cache/UniFiControllerCache.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/cache/UniFiControllerCache.java @@ -13,19 +13,20 @@ package org.openhab.binding.unifi.internal.api.cache; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; +import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement; import org.openhab.binding.unifi.internal.api.dto.UniFiClient; import org.openhab.binding.unifi.internal.api.dto.UniFiDevice; -import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable; +import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple; import org.openhab.binding.unifi.internal.api.dto.UniFiSite; import org.openhab.binding.unifi.internal.api.dto.UniFiWlan; import org.slf4j.Logger; @@ -47,7 +48,7 @@ public class UniFiControllerCache { private final UniFiDeviceCache devicesCache = new UniFiDeviceCache(); private final UniFiClientCache clientsCache = new UniFiClientCache(); private final UniFiClientCache insightsCache = new UniFiClientCache(); - private final Map> devicesToPortTables = new ConcurrentHashMap<>(); + private final Map> devicesToPortTables = new ConcurrentHashMap<>(); public void clear() { sitesCache.clear(); @@ -93,9 +94,25 @@ public class UniFiControllerCache { if (devices != null) { Stream.of(devices).filter(Objects::nonNull).forEach(d -> { Stream.ofNullable(d.getPortTable()).filter(ptl -> ptl.length > 0 && ptl[0].isPortPoe()).forEach(pt -> { - Stream.of(pt).forEach(p -> p.setDevice(d)); - devicesToPortTables.put(d.getMac(), - Stream.of(pt).collect(Collectors.toMap(UniFiPortTable::getPortIdx, Function.identity()))); + final Map tupleTable = devicesToPortTables.computeIfAbsent(d.getMac(), + p -> new HashMap<>()); + + Stream.of(pt).forEach(p -> { + final UniFiPortTuple tuple = tupleTable.computeIfAbsent(p.getPortIdx(), + t -> new UniFiPortTuple()); + + tuple.setDevice(d); + tuple.setTable(p); + }); + }); + Stream.ofNullable(d.getPortOverrides()).filter(ptl -> ptl.length > 0).forEach(po -> { + final Map tupleTable = devicesToPortTables.get(d.getMac()); + + if (tupleTable != null) { + Stream.of(po).filter(pof -> !pof.getAsJsonObject().entrySet().isEmpty()) + .map(UnfiPortOverrideJsonElement::new) + .forEach(p -> tupleTable.get(p.getPortIdx()).setJsonElement(p)); + } }); }); } @@ -105,11 +122,11 @@ public class UniFiControllerCache { return devicesCache.get(id); } - public Map getSwitchPorts(@Nullable final String deviceId) { + public Map getSwitchPorts(@Nullable final String deviceId) { return deviceId == null ? Map.of() : devicesToPortTables.getOrDefault(deviceId, Map.of()); } - public Collection> getSwitchPorts() { + public Collection> getSwitchPorts() { return devicesToPortTables.values(); } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverride.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverride.java deleted file mode 100644 index bd4a41ff06..0000000000 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverride.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2010-2022 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.unifi.internal.api.dto; - -import com.google.gson.annotations.Expose; - -/** - * The {@link UnfiPortOverride} represents the data model of UniFi port override. - * - * @author Hilbrand Bouwkamp - Initial contribution - */ -public class UnfiPortOverride { - - @Expose - private int portIdx; - - @Expose - private String portconfId; - - @Expose - private String poeMode; - - public UnfiPortOverride() { - // Constructor for GSON. - } - - public UnfiPortOverride(final int portIdx, final String portconfId, final String poeMode) { - this.portIdx = portIdx; - this.portconfId = portconfId; - this.poeMode = poeMode; - } - - public int getPortIdx() { - return portIdx; - } - - public String getPortconfId() { - return portconfId; - } - - public String getPoeMode() { - return poeMode; - } - - public void setPortIdx(final int portIdx) { - this.portIdx = portIdx; - } - - public void setPortconfId(final String portconfId) { - this.portconfId = portconfId; - } - - public void setPoeMode(final String poeMode) { - this.poeMode = poeMode; - } - - @Override - public String toString() { - return String.format("UnfiPortOverride{portIx: '%d', portconfId: '%s', poeMode: '%s'}", portIdx, portconfId, - poeMode); - } -} diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverrideJsonElement.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverrideJsonElement.java new file mode 100644 index 0000000000..2562503b7e --- /dev/null +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverrideJsonElement.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.unifi.internal.api.dto; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +/** + * The {@link UnfiPortOverride} represents the data model of UniFi port override. + * Using plain JsonObject to make sure any data in the object is not lost when writing the data back to the UniFi + * device. + * + * @author Hilbrand Bouwkamp - Initial contribution + */ +public class UnfiPortOverrideJsonElement { + + private static final String PORT_IDX = "port_idx"; + private static final String PORT_CONF_ID = "port_conf_id"; + private static final String POE_MODE = "poe_mode"; + + private final JsonObject jsonObject; + + public UnfiPortOverrideJsonElement(final JsonElement element) { + this.jsonObject = element.getAsJsonObject(); + } + + public JsonObject getJsonObject() { + return jsonObject; + } + + public int getPortIdx() { + return jsonObject.get(PORT_IDX).getAsInt(); + } + + public String getPortConfId() { + return jsonObject.get(PORT_CONF_ID).getAsString(); + } + + public String getPoeMode() { + return jsonObject.get(POE_MODE).getAsString(); + } + + public void setPoeMode(final String poeMode) { + jsonObject.addProperty(POE_MODE, poeMode); + } + + @Override + public String toString() { + return jsonObject.toString(); + } +} 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 0cd1e1b38a..644ba3e631 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 @@ -15,6 +15,7 @@ package org.openhab.binding.unifi.internal.api.dto; import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache; import org.openhab.binding.unifi.internal.api.util.UniFiTidyLowerCaseStringDeserializer; +import com.google.gson.JsonElement; import com.google.gson.annotations.JsonAdapter; import com.google.gson.annotations.SerializedName; @@ -43,6 +44,8 @@ public class UniFiDevice implements HasId { private UniFiPortTable[] portTable; + private JsonElement[] portOverrides; + public UniFiDevice(final UniFiControllerCache cache) { this.cache = cache; } @@ -72,6 +75,10 @@ public class UniFiDevice implements HasId { return portTable; } + public JsonElement[] getPortOverrides() { + return portOverrides; + } + @Override public String toString() { return String.format("UniFiDevice{mac: '%s', name: '%s', model: '%s', site: %s}", mac, name, model, getSite()); diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortOverrides.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortOverrides.java deleted file mode 100644 index f6645781dc..0000000000 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortOverrides.java +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Copyright (c) 2010-2022 Contributors to the openHAB project - * - * See the NOTICE file(s) distributed with this work for additional - * information. - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Public License 2.0 which is available at - * http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - */ -package org.openhab.binding.unifi.internal.api.dto; - -import java.util.ArrayList; -import java.util.List; - -import com.google.gson.annotations.Expose; - -/** - * The {@link UniFiPortOverrides} represents the data model of UniFi port overrides. - * - * @author Hilbrand Bouwkamp - Initial contribution - */ -public class UniFiPortOverrides { - - @Expose - private final List portOverrides = new ArrayList<>(); - - public void addPortOverride(final UnfiPortOverride unfiPortOverride) { - portOverrides.add(unfiPortOverride); - } - - public void addPortOverride(final int portIdx, final String portconfId, final String poeMode) { - portOverrides.add(new UnfiPortOverride(portIdx, portconfId, poeMode)); - } - - @Override - public String toString() { - return String.format("UniFiPortOverrides: {}", String.join(", ", portOverrides.toArray(new String[0]))); - } -} diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTable.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTable.java index 637ed2dc5e..6a4b239dfa 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTable.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTable.java @@ -12,14 +12,23 @@ */ package org.openhab.binding.unifi.internal.api.dto; +import com.google.gson.annotations.Expose; + /** * The {@link UniFiPortTable} represents the data model of UniFi port table, which is an extend of port override. * * @author Hilbrand Bouwkamp - Initial contribution */ -public class UniFiPortTable extends UnfiPortOverride { +public class UniFiPortTable { - private transient UniFiDevice device; + @Expose + private int portIdx; + + @Expose + private String portconfId; + + @Expose + private String poeMode; private String name; @@ -40,12 +49,16 @@ public class UniFiPortTable extends UnfiPortOverride { private String poeCurrent; - public UniFiDevice getDevice() { - return device; + public int getPortIdx() { + return portIdx; } - public void setDevice(final UniFiDevice device) { - this.device = device; + public String getPortconfId() { + return portconfId; + } + + public String getPoeMode() { + return poeMode; } public String getName() { @@ -83,7 +96,7 @@ public class UniFiPortTable extends UnfiPortOverride { @Override public String toString() { return String.format( - "UniFiPortTable{name: '%s', enable: '%b', up: '%b', portPoe: '%b', poeEnable: '%b, poePower: '%s', poeVoltage: '%s', poeCurrent: '%s'}", - name, enable, up, portPoe, poeEnable, poePower, poeVoltage, poeCurrent); + "UniFiPortTable{portIx: '%d', portconfId: '%s', poeMode: '%s', name: '%s', enable: '%b', up: '%b', portPoe: '%b', poeEnable: '%b, poePower: '%s', poeVoltage: '%s', poeCurrent: '%s'}", + portIdx, portconfId, poeMode, name, enable, up, portPoe, poeEnable, poePower, poeVoltage, poeCurrent); } } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTuple.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTuple.java new file mode 100644 index 0000000000..fa9865d87e --- /dev/null +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTuple.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.unifi.internal.api.dto; + +/** + * Tuple to store both the {@link UniFiPortTable}, which contains the all information related to the port, + * and the {@link UnfiPortOverrideJsonElement}, which contains the raw json data of the port override. + * + * @author Hilbrand Bouwkamp - Initial contribution + */ +public class UniFiPortTuple { + + private UniFiDevice device; + + private UniFiPortTable table; + + private UnfiPortOverrideJsonElement jsonElement; + + public UniFiDevice getDevice() { + return device; + } + + public void setDevice(final UniFiDevice device) { + this.device = device; + } + + public int getPortIdx() { + return table == null ? 0 : table.getPortIdx(); + } + + public UniFiPortTable getTable() { + return table; + } + + public void setTable(final UniFiPortTable table) { + this.table = table; + } + + public UnfiPortOverrideJsonElement getJsonElement() { + return jsonElement; + } + + public void setJsonElement(final UnfiPortOverrideJsonElement jsonElement) { + this.jsonElement = jsonElement; + } +} diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/util/UnfiPortOverrideJsonElementDeserializer.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/util/UnfiPortOverrideJsonElementDeserializer.java new file mode 100644 index 0000000000..498a54d8b6 --- /dev/null +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/util/UnfiPortOverrideJsonElementDeserializer.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.unifi.internal.api.util; + +import java.lang.reflect.Type; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement; + +import com.google.gson.JsonElement; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +/** + * Serializer for {@link UnfiPortOverrideJsonElement}. Returns the content of the jsonObject in the class. + * + * @author Hilbrand Bouwkamp - Initial contribution + */ +@NonNullByDefault +public class UnfiPortOverrideJsonElementDeserializer implements JsonSerializer { + + @Override + public JsonElement serialize(final UnfiPortOverrideJsonElement src, final Type typeOfSrc, + final JsonSerializationContext context) { + return src.getJsonObject(); + } +} diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiPoePortThingHandler.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiPoePortThingHandler.java index 236f1c0912..e0edb5d370 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiPoePortThingHandler.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiPoePortThingHandler.java @@ -25,8 +25,10 @@ import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_P import static org.openhab.binding.unifi.internal.UniFiBindingConstants.CHANNEL_PORT_POE_VOLTAGE; import static org.openhab.core.library.unit.MetricPrefix.MILLI; -import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import javax.measure.quantity.ElectricCurrent; import javax.measure.quantity.ElectricPotential; @@ -38,9 +40,10 @@ import org.openhab.binding.unifi.internal.UniFiPoePortThingConfig; import org.openhab.binding.unifi.internal.api.UniFiController; import org.openhab.binding.unifi.internal.api.UniFiException; import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache; -import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverride; +import org.openhab.binding.unifi.internal.api.dto.UnfiPortOverrideJsonElement; import org.openhab.binding.unifi.internal.api.dto.UniFiDevice; import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable; +import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple; import org.openhab.core.library.types.OnOffType; import org.openhab.core.library.types.QuantityType; import org.openhab.core.library.types.StringType; @@ -62,7 +65,7 @@ import org.slf4j.LoggerFactory; */ @NonNullByDefault public class UniFiPoePortThingHandler - extends UniFiBaseThingHandler, UniFiPoePortThingConfig> { + extends UniFiBaseThingHandler, UniFiPoePortThingConfig> { private final Logger logger = LoggerFactory.getLogger(UniFiPoePortThingHandler.class); @@ -89,13 +92,13 @@ public class UniFiPoePortThingHandler } @Override - protected @Nullable Map getEntity(final UniFiControllerCache cache) { + protected @Nullable Map getEntity(final UniFiControllerCache cache) { return cache.getSwitchPorts(config.getMacAddress()); } @Override - protected State getChannelState(final Map ports, final String channelId) { - final UniFiPortTable port = getPort(ports); + protected State getChannelState(final Map ports, final String channelId) { + final UniFiPortTable port = getPort(ports).getTable(); if (port == null) { logger.debug("No PoE port for thing '{}' could be found in the data. Refresh ignored.", @@ -129,12 +132,12 @@ public class UniFiPoePortThingHandler return state; } - private @Nullable UniFiPortTable getPort(final Map ports) { + private @Nullable UniFiPortTuple getPort(final Map ports) { return ports.get(config.getPortNumber()); } @Override - protected boolean handleCommand(final UniFiController controller, final Map ports, + protected boolean handleCommand(final UniFiController controller, final Map ports, final ChannelUID channelUID, final Command command) throws UniFiException { final String channelID = channelUID.getIdWithoutGroup(); @@ -160,44 +163,40 @@ public class UniFiPoePortThingHandler return false; } - private boolean handleModeCommand(final UniFiController controller, final Map ports, - final @Nullable UniFiPortTable portToUpdate, final String poeMode) throws UniFiException { + private boolean handleModeCommand(final UniFiController controller, final Map ports, + final @Nullable UniFiPortTuple uniFiPortTuple, final String poeMode) throws UniFiException { final UniFiDevice device = controller.getCache().getDevice(config.getMacAddress()); - if (device == null || portToUpdate == null) { + if (device == null || uniFiPortTuple == null) { logger.info("Could not change the PoE port state for thing '{}': device {} or portToUpdate {} null", - getThing().getUID(), device, portToUpdate); - return false; + getThing().getUID(), device, uniFiPortTuple); } else { - final UnfiPortOverride override = new UnfiPortOverride(); - override.setPortIdx(portToUpdate.getPortIdx()); - override.setPortconfId(portToUpdate.getPortconfId()); - override.setPoeMode(poeMode); - final Map newMap = new HashMap<>(ports); + final List updatedList = ports.entrySet().stream() + .map(e -> e.getValue().getJsonElement()).filter(Objects::nonNull).collect(Collectors.toList()); - newMap.put(portToUpdate.getPortIdx(), override); - controller.poeMode(device, newMap); - refresh(); - return true; + updatedList.stream().filter(p -> p.getPortIdx() == uniFiPortTuple.getPortIdx()).findAny() + .ifPresent(p -> p.setPoeMode(poeMode)); + controller.poeMode(device, updatedList); + // No refresh because UniFi device takes some time to update. Therefore a refresh would only show the + // old state. } + return true; } - private boolean handleCmd(final UniFiController controller, @Nullable final UniFiPortTable portToUpdate, + private boolean handleCmd(final UniFiController controller, @Nullable final UniFiPortTuple portToUpdate, final String command) throws UniFiException { final UniFiDevice device = controller.getCache().getDevice(config.getMacAddress()); if (device == null || portToUpdate == null) { logger.info("Could not change the PoE port state for thing '{}': device {} or portToUpdate {} null", getThing().getUID(), device, portToUpdate); - return false; } else { if (CHANNEL_PORT_POE_CMD_POWER_CYCLE.equalsIgnoreCase(command.replaceAll("[- ]", ""))) { controller.poePowerCycle(device, portToUpdate.getPortIdx()); - return true; } else { logger.info("Unknown command '{}' given to PoE port for thing '{}': device {} or portToUpdate {} null", command, getThing().getUID(), device, portToUpdate); - return false; } } + return true; } } diff --git a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiThingDiscoveryService.java b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiThingDiscoveryService.java index f204154ca2..0580b6b948 100644 --- a/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiThingDiscoveryService.java +++ b/bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiThingDiscoveryService.java @@ -23,6 +23,7 @@ import static org.openhab.binding.unifi.internal.UniFiBindingConstants.PARAMETER import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -31,7 +32,7 @@ import org.openhab.binding.unifi.internal.api.UniFiController; import org.openhab.binding.unifi.internal.api.UniFiException; import org.openhab.binding.unifi.internal.api.cache.UniFiControllerCache; import org.openhab.binding.unifi.internal.api.dto.UniFiClient; -import org.openhab.binding.unifi.internal.api.dto.UniFiPortTable; +import org.openhab.binding.unifi.internal.api.dto.UniFiPortTuple; import org.openhab.binding.unifi.internal.api.dto.UniFiSite; import org.openhab.binding.unifi.internal.api.dto.UniFiWlan; import org.openhab.core.config.discovery.AbstractDiscoveryService; @@ -58,7 +59,7 @@ public class UniFiThingDiscoveryService extends AbstractDiscoveryService private static final int UNIFI_DISCOVERY_TIMEOUT_SECONDS = 30; private static final long TTL_SECONDS = TimeUnit.MINUTES.toSeconds(5); private static final int THING_ID_LENGTH = 8; - private static final String DEFAULT_PORTNAME = "Port"; + private static final Pattern DEFAULT_PORTNAME = Pattern.compile("Port \\d+"); private final Logger logger = LoggerFactory.getLogger(UniFiThingDiscoveryService.class); @@ -160,9 +161,9 @@ public class UniFiThingDiscoveryService extends AbstractDiscoveryService } private void discoverPoePorts(final UniFiControllerCache cache, final ThingUID bridgeUID) { - for (final Map uc : cache.getSwitchPorts()) { - for (final Entry sp : uc.entrySet()) { - final UniFiPortTable pt = sp.getValue(); + for (final Map uc : cache.getSwitchPorts()) { + for (final Entry sp : uc.entrySet()) { + final UniFiPortTuple pt = sp.getValue(); final String deviceMac = pt.getDevice().getMac(); final String id = deviceMac.replace(":", "") + "_" + pt.getPortIdx(); final ThingUID thingUID = new ThingUID(UniFiBindingConstants.THING_TYPE_POE_PORT, bridgeUID, id); @@ -182,9 +183,9 @@ public class UniFiThingDiscoveryService extends AbstractDiscoveryService * @param pt port object * @return label for the discovered PoE port */ - private static @Nullable String portName(final UniFiPortTable pt) { - final String portName = pt.getName(); + private @Nullable String portName(final UniFiPortTuple pt) { + final String portName = pt.getTable().getName(); - return portName.startsWith(DEFAULT_PORTNAME) ? pt.getDevice().getName() + " " + portName : portName; + return DEFAULT_PORTNAME.matcher(portName).find() ? pt.getDevice().getName() + " " + portName : portName; } } 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 ccd435fd0e..b8c2d0e0e0 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 @@ -69,6 +69,8 @@ channel-type.unifi.macAddress.label = MAC Address channel-type.unifi.macAddress.description = MAC address of the client channel-type.unifi.online.label = Online channel-type.unifi.online.description = Online status of the client +channel-type.unifi.passphrase.label = Passphrase +channel-type.unifi.passphrase.description = Passphrase of the Wi-Fi network channel-type.unifi.poeCmd.label = PoE Command channel-type.unifi.poeCmd.description = Command that can be given to the PoE port channel-type.unifi.poeCmd.command.option.power-cycle = Power Cycle @@ -119,8 +121,6 @@ channel-type.unifi.wpaEnc.label = WPA Encoding channel-type.unifi.wpaEnc.description = WPA Encoding of the Wi-Fi network channel-type.unifi.wpaMode.label = WPA Mode channel-type.unifi.wpaMode.description = WPA Mode of the Wi-Fi network -channel-type.unifi.passphrase.label = Passphrase -channel-type.unifi.passphrase.description = Passphrase of the Wi-Fi network # channel types config