Skip to content

Add select entities for Roborock q10 s5+#166142

Draft
lboue wants to merge 24 commits intohome-assistant:devfrom
lboue:feat/roborock-q10-s5-plus-vacuum-select
Draft

Add select entities for Roborock q10 s5+#166142
lboue wants to merge 24 commits intohome-assistant:devfrom
lboue:feat/roborock-q10-s5-plus-vacuum-select

Conversation

@lboue
Copy link
Contributor

@lboue lboue commented Mar 21, 2026

Proposed change

This PR adds a cleaning mode select entity for the Roborock Q10 S5+ integration.

  • Added RoborockQ10CleanModeSelectEntity to expose cleaning mode selection in Home Assistant.
  • Mapped Q10 modes to existing keys for consistency:
    • BOTH_WORKvac_and_mop
    • ONLY_SWEEPvacuum
    • ONLY_MOPmop
  • Reused existing translation labels (no duplicate mode names).
  • Simplified the options property: removed redundant filtering of YXCleanType.UNKNOWN (now handled by the mapping function), improving code clarity and efficiency.
  • Added tests for current option, successful updates, and error handling.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

lboue added 3 commits March 21, 2026 20:52
Add select entity support for Q10 devices with:
- RoborockQ10CleanModeSelectEntity for setting cleaning mode
- Helper function _get_q10_cleaning_mode to extract current mode from Q10 data
- Integration with Q10UpdateCoordinator for push-based updates
- Support for YXCleanType enum modes (vacuum, vac_and_mop, mop, auto, etc.)
- Async command sending with set_clean_mode via Q10 vacuum trait

All existing select tests pass (18/18) for V1, Q7, and Zeo devices.
Add test coverage for the new RoborockQ10CleanModeSelectEntity:
- test_q10_cleaning_mode_select_current_option: Verify entity exists with valid options
- test_q10_cleaning_mode_select_update_success: Test setting a valid cleaning mode
- test_q10_cleaning_mode_select_update_failure: Test error handling when API call fails

All select tests pass (21/18 - 3 new Q10 tests added).
Add translation keys for Q10 specific cleaning modes:
- both_work: Vacuum and mop
- only_sweep: Vacuum only
- only_mop: Mop only

Keep existing Q7 mode translations for backward compatibility.
@home-assistant
Copy link

Hey there @Lash-L, @allenporter, mind taking a look at this pull request as it has been labeled with an integration (roborock) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of roborock can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign roborock Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component, problem in config, problem in device, feature-request) on the pull request.

- Add _map_q10_clean_mode_to_state_key() function to map YXCleanType enum values to existing Q7 keys
- BOTH_WORK → vac_and_mop
- ONLY_SWEEP → vacuum
- ONLY_MOP → mop
- Remove duplicate translations from strings.json (both_work, only_sweep, only_mop)
- Update Q10 entity to use mapped state keys instead of enum names
- Update tests to use correct mapped option names
- All 21 select tests passing (18 existing + 3 Q10)
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 a new select entity to the Roborock integration to control Q10 S5+ cleaning mode, with corresponding translations and tests.

Changes:

  • Add RoborockQ10CleanModeSelectEntity and wire it into async_setup_entry for Q10 coordinators.
  • Extend strings.json with additional cleaning_mode state translations used by Q10.
  • Add initial tests covering entity existence and service calls for the new Q10 select.

Reviewed changes

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

File Description
homeassistant/components/roborock/select.py Adds a Q10 cleaning mode select entity and setup wiring.
homeassistant/components/roborock/strings.json Adds translations for new Q10 cleaning mode option keys.
tests/components/roborock/test_select.py Adds tests for Q10 cleaning mode select existence and service behavior.

Copilot AI review requested due to automatic review settings March 21, 2026 20:11
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 2 out of 2 changed files in this pull request and generated 4 comments.

Copilot AI review requested due to automatic review settings March 21, 2026 21:19
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 2 out of 2 changed files in this pull request and generated 2 comments.

@lboue lboue marked this pull request as ready for review March 21, 2026 21:24
@lboue lboue requested a review from allenporter as a code owner March 21, 2026 21:24
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 2 out of 2 changed files in this pull request and generated 2 comments.

@lboue lboue marked this pull request as ready for review March 22, 2026 17:38
Copilot AI review requested due to automatic review settings March 22, 2026 17:38
@home-assistant home-assistant bot requested a review from allenporter March 22, 2026 17:38
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 2 out of 2 changed files in this pull request and generated 1 comment.

