]> git.basschouten.com Git - openhab-addons.git/commitdiff
[miio] additional vacuum channels for advanced rules (#10180)
authorMarcel <marcel@verpaalen.com>
Thu, 25 Feb 2021 18:22:45 +0000 (19:22 +0100)
committerGitHub <noreply@github.com>
Thu, 25 Feb 2021 18:22:45 +0000 (10:22 -0800)
* [miio] add feature channels
* [miio] additional vacuum channels for advanced rules
* [miio] update readme

Signed-off-by: Marcel Verpaalen <marcel@verpaalen.com>
bundles/org.openhab.binding.miio/README.base.md
bundles/org.openhab.binding.miio/README.md
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/MiIoCommand.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/handler/MiIoVacuumHandler.java
bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/robot/RobotCababilities.java
bundles/org.openhab.binding.miio/src/main/resources/OH-INF/thing/vacuumThing.xml

index 88306fd08807c11cae61dd3a04d1506538d8dbdf..8223a88c09f2ae789f8bad1cf28df048519fb665 100644 (file)
@@ -245,8 +245,20 @@ Image map "Cleaning Map" (gVacLast) {channel="miio:vacuum:034F0E45:cleaning#map"
 
 Note: cleaning map is only available with cloud access.
 
-Additionally depending on the capabilities of your robot vacuum other channels may be enabled at runtime
+There are several advanced channels, which may be useful in rules (e.g. for individual room cleaning etc)
+In case your vacuum does not support one of these commands, it will show "unsupported_method" for string channels or no value for numeric channels.
 
+| Type    | Channel                           | Description                |
+|---------|-----------------------------------|----------------------------|
+| Number  | status#segment_status             | Segment Status             |
+| Number  | status#map_status                 | Map Box Status             |
+| Number  | status#led_status                 | Led Box Status             |
+| String  | info#carpet_mode                  | Carpet Mode details        |
+| String  | info#fw_features                  | Firmware Features          |
+| String  | info#room_mapping                 | Room Mapping details       |
+| String  | info#multi_maps_list              | Maps Listing details       |
+
+Additionally depending on the capabilities of your robot vacuum other channels may be enabled at runtime
 
 | Type    | Channel                           | Description                |
 |---------|-----------------------------------|----------------------------|
index 44218acc5ebb22d0ebdae4d667daa6deeba6d0ed..806207bbf4f393bd241e94bea4329b81d869ecef 100644 (file)
@@ -2663,7 +2663,7 @@ e.g. `openhab:send actionCommand 'upd_timer["1498595904821", "on"]'` would enabl
 |----------------------|----------------------|------------------------------------------|------------|
 | power                | Switch               | Power                                    |            |
 | brightness           | Dimmer               | Brightness                               |            |
-| ambientBrightness    | Number               | Ambient Brightness                       |            |
+| ambientBrightness    | Dimmer               | Ambient Brightness                       |            |
 | delayoff             | Number:Time          | Shutdown Timer                           |            |
 | colorTemperature     | Number               | Color Temperature                        |            |
 | colorMode            | Number               | Color Mode                               |            |
@@ -2759,7 +2759,7 @@ e.g. `openhab:send actionCommand 'upd_timer["1498595904821", "on"]'` would enabl
 |----------------------|----------------------|------------------------------------------|------------|
 | power                | Switch               | Power                                    |            |
 | brightness           | Dimmer               | Brightness                               |            |
-| ambientBrightness    | Number               | Ambient Brightness                       |            |
+| ambientBrightness    | Dimmer               | Ambient Brightness                       |            |
 | delayoff             | Number:Time          | Shutdown Timer                           |            |
 | colorTemperature     | Number               | Color Temperature                        |            |
 | colorMode            | Number               | Color Mode                               |            |
@@ -4543,8 +4543,20 @@ Image map "Cleaning Map" (gVacLast) {channel="miio:vacuum:034F0E45:cleaning#map"
 
 Note: cleaning map is only available with cloud access.
 
-Additionally depending on the capabilities of your robot vacuum other channels may be enabled at runtime
+There are several advanced channels, which may be useful in rules (e.g. for individual room cleaning etc)
+In case your vacuum does not support one of these commands, it will show "unsupported_method" for string channels or no value for numeric channels.
 
+| Type    | Channel                           | Description                |
+|---------|-----------------------------------|----------------------------|
+| Number  | status#segment_status             | Segment Status             |
+| Number  | status#map_status                 | Map Box Status             |
+| Number  | status#led_status                 | Led Box Status             |
+| String  | info#carpet_mode                  | Carpet Mode details        |
+| String  | info#fw_features                  | Firmware Features          |
+| String  | info#room_mapping                 | Room Mapping details       |
+| String  | info#multi_maps_list              | Maps Listing details       |
+
+Additionally depending on the capabilities of your robot vacuum other channels may be enabled at runtime
 
 | Type    | Channel                           | Description                |
 |---------|-----------------------------------|----------------------------|
@@ -7155,7 +7167,7 @@ note: Autogenerated example. Replace the id (light) in the channel with your own
 Group G_light "Yeelight LED Ceiling Light" <status>
 Switch power "Power" (G_light) {channel="miio:basic:light:power"}
 Dimmer brightness "Brightness" (G_light) {channel="miio:basic:light:brightness"}
-Number ambientBrightness "Ambient Brightness" (G_light) {channel="miio:basic:light:ambientBrightness"}
+Dimmer ambientBrightness "Ambient Brightness" (G_light) {channel="miio:basic:light:ambientBrightness"}
 Number:Time delayoff "Shutdown Timer" (G_light) {channel="miio:basic:light:delayoff"}
 Number colorTemperature "Color Temperature" (G_light) {channel="miio:basic:light:colorTemperature"}
 Number colorMode "Color Mode" (G_light) {channel="miio:basic:light:colorMode"}
@@ -7272,7 +7284,7 @@ note: Autogenerated example. Replace the id (light) in the channel with your own
 Group G_light "Yeelight Crystal Pendant Lamp" <status>
 Switch power "Power" (G_light) {channel="miio:basic:light:power"}
 Dimmer brightness "Brightness" (G_light) {channel="miio:basic:light:brightness"}
-Number ambientBrightness "Ambient Brightness" (G_light) {channel="miio:basic:light:ambientBrightness"}
+Dimmer ambientBrightness "Ambient Brightness" (G_light) {channel="miio:basic:light:ambientBrightness"}
 Number:Time delayoff "Shutdown Timer" (G_light) {channel="miio:basic:light:delayoff"}
 Number colorTemperature "Color Temperature" (G_light) {channel="miio:basic:light:colorTemperature"}
 Number colorMode "Color Mode" (G_light) {channel="miio:basic:light:colorMode"}
index 447b51d1c5dd60dfb0e6bed2e6512ec7db2a403d..f16df318f268d1d00876f689fc8c04dbd2b23a7d 100644 (file)
@@ -86,6 +86,15 @@ public enum MiIoCommand {
     REMOTE_END("app_rc_end"),
     REMOTE_MOVE("app_rc_move"),
 
+    GET_MAP_STATUS("get_map_status"),
+    GET_SEGMENT_STATUS("get_segment_status"),
+    GET_LED_STATUS("get_led_status"),
+    GET_CARPET_MODE("get_carpet_mode"),
+    GET_FW_FEATURES("get_fw_features"),
+    GET_CUSTOMIZED_CLEAN_MODE("get_customize_clean_mode"),
+    GET_MULTI_MAP_LIST("get_multi_maps_list"),
+    GET_ROOM_MAPPING("get_room_mapping"),
+
     UNKNOWN("");
 
     private final String command;
index 3b3eba803aa5d0256de2dcfcf89fb12592bde80f..30fe0fbe844224dbaddb738f2bb2b3ef469505f0 100644 (file)
@@ -22,10 +22,14 @@ import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
+import java.util.Collections;
 import java.util.Date;
 import java.util.Map.Entry;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import javax.imageio.ImageIO;
 
@@ -89,6 +93,12 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
     private static final Gson GSON = new GsonBuilder().serializeNulls().create();
     private final ChannelUID mapChannelUid;
 
+    private static final Set<RobotCababilities> FEATURES_CHANNELS = Collections.unmodifiableSet(Stream
+            .of(RobotCababilities.SEGMENT_STATUS, RobotCababilities.MAP_STATUS, RobotCababilities.LED_STATUS,
+                    RobotCababilities.CARPET_MODE, RobotCababilities.FW_FEATURES, RobotCababilities.ROOM_MAPPING,
+                    RobotCababilities.MULTI_MAP_LIST, RobotCababilities.CUSTOMIZE_CLEAN_MODE)
+            .collect(Collectors.toSet()));
+
     private ExpiringCache<String> status;
     private ExpiringCache<String> consumables;
     private ExpiringCache<String> dnd;
@@ -289,6 +299,7 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
         safeUpdateState(CHANNEL_IN_CLEANING, statusInfo.getInCleaning());
         safeUpdateState(CHANNEL_MAP_PRESENT, statusInfo.getMapPresent());
         if (statusInfo.getState() != null) {
+            stateId = statusInfo.getState();
             StatusType state = StatusType.getType(statusInfo.getState());
             updateState(CHANNEL_STATE, new StringType(state.getDescription()));
             updateState(CHANNEL_STATE_ID, new DecimalType(statusInfo.getState()));
@@ -464,6 +475,11 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
                     map.getValue();
                 }
             }
+            for (RobotCababilities cmd : FEATURES_CHANNELS) {
+                if (isLinked(cmd.getChannel())) {
+                    sendCommand(cmd.getCommand());
+                }
+            }
         } catch (Exception e) {
             logger.debug("Error while updating '{}': '{}", getThing().getUID().toString(), e.getLocalizedMessage());
         }
@@ -530,11 +546,54 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
                     }
                 }
                 break;
