From 306b3c4853bc1615edeecd7569f5893c6fcd53fe Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 30 Oct 2021 18:07:47 +0200 Subject: [PATCH] [miio] Save last msgId and misc minor updates (#11464) Signed-off-by: Marcel Verpaalen --- .../binding/miio/internal/MiIoCommand.java | 2 + .../miio/internal/MiIoQuantiyTypes.java | 5 +- .../miio/internal/SavedDeviceInfoDTO.java | 56 +++++++++++++++++++ .../openhab/binding/miio/internal/Utils.java | 26 +++++++++ .../internal/basic/CommandParameterType.java | 2 + .../miio/internal/cloud/CloudConnector.java | 2 +- .../miio/internal/cloud/MiCloudConnector.java | 2 +- .../internal/handler/MiIoAbstractHandler.java | 29 ++++++++-- 8 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/SavedDeviceInfoDTO.java diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoCommand.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoCommand.java index f16df318f26..b65294a9110 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoCommand.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoCommand.java @@ -30,6 +30,8 @@ public enum MiIoCommand { // Basic device commands GET_PROPERTY("get_prop"), GET_PROPERTIES("get_properties"), + GET_DEVICE_PROPERTY_EXP("get_device_prop_exp"), + GET_DEVICE_PROPERTY("get_device_prop"), GET_VALUE("get_value"), SET_PROPERTIES("set_properties"), SET_MODE_BASIC("set_mode"), diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoQuantiyTypes.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoQuantiyTypes.java index 2cea22614a4..8cb3291d882 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoQuantiyTypes.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoQuantiyTypes.java @@ -12,7 +12,7 @@ */ package org.openhab.binding.miio.internal; -import static org.openhab.core.library.unit.MetricPrefix.MILLI; +import static org.openhab.core.library.unit.MetricPrefix.*; import java.util.Arrays; import java.util.HashMap; @@ -39,7 +39,8 @@ public enum MiIoQuantiyTypes { CELSIUS(SIUnits.CELSIUS, "C", "celcius"), FAHRENHEIT(ImperialUnits.FAHRENHEIT), KELVIN(Units.KELVIN, "K"), - PASCAL(SIUnits.PASCAL), + PASCAL(SIUnits.PASCAL, "pa"), + HPA(HECTO(SIUnits.PASCAL)), SECOND(Units.SECOND, "seconds"), MINUTE(Units.MINUTE, "minutes"), HOUR(Units.HOUR, "hours"), diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/SavedDeviceInfoDTO.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/SavedDeviceInfoDTO.java new file mode 100644 index 00000000000..4e580f6c4d1 --- /dev/null +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/SavedDeviceInfoDTO.java @@ -0,0 +1,56 @@ +/** + * 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 org.eclipse.jdt.annotation.NonNullByDefault; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * Storing last id to to be able to reconnect better after binding restart + * + * @author Marcel Verpaalen - Initial contribution + */ +@NonNullByDefault +public class SavedDeviceInfoDTO { + + @SerializedName("lastId") + @Expose + private int lastId = 0; + @SerializedName("deviceId") + @Expose + private String deviceId; + + public SavedDeviceInfoDTO(int lastId, String deviceId) { + super(); + this.lastId = lastId; + this.deviceId = deviceId; + } + + public int getLastId() { + return lastId; + } + + public void setLastId(int lastId) { + this.lastId = lastId; + } + + public String getDeviceId() { + return deviceId; + } + + public void setDeviceId(String deviceId) { + this.deviceId = deviceId; + } +} diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/Utils.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/Utils.java index bb7ec557cce..95285888bad 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/Utils.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/Utils.java @@ -12,6 +12,10 @@ */ package org.openhab.binding.miio.internal; +import static org.openhab.binding.miio.internal.MiIoBindingConstants.BINDING_USERDATA_PATH; + +import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -21,6 +25,7 @@ import java.nio.charset.StandardCharsets; import java.nio.file.NoSuchFileException; import org.eclipse.jdt.annotation.NonNullByDefault; +import org.slf4j.Logger; import com.google.gson.JsonElement; import com.google.gson.JsonIOException; @@ -106,6 +111,27 @@ public final class Utils { } } + /** + * Saves string to file in userdata folder + * + * @param filename + * @param string with content + * @param logger + */ + public static void saveToFile(String filename, String data, Logger logger) { + File folder = new File(BINDING_USERDATA_PATH); + if (!folder.exists()) { + folder.mkdirs(); + } + File dataFile = new File(folder, filename); + try (FileWriter writer = new FileWriter(dataFile)) { + writer.write(data); + logger.debug("Saved to {}", dataFile.getAbsolutePath()); + } catch (IOException e) { + logger.debug("Failed to write file '{}': {}", dataFile.getName(), e.getMessage()); + } + } + public static String minLengthString(String string, int length) { return String.format("%-" + length + "s", string); } diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/CommandParameterType.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/CommandParameterType.java index 7a379a581dd..d448011d8af 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/CommandParameterType.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/basic/CommandParameterType.java @@ -28,6 +28,8 @@ public enum CommandParameterType { ONOFFBOOL("onoffbool"), ONOFFBOOLSTRING("onoffboolstring"), ONOFFNUMBER("onoffnumber"), + OPENCLOSENUMBER("openclosenumber"), + OPENCLOSE("openclose"), STRING("string"), CUSTOMSTRING("customstring"), NUMBER("number"), diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudConnector.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudConnector.java index 137c65774a1..dab457b235e 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudConnector.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudConnector.java @@ -136,7 +136,7 @@ public class CloudConnector { if (cl == null || !isConnected()) { throw new MiCloudException("Cannot execute request. Cloud service not available"); } - return cl.request(urlPart, country, parameters); + return cl.request(urlPart.startsWith("/") ? urlPart : "/" + urlPart, country, parameters); } public @Nullable RawType getMap(String mapId, String country) throws MiCloudException { diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/MiCloudConnector.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/MiCloudConnector.java index 38fb7143e02..7fe9140e788 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/MiCloudConnector.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/MiCloudConnector.java @@ -237,7 +237,7 @@ public class MiCloudConnector { public String getDeviceString(String country) { String resp; try { - resp = request("/home/device_list_page", country, "{\"getVirtualModel\":false,\"getHuamiDevices\":1}"); + resp = request("/home/device_list_page", country, "{\"getVirtualModel\":true,\"getHuamiDevices\":1}"); logger.trace("Get devices response: {}", resp); if (resp.length() > 2) { CloudUtil.saveDeviceInfoFile(resp, country, logger); diff --git a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java index 2dcf5d54e3a..f2034f0eb37 100644 --- a/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java +++ b/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java @@ -14,8 +14,11 @@ package org.openhab.binding.miio.internal.handler; import static org.openhab.binding.miio.internal.MiIoBindingConstants.*; +import java.io.File; import java.io.IOException; import java.math.BigDecimal; +import java.net.URISyntaxException; +import java.net.URL; import java.time.Instant; import java.time.LocalDateTime; import java.util.HashMap; @@ -39,6 +42,7 @@ import org.openhab.binding.miio.internal.MiIoInfoApDTO; import org.openhab.binding.miio.internal.MiIoInfoDTO; import org.openhab.binding.miio.internal.MiIoMessageListener; import org.openhab.binding.miio.internal.MiIoSendCommand; +import org.openhab.binding.miio.internal.SavedDeviceInfoDTO; import org.openhab.binding.miio.internal.Utils; import org.openhab.binding.miio.internal.basic.MiIoDatabaseWatchService; import org.openhab.binding.miio.internal.cloud.CloudConnector; @@ -62,6 +66,7 @@ import org.slf4j.LoggerFactory; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSyntaxException; @@ -158,6 +163,17 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi isIdentified = false; deviceVariables.put(TIMESTAMP, Instant.now().getEpochSecond()); deviceVariables.put(PROPERTY_DID, configuration.deviceId); + try { + URL url = new File(BINDING_USERDATA_PATH, "info_" + getThing().getUID().getId() + ".json").toURI().toURL(); + SavedDeviceInfoDTO lastIdInfo = GSON.fromJson(Utils.convertFileToJSON(url), SavedDeviceInfoDTO.class); + if (lastIdInfo != null) { + lastId = lastIdInfo.getLastId(); + logger.debug("Last Id set to {} for {}", lastId, getThing().getUID()); + } + } catch (JsonParseException | IOException | URISyntaxException e) { + logger.debug("Could not read last connection id for {} : {}", getThing().getUID(), e.getMessage()); + } + miIoScheduler.schedule(this::initializeData, 1, TimeUnit.SECONDS); int pollingPeriod = configuration.refreshInterval; if (pollingPeriod > 0) { @@ -221,6 +237,11 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi this.miioCom = null; } miIoScheduler.shutdownNow(); + logger.debug("Last Id saved for {}: {} -> {} ", getThing().getUID(), lastId, + GSON.toJson(new SavedDeviceInfoDTO(lastId, + (String) deviceVariables.getOrDefault(PROPERTY_DID, getThing().getUID().getId())))); + Utils.saveToFile("info_" + getThing().getUID().getId() + ".json", GSON.toJson(new SavedDeviceInfoDTO(lastId, + (String) deviceVariables.getOrDefault(PROPERTY_DID, getThing().getUID().getId()))), logger); } protected int sendCommand(MiIoCommand command) { @@ -237,13 +258,11 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi /** * This is used to execute arbitrary commands by sending to the commands channel. Command parameters to be added - * between - * [] brackets. This to allow for unimplemented commands to be executed (e.g. get detailed historical cleaning - * records) + * between [] brackets. This to allow for unimplemented commands to be executed * * @param commandString command to be executed * @param cloud server to be used or empty string for direct sending to the device - * @return vacuum response + * @return message id */ protected int sendCommand(String commandString, String cloudServer) { String command = commandString.trim(); @@ -284,7 +303,7 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi return 0; } - String getCloudServer() { + public String getCloudServer() { // This can be improved in the future with additional / more advanced options like e.g. directFirst which would // use direct communications and in case of failures fall back to cloud communication. For now we keep it // simple and only have the option for cloud or direct.