Skip to content

feat: add Q10 customized cleaning controls - #935

Open
hCoureau wants to merge 3 commits into
Python-roborock:mainfrom
hCoureau:feat/q10-cleaning-controls
Open

hCoureau wants to merge 3 commits into
Python-roborock:mainfrom
hCoureau:feat/q10-cleaning-controls

Conversation

@hCoureau

@hCoureau hCoureau commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

Add Q10 per-room cleaning settings and customized room cleaning, plus global water level, pass count, and route controls.

room_cleaning.set_settings() publishes settings and requests a full update. Device pushes populate a typed list: None means no settings push has arrived, [] means the reported settings are empty. Full pushes replace the list, compact pushes merge reported rooms, and unchanged values do not notify listeners.

vacuum.clean_rooms() publishes settings, selects customized mode, and starts the selected rooms in sequence. A failed send stops subsequent commands; a successful start cancels an active emulated goto. Commands return after publication, and device pushes update cached state. Unknown firmware codes retain enum fallbacks.

Validation on upstream main (acd298ee, 7.19.0):

  • Full pytest suites on Python 3.11 and 3.14: 2,276 passed and 53 xfailed on each; the default configuration excludes 11 MQTT-broker tests.
  • Focused room-cleaning, vacuum, status, and protocol suites: 133 passed on each Python version.
  • All pre-commit checks, commitlint, and wheel/source distribution builds passed.

GitHub CI passed, including MQTT-broker suites on Python 3.11 and 3.14. No physical-device validation was run for this revision. Related: #767.

@hCoureau hCoureau mentioned this pull request Aug 31, 2026
9 of 23 tasks
@hCoureau

Copy link
Copy Markdown
Contributor Author

On hold following the review feedback on #933: please do not review the current cumulative diff.

After the read-only and map-control stacks land, this draft will be rebased and repartitioned into focused changes:

  1. advanced-cleaning enums and global water/pass/route controls
  2. per-room customized-setting models and wire codec
  3. the confirmation-driven room-cleaning trait and selected-room start flow

Each part will be submitted sequentially against main, with its own focused tests and reviewer guide.

@allenporter allenporter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Conducting this code review following our /review skill using Antigravity (AGY) and Gemini 4 Argon.

I know this PR is marked as draft while waiting on the earlier PRs in the stack, so leaving high-level architectural feedback now to save rework when you rebase and split it:

  1. Align RoomCleaningTrait with the standard Q10 push pattern:

    • Similar to the feedback on #937, RoomCleaningTrait shouldn't emulate a blocking RPC with _write_lock, _pending_confirmation: asyncio.Future, asyncio.shield, _active_task cancellation in close(), _map_revision, and map_changed_callback wired into MapsTrait.
    • Instead, keep RoomCleaningTrait as a straightforward push-driven UpdatableTrait:
      • refresh() publishes CUSTOMER_CLEAN_REQUEST (DP 63: 0).
      • set_settings(settings) encodes and publishes CUSTOMER_CLEAN (DP 62) without requiring refresh() to have completed first or waiting on a confirmation future.
      • clean(settings) publishes CUSTOMER_CLEAN, CLEAN_MODE, and START_CLEAN.
      • update_from_dps() updates self.settings and notifies listeners.
  2. Single Q10RoomCleanSettings(RoborockBase) model without | int unions:

    • Rather than having separate Q10RoomCleanSettings and Q10ReportedRoomCleanSettings models where every enum field is typed as EnumType | int, let's fall back to .UNKNOWN on unrecognized wire codes and use a single Q10RoomCleanSettings model.
  3. Remove hardcoded model == "roborock.vacuum.ss07" gating:

    • All Q10 devices are routed by the ss model prefix in device_manager.py, and existing VacuumTrait methods (set_clean_mode, set_fan_level, clean_zone, goto_position) are not gated to ss07 only. Let's remove advanced_cleaning_supported / _raise_if_advanced_cleaning_unsupported().
  4. Remove defensive runtime isinstance checks on statically typed parameters:

    • See inline comments in roborock/protocols/b01_q10_protocol.py and roborock/devices/traits/b01/q10/vacuum.py.

Comment thread roborock/protocols/b01_q10_protocol.py Resolved
@hCoureau
hCoureau force-pushed the feat/q10-cleaning-controls branch from 6c8075d to 0594819 Compare November 7, 2026 19:04
@hCoureau
hCoureau marked this pull request as ready for review November 7, 2026 19:07

@allenporter allenporter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Conducting this code review following our /review skill using Antigravity (AGY) and Gemini 4 Argon.

Thanks for the thorough update in 0594819! This is a big improvement—it cleanly addresses all four architectural points from the previous review (push-driven RoomCleaningTrait without confirmation futures/locks, single Q10RoomCleanSettings model, uniform Q10 behavior without ss07 model gating, and removal of runtime isinstance checks), and separating Q10RoomFanLevel (MAX_PLUS = 5) from YXFanLevel (MAX_PLUS = 8) makes complete sense.

I know this branch currently has a small merge conflict with main after #938 landed (around MapContentTrait / VacuumTrait in roborock/devices/traits/b01/q10/__init__.py), so leaving a few remaining review comments now for when you rebase:

  1. Consolidate room_cleaning.clean() and vacuum.clean_rooms() onto VacuumTrait.clean_rooms():
    • Calling room_cleaning.clean(settings) directly skips VacuumTrait.cancel_goto(), leaving any active emulated goto_position task armed, and RoomCleaningTrait.clean() doesn't read or mutate any RoomCleaningTrait state. Moving the 3-step command sequence directly into VacuumTrait.clean_rooms() gives callers a single canonical task-starting API, guarantees cancel_goto() runs, and avoids adding room_cleaning to VacuumTrait.__init__ (which also simplifies the rebase conflict in q10/__init__.py).
  2. Use settings: list[Q10RoomCleanSettings] | None = None on RoomCleaning:
    • Representing unpopulated state as None and an empty push ("AA==") as [] removes the need for a separate settings_available boolean, uses list consistently with other Q10 containers, and keeps as_dict() as {} before any push arrives.
  3. Fall back to Q10CleanCount.UNKNOWN in Q10Status.clean_count_mode (and add unit test coverage in test_status.py).
  4. Minor test colocation & cleanup in test_room_cleaning.py, test_vacuum.py, and test_b01_q10_protocol.py (see inline comments).

Comment thread roborock/protocols/b01_q10_protocol.py Resolved
@lboue

lboue commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

@hCoureau This branch has conflicts,

@hCoureau
hCoureau marked this pull request as draft November 8, 2026 18:57
@hCoureau
hCoureau marked this pull request as ready for review November 8, 2026 19:04

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants