]> git.basschouten.com Git - openhab-addons.git/commitdiff
[ecovacs] Add support for DEEBOT X2 Omni (#16487)
authormaniac103 <dannybaumann@web.de>
Tue, 12 Mar 2024 13:52:59 +0000 (14:52 +0100)
committerGitHub <noreply@github.com>
Tue, 12 Mar 2024 13:52:59 +0000 (14:52 +0100)
Fixes #16117

* [ecovacs] Interpret empty error code list as 'no error'

Newer devices don't explicitly report 'no error' anymore, but instead
send an empty list.

Signed-off-by: Danny Baumann <dannybaumann@web.de>
bundles/org.openhab.binding.ecovacs/src/main/java/org/openhab/binding/ecovacs/internal/api/commands/GetErrorCommand.java
bundles/org.openhab.binding.ecovacs/src/main/java/org/openhab/binding/ecovacs/internal/api/commands/SpotAreaCleaningCommand.java
bundles/org.openhab.binding.ecovacs/src/main/java/org/openhab/binding/ecovacs/internal/api/impl/JsonReportParser.java
bundles/org.openhab.binding.ecovacs/src/main/java/org/openhab/binding/ecovacs/internal/api/model/CleanMode.java
bundles/org.openhab.binding.ecovacs/src/main/java/org/openhab/binding/ecovacs/internal/api/model/DeviceCapability.java
bundles/org.openhab.binding.ecovacs/src/main/java/org/openhab/binding/ecovacs/internal/handler/EcovacsVacuumHandler.java
bundles/org.openhab.binding.ecovacs/src/main/resources/devices/supported_device_list.json

index 4b5dcc6788dd37d23c60a94dc751c7756678802a..4c8b5764b0850c013f70ae81cc2107e1e5acee97 100644 (file)
@@ -44,10 +44,8 @@ public class GetErrorCommand extends IotDeviceCommand<Optional<Integer>> {
             Gson gson) throws DataParsingException {
         if (response instanceof PortalIotCommandJsonResponse jsonResponse) {
             ErrorReport resp = jsonResponse.getResponsePayloadAs(gson, ErrorReport.class);
-            if (resp.errorCodes.isEmpty()) {
-                return Optional.empty();
-            }
-            return Optional.of(resp.errorCodes.get(0));
+            int responseCode = resp.errorCodes.isEmpty() ? 0 : resp.errorCodes.get(0);
+            return Optional.of(responseCode);
         } else {
             String payload = ((PortalIotCommandXmlResponse) response).getResponsePayloadXml();
             return DeviceInfo.parseErrorInfo(payload);
index 92b904d8112e6b60c7679420e426239531d7037e..06dd9abcc2e358aa468883c31c3c4188d2ab7866 100644 (file)
@@ -21,7 +21,13 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
  */
 @NonNullByDefault
 public class SpotAreaCleaningCommand extends AbstractAreaCleaningCommand {
-    public SpotAreaCleaningCommand(List<String> roomIds, int cleanPasses) {
-        super("spotArea", String.join(",", roomIds), cleanPasses);
+    public SpotAreaCleaningCommand(List<String> roomIds, int cleanPasses, boolean usesFreeClean) {
+        super(usesFreeClean ? "freeClean" : "spotArea", prepareRoomIds(roomIds, usesFreeClean), cleanPasses);
+    }
+
+    private static String prepareRoomIds(List<String> roomIds, boolean usesFreeClean) {
+        String prefix = usesFreeClean ? "1," : "";
+        String separator = usesFreeClean ? ";" : ",";
+        return prefix + String.join(separator, roomIds);
     }
 }
index ae9ed9918bd6d563bbbec1096e47bb2c561391a9..0acb6f52b34885ceeab52ce654b6d38b0eec8d85 100644 (file)
@@ -109,8 +109,12 @@ class JsonReportParser implements ReportParser {
             }
             case "error": {
                 ErrorReport report = payloadAs(response, ErrorReport.class);
-                for (Integer code : report.errorCodes) {
-                    listener.onErrorReported(device, code);
+                if (report.errorCodes.isEmpty()) {
+                    listener.onErrorReported(device, 0);
+                } else {
+                    for (Integer code : report.errorCodes) {
+                        listener.onErrorReported(device, code);
+                    }
                 }
             }
             case "stats": {
index 65cd12a6812c730310b52f7e3efdaf046b4d3242..ab813befe15f73c6f2452bffc6266a936aa0a44e 100644 (file)
@@ -27,7 +27,7 @@ public enum CleanMode {
     EDGE,
     @SerializedName("spot")
     SPOT,
-    @SerializedName(value = "SpotArea", alternate = { "spotArea" })
+    @SerializedName(value = "SpotArea", alternate = { "spotArea", "freeClean" })
     SPOT_AREA,
     @SerializedName(value = "CustomArea", alternate = { "customArea" })
     CUSTOM_AREA,
index 286e38644ca9c15d34a06c32bea9916066d7ca11..c9cea1422aa1d1fa538ba2c07df0b18a9141a3a7 100644 (file)
@@ -29,6 +29,8 @@ public enum DeviceCapability {
     VOICE_REPORTING,
     @SerializedName("spot_area_cleaning")
     SPOT_AREA_CLEANING,
+    @SerializedName("free_clean_command")
+    FREE_CLEAN_FOR_SPOT_AREA,
     @SerializedName("custom_area_cleaning")
     CUSTOM_AREA_CLEANING,
     @SerializedName("single_room_cleaning")
index 34b7ce703df265fbe6b17785925c5d346b0b2f77..32a5881ae2c819b74f7bb58673e242a67faf127b 100644 (file)
@@ -761,7 +761,8 @@ public class EcovacsVacuumHandler extends BaseThingHandler implements EcovacsDev
                     }
                 }
                 if (!roomIds.isEmpty()) {
-                    return new SpotAreaCleaningCommand(roomIds, passes);
+                    return new SpotAreaCleaningCommand(roomIds, passes,
+                            device.hasCapability(DeviceCapability.FREE_CLEAN_FOR_SPOT_AREA));
                 }
             } else {
                 logger.info("{}: spotArea command needs to have the form spotArea:<room1>[;<room2>][;<...roomX>][:x2]",
index f68b93f480ae4f6433f6fac80845e3d84941a52b..c585cf4baf1ef496da2f7146c7368cea018bbc4d 100644 (file)
         "modelName": "DEEBOT U2 SE",
         "deviceClass": "zjna8m",
         "deviceClassLink": "ipzjy0"
+    },
+
+    {
+        "modelName": "DEEBOT X2",
+        "deviceClass": "e6ofmn",
+        "protoVersion": "json_v2",
+        "usesMqtt": true,
+        "capabilities": [
+            "mopping_system",
+            "main_brush",
+            "spot_area_cleaning",
+            "free_clean_command",
+            "custom_area_cleaning",
+            "clean_speed_control",
+            "voice_reporting",
+            "read_network_info",
+            "unit_care_lifespan",
+            "true_detect_3d",
+            "mapping",
+            "auto_empty_station"
+        ]
+    },
+    {
+        "modelName": "DEEBOT X2 OMNI",
+        "deviceClass": "lf3bn4",
+        "deviceClassLink": "e6ofmn"
+    },
+    {
+        "modelName": "DEEBOT X2 COMBO",
+        "deviceClass": "e6rcnf",
+        "deviceClassLink": "e6ofmn"
+    },
+    {
+        "modelName": "DEEBOT X2 PRO OMNI",
+        "deviceClass": "ip3mmy",
+        "deviceClassLink": "e6ofmn"
     }
 ]