From c42fdc52f1eaceb1f1c2071bf41f7c2e4be47d64 Mon Sep 17 00:00:00 2001 From: Marcel Verpaalen Date: Sun, 28 Nov 2021 23:40:05 +0100 Subject: [PATCH 1/6] [miio] add support for BT Gateway switch on chuangmi.plug.212a01 Signed-off-by: Marcel Verpaalen --- bundles/org.openhab.binding.miio/README.md | 4 +- .../miio/internal/basic/Conversions.java | 21 ++++++++ .../database/chuangmi.plug.212a01-miot.json | 51 ++++++++++++++++++- 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.miio/README.md b/bundles/org.openhab.binding.miio/README.md index c8251f60c582..068939205de8 100644 --- a/bundles/org.openhab.binding.miio/README.md +++ b/bundles/org.openhab.binding.miio/README.md @@ -187,7 +187,7 @@ Currently the miio binding supports more than 300 different models. | Mi Multifunction Air Monitor | miio:basic | [cgllc.airmonitor.b1](#cgllc-airmonitor-b1) | Yes | | | Qingping Air Monitor | miio:basic | [cgllc.airmonitor.s1](#cgllc-airmonitor-s1) | Yes | | | Mi Universal Remote | miio:unsupported | chuangmi.ir.v2 | No | | -| Mi Smart Power Plug 2 (Wi-Fi and Bluetooth Gateway) | miio:basic | [chuangmi.plug.212a01](#chuangmi-plug-212a01) | Yes | Experimental support. Please report back if all channels are functional. Preferably share the debug log of property refresh and command responses | +| Mi Smart Power Plug 2 (Wi-Fi and Bluetooth Gateway) | miio:basic | [chuangmi.plug.212a01](#chuangmi-plug-212a01) | Yes | | | Mi Smart Plug WiFi | miio:basic | [chuangmi.plug.hmi205](#chuangmi-plug-hmi205) | Yes | | | Mi Smart Plug (WiFi) | miio:basic | [chuangmi.plug.hmi206](#chuangmi-plug-hmi206) | Yes | | | Mi Smart Wi-Fi Plug (Bluetooth Gateway) | miio:basic | [chuangmi.plug.hmi208](#chuangmi-plug-hmi208) | Yes | | @@ -693,6 +693,7 @@ Note, not all the values need to be in the json file, e.g. a subset of the param | countdown | Number:Time | Imilab Timer - Countdown | | | task-switch | Switch | Imilab Timer - Task Switch | | | countdown-info | Switch | Imilab Timer - Countdown Info | | +| bt-gw | String | BT Gateway | Value mapping `["disable"="Disable","enable"="Enable"]` | ### Mi Smart Plug WiFi (chuangmi.plug.hmi205) Channels @@ -5469,6 +5470,7 @@ Number:Time off_duration "Imilab Timer - Off Duration" (G_plug) {channel="miio:b Number:Time countdown "Imilab Timer - Countdown" (G_plug) {channel="miio:basic:plug:countdown"} Switch task_switch "Imilab Timer - Task Switch" (G_plug) {channel="miio:basic:plug:task-switch"} Switch countdown_info "Imilab Timer - Countdown Info" (G_plug) {channel="miio:basic:plug:countdown-info"} +String bt_gw "BT Gateway" (G_plug) {channel="miio:basic:plug:bt-gw"} ``` ### Mi Smart Plug WiFi (chuangmi.plug.hmi205) item file lines diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java index ba79c31cac9f..0c0e2ab10c4e 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java @@ -23,6 +23,8 @@ import org.slf4j.LoggerFactory; import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; /** @@ -121,9 +123,28 @@ public static JsonElement tankLevel(JsonElement value12) throws ClassCastExcepti } } + public static JsonElement getJsonElement(String element, JsonElement responseValue) + throws ClassCastException, IllegalStateException { + if (responseValue.isJsonPrimitive()) { + JsonElement jsonElement = JsonParser.parseString(responseValue.getAsString()); + if (jsonElement.isJsonObject()) { + JsonObject value = jsonElement.getAsJsonObject(); + if (value.has(element)) { + return value.get(element); + } + } + } else { + LOGGER.debug("JsonElement '{}' not found in '{}'", element, responseValue); + } + return responseValue; + } + public static JsonElement execute(String transformation, JsonElement value, @Nullable Map deviceVariables) { try { + if (transformation.toUpperCase().startsWith("GETJSONELEMENT")) { + return getJsonElement(transformation.length() > 15 ? transformation.substring(15) : "", value); + } switch (transformation.toUpperCase()) { case "YEELIGHTSCENEID": return yeelightSceneConversion(value); diff --git a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json index 4827ef6cd6df..9ee47e5e69f3 100644 --- a/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json +++ b/bundles/org.openhab.binding.miio/src/main/resources/database/chuangmi.plug.212a01-miot.json @@ -274,8 +274,57 @@ }, "refresh": true, "actions": [] + }, + { + "property": "", + "friendlyName": "BT Gateway", + "channel": "bt-gw", + "type": "String", + "stateDescription": { + "readOnly": false, + "options": [ + { + "value": "disable", + "label": "Disable" + }, + { + "value": "enable", + "label": "Enable" + } + ] + }, + "refresh": true, + "customRefreshCommand": "bt_gateway_status", + "transformation": "getJsonElement-gateway_status", + "actions": [ + { + "command": "bt_gateway_enable", + "parameterType": "EMPTY", + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "enable" + } + ] + } + }, + { + "command": "bt_gateway_disable", + "parameterType": "EMPTY", + "condition": { + "name": "matchValue", + "parameters": [ + { + "matchValue": "disable" + } + ] + } + } + ], + "readmeComment": "Value mapping `[\"disable\"\u003d\"Disable\",\"enable\"\u003d\"Enable\"]`" } ], - "experimental": true + "experimental": false } } From 00ea02ec1fcd6dd9f61d5b3035d47b07311f6b0c Mon Sep 17 00:00:00 2001 From: Marcel Verpaalen Date: Mon, 29 Nov 2021 09:40:14 +0100 Subject: [PATCH 2/6] [miio] improve conversion & add test for it Signed-off-by: Marcel Verpaalen --- .../miio/internal/basic/Conversions.java | 27 ++++-- .../miio/internal/ConversionsTest.java | 90 +++++++++++++++++++ 2 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java index 0c0e2ab10c4e..09ed5b867b98 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java @@ -24,6 +24,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; @@ -125,17 +126,21 @@ public static JsonElement tankLevel(JsonElement value12) throws ClassCastExcepti public static JsonElement getJsonElement(String element, JsonElement responseValue) throws ClassCastException, IllegalStateException { - if (responseValue.isJsonPrimitive()) { - JsonElement jsonElement = JsonParser.parseString(responseValue.getAsString()); - if (jsonElement.isJsonObject()) { - JsonObject value = jsonElement.getAsJsonObject(); - if (value.has(element)) { - return value.get(element); + try { + if (responseValue.isJsonPrimitive() || responseValue.isJsonObject()) { + JsonElement jsonElement = responseValue.isJsonObject() ? responseValue + : JsonParser.parseString(responseValue.getAsString()); + if (jsonElement.isJsonObject()) { + JsonObject value = jsonElement.getAsJsonObject(); + if (value.has(element)) { + return value.get(element); + } } } - } else { - LOGGER.debug("JsonElement '{}' not found in '{}'", element, responseValue); + } catch (JsonParseException e) { + // ignore } + LOGGER.debug("JsonElement '{}' not found in '{}'", element, responseValue); return responseValue; } @@ -143,7 +148,11 @@ public static JsonElement execute(String transformation, JsonElement value, @Nullable Map deviceVariables) { try { if (transformation.toUpperCase().startsWith("GETJSONELEMENT")) { - return getJsonElement(transformation.length() > 15 ? transformation.substring(15) : "", value); + if (transformation.length() > 15) { + return getJsonElement(transformation.substring(15), value); + } else { + LOGGER.info("Transformation {} missing element. Returning '{}'", transformation, value.toString()); + } } switch (transformation.toUpperCase()) { case "YEELIGHTSCENEID": diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java new file mode 100644 index 000000000000..efeda21501b8 --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2010-2021 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.miio.internal; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Collections; +import java.util.Map; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.miio.internal.basic.Conversions; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; + +/** + * Test case for {@link ConversionsTest} + * + * @author Marcel Verpaalen - Initial contribution + * + */ +@NonNullByDefault +public class ConversionsTest { + + @Test + public void getJsonElementTest() { + + Map deviceVariables = Collections.emptyMap(); + + // test invalid missing element + String transformation = "getJsonElement"; + JsonElement value = new JsonPrimitive(""); + JsonElement resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + value = new JsonPrimitive("{\"test\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + // test without deviceVariables + transformation = "getJsonElement-test"; + resp = Conversions.execute(transformation, value, null); + assertNotNull(resp); + assertEquals(new JsonPrimitive("testresponse"), resp); + + // test non json + value = new JsonPrimitive("some non json value"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + // test input as jsonString + value = new JsonPrimitive("{\"test\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive("testresponse"), resp); + + // test input as jsonObject + value = JsonParser.parseString("{\"test\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive("testresponse"), resp); + + // test input as jsonString for non-existing element + value = new JsonPrimitive("{\"nottest\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + + // test input as jsonString for non-existing element + value = JsonParser.parseString("{\"nottest\": \"testresponse\"}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + } +} From 069f3c77809f203868061b7a74f088231c2a3794 Mon Sep 17 00:00:00 2001 From: Marcel Verpaalen Date: Mon, 29 Nov 2021 09:48:34 +0100 Subject: [PATCH 3/6] [miio] add one empty string test Signed-off-by: Marcel Verpaalen --- .../openhab/binding/miio/internal/ConversionsTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java index efeda21501b8..f6edcceadb50 100644 --- a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java @@ -46,13 +46,15 @@ public void getJsonElementTest() { assertNotNull(resp); assertEquals(value, resp); + // test invalid missing element value = new JsonPrimitive("{\"test\": \"testresponse\"}"); resp = Conversions.execute(transformation, value, deviceVariables); assertNotNull(resp); assertEquals(value, resp); - // test without deviceVariables transformation = "getJsonElement-test"; + + // test without deviceVariables resp = Conversions.execute(transformation, value, null); assertNotNull(resp); assertEquals(new JsonPrimitive("testresponse"), resp); @@ -63,6 +65,12 @@ public void getJsonElementTest() { assertNotNull(resp); assertEquals(value, resp); + // test non json empty string + value = new JsonPrimitive(""); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(value, resp); + // test input as jsonString value = new JsonPrimitive("{\"test\": \"testresponse\"}"); resp = Conversions.execute(transformation, value, deviceVariables); From e5f4f2a61678399769072903da9f34ebd12b7775 Mon Sep 17 00:00:00 2001 From: Marcel Verpaalen Date: Mon, 29 Nov 2021 11:05:32 +0100 Subject: [PATCH 4/6] [miio] remove unnessesary exceptions Signed-off-by: Marcel Verpaalen --- .../org/openhab/binding/miio/internal/basic/Conversions.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java index 09ed5b867b98..e20487d09a0b 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/Conversions.java @@ -124,8 +124,7 @@ public static JsonElement tankLevel(JsonElement value12) throws ClassCastExcepti } } - public static JsonElement getJsonElement(String element, JsonElement responseValue) - throws ClassCastException, IllegalStateException { + public static JsonElement getJsonElement(String element, JsonElement responseValue) { try { if (responseValue.isJsonPrimitive() || responseValue.isJsonObject()) { JsonElement jsonElement = responseValue.isJsonObject() ? responseValue From 552b4e397dcc7a5ed68969dfa494345edbdd9fd5 Mon Sep 17 00:00:00 2001 From: Marcel Verpaalen Date: Mon, 29 Nov 2021 11:11:23 +0100 Subject: [PATCH 5/6] [miio] add one more test for different inputs Signed-off-by: Marcel Verpaalen --- .../miio/internal/ConversionsTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java index f6edcceadb50..28003fdbf145 100644 --- a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test; import org.openhab.binding.miio.internal.basic.Conversions; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; @@ -83,6 +84,30 @@ public void getJsonElementTest() { assertNotNull(resp); assertEquals(new JsonPrimitive("testresponse"), resp); + // test input as jsonString for a number + value = new JsonPrimitive("{\"test\": 3}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive(3), resp); + + // test input as jsonString for a array + value = new JsonPrimitive("{\"test\": []}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonArray(), resp); + + // test input as jsonString for a array + value = new JsonPrimitive("{\"test\": false}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive(false), resp); + + // test input as jsonObject for a number + value = JsonParser.parseString("{\"test\": 3}"); + resp = Conversions.execute(transformation, value, deviceVariables); + assertNotNull(resp); + assertEquals(new JsonPrimitive(3), resp); + // test input as jsonString for non-existing element value = new JsonPrimitive("{\"nottest\": \"testresponse\"}"); resp = Conversions.execute(transformation, value, deviceVariables); From a58544900569cbf22ca032618005fb508259906c Mon Sep 17 00:00:00 2001 From: Marcel Verpaalen Date: Mon, 29 Nov 2021 11:12:29 +0100 Subject: [PATCH 6/6] [miio] typo Signed-off-by: Marcel Verpaalen --- .../java/org/openhab/binding/miio/internal/ConversionsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java index 28003fdbf145..2ee46a065f5d 100644 --- a/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java +++ b/bundles/org.openhab.binding.miio/src/test/java/org/openhab/binding/miio/internal/ConversionsTest.java @@ -96,7 +96,7 @@ public void getJsonElementTest() { assertNotNull(resp); assertEquals(new JsonArray(), resp); - // test input as jsonString for a array + // test input as jsonString for a boolean value = new JsonPrimitive("{\"test\": false}"); resp = Conversions.execute(transformation, value, deviceVariables); assertNotNull(resp);