Working room-by-room cleaning — including per-room custom settings (suction, mop water, mode, passes) — for the Xiaomi Robot Vacuum X20 Pro (xiaomi.vacuum.d102gl) in Home Assistant.
No dedicated integration supports this model: it is Xiaomi in-house firmware (not Dreame-based, so dreame-vacuum can't help), the official ha_xiaomi_home doesn't expose room IDs, and the map extractor can't parse its maps. This project fills the gap with a thin, reliable layer on top of al-one/hass-xiaomi-miot (Xiaomi Miot Auto), based on live-tested MIoT calls. The full protocol findings are in docs/METHOD.md.
This project demonstrates practical reverse-engineering and Home Assistant automation work:
- Custom Home Assistant services layered on top of Xiaomi Miot Auto for a model with incomplete public integration support
- Live-verified MIoT action mapping for room cleaning, per-room settings, app-saved presets, and station actions
- Command acceptance verification with retry logic, because Xiaomi cloud acknowledgements do not always mean the robot executed the command
- Defensive parameter construction to avoid Home Assistant/YAML coercion bugs that can send invalid room-cleaning commands
- HACS-compatible packaging, script blueprints, and validation workflow for distribution
xiaomi_x20pro.clean_rooms— clean one or more rooms, optionally with per-room settings, with acceptance verification and automatic retry (the Xiaomi cloud often acks commands the robot never executes — see docs/METHOD.md).xiaomi_x20pro.set_room_config— store per-room settings without starting a clean (works even while the robot is in deep sleep; never moves it).xiaomi_x20pro.start_preset— start an app-saved custom cleanup (zones/rooms with their own settings). This is the reliable way to get zone cleaning: raw zone coordinates viastart-zone-sweepare rejected in ways nobody has cracked yet (details), but presets saved in the Xiaomi Home app replay perfectly.- Station controls:
start_mop_wash/stop_mop_wash,start_dry/stop_dry,start_dust_collection— direct actions for the wash-dry station. - Standalone script blueprints if you prefer pure YAML over a custom component.
- Xiaomi Miot Auto (HACS) with your X20 Pro added in cloud mode (the robot ignores local commands for these actions).
- HACS → ⋮ → Custom repositories → add
https://github.com/AldenDana/ha-xiaomi-vacuum-x20proas type Integration. - Install Xiaomi Vacuum X20 Pro Room Clean.
- Add this line to
configuration.yamland restart Home Assistant:
xiaomi_x20pro:Copy custom_components/xiaomi_x20pro/ into your config/custom_components/, add xiaomi_x20pro: to configuration.yaml, restart.
Import the script blueprints (Settings → Automations & Scenes → Blueprints → Import) and skip the integration entirely.
Room IDs live in the vacuum entity's vacuum.room_information attribute:
{"rooms":[{"id":6,"name":""},{"id":8,"name":""},...],"map_uid":8}
Two traps, both learned the hard way:
- IDs change every time the map is remade. After a remap, every automation with hardcoded IDs silently cleans the wrong rooms.
- The room numbers shown in the Xiaomi Home app do NOT match these IDs. The only reliable mapping method: clean one ID at a time and watch where the robot goes.
# Clean the kitchen (room 8) quietly with one pass:
action: xiaomi_x20pro.clean_rooms
data:
entity_id: vacuum.xiaomi_d102gl_xxxx_robot_cleaner
rooms: [8]
fan_level: 1 # 1=Silent 2=Basic 3=Strong 4=Full Speed
water_level: 1 # 0=Off 1=Low 2=Medium 3=High
clean_mode: 3 # 1=Sweep 2=Mop 3=Sweep+Mop 4=Sweep then Mop
clean_times: 1
# Two rooms with their stored per-room defaults:
action: xiaomi_x20pro.clean_rooms
data:
entity_id: vacuum.xiaomi_d102gl_xxxx_robot_cleaner
rooms: [8, 13]
# Pre-configure a room without cleaning (safe anytime, even in deep sleep):
action: xiaomi_x20pro.set_room_config
data:
entity_id: vacuum.xiaomi_d102gl_xxxx_robot_cleaner
rooms: [8]
fan_level: 1
# Start an app-saved custom cleanup (e.g. a zone around the dining table):
action: xiaomi_x20pro.start_preset
data:
entity_id: vacuum.xiaomi_d102gl_xxxx_robot_cleaner
preset: 1- In the Xiaomi Home app, create and save a custom cleanup covering your zone (with the settings you want).
- Read the vacuum's stored presets with
xiaomi_miot.get_properties(siid: 2, piid: 42). You get something like:{"user_labels":[{"id":1593689101,"name":"Dining table","v":1,...}]} - Use the small
vvalue aspreset— not the longid; the long id gets a cloud ack but the robot silently ignores it.
clean_rooms polls vacuum.current_cleaning_config after each start command and re-fires (default: 5 retries, 25 s apart) until the robot reports the requested rooms — this rides out the post-clean station mop-wash and the dock's battery-cycling window that silently swallow commands.
- This integration does not store Xiaomi credentials; authentication and device access remain handled by Xiaomi Miot Auto.
- Service examples use placeholder entity IDs and room IDs; users should map their own rooms locally.
- Raw map samples under
docs/map-samples/are included only as protocol-research artifacts and are documented as encrypted/opaque data. - The implementation avoids logging sensitive service payloads beyond normal Home Assistant service-call context.
Known gotchas (see docs/METHOD.md for the full list)
- Cloud session death: if the entity goes to
unknownfor a long period, only a Home Assistant restart recovers it (xiaomi_miothassupports_unload: false). - Never template
paramsintoxiaomi_miot.call_actionas a bare comma string — HA coerces it into an int list and the robot can end up in a stuck state (hass-xiaomi-miot#2735). This integration builds params in Python to avoid the issue. send_command app_segment_cleanfails silently in cloud mode;current_cleaning_configis read-only.
- al-one/hass-xiaomi-miot does all the heavy lifting.
- The per-room
room_attrsformat was first confirmed on the sibling S20+ (xiaomi.vacuum.b108gl) in this HA community thread; action IDs translated for the d102gl from its MIoT spec and live-verified.
Tested on firmware 0.0.23, Home Assistant 2026.6, xiaomi_miot cloud mode. PRs and reports for other xiaomi.vacuum.* models welcome — the S20/S20+/X20/X20+ family likely works with different aiids (S20+: config=aiid 10, start=aiid 13).