From 3d0e8e638170bcdff46b46a717c1adf49a64caa6 Mon Sep 17 00:00:00 2001 From: Yangqian Date: Sat, 5 Sep 2026 09:59:48 +0800 Subject: [PATCH] fix: skip DP 225 on Zeo H1 (roborock.wm.a63) The H1 has a softener compartment, so build_force_load_dp_list() asked it for DEFAULT_SETTING (DP 225), which the device never returns. Since send_decoded_command() only completes a query once every requested DP has arrived, the whole force-load timed out after 10s and every DP the device did answer was discarded, leaving no Zeo state loaded. Gate DP 225 behind a model set, matching how FEATURE_BITS (DP 237) is already handled for this same device. --- roborock/devices/traits/a01/device_feature.py | 18 ++++++++ .../devices/traits/a01/test_device_feature.py | 41 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 tests/devices/traits/a01/test_device_feature.py diff --git a/roborock/devices/traits/a01/device_feature.py b/roborock/devices/traits/a01/device_feature.py index ae77ccad..001ee3c9 100644 --- a/roborock/devices/traits/a01/device_feature.py +++ b/roborock/devices/traits/a01/device_feature.py @@ -143,6 +143,13 @@ } ) +# Devices known to lack DEFAULT_SETTING (DP 225). +_UNSUPPORTED_DEFAULT_SETTING: frozenset[str] = frozenset( + { + "roborock.wm.a63", # H1 + } +) + # Series that support UV light (DP 228). _UV_LIGHT_SERIES: frozenset[str] = ( _H1_LITE_SERIES # a90, a91, a237 @@ -242,6 +249,13 @@ def supports_feature_bits(model: str | None) -> bool: return model not in _UNSUPPORTED_FEATURE_BITS +def supports_default_setting(model: str | None) -> bool: + """H1 (a63) does not support DP 225 even though it has a softener compartment.""" + if model is None: + return True # conservative: assume yes + return model not in _UNSUPPORTED_DEFAULT_SETTING + + def supports_remote_control(model: str | None) -> bool: """Remote control (DP 232) is supported on all overseas models.""" if model is None: @@ -309,6 +323,10 @@ def build_force_load_dp_list(model: str | None) -> list[RoborockZeoProtocol]: if not supports_feature_bits(model): base = [dp for dp in base if dp != RoborockZeoProtocol.FEATURE_BITS] + # ── Strip unsupported DEFAULT_SETTING ── + if not supports_default_setting(model): + base = [dp for dp in base if dp != RoborockZeoProtocol.DEFAULT_SETTING] + return base diff --git a/tests/devices/traits/a01/test_device_feature.py b/tests/devices/traits/a01/test_device_feature.py new file mode 100644 index 00000000..75d92b27 --- /dev/null +++ b/tests/devices/traits/a01/test_device_feature.py @@ -0,0 +1,41 @@ +"""Tests for A01 (Zeo) per-model feature gating.""" + +import pytest + +from roborock.devices.traits.a01.device_feature import build_force_load_dp_list, supports_default_setting +from roborock.roborock_message import RoborockZeoProtocol + + +@pytest.mark.parametrize( + ("model", "expected"), + [ + ("roborock.wm.a63", False), # H1 + ("roborock.wm.a102", True), # H1 Overseas + ("roborock.wm.a90", True), # H1 Lite + (None, True), # unknown model: assume supported + ], +) +def test_supports_default_setting(model: str | None, expected: bool) -> None: + """DP 225 is unsupported on H1 (a63) only.""" + assert supports_default_setting(model) is expected + + +def test_force_load_omits_default_setting_for_h1() -> None: + """H1 (a63) has a softener compartment but must not be queried for DP 225.""" + dp_list = build_force_load_dp_list("roborock.wm.a63") + + assert RoborockZeoProtocol.DEFAULT_SETTING not in dp_list + # The remaining softener DPs are still queried. + assert RoborockZeoProtocol.SOFTENER_SET in dp_list + assert RoborockZeoProtocol.SOFTENER_TYPE in dp_list + assert RoborockZeoProtocol.SOFTENER_EMPTY in dp_list + + +def test_force_load_keeps_default_setting_for_other_softener_models() -> None: + """Other softener-equipped models still query DP 225.""" + assert RoborockZeoProtocol.DEFAULT_SETTING in build_force_load_dp_list("roborock.wm.a102") + + +def test_force_load_omits_default_setting_without_softener() -> None: + """Models without a softener compartment never query DP 225.""" + assert RoborockZeoProtocol.DEFAULT_SETTING not in build_force_load_dp_list("roborock.wm.a92")