From 4218b7b03765e1d36b31ed28051d6cbf609ff891 Mon Sep 17 00:00:00 2001 From: infy1995 Date: Sat, 7 Nov 2026 19:40:41 +0100 Subject: [PATCH 1/3] fix(dyad): add steam and hot water clean modes The F25 Ultra reports DyadCleanMode codes 5 (hot water) and 6 (steam), which were logged as missing and decoded as "auto". Add both modes and an explicit `unknown` member so future unknown codes no longer masquerade as "auto". --- roborock/data/dyad/dyad_code_mappings.py | 4 ++++ tests/conformance/test_enum_conformance.py | 1 - tests/data/test_code_mappings.py | 14 +++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/roborock/data/dyad/dyad_code_mappings.py b/roborock/data/dyad/dyad_code_mappings.py index ec12fdb2a..d018ce4db 100644 --- a/roborock/data/dyad/dyad_code_mappings.py +++ b/roborock/data/dyad/dyad_code_mappings.py @@ -45,10 +45,14 @@ class DyadMode(RoborockEnum): class DyadCleanMode(RoborockEnum): + unknown = -1 auto = 1 max = 2 dehydration = 3 power_saving = 4 + # Heated modes on the F25 Ultra, confirmed by switching modes on the device. + hot_water = 5 + steam = 6 class DyadSuction(RoborockEnum): diff --git a/tests/conformance/test_enum_conformance.py b/tests/conformance/test_enum_conformance.py index a22eb23b7..0a8d2b3a4 100644 --- a/tests/conformance/test_enum_conformance.py +++ b/tests/conformance/test_enum_conformance.py @@ -24,7 +24,6 @@ # As these enums are remediated, remove them from this baseline. KNOWN_ENUMS_MISSING_UNKNOWN = { "roborock.data.dyad.dyad_code_mappings.DyadBrushSpeed", - "roborock.data.dyad.dyad_code_mappings.DyadCleanMode", "roborock.data.dyad.dyad_code_mappings.DyadCleanser", "roborock.data.dyad.dyad_code_mappings.DyadError", "roborock.data.dyad.dyad_code_mappings.DyadMode", diff --git a/tests/data/test_code_mappings.py b/tests/data/test_code_mappings.py index f66970a55..b487873a0 100644 --- a/tests/data/test_code_mappings.py +++ b/tests/data/test_code_mappings.py @@ -9,7 +9,7 @@ from roborock import CleanRoutes, HomeDataProduct, RoborockCategory from roborock.data.b01_q10.b01_q10_code_mappings import B01_Q10_DP, YXCleanType from roborock.data.code_mappings import completed_warnings -from roborock.data.dyad.dyad_code_mappings import DyadError +from roborock.data.dyad.dyad_code_mappings import DyadCleanMode, DyadError from roborock.data.v1.v1_code_mappings import ( RoborockErrorCode, RoborockFinishReason, @@ -170,3 +170,15 @@ def test_roborock_mode_enum_display_names_group_duplicate_protocol_codes() -> No assert CleanRoutes.DEEP_PLUS_CN.display_name == "deep_plus" assert CleanRoutes.keys().count("deep_plus") == 1 assert "deep_plus_cn" not in CleanRoutes.keys() + + +def test_dyad_clean_mode_codes(caplog: pytest.LogCaptureFixture) -> None: + """Dyad clean mode codes reported by devices decode without warnings.""" + completed_warnings.clear() + with caplog.at_level(logging.WARNING): + assert DyadCleanMode(5) == DyadCleanMode.hot_water + assert DyadCleanMode(6) == DyadCleanMode.steam + assert "Missing DyadCleanMode" not in caplog.text + + # A genuinely unknown code falls back to 'unknown' instead of 'auto'. + assert DyadCleanMode(99) == DyadCleanMode.unknown From dd01ae546e7ca1f9b889f4708d70b5df20b86451 Mon Sep 17 00:00:00 2001 From: infy1995 Date: Sat, 7 Nov 2026 20:01:31 +0100 Subject: [PATCH 2/3] docs(dyad): note F25 Ultra reports Sponge mode as clean mode 3 --- roborock/data/dyad/dyad_code_mappings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/roborock/data/dyad/dyad_code_mappings.py b/roborock/data/dyad/dyad_code_mappings.py index d018ce4db..47662fcc3 100644 --- a/roborock/data/dyad/dyad_code_mappings.py +++ b/roborock/data/dyad/dyad_code_mappings.py @@ -48,7 +48,7 @@ class DyadCleanMode(RoborockEnum): unknown = -1 auto = 1 max = 2 - dehydration = 3 + dehydration = 3 # The F25 Ultra reports its "Sponge" mode with this code. power_saving = 4 # Heated modes on the F25 Ultra, confirmed by switching modes on the device. hot_water = 5 From e667b42ed43504afe83178fe6d254578067fbaa8 Mon Sep 17 00:00:00 2001 From: infy1995 Date: Sat, 7 Nov 2026 21:30:03 +0100 Subject: [PATCH 3/3] fix(dyad): parametrize clean mode tests with F25 Ultra codes --- tests/data/test_code_mappings.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tests/data/test_code_mappings.py b/tests/data/test_code_mappings.py index b487873a0..741046fb5 100644 --- a/tests/data/test_code_mappings.py +++ b/tests/data/test_code_mappings.py @@ -172,13 +172,24 @@ def test_roborock_mode_enum_display_names_group_duplicate_protocol_codes() -> No assert "deep_plus_cn" not in CleanRoutes.keys() -def test_dyad_clean_mode_codes(caplog: pytest.LogCaptureFixture) -> None: +@pytest.mark.parametrize( + "code, expected", + [ + # Codes reported by an F25 Ultra when switching modes in the app. + (1, DyadCleanMode.auto), + (3, DyadCleanMode.dehydration), # "Sponge" on the F25 Ultra + (5, DyadCleanMode.hot_water), + (6, DyadCleanMode.steam), + ], +) +def test_dyad_clean_mode_codes(code: int, expected: DyadCleanMode, caplog: pytest.LogCaptureFixture) -> None: """Dyad clean mode codes reported by devices decode without warnings.""" completed_warnings.clear() with caplog.at_level(logging.WARNING): - assert DyadCleanMode(5) == DyadCleanMode.hot_water - assert DyadCleanMode(6) == DyadCleanMode.steam + assert DyadCleanMode(code) == expected assert "Missing DyadCleanMode" not in caplog.text - # A genuinely unknown code falls back to 'unknown' instead of 'auto'. + +def test_dyad_clean_mode_unknown_code() -> None: + """An unrecognized Dyad clean mode falls back to 'unknown' instead of 'auto'.""" assert DyadCleanMode(99) == DyadCleanMode.unknown