[miio] additional vacuum channels for advanced rules (#10180)

* [miio] add feature channels
* [miio] additional vacuum channels for advanced rules
* [miio] update readme

Signed-off-by: Marcel Verpaalen <marcel@verpaalen.com>
This commit is contained in:
Marcel
2021-02-25 19:22:45 +01:00
committed by GitHub
parent 8928e8520c
commit d1d42c4de9
6 changed files with 178 additions and 17 deletions

View 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;

View 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())) {

View 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);
}
}

View 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">
@@ -95,6 +99,16 @@
<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">
@@ -152,6 +166,21 @@
<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">
@@ -358,4 +387,29 @@
<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>