- 🔴 P1 — Bug / broken functionality
- 🟠 P2 — Important improvement
- 🔵 P3 — Nice to have
- ⚪ P4 — Research / exploration
- 🔴 Room-specific cleaning still needs on-device verification —
clean_rooms_miot()now preloadssiid 4 piid 10clean-extend-dataand then calls officialsiid 2 aiid 3, and xiao now warns/returns exit code 80 when the action is accepted but the robot still looks docked/charging. Actual X20+ hardware behavior still needs confirmation after this sequence change. (Updated 2026-05-01) - 🔴 FIXED:
set_fan_speed()was writing to siid 2 piid 2 (device fault, read-only!) instead of piid 3 (mode/fan). This means everyxiao speed setcommand was attempting to write a fault code. Alsostatus()was mapping piid 2 (fault) →fan_speeddisplay, causing garbage values. Fixed 2026-03-31. - 🔴 FIXED:
set_water_level()was writing to siid 18 piid 1 (mop-life-level, READ-ONLY %) instead of siid 4 piid 5 (mop-mode, 1=Low, 2=Medium, 3=High). Every water level command was corrupting mop consumable tracking. Alsowater_level()returned a stub string instead of reading from the device. Fixed 2026-04-02. - 🔴 FIXED:
status()mapped state 13 → "In Dock" but official MIoT spec says 13 = "Charging Completed". Fixed 2026-04-02.
- ⚪ Map extraction — MITM Mi Home app traffic to find decryption key for cloud map data
- ⚪ Room IDs verification — map room IDs to actual room names from Mi Home app
- ⚪ clean-logs (siid 12) corrected from official miot-spec.org JSON (2026-04-07):
- piid 1 =
first-clean-time(unix timestamp) — NOTlast-clean-time - piid 2 =
total-clean-time(minutes) - piid 3 =
total-clean-times(count) - piid 4 =
total-clean-area - Implication: current cloud API/spec does not expose a dedicated
last-clean-datefield for c102gl via siid 12; any real per-run history likely needs app/cloud log endpoints or map/log filenames from siid 4 piid 9.
- piid 1 =
- ⚪ vacuum-extend (siid 4) — fully mapped from official miot-spec.org JSON (2026-04-02):
- piid 4 = cleaning-mode (0=Quiet, 1=Standard, 2=Medium, 3=Strong) — READ-ONLY mirror of fan mode
- piid 5 = mop-mode / water level (1=Low, 2=Medium, 3=High) — WRITABLE ✅ Now implemented
- piid 6 = waterbox-status (0=No, 1=Yes) — reads whether water box is attached
- piid 7 = task-status (uint8 0-255) — unknown semantics
- piid 10 = clean-extend-data (string, write-only) — likely the room cleaning JSON param!
- piid 11 = break-point-restart (0=Off, 1=On) — resume after charging — writable
- piid 12 = carpet-press (0=Off, 1=On) — carpet boost — writable
- piid 16 = clean-rags-tip (0-120 minutes) — mop wash reminder — writable
- piid 17 = keep-sweeper-time (int32 minutes) — unknown
- piid 18 = faults (string) — extended fault string
- piid 27 = child-lock (0=Off, 1=On) — writable
- piid 34 = smart-wash-switch (0=Off, 1=On) — smart mop wash
- piid 36 = carpet-escape (1=Escape, 2=Auto) — carpet avoidance mode
- ⚪ Room cleaning deep dive: Official spec:
siid 2 aiid 3 = start-room-sweep, in=[piid 4 (Room IDs string)]. The piid 4 (room-ids) hasaccess: []meaning NO standalone read/write — it only works as an action param. Next step: testclean_rooms_miot()with piid 4 value as comma-separated string like "3,8,7,6". Also tryclean-extend-data(siid 4 piid 10) as alternative path — write JSON before calling start-sweep. - ⚪ Room cleaning research update (2026-04-08):
- Official spec page for
xiaomi.vacuum.c102glstill points tosiid 2 aiid 3(start-room-sweep) with room IDs passed aspiid 4string. hass-xiaomi-miotREADME example shows Dreame/Xiaomi custom room cleaning viasiid 4 aiid 1with paramspiid 1 = 18andpiid 10 = clean-extend-data, whereclean-extend-datais JSON underselects.dreame-vacuumissue #910 logs show theselectsrows encode at least room id, repeat count, fan mode, water mode, and explicit order: e.g.[[1,1,3,1,1],[3,1,3,1,2], ...].openHABmiio binding docs list bothvacuum-start-room-sweepandvacuum-extend-start-cleanactions forxiaomi.vacuum.c102gl, which supports the idea that both paths exist on X20+.- Community reports still describe
code=0/ accepted actions that do nothing, so success responses alone are not proof of movement.
- Official spec page for
- ⚪ X20+ / c102gl community notes (2026-04-10):
hass-xiaomi-miotissue#2767reports X20+ room-cleaning action (siid 2 aiid 3) still returning accepted responses while not actually starting room jobs for some users; reinforces thatcode=0is not enough without on-device movement verification.python-miioissue#2071tracks new X20 Max model gaps (xiaomi.vacuum.d109gl) and timeout/auth pain in HA stacks; X20 family support is still uneven across ecosystem tools.- Xiaomi Cloud Map Extractor issue
#697continues to show cloud login/session fragility (captcha/2FA/token churn), supporting our token-refresh-first strategy. - No clear Valetudo support signal for
xiaomi.vacuum.c102glturned up in this pass; keep this as watch-only research, not an actionable integration path yet.
- ⚪ Dashboard diagnostics UX research (2026-04-21):
home-assistant/frontenduses native HTML<details>/<summary>for dense system-information and repair diagnostics blocks, which keeps advanced data accessible without overwhelming the default view.openhab/openhab-webuidocuments accordion lists specifically for collapsible technical sections, reinforcing that diagnostics/debug data should be progressively disclosed rather than always expanded.- For xiao, the lowest-risk ship is to collapse the three verbose lower panels (Audio, Clean Log Raw, All Properties) by default while preserving their existing live data and DOM ids.
- ⚪ Session blocker (2026-04-08):
- This sandbox allows editing tracked files but denies writes inside
.git/.git add/git commitfailed withfatal: Unable to create '.git/index.lock': Operation not permitted, so this session could not create the requested local commit.
- This sandbox allows editing tracked files but denies writes inside
- ⚪ Test-suite findings (2026-04-09):
- Full
pytest tests/ -vcurrently still has 8 unrelated failures intests/test_cloud_vacuum.py. - Failing areas: status parsing / fan-speed decoding regressions, plus missing
total_clean_duration_displayinclean_history(). - These pre-existing failures are outside the token-refresh scope and should be handled as a separate bugfix pass.
- Full
- ⚪ Local UDP fallback — periodically check if vacuum becomes reachable locally
- ⚪ Valetudo compatibility — monitor if X20+ (c102gl) gets rooting support
- ⚪ Home Assistant integration — MQTT or REST sensor for HA
- ⚪ Notification system — Telegram alerts for cleaning complete, errors, consumable low
- ⚪ Floor plan editor — manual room layout in dashboard (drag & drop)
- ⚪ vacuum-extend service (siid 4) — investigate writable properties found in official spec:
- piid 5 = mop-mode (1=Low, 2=Medium, 3=High) — actual water level control!
- piid 11 = break-point-restart (0=Close, 1=Open) — resume after charging
- piid 12 = carpet-press (0=Close, 1=Open) — carpet boost
- piid 27 = child-lock (0=Close, 1=Open)
- piid 16 = clean-rags-tip (minutes, 0-120) — mop wash reminder interval
- ⚪ vacuum-extend piid 10 (clean-extend-data, write-only string) — this is likely the room cleaning param! Format: probably JSON with segments, fan level, water level. Worth testing with clean_rooms_miot().
Sources: Valetudo, python-miio, hass-xiaomi-miot, r/Xiaomi, r/homeassistant
- Zone cleaning with coordinates
- Virtual walls / no-go zones
- Carpet detection behavior
- Multi-floor map support
- Cleaning history heatmap
- Custom voice packs
- OTA firmware management
- ✅ Mission Control vacuum-extend value decoding — the advanced diagnostics panel now translates the known
siid 4enum-backed values into human-readable labels while still showing the raw number for debugging (for exampleQuiet · raw 0,Attached · raw 1,Enabled · raw 1). Added a TDD dashboard regression that failed before the new formatter/mappings were introduced. Research notes: the officialxiaomi.vacuum.c102glMIoT/OpenHAB mappings still identifycleaning-modeas0=Quiet/1=Standard/2=Medium/3=Strong,mop-modeas1=Low/2=Medium/3=High,waterbox-statusas0=No/1=Yes, and bothbreak-point-restartpluscarpet-pressas0=Close/1=Open;openhab/openhab-addonsmirrors the same enums for the X20+ database; andhass-xiaomi-miotissue#2767still keeps hardware-dependent room-cleaning changes in the higher-risk bucket, which made another diagnostics-only UX ship the safer unattended choice. (2026-05-26) - 🔜 Next planned item: Mission Control vacuum-extend diagnostics expansion — add the next confirmed
siid 4controls (child-lock,smart-wash, andcarpet-avoidance) to the advanced diagnostics panel with the same human-readable-plus-raw formatting so dashboard users can inspect the full known writable settings set at a glance. (Planned 2026-05-26) - ✅ Mission Control vacuum-extend diagnostics copy cleanup — the advanced diagnostics panel now relabels the known
siid 4fields asCleaning Mode,Mop Mode,Waterbox Status,Task Status,Resume After Charge, andCarpet Boostinstead of showing genericUnknownplaceholders, while still leaving the underlying raw values untouched for debugging. Added a TDD dashboard regression that failed on the old labels before updating the frontend copy. Research notes: the officialxiaomi.vacuum.c102glMIoT spec still exposes thesevacuum-extendproperties undersiid 4(mop-mode,waterbox-status,task-status,break-point-restart,carpet-press);openhab/openhab-addonsmirrors the same channel names for the X20+ model; andhass-xiaomi-miotissue#2767still shows room-cleaning behavior is the riskier area, which kept this run focused on a safe diagnostics UX win instead of hardware-dependent action changes. (2026-05-14) - ✅ Waterbox attachment status surfaced across CLI + Mission Control —
status()now reads the official X20+vacuum-extendwaterbox-statusproperty (siid 4 piid 6) and exposes it asattached/detached, while the rich CLI formatters and Mission Control status tags now show whether the mop water box is present without forcing users into raw property dumps. Added TDD regression coverage for the cloud status decoder, full-status formatter, and dashboard HTML hook before implementation. Research notes: the local backlog/spec mapping already identifiedsiid 4 piid 6aswaterbox-status; the officialxiaomi.vacuum.c102glMIoT/OpenHAB database maps it as a read-only0 = No,1 = Yesenum; and that made this a safe, user-visible diagnostics improvement for mopping/setup issues without depending on on-device room-clean verification. (2026-05-12) - ✅ State 21 naming fix (
WashingMopPause) —status(),full_status(), Mission Control API responses, and dashboard state maps now keep the official X20+ state-21 name instead of mislabeling it asWater Tank Alert, while still surfacing separate recovery guidance to check/refill the base tanks when that pause appears. Also updated the tank auto-reset heuristic to key off the real state-21 name so the existing estimate-reset behavior keeps working after the label correction. Added TDD regression coverage for the cloud status decoder,full_status()alert wiring, Mission Control/api/status, tank-update auto-reset logic, and the dashboard HTML state map before implementation. Research notes: the local X20+ MIoT mapping/tests already called state 21WashingMopPause, and the adjacentopenhab/openhab-addonsMIIO binding docs list the same status enum label forxiaomi.vacuum.c102gl; that made this a safe terminology/UX fix while preserving the existing tank-service recovery advice. (2026-05-11) - ✅ Estimated cleaning energy from clean logs —
clean_history()now derives a clearly labeled lifetime energy estimate from the X20+ clean-log totals, and Mission Control plus the rich CLI history surfaces now show that estimate askWh @ 75Wso users do not have to do the math manually. Added TDD regression coverage for the cloud-history payload, full-status formatter, report formatter, and dashboard history card before implementation. Research notes: Xiaomi's publishedXiaomi Robot Vacuum X20+specs listRated Power 75W, the officialxiaomi.vacuum.c102glclean-log fields still expose only aggregate cleaning time/count/area, and adjacent Home Assistant energy tooling (Vortitron/energy-sensor-generator) reinforced keeping the output explicitly in kWh while labeling it as an estimate rather than measured telemetry. (2026-05-08) - ✅ Room-clean accepted-vs-started diagnostics —
xiao clean, Mission Control, and the MCP server no longer treat X20+ room-cleancode=0responses as guaranteed movement. They now share a verification helper that polls follow-up status, warns when the robot still looks docked/charging, and emits CLI exit code80for the clearly unresponsive case. Added TDD regression coverage for the shared verification helper plus CLI, dashboard, dashboard API, and MCP surfaces before implementation. Research notes: the officialxiaomi.vacuum.c102glMIoT spec still points room cleaning atsiid 2 aiid 3with room IDs passed as a string param; thehass-xiaomi-miotREADME continues to document a separatevacuum-extendclean-extend-datapath (siid 4 aiid 1+piid 10JSON payload) for adjacent Dreame/Xiaomi models; andhass-xiaomi-miotissue#2767shows X20+ users still getting accepted room-clean calls with no actual movement, which confirmed that shipping an accepted-vs-started diagnostic was safer than pretending success. (2026-05-01) - ✅ Clean-history surfaces now match the official X20+ clean-log fields — Mission Control history cards,
xiao status --full,xiao report, andxiao device history --fullnow showfirst_clean_dateplus aggregate totals instead of stalelast_clean_*wording that the cloud backend no longer provides. Added TDD regression coverage for the dashboard history card copy, full-status formatter output, and the cloud-history merge path before implementation. Research notes: the officialxiaomi.vacuum.c102glMIoT clean-log spec still exposes onlyfirst-clean-time,total-clean-time,total-clean-times, andtotal-clean-area;openhab/openhab-addonsmirrors those same four labels forxiaomi.vacuum.c102gl; and that confirmed our remainingLast CleanUI copy was frontend drift, not missing device data. (2026-04-30) - ✅ Mission Control advanced settings parity — the web dashboard now reads and writes the full shipped X20+
vacuum-extendcontrols (resume-after-charge,carpet-boost,child-lock,smart-wash,carpet-avoidance, andclean-rags-tip) instead of forcing users back to CLI-only commands. Added TDD regression coverage for the expanded/api/settingssnapshot, the new write endpoints, invalid minutes rejection, and the dashboard DOM/API wiring before implementation. Research notes: the officialxiaomi.vacuum.c102glMIoT spec continues to expose these properties undersiid 4as stable cloud-backed controls;openhab/openhab-addons#17796still reinforces that X20+ support is cloud-centric, which made dashboard parity a safer unattended ship than hardware-dependent room-cleaning work; andopenhab/openhab-addonsalso surfaces adjacentvacuum-extendchannels likechild_lock,carpet-press, andclean_rags_tip, which supported treating these as first-class UI settings rather than hidden expert-only knobs. (2026-04-29) - ✅ Carpet avoidance mode — added first-class CLI support for
xiao settings carpet-avoidance [avoid|auto], backed by cloud-service helpers for the X20+vacuum-extendcarpet-excapeproperty (siid 4 piid 36), and included it in the dashboard/api/settingssnapshot for programmatic consumers. Added TDD regression coverage for the cloud enum reads/writes, validation, the new CLI command, and the settings snapshot before implementation. Research notes: the officialmiot-spec.orgJSON forxiaomi.vacuum.c102glexposessiid 4 piid 36with enum values1 = Escapeand2 = Auto;openhab/openhab-addons#17796continues to reinforce that X20+ support is cloud-centric, which kept this as a safer cloud-backed settings release than hardware-dependent room-cleaning work; andal-one/hass-xiaomi-miot#2767shows users still struggling with room-cleaning action parameters, which further supported prioritizing a spec-backed setting over more experimental cleaning flows. CLI wording ships asavoid|auto, while still accepting the raw Xiaomiescapeterm for compatibility. (2026-04-28) - ✅ Clean rags tip interval — added first-class CLI support for
xiao settings clean-rags-tip [minutes], backed by cloud-service helpers for the X20+vacuum-extendclean-rags-tipproperty (siid 4 piid 16), with strict0-120minute validation and inclusion in the dashboard settings snapshot API for programmatic consumers. Added TDD regression coverage for the cloud property reads/writes, range validation, and the new CLI command before implementation. Research notes: the local MIoT mapping already identifiedpiid 16as writableclean-rags-tip, the officialhome.miot-spec.com/spec/xiaomi.vacuum.c102glpage continues to expose it undervacuum-extendwith a0-120minute range, andopenhab/openhab-addonssurfaces the same field asNumber:Time clean_rags_tip, which reinforced shipping a raw minutes control instead of guessing unsupported presets. (2026-04-27) - ✅ Smart wash switch toggle — added first-class CLI support for
xiao settings smart-washplus cloud-service helpers for the X20+vacuum-extendsmart-wash-switchboolean (siid 4 piid 34), and included it in the dashboard settings snapshot API for programmatic consumers. Added TDD regression coverage for both the cloud property reads/writes and the new CLI command before implementation. Research notes: the local MIoT mapping already identifiedpiid 34as writable, the officialhome.miot-spec.com/spec/xiaomi.vacuum.c102glpage still exposes it undervacuum-extend, and adjacent ecosystem threads (al-one/hass-xiaomi-miot#2767,openhab/openhab-addons#17796) continue to reinforce that X20+ support remains cloud-centric, making another spec-backed boolean toggle a safer unattended release than room-cleaning experiments. (2026-04-26) - ✅ Advanced vacuum-extend settings toggles — added first-class CLI support for
xiao settings resume-after-charge,xiao settings carpet-boost, andxiao settings child-lock, all backed by the official X20+ MIoTvacuum-extendbooleans (siid 4 piid 11/12/27). Added TDD regression coverage for both the cloud property reads/writes and the new CLI commands before implementing the feature. Research notes: the local MIoT mapping already identified these three properties as writable booleans, the officialhome.miot-spec.com/spec/xiaomi.vacuum.c102glpage still exposes them undervacuum-extend, and adjacent ecosystem threads (al-one/hass-xiaomi-miot#2767,openhab/openhab-addons#17796) continue to show X20+ users relying on cloud-only MIoT paths, which made CLI exposure of stable spec-backed toggles a safer unattended ship than more experimental room-cleaning work. (2026-04-25) - ✅ Sweep type decoding cleanup — removed the stale dashboard
sweep_typewording and now surfacedry_left_time_minexplicitly as dry-time-left in both Mission Control and CLI rich status output, including a drying-specific status tag. Added TDD regression coverage for the dashboard copy and formatter label before implementing the fix. Research notes: the officialmiot-spec.orgJSON forxiaomi.vacuum.c102glconfirmssiid 2 piid 5isdry-left-timein minutes,hass-xiaomi-miotexamples continue to useclean-extend-datafor room cleaning instead of any sweep-type property, andopenhabstill exposesvacuum-start-room-sweepplusvacuum-extend-start-clean, which reinforced that our old sweep-type label was legacy/spec drift rather than a real X20+ field. Also corrected the dashboard's lingering state-13 label toCharging Completedfor consistency with the already-fixed backend mapping. (2026-04-24) - ✅ Dashboard dark/light theme toggle — Mission Control now keeps the current dark glassmorphism default, but adds an explicit light theme switch in the header and persists the user's choice in local storage so daytime use is less fatiguing without re-theming every visit. Added TDD regression coverage for the toggle markup and persistence hook. Research notes: the local README already positions Mission Control as a day-to-day dashboard surface, MDN's
prefers-color-schemeguidance reinforced shipping named light/dark themes instead of ad-hoc color overrides, andhome-assistant/frontendpersistsselectedThemein browser storage with defensive fallbacks, which informed our saved-preference approach and storage guards. (2026-04-23) - ✅ CLI schedule default view + compact cadence labels —
xiao schedulenow shows the parsed schedule table directly without requiring the extralistsubcommand, and schedule cadence text now compacts common masks toEvery day,Weekdays,Weekends, andOne timefor faster scanning. Added TDD regression coverage for both the parser labels and the root CLI behavior. Research notes: local README/docs already positioned schedule viewing as a primary CLI workflow, and Home Assistant's schedule model explicitly treats weekdays as first-class recurrence data rather than a raw bitmask, which reinforced shipping human-readable cadence labels instead of the previous verbose day list. (2026-04-22) - ✅ Dashboard diagnostics cleanup — collapsed the lower-noise Audio, Clean Log (Raw), and All Properties panels by default using native
<details>/<summary>sections, while keeping the same content and live refresh hooks once expanded. Added a regression test that failed before the markup change and now locks the collapsed-by-default contract. (2026-04-21) - ✅ CLI rooms rename command — added
xiao rooms rename <id> <name>as a first-class command (same underlying behavior as alias set) so room naming flows are more discoverable. Added TDD regression test (TestCLIRooms::test_rooms_rename) that failed before command implementation and passes now. (2026-04-10) - ✅ Device list token auto-refresh —
XiaomiCloud.get_devices()now catchesTokenExpiredError, refreshes cloud tokens via browser CDP helper, and retries once before surfacing the error. This closes the remaining gap where setup/device listing could still fail on expired Xiaomi cloud sessions even though RPC/property helpers already retried. Added regression tests for both refresh-success and refresh-failure paths. (2026-04-09) - ✅ Room cleaning reliability improvement —
clean_rooms_miot()now preloadsvacuum-extendclean-extend-data(siid 4 piid 10) using aselectspayload derived from room order, repeat count, current fan mode, and current water mode, then calls the officialsiid 2 aiid 3room-sweep action. CLIxiao clean --room ... --repeat Nnow forwardsrepeatinto that MIoT path instead of silently dropping it. Added regression tests. Hardware verification still pending. (2026-04-08) - ✅ Clean history / first-clean-time mapping fix —
siid 12 piid 1was incorrectly treated aslast-clean-time, which madelast_clean_datestale/misleading. Official MIoT spec confirms siid 12 isclean-logs: piid 1 =first-clean-time, piid 2 =total-clean-time, piid 3 =total-clean-times, piid 4 =total-clean-area. Updatedclean_history(),last_clean(), and history scan output to exposefirst_clean_dateand correct aggregate totals instead of fake last-run fields. Added regression tests. (2026-04-07) - ✅ Water level MIoT property bug fix —
set_water_level()was writing to siid 18 piid 1 (mop-life-level, READ-ONLY %) instead of siid 4 piid 5 (mop-mode, writable). Official MIoT spec confirms: siid 4 piid 5 =mop-mode(1=Low, 2=Medium, 3=High). Also fixedwater_level()to actually read from the device instead of returning stub string. Added 7 new tests. (2026-04-02) - ✅ Status 13 corrected —
status()mapped state 13 → "In Dock" but official MIoT spec says 13 = "Charging Completed". Fixed with test. (2026-04-02) - ✅ MIOT_SPEC extended — Added mop-mode, break-point-restart, carpet-press, child-lock, clean-rags-tip, clean-extend-data to MIOT_SPEC dict. Updated module comments to reflect siid 4 = vacuum-extend (not clean-log). (2026-04-02)
- ✅ Fan speed MIoT property bug fix —
set_fan_speed()was writing to siid 2 piid 2 (device fault, read-only!). Official MIoT spec confirms: piid 2 = fault, piid 3 = mode/fan speed (0=Silent, 1=Basic, 2=Strong, 3=Full Speed). Fixed read and write paths. Added 5 new tests confirming correct piid usage. (2026-03-31) - ✅ Status fan_speed parsing corrected — was mapping piid 2 (fault code) to fan speed display. Now correctly reads piid 3 for fan speed and stores piid 2 as
fault_code. (2026-03-31) - ✅ MIOT_SPEC corrected —
fan_levelnow points to piid 3,fault_codeadded for piid 2,dry_left_timeadded for piid 5 (was wrongly calledsweep_type). (2026-03-31) - ✅ Dashboard history section: fixed "--" for zero/falsy values — added
total_clean_duration_displayfield toclean_history()(e.g. "2h 10min"), fixed JS to use??null-coalescing so0shows as0not--, fixed total-time label (was incorrectly appendinghto a minutes value). - ✅ Cloud mode control (all basic actions)
- ✅ Mission Control dashboard (glassmorphism, real-time)
- ✅ Water Tank Alert detection (state 21) + auto-reset
- ✅ Water tank level estimator (area-based)
- ✅ Mop consumable tracking + reset
- ✅ Network info in dashboard (IP, WiFi, RSSI, MAC)
- ✅ All 4 consumable resets (main brush, side brush, filter, mop)
- ✅ Full MIoT property scan (39 properties documented)
- ✅ Schedule parser with room names
- ✅ Base station controls (wash, dry, dust, eject)
- ✅ Fan speed / water level / volume / DND settings
- ✅ Token refresh via browser CDP