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 |
|---------|-----------------------------------|----------------------------|
|----------------------|----------------------|------------------------------------------|------------|
| 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 | |
|----------------------|----------------------|------------------------------------------|------------|
| 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 | |
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 |
|---------|-----------------------------------|----------------------------|
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"}
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"}
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;
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;
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;
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()));
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());
}
}
}
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())) {
@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() {
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);
}
}
<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>
<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>