[miio] Add a few new vacuum robots and station channels (#15704)

* Added a few new channels:
- cleaning the mop
- check if mop drying is enabled
- remaining time for mop drying

Signed-off-by: David Kumar <github@truidix.de>
This commit is contained in:
truidix 2023-11-08 21:39:59 +01:00 committed by GitHub
parent 91b294521e
commit 5555d68f92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 239 additions and 10 deletions

View File

@ -252,6 +252,13 @@ Additionally depending on the capabilities of your robot vacuum other channels m
| Switch | status#mop_forbidden_enable | Mop Forbidden |
| Switch | status#is_locating | Robot is locating |
| Number | actions#segment | Room Clean (enter room #) |
| Switch | actions#collect_dust | Start collecting dust |
| Switch | actions#clean_mop_start | Start mop wash |
| Switch | actions#clean_mop_stop | Stop mop wash |
| Number | status#mop_drying_time | Mop drying Time |
| Switch | status#is_mop_drying | Mop cleaning active |
| Number | status#dock_state_id | Dock status id |
| String | status#dock_state | Dock status message |
Note: cleaning map is only available with cloud access.

View File

@ -646,6 +646,13 @@ Additionally depending on the capabilities of your robot vacuum other channels m
| Switch | status#mop_forbidden_enable | Mop Forbidden |
| Switch | status#is_locating | Robot is locating |
| Number | actions#segment | Room Clean (enter room #) |
| Switch | actions#collect_dust | Start collecting dust |
| Switch | actions#clean_mop_start | Start mop wash |
| Switch | actions#clean_mop_stop | Stop mop wash |
| Number | status#mop_drying_time | Mop drying Time |
| Switch | status#is_mop_drying | Mop cleaning active |
| Number | status#dock_state_id | Dock status id |
| String | status#dock_state | Dock status message |
Note: cleaning map is only available with cloud access.

View File

@ -61,6 +61,8 @@ public final class MiIoBindingConstants {
public static final String CHANNEL_MAP_PRESENT = "status#map_present";
public static final String CHANNEL_STATE = "status#state";
public static final String CHANNEL_STATE_ID = "status#state_id";
public static final String CHANNEL_DOCK_STATE = "status#dock_state";
public static final String CHANNEL_DOCK_STATE_ID = "status#dock_state_id";
public static final String CHANNEL_CONTROL = "actions#control";
public static final String CHANNEL_COMMAND = "actions#commands";
@ -94,6 +96,8 @@ public final class MiIoBindingConstants {
public static final String CHANNEL_HISTORY_TOTALAREA = "history#total_clean_area";
public static final String CHANNEL_HISTORY_COUNT = "history#total_clean_count";
public static final String CHANNEL_MOP_TOTALDRYTIME = "status#mop_drying_time";
public static final String CHANNEL_HISTORY_START_TIME = "cleaning#last_clean_start_time";
public static final String CHANNEL_HISTORY_END_TIME = "cleaning#last_clean_end_time";
public static final String CHANNEL_HISTORY_AREA = "cleaning#last_clean_area";

View File

@ -96,6 +96,9 @@ public enum MiIoCommand {
GET_CUSTOMIZED_CLEAN_MODE("get_customize_clean_mode"),
GET_MULTI_MAP_LIST("get_multi_maps_list"),
GET_ROOM_MAPPING("get_room_mapping"),
SET_COLLECT_DUST("app_start_collect_dust"),
SET_CLEAN_MOP_START("app_start_wash"),
SET_CLEAN_MOP_STOP("app_stop_wash"),
// Gateway & child device commands
GET_ARMING("get_arming"),

View File

@ -46,6 +46,7 @@ import org.openhab.binding.miio.internal.cloud.CloudUtil;
import org.openhab.binding.miio.internal.cloud.HomeRoomDTO;
import org.openhab.binding.miio.internal.cloud.MiCloudException;
import org.openhab.binding.miio.internal.robot.ConsumablesType;
import org.openhab.binding.miio.internal.robot.DockStatusType;
import org.openhab.binding.miio.internal.robot.FanModeType;
import org.openhab.binding.miio.internal.robot.HistoryRecordDTO;
import org.openhab.binding.miio.internal.robot.RRMapDraw;
@ -100,11 +101,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 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, RobotCababilities.COLLECT_DUST,
RobotCababilities.CLEAN_MOP_START, RobotCababilities.CLEAN_MOP_STOP, RobotCababilities.MOP_DRYING,
RobotCababilities.MOP_DRYING_REMAINING_TIME, RobotCababilities.DOCK_STATE_ID).collect(Collectors.toSet()));
private ExpiringCache<String> status;
private ExpiringCache<String> consumables;
@ -242,6 +244,7 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
forceStatusUpdate();
return;
}
if (channelUID.getId().equals(RobotCababilities.WATERBOX_MODE.getChannel())) {
sendCommand(MiIoCommand.SET_WATERBOX_MODE, "[" + command.toString() + "]");
forceStatusUpdate();
@ -265,6 +268,26 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
sendCommand(MiIoCommand.CONSUMABLES_RESET, "[" + command.toString() + "]");
updateState(CHANNEL_CONSUMABLE_RESET, new StringType("none"));
}
if (channelUID.getId().equals(RobotCababilities.COLLECT_DUST.getChannel()) && !command.toString().isEmpty()
&& !command.toString().contentEquals("-")) {
sendCommand(MiIoCommand.SET_COLLECT_DUST);
forceStatusUpdate();
return;
}
if (channelUID.getId().equals(RobotCababilities.CLEAN_MOP_START.getChannel()) && !command.toString().isEmpty()
&& !command.toString().contentEquals("-")) {
sendCommand(MiIoCommand.SET_CLEAN_MOP_START);
forceStatusUpdate();
return;
}
if (channelUID.getId().equals(RobotCababilities.CLEAN_MOP_STOP.getChannel()) && !command.toString().isEmpty()
&& !command.toString().contentEquals("-")) {
sendCommand(MiIoCommand.SET_CLEAN_MOP_STOP);
forceStatusUpdate();
return;
}
}
private void forceStatusUpdate() {
@ -352,6 +375,11 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
}
updateState(CHANNEL_VACUUM, vacuum);
}
if (this.deviceCapabilities.containsKey(RobotCababilities.DOCK_STATE_ID)) {
DockStatusType state = DockStatusType.getType(statusInfo.getDockErrorStatus().intValue());
updateState(CHANNEL_DOCK_STATE, new StringType(state.getDescription()));
updateState(CHANNEL_DOCK_STATE_ID, new DecimalType(state.getId()));
}
if (deviceCapabilities.containsKey(RobotCababilities.WATERBOX_MODE)) {
safeUpdateState(RobotCababilities.WATERBOX_MODE.getChannel(), statusInfo.getWaterBoxMode());
}
@ -370,6 +398,22 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
if (deviceCapabilities.containsKey(RobotCababilities.LOCATING)) {
safeUpdateState(RobotCababilities.LOCATING.getChannel(), statusInfo.getIsLocating());
}
if (deviceCapabilities.containsKey(RobotCababilities.CLEAN_MOP_START)) {
safeUpdateState(RobotCababilities.CLEAN_MOP_START.getChannel(), 0);
}
if (deviceCapabilities.containsKey(RobotCababilities.CLEAN_MOP_STOP)) {
safeUpdateState(RobotCababilities.CLEAN_MOP_STOP.getChannel(), 0);
}
if (deviceCapabilities.containsKey(RobotCababilities.COLLECT_DUST)) {
safeUpdateState(RobotCababilities.COLLECT_DUST.getChannel(), 0);
}
if (deviceCapabilities.containsKey(RobotCababilities.MOP_DRYING)) {
safeUpdateState(RobotCababilities.MOP_DRYING.getChannel(), statusInfo.getIsMopDryingActive());
}
if (deviceCapabilities.containsKey(RobotCababilities.MOP_DRYING_REMAINING_TIME)) {
updateState(CHANNEL_MOP_TOTALDRYTIME,
new QuantityType<>(TimeUnit.SECONDS.toMinutes(statusInfo.getMopDryTime()), Units.MINUTE));
}
return true;
}
@ -690,6 +734,11 @@ public class MiIoVacuumHandler extends MiIoAbstractHandler {
case GET_FW_FEATURES:
case GET_CUSTOMIZED_CLEAN_MODE:
case GET_MULTI_MAP_LIST:
case SET_COLLECT_DUST:
case SET_CLEAN_MOP_START:
case SET_CLEAN_MOP_STOP:
for (RobotCababilities cmd : FEATURES_CHANNELS) {
if (response.getCommand().getCommand().contentEquals(cmd.getCommand())) {
updateState(cmd.getChannel(), new StringType(response.getResult().toString()));

View File

@ -0,0 +1,66 @@
/**
* Copyright (c) 2010-2023 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.miio.internal.robot;
import org.eclipse.jdt.annotation.NonNullByDefault;
/**
* List of dockingstation status
*
* @author David Kumar - Initial contribution
*/
@NonNullByDefault
public enum DockStatusType {
UNKNOWN(-1, "Unknown"),
OK(0, "OK"),
ERROR_SUCTION(34, "Suction Error"),
ERROR_FRESH_WATER_TANK(38, "Error fresh water tank"),
ERROR_FRESH_DIRTY_WATER_TANK(39, "Error dirty water tank"),
ERROR_DUST_CONTAINER(46, "Missing dust container/dust bag");
private final int id;
private final String description;
DockStatusType(int id, String description) {
this.id = id;
this.description = description;
}
public int getId() {
return this.id;
}
public static DockStatusType getType(int value) {
byte b;
int i;
DockStatusType[] arrayOfDockStatusType;
for (i = (arrayOfDockStatusType = values()).length, b = 0; b < i;) {
DockStatusType st = arrayOfDockStatusType[b];
if (st.getId() == value) {
return st;
}
b++;
}
return UNKNOWN;
}
public String getDescription() {
return this.description;
}
@Override
public String toString() {
return "Status " + Integer.toString(this.id) + ": " + this.description;
}
}

View File

@ -38,7 +38,14 @@ public enum RobotCababilities {
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", "");
SEGMENT_CLEAN("", "actions#segment", "miio:segment", ""),
COLLECT_DUST("auto_dust_collection", "actions#collect_dust", "miio:collect_dust", ""),
CLEAN_MOP_START("dry_status", "actions#clean_mop_start", "miio:clean_mop_start", ""),
CLEAN_MOP_STOP("dry_status", "actions#clean_mop_stop", "miio:clean_mop_stop", ""),
MOP_DRYING("dry_status", "status#is_mop_drying", "miio:is_mop_drying", ""),
MOP_DRYING_REMAINING_TIME("dry_status", "status#mop_drying_time", "miio:mop_drying_time", ""),
DOCK_STATE("dock_error_status", "status#dock_state", "miio:dock_state", ""),
DOCK_STATE_ID("dock_error_status", "status#dock_state_id", "miio:dock_state_id", "");
private final String statusFieldName;
private final String channel;

View File

@ -85,6 +85,15 @@ public class StatusDTO {
@SerializedName("mop_forbidden_enable")
@Expose
private Integer mopForbiddenEnable;
@SerializedName("dry_status")
@Expose
private Integer isMopDryingActive;
@SerializedName("rdt")
@Expose
private Long mopDryTime;
@SerializedName("dock_error_status")
@Expose
private Integer dockErrorStatus;
public final Integer getMsgVer() {
return msgVer;
@ -169,4 +178,20 @@ public class StatusDTO {
public final Integer getMopForbiddenEnable() {
return mopForbiddenEnable;
}
public Integer getIsMopDryingActive() {
return isMopDryingActive;
}
public Long getMopDryTime() {
return mopDryTime;
}
public Integer getDockErrorStatus() {
return this.dockErrorStatus;
}
public void setDockErrorStatus(Integer dockErrorStatus) {
this.dockErrorStatus = dockErrorStatus;
}
}

View File

@ -9,7 +9,7 @@ addon.config.miio.cloudDiscoveryMode.label = Cloud Discovery Mode
addon.config.miio.cloudDiscoveryMode.description = Allow for discovery via the cloud. This may be used for devices that are not on the same network as OpenHAB server
addon.config.miio.cloudDiscoveryMode.option.disabled = Local discovery only (Default)
addon.config.miio.cloudDiscoveryMode.option.supportedOnly = Discover online supported devices from Xiaomi cloud
addon.config.miio.cloudDiscoveryMode.option.all = Discover all online devices from Xiaomi cloud
addon.config.miio.cloudDiscoveryMode.option.all = Discover all on & offline devices from Xiaomi cloud (advanced, see readme for usage)
addon.config.miio.country.label = Xiaomi server country
addon.config.miio.country.description = Xiaomi server country(s) (e.g. sg,de). Separate multiple servers with comma. Leave empty for all. See binding readme for country to server mapping
addon.config.miio.password.label = Xiaomi cloud password
@ -19,13 +19,16 @@ addon.config.miio.username.description = Xiaomi cloud username. Typically your e
# thing types
thing-type.miio.basic.label = Xiaomi Mi Basic Device
thing-type.miio.gateway.label = Xiaomi Mi Gateway
thing-type.miio.generic.label = Xiaomi Mi Device
thing-type.miio.lumi.label = Xiaomi Mi Lumi Device
thing-type.miio.unsupported.label = Unsupported Xiaomi Mi Device
thing-type.miio.vacuum.label = Xiaomi Robot Vacuum
# thing types config
thing-type.config.miio.config.cloudServer.label = Xiaomi cloud Server (county code)
thing-type.config.miio.config.cloudServer.label = Cloud Server Country Code
thing-type.config.miio.config.cloudServer.description = Country code (2 characters) of the Xiaomi cloud server. See binding documentation for mapping of the country to cloud server
thing-type.config.miio.config.communication.label = Communication Method
thing-type.config.miio.config.communication.description = Determines how the binding communicates with this device
thing-type.config.miio.config.communication.option.direct = Direct (Default)
@ -41,11 +44,23 @@ thing-type.config.miio.config.timeout.label = Timeout
thing-type.config.miio.config.timeout.description = Timeout time in milliseconds
thing-type.config.miio.config.token.label = Token
thing-type.config.miio.config.token.description = Token for communication (in Hex)
thing-type.config.miio.configGatewayDevices.cloudServer.label = Cloud Server Country Code
thing-type.config.miio.configGatewayDevices.cloudServer.description = Country code (2 characters) of the Xiaomi cloud server. See binding documentation for mapping of the country to cloud server
thing-type.config.miio.configGatewayDevices.deviceId.label = Device ID
thing-type.config.miio.configGatewayDevices.deviceId.description = Device ID number for communication (in Hex)
thing-type.config.miio.configGatewayDevices.model.label = Device Model String
thing-type.config.miio.configGatewayDevices.model.description = Device model string, used to determine the subtype.
thing-type.config.miio.configGatewayDevices.refreshInterval.label = Refresh Interval
thing-type.config.miio.configGatewayDevices.refreshInterval.description = Refresh interval for refreshing the data in seconds. (0=disabled)
thing-type.config.miio.configGatewayDevices.timeout.label = Timeout
thing-type.config.miio.configGatewayDevices.timeout.description = Timeout time in milliseconds
# channel group types
channel-group-type.miio.actions.label = Action
channel-group-type.miio.basicactions.label = Actions
channel-group-type.miio.basicactions.label = Actions
channel-group-type.miio.basicactions.label = Actions
channel-group-type.miio.cleaning.label = Last Cleaning Details
channel-group-type.miio.consumables.label = Consumables
channel-group-type.miio.dnd.label = Do Not Disturb
@ -60,7 +75,12 @@ channel-group-type.miio.status.label = Status
channel-type.miio.bssid.label = BSSID
channel-type.miio.carpet_mode.label = Carpet Mode
channel-type.miio.clean_area.label = Cleaning Area
channel-type.miio.clean_mop_start.label = Start Mop Wash
channel-type.miio.clean_mop_start.description = Once the vacuum cleaner is back in place, you can start cleaning the mop
channel-type.miio.clean_mop_stop.label = Stop Mop Wash
channel-type.miio.clean_time.label = Cleaning Time
channel-type.miio.collect_dust.label = Start Collecting Dust
channel-type.miio.collect_dust.description = Once the vacuum cleaner is back in place, you can start collecting the dust
channel-type.miio.color.label = Generic Color Channel
channel-type.miio.commands.label = Execute Command
channel-type.miio.consumable_reset.label = Reset Consumable
@ -82,6 +102,8 @@ channel-type.miio.dnd_enabled.label = Do Not Disturb
channel-type.miio.dnd_end.label = End Time DND
channel-type.miio.dnd_function.label = Do Not Disturb Functionality
channel-type.miio.dnd_start.label = Start Time DND
channel-type.miio.dock_state.label = Dock State
channel-type.miio.dock_state_id.label = Dock State ID
channel-type.miio.error_code.label = Error Code
channel-type.miio.error_id.label = Error ID
channel-type.miio.fan.label = Control Fan Level
@ -104,12 +126,15 @@ channel-type.miio.fw_features.label = Firmware Features
channel-type.miio.image.label = Generic Image Channel
channel-type.miio.in_cleaning.label = In Cleaning
channel-type.miio.is_locating.label = Robot Locating
channel-type.miio.is_mop_drying.label = Mop Cleaning Active
channel-type.miio.last_clean_area.label = Cleaning Area
channel-type.miio.last_clean_duration.label = Cleaning Duration
channel-type.miio.last_clean_dustcollection_status.label = Dust Collection Status
channel-type.miio.last_clean_end_time.label = Cleaning End
channel-type.miio.last_clean_end_time.description = Last Cleaning End Time
channel-type.miio.last_clean_error.label = Error
channel-type.miio.last_clean_finish.label = Cleaning Finished
channel-type.miio.last_clean_finish_reason.label = Cleaning Finished Reason
channel-type.miio.last_clean_record.label = Cleaning Record
channel-type.miio.last_clean_start_time.label = Cleaning Start
channel-type.miio.last_clean_start_time.description = Last Cleaning Start Time
@ -122,6 +147,7 @@ channel-type.miio.main_brush_time.label = Main Brush Time till Replacement
channel-type.miio.map.label = Cleaning Map
channel-type.miio.map_present.label = Map Present
channel-type.miio.map_status.label = Map Status
channel-type.miio.mop_drying_time.label = Mop Drying Time
channel-type.miio.mop_forbidden_enable.label = Mop Forbidden
channel-type.miio.msg_seq.label = Msg Seq
channel-type.miio.multi_maps_list.label = Multi Map List
@ -144,7 +170,7 @@ channel-type.miio.state_id.label = State ID
channel-type.miio.string.label = Generic String Channel
channel-type.miio.switch.label = Generic Switch Channel
channel-type.miio.testcommands.label = (experimental) Create channels / test properties for unsupported devices (legacy protocol)
channel-type.miio.testcommands.description = Execute test for all known properties to find channels supported by your device. This is for older /legacy devices, newer devices mostly use MIOT. Check your log, share your results.
channel-type.miio.testcommands.description = Execute test for all known properties to find channels supported by your device. This is for older / legacy devices, newer devices mostly use MIOT. Check your log, share your results.
channel-type.miio.testmiot.label = (experimental) Create channels for new/unsupported devices (MIOT protocol)
channel-type.miio.testmiot.description = Create experimental support for MIOT protocol devices based on the online specification. Check your log, share your results.
channel-type.miio.total_clean_area.label = Total Cleaning Area
@ -155,7 +181,8 @@ channel-type.miio.water_box_carriage_status.label = Water Box Carriage State
channel-type.miio.water_box_mode.label = Water Box Mode
channel-type.miio.water_box_status.label = Water Box State
# Thing status descriptions
# thing status descriptions
offline.config-error-ip = IP address required. Configure IP address
offline.config-error-token = Token required. Configure token
offline.config-error-cloud = Cloud communication requires defined deviceId in the config

View File

@ -215,6 +215,40 @@
<label>Robot Locating</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="dock_state">
<item-type>String</item-type>
<label>Dock State</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="dock_state_id">
<item-type>Number</item-type>
<label>Dock State ID</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="mop_drying_time">
<item-type>Number:Time</item-type>
<label>Mop Drying Time</label>
<state pattern="%.0f %unit%" readOnly="true"/>
</channel-type>
<channel-type id="is_mop_drying">
<item-type>Switch</item-type>
<label>Mop Cleaning Active</label>
<state readOnly="true"/>
</channel-type>
<channel-type id="collect_dust">
<item-type>Switch</item-type>
<label>Start Collecting Dust</label>
<description>Once the vacuum cleaner is back in place, you can start collecting the dust</description>
</channel-type>
<channel-type id="clean_mop_start">
<item-type>Switch</item-type>
<label>Start Mop Wash</label>
<description>Once the vacuum cleaner is back in place, you can start cleaning the mop</description>
</channel-type>
<channel-type id="clean_mop_stop">
<item-type>Switch</item-type>
<label>Stop Mop Wash</label>
</channel-type>
<!-- Consumables channels -->
<channel-type id="main_brush_percent">