]> git.basschouten.com Git - openhab-addons.git/commitdiff
[unifi] Fix portoverride to not remove any other data (#13362)
authorHilbrand Bouwkamp <hilbrand@h72.nl>
Sat, 10 Sep 2022 14:59:42 +0000 (16:59 +0200)
committerGitHub <noreply@github.com>
Sat, 10 Sep 2022 14:59:42 +0000 (16:59 +0200)
When a user has configured additional settings on a PoE port, like name.
These settings where lost when changing the PoEPort status in openHAB.
This was because in the binding only some information of the override was stored and when writing the new state this information would have been sent too.
In this change the object to store the override has been replaced by a plain json object. Therefore we don't have to know what is in it and all information is kept.

Signed-off-by: Hilbrand Bouwkamp <hilbrand@h72.nl>
13 files changed:
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiController.java
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/UniFiControllerRequest.java
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/cache/UniFiControllerCache.java
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverride.java [deleted file]
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UnfiPortOverrideJsonElement.java [new file with mode: 0644]
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiDevice.java
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortOverrides.java [deleted file]
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTable.java
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/dto/UniFiPortTuple.java [new file with mode: 0644]
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/api/util/UnfiPortOverrideJsonElementDeserializer.java [new file with mode: 0644]
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiPoePortThingHandler.java
bundles/org.openhab.binding.unifi/src/main/java/org/openhab/binding/unifi/internal/handler/UniFiThingDiscoveryService.java
bundles/org.openhab.binding.unifi/src/main/resources/OH-INF/i18n/unifi.properties

index d0c6678a0b6ba47d511f5a46e101977dd43c1971..41f18fd3f3f652ba7faf773703ce7c50bf69b3c7 100644 (file)
@@ -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<Integer, UniFiPortTable> getSwitchPorts(@Nullable final String deviceId) {
+    public @Nullable Map<Integer, UniFiPortTuple> 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<Integer, UnfiPortOverride> data) throws UniFiException {
-        final UniFiControllerRequest<Void> 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<UnfiPortOverrideJsonElement> 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<Void> 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 {
index 4acf1e0b464f97fa0632b5c62943605e25d0157d..2d021588987785a0e6fe59fccab138aad7e0dabb 100644 (file)
@@ -230,6 +230,7 @@ class UniFiControllerRequest<T> {
         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));
         }
index 174062cca1fda44fdd5383dab9c666a890fade58..e8189ddaa8c5c57ab2eb03e85ddf757ae4ef1686 100644 (file)
 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<String, Map<Integer, UniFiPortTable>> devicesToPortTables = new ConcurrentHashMap<>();
+    private final Map<String, Map<Integer, UniFiPortTuple>> 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<Integer, UniFiPortTuple> 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<Integer, UniFiPortTuple> 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<Integer, UniFiPortTable> getSwitchPorts(@Nullable final String deviceId) {
+    public Map<Integer, UniFiPortTuple> getSwitchPorts(@Nullable final String deviceId) {
         return deviceId == null ? Map.of() : devicesToPortTables.getOrDefault(deviceId, Map.of());
     }
 
-    public Collection<Map<Integer, UniFiPortTable>> getSwitchPorts() {
+    public Collection<Map<Integer, UniFiPortTuple>> 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 (file)
index bd4a41f..0000000
+++ /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 (file)
index 0000000..2562503
--- /dev/null
@@ -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();
+    }
+}
index 0cd1e1b38a00e971ee1f5c49fed902b25cd60c56..644ba3e6314c79a3faa9b0105be61207b9563b30 100644 (file)
@@ -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 (file)
index f664578..0000000
+++ /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<UnfiPortOverride> 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])));
-    }
-}
index 637ed2dc5ed679bd7dc24cf9e60339554f34327d..6a4b239dfa0be7ec3aee117667bb49cb14eb7fd9 100644 (file)
  */
 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 {
+
+    @Expose
+    private int portIdx;
+
+    @Expose
+    private String portconfId;
 
-    private transient UniFiDevice device;
+    @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 String getPortconfId() {
+        return portconfId;
     }
 
-    public void setDevice(final UniFiDevice device) {
-        this.device = device;
+    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 (file)
index 0000000..fa9865d
--- /dev/null
@@ -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 (file)
index 0000000..498a54d
--- /dev/null
@@ -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<UnfiPortOverrideJsonElement> {
+
+    @Override
+    public JsonElement serialize(final UnfiPortOverrideJsonElement src, final Type typeOfSrc,
+            final JsonSerializationContext context) {
+        return src.getJsonObject();
+    }
+}
index 236f1c09128a5d55db2cd526a6a9aae8cc774ccf..e0edb5d37094988c3ce4a47fec3d4172a94efce8 100644 (file)
@@ -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<Map<Integer, UniFiPortTable>, UniFiPoePortThingConfig> {
+        extends UniFiBaseThingHandler<Map<Integer, UniFiPortTuple>, UniFiPoePortThingConfig> {
 
     private final Logger logger = LoggerFactory.getLogger(UniFiPoePortThingHandler.class);
 
@@ -89,13 +92,13 @@ public class UniFiPoePortThingHandler
     }
 
     @Override
-    protected @Nullable Map<Integer, UniFiPortTable> getEntity(final UniFiControllerCache cache) {
+    protected @Nullable Map<Integer, UniFiPortTuple> getEntity(final UniFiControllerCache cache) {
         return cache.getSwitchPorts(config.getMacAddress());
     }
 
     @Override
-    protected State getChannelState(final Map<Integer, UniFiPortTable> ports, final String channelId) {
-        final UniFiPortTable port = getPort(ports);
+    protected State getChannelState(final Map<Integer, UniFiPortTuple> 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<Integer, UniFiPortTable> ports) {
+    private @Nullable UniFiPortTuple getPort(final Map<Integer, UniFiPortTuple> ports) {
         return ports.get(config.getPortNumber());
     }
 
     @Override
-    protected boolean handleCommand(final UniFiController controller, final Map<Integer, UniFiPortTable> ports,
+    protected boolean handleCommand(final UniFiController controller, final Map<Integer, UniFiPortTuple> 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<Integer, UniFiPortTable> ports,
-            final @Nullable UniFiPortTable portToUpdate, final String poeMode) throws UniFiException {
+    private boolean handleModeCommand(final UniFiController controller, final Map<Integer, UniFiPortTuple> 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<Integer, UnfiPortOverride> newMap = new HashMap<>(ports);
-
-            newMap.put(portToUpdate.getPortIdx(), override);
-            controller.poeMode(device, newMap);
-            refresh();
-            return true;
+            final List<UnfiPortOverrideJsonElement> updatedList = ports.entrySet().stream()
+                    .map(e -> e.getValue().getJsonElement()).filter(Objects::nonNull).collect(Collectors.toList());
+
+            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;
     }
 }
index f204154ca2bac0db3a850e4b964231772b734296..0580b6b948df3f656442202180139045449423a3 100644 (file)
@@ -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<Integer, UniFiPortTable> uc : cache.getSwitchPorts()) {
-            for (final Entry<Integer, UniFiPortTable> sp : uc.entrySet()) {
-                final UniFiPortTable pt = sp.getValue();
+        for (final Map<Integer, UniFiPortTuple> uc : cache.getSwitchPorts()) {
+            for (final Entry<Integer, UniFiPortTuple> 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;
     }
 }
index ccd435fd0e6b26a086a930f808393199a895539e..b8c2d0e0e052f981b49a29b86e4c101e4df33a68 100644 (file)
@@ -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