+            case GET_MAP_STATUS:
+            case GET_SEGMENT_STATUS:
+            case GET_LED_STATUS:
+                updateNumericChannel(response);
+                break;
+            case GET_CARPET_MODE:
+            case GET_FW_FEATURES:
+            case GET_CUSTOMIZED_CLEAN_MODE:
+            case GET_MULTI_MAP_LIST:
+            case GET_ROOM_MAPPING:
+                for (RobotCababilities cmd : FEATURES_CHANNELS) {
+                    if (response.getCommand().getCommand().contentEquals(cmd.getCommand())) {
+                        updateState(cmd.getChannel(), new StringType(response.getResult().toString()));
+                        break;
+                    }
+                }
+                break;
             default:
                 break;
         }
     }
 
+    private void updateNumericChannel(MiIoSendCommand response) {
+        RobotCababilities capabilityChannel = null;
+        for (RobotCababilities cmd : FEATURES_CHANNELS) {
+            if (response.getCommand().getCommand().contentEquals(cmd.getCommand())) {
+                capabilityChannel = cmd;
+                break;
+            }
+        }
+        if (capabilityChannel != null) {
+            if (response.getResult().isJsonArray() && response.getResult().getAsJsonArray().get(0).isJsonPrimitive()) {
+                try {
+                    Integer stat = response.getResult().getAsJsonArray().get(0).getAsInt();
+                    updateState(capabilityChannel.getChannel(), new DecimalType(stat));
+                    return;
+                } catch (ClassCastException | IllegalStateException e) {
+                    logger.debug("Could not update numeric channel {} with '{}': {}", capabilityChannel.getChannel(),
+                            response.getResult(), e.getMessage());
+                }
+            } else {
+                logger.debug("Could not update numeric channel {} with '{}': Not in expected format",
+                        capabilityChannel.getChannel(), response.getResult());
+            }
+            updateState(capabilityChannel.getChannel(), UnDefType.UNDEF);
+        }
+    }
+
     private void setCapabilities(JsonObject statusResponse) {
         for (RobotCababilities capability : RobotCababilities.values()) {
             if (statusResponse.has(capability.getStatusFieldName())) {
index 2d8d5dc339a6266edd03b3cd296e67249d3f2faf..d30eca08c4d327deaa58978d7eb2f202d46814f1 100644 (file)
@@ -23,23 +23,33 @@ import org.openhab.core.thing.type.ChannelTypeUID;
 @NonNullByDefault
 public enum RobotCababilities {
 
-    WATERBOX_STATUS("water_box_status", "status#water_box_status", "miio:water_box_status"),
-    LOCKSTATUS("lock_status", "status#lock_status", "miio:lock_status"),
-    WATERBOX_MODE("water_box_mode", "status#water_box_mode", "miio:water_box_mode"),
-    WATERBOX_CARRIAGE("water_box_carriage_status", "status#water_box_carriage_status",
-            "miio:water_box_carriage_status"),
-    MOP_FORBIDDEN("mop_forbidden_enable", "status#mop_forbidden_enable", "miio:mop_forbidden_enable"),
-    LOCATING("is_locating", "status#is_locating", "miio:is_locating"),
-    SEGMENT_CLEAN("", "actions#segment", "miio:segment");
+    WATERBOX_STATUS("water_box_status", "status#water_box_status", "miio:water_box_status", ""),
+    LOCKSTATUS("lock_status", "status#lock_status", "miio:lock_status", ""),
+    WATERBOX_MODE("water_box_mode", "status#water_box_mode", "miio:water_box_mode", ""),
+    WATERBOX_CARRIAGE("water_box_carriage_status", "status#water_box_carriage_status", "miio:water_box_carriage_status",
+            ""),
+    MOP_FORBIDDEN("mop_forbidden_enable", "status#mop_forbidden_enable", "miio:mop_forbidden_enable", ""),
+    LOCATING("is_locating", "status#is_locating", "miio:is_locating", ""),
+    SEGMENT_STATUS("", "status#segment_status", "miio:segment_status", "get_segment_status"),
+    MAP_STATUS("", "status#map_status", "miio:map_status", "get_map_status"),
+    LED_STATUS("", "status#led_status", "miio:led_status", "get_led_status"),
+    CARPET_MODE("", "info#carpet_mode", "miio:carpet_mode", "get_carpet_mode"),
+    FW_FEATURES("", "info#fw_features", "miio:fw_features", "get_fw_features"),
+    ROOM_MAPPING("", "info#room_mapping", "miio:room_mapping", "get_room_mapping"),
+    MULTI_MAP_LIST("", "info#multi_maps_list", "miio:multi_maps_list", "get_multi_maps_list"),
+    CUSTOMIZE_CLEAN_MODE("", "info#customize_clean_mode", "miio:customize_clean_mode", "get_customize_clean_mode"),
+    SEGMENT_CLEAN("", "actions#segment", "miio:segment", "");
 
     private final String statusFieldName;
     private final String channel;
     private final String channelType;
+    private final String command;
 
-    RobotCababilities(String statusKey, String channel, String channelType) {
+    RobotCababilities(String statusKey, String channel, String channelType, String command) {
         this.statusFieldName = statusKey;
         this.channel = channel;
         this.channelType = channelType;
+        this.command = command;
     }
 
     public String getStatusFieldName() {
@@ -54,9 +64,14 @@ public enum RobotCababilities {
         return new ChannelTypeUID(channelType);
     }
 
+    public String getCommand() {
+        return command;
+    }
+
     @Override
     public String toString() {
-        return String.format("Capability %s: status field name: '%s', channel: '%s', channeltype: '%s'.", this.name(),
-                statusFieldName, channel, channelType);
+        return String.format("Capability %s: status field name: '%s', channel: '%s', channeltype: '%s'%s%s.",
+                this.name(), statusFieldName, channel, channelType, command.isBlank() ? "" : ", custom command: ",
+                command);
     }
 }
index caee93a44ecf44e10a20f0aead43568034a3ef5c..c9e5e713eedaa8bf8294a2de23d467587e35d295 100644 (file)
@@ -15,6 +15,7 @@
                        <channel-group id="history" typeId="history"/>
                        <channel-group id="cleaning" typeId="cleaning"/>
                        <channel-group id="network" typeId="network"/>
+                       <channel-group id="info" typeId="info"/>
                </channel-groups>
 
                <properties>
@@ -50,6 +51,9 @@
                        <channel id="map_present" typeId="map_present"/>
                        <channel id="state" typeId="state"/>
                        <channel id="state_id" typeId="state_id"/>
+                       <channel id="segment_status" typeId="segment_status"/>
+                       <channel id="map_status" typeId="map_status"/>
+                       <channel id="led_status" typeId="led_status"/>
                </channels>
        </channel-group-type>
        <channel-group-type id="consumables">
                        <channel id="total_clean_count" typeId="total_clean_count"/>
                </channels>
        </channel-group-type>
+       <channel-group-type id="info">
+               <label>Info</label>
+               <channels>
+                       <channel id="multi_maps_list" typeId="multi_maps_list"/>
+                       <channel id="room_mapping" typeId="room_mapping"/>
+                       <channel id="fw_features" typeId="fw_features"/>
+                       <channel id="customize_clean_mode" typeId="customize_clean_mode"/>
+                       <channel id="carpet_mode" typeId="carpet_mode"/>
+               </channels>
+       </channel-group-type>
 
        <!-- Status channels -->
        <channel-type id="clean_area">
                <label>State ID</label>
                <state readOnly="true"/>
        </channel-type>
+       <channel-type id="segment_status" advanced="true">
+               <item-type>Number</item-type>
+               <label>Segment Status</label>
+               <state pattern="%.0f" readOnly="true"/>
+       </channel-type>
+       <channel-type id="map_status" advanced="true">
+               <item-type>Number</item-type>
+               <label>Map Status</label>
+               <state pattern="%.0f" readOnly="true"/>
+       </channel-type>
+       <channel-type id="led_status" advanced="true">
+               <item-type>Number</item-type>
+               <label>Led Status</label>
+               <state pattern="%.0f" readOnly="true"/>
+       </channel-type>
 
        <!-- Dynamic Status Channels -->
        <channel-type id="water_box_mode">
                <label>Cleaning Map</label>
                <state readOnly="true"/>
        </channel-type>
+
+       <!-- Info channels -->
+       <channel-type id="fw_features" advanced="true">
+               <item-type>String</item-type>
+               <label>Firmware Features</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="room_mapping" advanced="true">
+               <item-type>String</item-type>
+               <label>Room Mapping</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="multi_maps_list" advanced="true">
+               <item-type>String</item-type>
+               <label>Multi Map List</label>
+               <state readOnly="true"/>
+       </channel-type>
+       <channel-type id="carpet_mode" advanced="true">
+               <item-type>String</item-type>
+               <label>Carpet Mode</label>
+       </channel-type>
+       <channel-type id="customize_clean_mode" advanced="true">
+               <item-type>String</item-type>
+               <label>Customized Clean Mode</label>
+       </channel-type>
 </thing:thing-descriptions>