Add select entities for Roborock q10 s5+#166142
Add select entities for Roborock q10 s5+#166142lboue wants to merge 24 commits intohome-assistant:devfrom
Conversation
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.
|
Hey there @Lash-L, @allenporter, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
- 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)
There was a problem hiding this comment.
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
RoborockQ10CleanModeSelectEntityand wire it intoasync_setup_entryfor Q10 coordinators. - Extend
strings.jsonwith additionalcleaning_modestate 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. |
…update references
…rror for invalid options
…plify state key mapping
| 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 |
There was a problem hiding this comment.
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.
| 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 |
| mode = None | ||
| for m in YXCleanType: | ||
| if m.value == option: | ||
| mode = m | ||
| break | ||
| if mode is None: |
There was a problem hiding this comment.
| 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: |
| 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 |
There was a problem hiding this comment.
I was expecting to see something like this:
| 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)) |
There was a problem hiding this comment.
This is not needed given the previous line right?
| assert len(options) == len(set(options)) |
| assert updated_state.state != STATE_UNKNOWN | ||
| assert updated_state.state == "vac_and_mop" |
There was a problem hiding this comment.
We can just directly check the final value, right?
| 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 |
There was a problem hiding this comment.
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( |
There was a problem hiding this comment.
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.
Proposed change
This PR adds a cleaning mode select entity for the Roborock Q10 S5+ integration.
RoborockQ10CleanModeSelectEntityto expose cleaning mode selection in Home Assistant.BOTH_WORK→vac_and_mopONLY_SWEEP→vacuumONLY_MOP→mopYXCleanType.UNKNOWN(now handled by the mapping function), improving code clarity and efficiency.Type of change
Additional information
Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: