Skip to content

Conversation

@lboue
Copy link
Contributor

@lboue lboue commented Feb 1, 2026

feat(q10): Add Q10 vacuum CLI commands and Status API

Overview

This PR adds complete CLI command support for Roborock Q10 vacuum devices including five vacuum control commands and a new Status API trait for reading device state. All code review feedback has been addressed, and the implementation is tested on a real Q10 S5+ device.

What's Changed

1. CLI Commands for Q10 Vacuum Control

Added 5 new Click commands to control Q10 devices from the CLI:

  • q10-vacuum-start - Start vacuum cleaning
  • q10-vacuum-pause - Pause vacuum cleaning
  • q10-vacuum-resume - Resume vacuum cleaning
  • q10-vacuum-stop - Stop vacuum cleaning
  • q10-vacuum-dock - Return vacuum to dock

All commands:

  • Require --device_id parameter
  • Handle unsupported devices gracefully with user-friendly error messages
  • Are registered in both the main CLI and the interactive session shell
  • Use centralized _q10_vacuum_trait() helper to reduce code duplication

2. Status API for Q10 Devices

Implemented a new StatusTrait to read Q10 device state with properties for:

  • state - Device state (sleepstate, charging, cleaning, etc.)
  • battery - Battery percentage (0-100)
  • fan_level - Fan level (quiet, standard, strong, max, super, custom)
  • water_level - Water level for mopping (low, medium, high)
  • clean_mode - Cleaning mode (quiet, balanced, standard, high)
  • clean_task - Task type (unknown, room, goroom, zone, area, spot)
  • cleaning_progress - Progress percentage

3. Decoded MQTT Response Handler