Copilot AI review requested due to automatic review settings March 22, 2026 21:46
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 2 out of 2 changed files in this pull request and generated no new comments.

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 2 out of 2 changed files in this pull request and generated no new comments.

@joostlek joostlek changed the title Feat/roborock q10 s5 plus vacuum select Add select entities for Roborock q10 s5+ Mar 22, 2026
@home-assistant home-assistant bot marked this pull request as draft March 22, 2026 23:28
@lboue lboue requested a review from allenporter March 23, 2026 12:08
@lboue lboue marked this pull request as ready for review March 23, 2026 12:16
Copilot AI review requested due to automatic review settings March 23, 2026 12:16
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 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +512 to +520
if clean_mode is None or clean_mode.code is None:
return None
code = clean_mode.code
for mode in YXCleanType:
if getattr(mode, "code", None) == code:
if mode == YXCleanType.UNKNOWN:
return None
return mode.value
return None
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

current_option appears to treat status.clean_mode as a code-bearing object and then loops over YXCleanType to find a matching member. Since other Q10 entities (e.g. RoborockQ10Vacuum.fan_speed) use the enum value directly, consider returning clean_mode.value when clean_mode is a YXCleanType (and None for None/UNKNOWN). This removes the redundant enum scan and avoids coupling to a .code attribute.

Suggested change
if clean_mode is None or clean_mode.code is None:
return None
code = clean_mode.code
for mode in YXCleanType:
if getattr(mode, "code", None) == code:
if mode == YXCleanType.UNKNOWN:
return None
return mode.value
return None
# Treat clean_mode as a YXCleanType enum when possible.
if not isinstance(clean_mode, YXCleanType):
return None
if clean_mode is YXCleanType.UNKNOWN:
return None
return clean_mode.value

Copilot uses AI. Check for mistakes.
Comment on lines +525 to +530
mode = None
for m in YXCleanType:
if m.value == option:
mode = m
break
if mode is None:
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
mode = None
for m in YXCleanType:
if m.value == option:
mode = m
break
if mode is None:
if (mode := YXCleanType.from_code_optional(option) is None:

Comment on lines +511 to +520
clean_mode = self.coordinator.api.status.clean_mode
if clean_mode is None or clean_mode.code is None:
return None
code = clean_mode.code
for mode in YXCleanType:
if getattr(mode, "code", None) == code:
if mode == YXCleanType.UNKNOWN:
return None
return mode.value
return None
Copy link
Contributor

Choose a reason for hiding this comment

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

I was expecting to see something like this:

Suggested change
clean_mode = self.coordinator.api.status.clean_mode
if clean_mode is None or clean_mode.code is None:
return None
code = clean_mode.code
for mode in YXCleanType:
if getattr(mode, "code", None) == code:
if mode == YXCleanType.UNKNOWN:
return None
return mode.value
return None
clean_mode = self.coordinator.api.status.clean_mode
if clean_mode is None or clean_mode.code is None:
return None
return clean_mode.value

options = state.attributes.get("options")
assert options is not None
assert set(options) == {"vac_and_mop", "vacuum", "mop"}
assert len(options) == len(set(options))
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not needed given the previous line right?

Suggested change
assert len(options) == len(set(options))

Comment on lines +412 to +413
assert updated_state.state != STATE_UNKNOWN
assert updated_state.state == "vac_and_mop"
Copy link
Contributor

Choose a reason for hiding this comment

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

We can just directly check the final value, right?

Suggested change
assert updated_state.state != STATE_UNKNOWN
assert updated_state.state == "vac_and_mop"
assert updated_state.state == "vac_and_mop"

"""Test Q10 cleaning mode select entity current option."""
entity_id = "select.roborock_q10_s5_cleaning_mode"
state = hass.states.get(entity_id)
assert state is not None
Copy link
Contributor

Choose a reason for hiding this comment

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

Below we assert that state.state changes, so i think we should assert on its starting value here otherwise we haven't confirmed the update really happened.

)


async def test_q10_cleaning_mode_select_invalid_option(
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't write tests that directly depend on entities, and instead use the home assistant APIs to communicate with them. Please use hass.services.async_call like is done in the other previous tests.

@home-assistant home-assistant bot marked this pull request as draft March 24, 2026 03:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants