]> git.basschouten.com Git - openhab-addons.git/commitdiff
[miio] add new custom refresh methods (#10957)
authorMarcel <marcel@verpaalen.com>
Mon, 12 Jul 2021 07:55:16 +0000 (09:55 +0200)
committerGitHub <noreply@github.com>
Mon, 12 Jul 2021 07:55:16 +0000 (09:55 +0200)
* Improve matching the command responses to the sending channel
* Use newer method to get device list using `device_list_page`
* Adding the ability to send custom requests to cloud
* Adding the ability to send custom commands with additional elements in
the json

Signed-off-by: Marcel Verpaalen <marcel@verpaalen.com>
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudConnector.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/MiCloudConnector.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoAbstractHandler.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoBasicHandler.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/transport/MiIoAsyncCommunication.java

index 9e974d7991448ff1db913233c1b438fe39dcaba6..626b7515c2ba51a458dd1e7ade8feec800fe797a 100644 (file)
@@ -124,6 +124,14 @@ public class CloudConnector {
         return cl.sendRPCCommand(device, country.trim().toLowerCase(), command.getCommandString());
     }
 
+    public String sendCloudCommand(String urlPart, String country, String parameters) throws MiCloudException {
+        final @Nullable MiCloudConnector cl = this.cloudConnector;
+        if (cl == null || !isConnected()) {
+            throw new MiCloudException("Cannot execute request. Cloud service not available");
+        }
+        return cl.request(urlPart, country, parameters);
+    }
+
     public @Nullable RawType getMap(String mapId, String country) throws MiCloudException {
         logger.debug("Getting vacuum map {} from Xiaomi cloud server: '{}'", mapId, country);
         String mapCountry;
index 3ecabee39c9f1f65a57beb04588f577dcd26a183..38fb7143e02c78c5a26266282bf96260c9f1425f 100644 (file)
@@ -237,7 +237,7 @@ public class MiCloudConnector {
     public String getDeviceString(String country) {
         String resp;
         try {
-            resp = request("/home/device_list", country, "{\"getVirtualModel\":false,\"getHuamiDevices\":0}");
+            resp = request("/home/device_list_page", country, "{\"getVirtualModel\":false,\"getHuamiDevices\":1}");
             logger.trace("Get devices response: {}", resp);
             if (resp.length() > 2) {
                 CloudUtil.saveDeviceInfoFile(resp, country, logger);
@@ -260,7 +260,7 @@ public class MiCloudConnector {
         String url = urlPart.trim();
         url = getApiUrl(country) + (url.startsWith("/app") ? url.substring(4) : url);
         String response = request(url, params);
-        logger.debug("Request to {} server {}. Response: {}", country, urlPart, response);
+        logger.debug("Request to '{}' server '{}'. Response: '{}'", country, urlPart, response);
         return response;
     }
 
@@ -270,7 +270,7 @@ public class MiCloudConnector {
         }
         loginFailedCounterCheck();
         startClient();
-        logger.debug("Send request: {} to {}", params.get("data"), url);
+        logger.debug("Send request to {} with data '{}'", url, params.get("data"));
         Request request = httpClient.newRequest(url).timeout(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
         request.agent(USERAGENT);
         request.header("x-xiaomi-protocal-flag-cli", "PROTOCAL-HTTP2");
index b14d6ddaa1e4480463f8d554238fb0fb2cb8d9f7..0d37746e14af76389975004c7d070311fd43122e 100644 (file)
@@ -112,11 +112,11 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
 
     protected boolean handleCommandsChannels(ChannelUID channelUID, Command command) {
         if (channelUID.getId().equals(CHANNEL_COMMAND)) {
-            cmds.put(sendCommand(command.toString(), ""), command.toString());
+            cmds.put(sendCommand(command.toString()), channelUID.getId());
             return true;
         }
         if (channelUID.getId().equals(CHANNEL_RPC)) {
-            cmds.put(sendCommand(command.toString(), cloudServer), command.toString());
+            cmds.put(sendCommand(command.toString(), cloudServer), channelUID.getId());
             return true;
         }
         return false;
@@ -553,12 +553,11 @@ public abstract class MiIoAbstractHandler extends BaseThingHandler implements Mi
                     break;
             }
             if (cmds.containsKey(response.getId())) {
-                if (response.getCloudServer().isBlank()) {
-                    updateState(CHANNEL_COMMAND, new StringType(response.getResponse().toString()));
-                } else {
-                    updateState(CHANNEL_RPC, new StringType(response.getResponse().toString()));
+                String channel = cmds.get(response.getId());
+                if (channel != null && (CHANNEL_COMMAND.contentEquals(channel) || CHANNEL_RPC.contentEquals(channel))) {
+                    updateState(channel, new StringType(response.getResponse().toString()));
+                    cmds.remove(response.getId());
                 }
-                cmds.remove(response.getId());
             }
         } catch (Exception e) {
             logger.debug("Error while handing message {}", response.getResponse(), e);
index 2abc7db3213b185f115c31168db017797f850823..3b81c3db3c889dd1cee75ed6b3d1926744c7ae51 100644 (file)
@@ -328,7 +328,17 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
                         getThing().getUID());
                 continue;
             }
-            sendCommand(miChannel.getChannelCustomRefreshCommand());
+            String cmd = miChannel.getChannelCustomRefreshCommand();
+            if (!cmd.startsWith("/")) {
+                cmds.put(sendCommand(miChannel.getChannelCustomRefreshCommand()), miChannel.getChannel());
+            } else {
+                if (cloudServer.isBlank()) {
+                    logger.debug("Cloudserver empty. Skipping refresh for {} channel '{}'", getThing().getUID(),
+                            miChannel.getChannel());
+                } else {
+                    cmds.put(sendCommand(cmd, cloudServer), miChannel.getChannel());
+                }
+            }
         }
     }
 
@@ -515,6 +525,16 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
         return null;
     }
 
+    private @Nullable MiIoBasicChannel getCustomRefreshChannel(String channelName) {
+        for (MiIoBasicChannel refreshEntry : refreshListCustomCommands.values()) {
+            if (refreshEntry.getChannel().equals(channelName)) {
+                return refreshEntry;
+            }
+        }
+        logger.trace("Did not find channel for {} in {}", channelName, refreshList);
+        return null;
+    }
+
     private void updatePropsFromJsonArray(MiIoSendCommand response) {
         JsonArray res = response.getResult().getAsJsonArray();
         JsonArray para = JsonParser.parseString(response.getCommandString()).getAsJsonObject().get("params")
@@ -679,10 +699,11 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
                     }
                     break;
                 default:
-                    if (refreshListCustomCommands.containsKey(response.getMethod())) {
+                    String channel = cmds.get(response.getId());
+                    if (channel != null) {
                         logger.debug("Processing custom refresh command response for '{}' - {}", response.getMethod(),
                                 response.getResult());
-                        final MiIoBasicChannel ch = refreshListCustomCommands.get(response.getMethod());
+                        final MiIoBasicChannel ch = getCustomRefreshChannel(channel);
                         if (ch != null) {
                             if (response.getResult().isJsonArray()) {
                                 JsonArray cmdResponse = response.getResult().getAsJsonArray();
@@ -698,6 +719,7 @@ public class MiIoBasicHandler extends MiIoAbstractHandler {
                                 updateChannel(ch, ch.getChannel(), new JsonPrimitive(response.getResult().toString()));
                             }
                         }
+                        cmds.remove(response.getId());
                     }
                     break;
             }
index bc0335865e21e6b66c01ec05464ec26c017af058..7be4bd454a231d6b8f8fddb7cb16c4a9ae4470d3 100644 (file)
@@ -146,9 +146,17 @@ public class MiIoAsyncCommunication {
             if (cmdId > MAX_ID) {
                 id.set(0);
             }
-            fullCommand.addProperty("id", cmdId);
-            fullCommand.addProperty("method", command);
-            fullCommand.add("params", JsonParser.parseString(params));
+            if (command.startsWith("{") && command.endsWith("}")) {
+                fullCommand = JsonParser.parseString(command).getAsJsonObject();
+                fullCommand.addProperty("id", cmdId);
+                if (!fullCommand.has("params") && !params.isBlank()) {
+                    fullCommand.add("params", JsonParser.parseString(params));
+                }
+            } else {
+                fullCommand.addProperty("id", cmdId);
+                fullCommand.addProperty("method", command);
+                fullCommand.add("params", JsonParser.parseString(params));
+            }
             MiIoSendCommand sendCmd = new MiIoSendCommand(cmdId, MiIoCommand.getCommand(command), fullCommand,
                     cloudServer);
             concurrentLinkedQueue.add(sendCmd);
@@ -163,7 +171,7 @@ public class MiIoAsyncCommunication {
                 sendPing(ip);
             }
             return cmdId;
-        } catch (JsonSyntaxException e) {
+        } catch (JsonSyntaxException | IllegalStateException e) {
             logger.warn("Send command '{}' with parameters {} -> {} (Device: {}) gave error {}", command, params, ip,
                     deviceId, e.getMessage());
             throw e;
@@ -177,11 +185,24 @@ public class MiIoAsyncCommunication {
             if (miIoSendCommand.getCloudServer().isBlank()) {
                 decryptedResponse = sendCommand(miIoSendCommand.getCommandString(), token, ip, deviceId);
             } else {
-                decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHexId(deviceId),
-                        miIoSendCommand.getCloudServer(), miIoSendCommand);
-                logger.debug("Command {} send via cloudserver {}", miIoSendCommand.getCommandString(),
-                        miIoSendCommand.getCloudServer());
-                updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
+                if (!miIoSendCommand.getMethod().startsWith("/")) {
+                    decryptedResponse = cloudConnector.sendRPCCommand(Utils.getHexId(deviceId),
+                            miIoSendCommand.getCloudServer(), miIoSendCommand);
+                    logger.debug("Command {} send via cloudserver {}", miIoSendCommand.getCommandString(),
+                            miIoSendCommand.getCloudServer());
+                    updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);
+                } else {
+                    String data = miIoSendCommand.getParams().isJsonArray()
+                            && miIoSendCommand.getParams().getAsJsonArray().size() > 0
+                                    ? miIoSendCommand.getParams().getAsJsonArray().get(0).toString()
+                                    : "";
+                    logger.debug("Custom cloud request send to url '{}' with data '{}'", miIoSendCommand.getMethod(),
+                            data);
+                    decryptedResponse = cloudConnector.sendCloudCommand(miIoSendCommand.getMethod(),
+                            miIoSendCommand.getCloudServer(), data);
+                    miIoSendCommand.setResponse(JsonParser.parseString(decryptedResponse).getAsJsonObject());
+                    return miIoSendCommand;
+                }
             }
             // hack due to avoid invalid json errors from some misbehaving device firmwares
             decryptedResponse = decryptedResponse.replace(",,", ",");