Added send_decoded_command() for handling Q10's MQTT request/response pattern:

  • Filters responses by expected datapoints (Q10 doesn't correlate by message ID)
  • Includes 10-second timeout to prevent indefinite waiting
  • Properly handles decode errors and missing responses

4. Fan Level Mapping Enhancement

Added missing YXFanLevel.CUSTOM mapping for code 8 to handle all Q10 fan modes.

Code Quality & Testing

✅ All 7 code review comments addressed and resolved
✅ All 5 CLI commands tested on real Q10 S5+ device
✅ Status API tested and working (battery=91%, state=sleepstate, fan_level=custom)
✅ All pre-commit checks passing (ruff format, mypy types, debug checks)
✅ All CI tests passing (lint, test 3.11, test 3.14, build, semantic release)
✅ Code duplication eliminated with reusable helpers
✅ Proper error handling with user-friendly messages

Files Changed

  • roborock/cli.py - Added 5 Q10 commands + _q10_vacuum_trait() helper
  • roborock/devices/traits/b01/q10/status.py - NEW StatusTrait class (79 lines)
  • roborock/devices/rpc/b01_q10_channel.py - Added send_decoded_command() (61 lines)
  • roborock/devices/traits/b01/q10/__init__.py - Exposed StatusTrait in API
  • roborock/data/b01_q10/b01_q10_code_mappings.py - Added YXFanLevel.CUSTOM

Usage Examples

CLI Commands

roborock q10-vacuum-start --device_id <device_id>
roborock q10-vacuum-pause --device_id <device_id>
roborock q10-vacuum-resume --device_id <device_id>
roborock q10-vacuum-stop --device_id <device_id>
roborock q10-vacuum-dock --device_id <device_id>

Status API

device = await device_manager.get_device(device_id)
await device.b01_q10_properties.status.refresh()
print(f"Battery: {device.b01_q10_properties.status.battery}%")
print(f"State: {device.b01_q10_properties.status.state}")

Interactive Session

roborock session
> q10-vacuum-start --device_id <device_id>

Related

Copilot AI review requested due to automatic review settings February 1, 2026 07:47
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds CLI commands to control Roborock Q10 vacuum operations (start/pause/resume/stop/dock) from the roborock command line tool.

Changes:

  • Added five new Click commands for Q10 vacuum control.
  • Wired the new commands into the root CLI command registry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@lboue lboue requested a review from Copilot February 1, 2026 08:57
@lboue lboue changed the title feat(q10): Add Q10 vacuum CLI commands feat(q10): Add Q10 vacuum CLI commands and Status API Feb 1, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +31 to +40
async def refresh(self) -> dict[B01_Q10_DP, Any]:
"""Refresh status values from the device."""
decoded = await send_decoded_command(
self._channel,
command=B01_Q10_DP.REQUETDPS,
params={},
expected_dps={B01_Q10_DP.STATUS, B01_Q10_DP.BATTERY},
)
self._data = decoded
return decoded
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

StatusTrait is new and introduces device-state parsing/refresh behavior, but there are no unit tests covering refresh() and the typed property accessors (state/battery/fan_level/etc.). The repo already has Q10 trait tests (e.g., tests/devices/traits/b01/q10/test_vacuum.py); please add similar tests for status responses (including enum decoding) to prevent regressions.

Copilot uses AI. Check for mistakes.
Comment on lines +45 to +55
async def send_decoded_command(
mqtt_channel: MqttChannel,
command: B01_Q10_DP,
params: ParamsType,
expected_dps: Iterable[B01_Q10_DP] | None = None,
) -> dict[B01_Q10_DP, Any]:
"""Send a command and await the first decoded response.

Q10 responses are not correlated with a message id, so we filter on
expected datapoints when provided.
"""
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

send_decoded_command() adds new request/response correlation logic (expected datapoint filtering + timeout), but there are no unit tests validating: (1) it returns the decoded dps for a matching response, (2) it ignores non-matching responses when expected_dps is set, and (3) it raises on timeout. There are existing channel tests (e.g., tests/devices/rpc/test_a01_channel.py); please add analogous tests for the B01 Q10 channel to lock in behavior.

Copilot uses AI. Check for mistakes.
raise


async def send_decoded_command(
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this work? My impression is that q10 doesn't support this kind of mapping between request and response. We have a different approach in
#709

@property
def state(self) -> YXDeviceState | None:
code = self.state_code
return cast(YXDeviceState | None, YXDeviceState.from_code_optional(code)) if code is not None else None
Copy link
Collaborator

Choose a reason for hiding this comment

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

cast should not be needed after this change #761

lboue added a commit to lboue/python-roborock that referenced this pull request Feb 1, 2026
- Add type annotations to Q10 command parameters (ctx: click.Context, device_id: str)
- Add return type annotations (-> None, -> VacuumTrait) for all Q10 commands
- Change Q10 commands from @click.command() to @session.command() for session mode availability
- Add VacuumTrait import for proper type hints
- Create comprehensive StatusTrait tests (5 tests covering refresh, properties, enums)
- Create comprehensive send_decoded_command tests (6 tests covering success, filtering, timeout, errors)

Resolves all 6 unresolved comments from code review
lboue added a commit to lboue/python-roborock that referenced this pull request Feb 1, 2026
- Add type annotations to Q10 command parameters (ctx: click.Context, device_id: str)
- Add return type annotations (-> None, -> VacuumTrait) for all Q10 commands
- Change Q10 commands from @click.command() to @session.command() for session mode availability
- Add VacuumTrait import for proper type hints
- Create comprehensive StatusTrait tests (5 tests covering refresh, properties, enums)
- Create comprehensive send_decoded_command tests (6 tests covering success, filtering, timeout, errors)

Resolves all 6 unresolved comments from code review
@lboue lboue force-pushed the feat/q10-cli-commands branch from 829d338 to ff4d425 Compare February 1, 2026 23:11
lboue and others added 12 commits February 1, 2026 23:14
- Add q10-vacuum-start command to start vacuum cleaning
- Add q10-vacuum-pause command to pause vacuum cleaning
- Add q10-vacuum-resume command to resume vacuum cleaning
- Add q10-vacuum-stop command to stop vacuum cleaning
- Add q10-vacuum-dock command to return vacuum to dock
- All commands require device_id parameter
- Commands validate that device has VacuumTrait (Q10 only)
- Add _q10_vacuum_trait() helper function similar to _v1_trait()
- Refactor all 5 Q10 commands to use the helper
- Centralizes device lookup and trait validation logic
- Addresses code review feedback from copilot-pull-request-reviewer
- Add try/except blocks to catch RoborockUnsupportedFeature
- Display user-friendly error messages instead of stack traces
- Follow same pattern as _display_v1_trait for expected errors
- Addresses code review feedback from copilot-pull-request-reviewer
- Change from device.traits.get('VacuumTrait') to device.b01_q10_properties.vacuum
- Fix AttributeError that would occur at runtime
- Update error messages to reflect B01 Q10 protocol requirement
- Addresses code review feedback from copilot-pull-request-reviewer
- Add type annotations to Q10 command parameters (ctx: click.Context, device_id: str)
- Add return type annotations (-> None, -> VacuumTrait) for all Q10 commands
- Change Q10 commands from @click.command() to @session.command() for session mode availability
- Add VacuumTrait import for proper type hints
- Create comprehensive StatusTrait tests (5 tests covering refresh, properties, enums)
- Create comprehensive send_decoded_command tests (6 tests covering success, filtering, timeout, errors)

Resolves all 6 unresolved comments from code review
These files are auto-generated/updated on merge to main,
per project guidelines. Reverting to their state before this PR.
@lboue lboue force-pushed the feat/q10-cli-commands branch from ff4d425 to 28716c9 Compare February 1, 2026 23:19
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