From 5d7789eb4eaf485ff9c112e533627d35da43c705 Mon Sep 17 00:00:00 2001 From: Marc Billow Date: Mon, 27 Jul 2026 00:47:16 +0000 Subject: [PATCH] Add confirmed washer/dryer cycle code labels (issue #80) Five raw course codes were rendering unlabeled because no translation entry existed for them, confirmed by the reporter selecting each cycle on the physical appliance and reading back the raw code from the entity's state: - washer_cycle_table_02: '52' Eco Cold, '54' Towels, '60' Self Clean+ (a WF50A8600AV/US). '54' shares a display name with the existing '24' Towels -- a different code on the same table legitimately landing on the same label, matching the existing '21'/'65' Colors and '27'/'5E' Rinse+Spin pairs, not a duplicate-in-error. - dryer_cycle_table_03: '01' Normal, '06' Time dry (a DVE50A8600V/A3, the same model added in the previous commit's detection fix). No code changes -- select.py already derives which raw values it normalizes from the shipped catalog, so labelling a code is purely a translations/en.json (mirrored to nl.json) addition. --- .../localthings/registry/capabilities/dryer.py | 5 ++++- .../localthings/registry/capabilities/washer.py | 8 ++++++++ .../localthings/translations/en.json | 5 +++++ .../localthings/translations/nl.json | 5 +++++ tests/test_translations.py | 15 +++++++++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/custom_components/localthings/registry/capabilities/dryer.py b/custom_components/localthings/registry/capabilities/dryer.py index f1fcb70..8d5224c 100644 --- a/custom_components/localthings/registry/capabilities/dryer.py +++ b/custom_components/localthings/registry/capabilities/dryer.py @@ -42,7 +42,10 @@ DRYER_SETTINGS = Capability( # under entity.select.dryer_cycle (Table_03, DV5000-class, captured # 2026-05-29). Codes 0x21 and 0x4C appear in the issue #14 DV90BB5245AES1 # editCourseList but aren't identified yet -- they render as the raw code -# until named. The /st/dryercourse/vs/0 resource re-encodes the same selected +# until named. Codes '01' Normal and '06' Time dry were confirmed on a +# DVE50A8600V/A3 (also Table_03) by selecting each cycle on the physical +# appliance and reading back the raw code from the entity's state (issue +# #80). The /st/dryercourse/vs/0 resource re-encodes the same selected # course and is ignored (ignored.py) -- the mirror of how /st/washercourse/vs/0 # is ignored for washers. DRYER_COURSE = Capability( diff --git a/custom_components/localthings/registry/capabilities/washer.py b/custom_components/localthings/registry/capabilities/washer.py index 615f058..a006c16 100644 --- a/custom_components/localthings/registry/capabilities/washer.py +++ b/custom_components/localthings/registry/capabilities/washer.py @@ -45,6 +45,14 @@ from .laundry import ( # (issue #22). Combo units carry their own course set, so these codes # don't imply anything about '1F' on a plain washer. # +# Three more -- '52' Eco Cold, '54' Towels, '60' Self Clean+ -- came from a +# WF50A8600AV/US, verified directly rather than by inference: the reporter +# selected each cycle on the physical appliance and read back the resulting +# raw code from the cycle_select entity's state (issue #80). '54' shares a +# display name with the existing '24' Towels -- a different code on a +# different course table legitimately landing on the same label, not a typo +# (same pattern as '21'/'65' Colors and '27'/'5E' Rinse+Spin above). +# # No static fallback list of those codes is kept here, deliberately: other # washer models have a different actual course set (a second dump's active # course, '65', isn't even in the list above; models with 'AI Wash'/'Mixed diff --git a/custom_components/localthings/translations/en.json b/custom_components/localthings/translations/en.json index f990cc6..ac199df 100644 --- a/custom_components/localthings/translations/en.json +++ b/custom_components/localthings/translations/en.json @@ -201,6 +201,8 @@ "dryer_cycle_table_03": { "name": "Cycle", "state": { + "01": "Normal", + "06": "Time dry", "16": "Cotton", "18": "Synthetics", "19": "Delicates", @@ -389,10 +391,13 @@ "37": "Air Wash", "38": "Cotton Dry", "39": "Synthetics Dry", + "52": "Eco Cold", "53": "Heavy Duty", + "54": "Towels", "55": "Activewear", "57": "Delicate", "5e": "Rinse+Spin", + "60": "Self Clean+", "65": "Colors", "66": "Denim", "7c": "Whites", diff --git a/custom_components/localthings/translations/nl.json b/custom_components/localthings/translations/nl.json index c922d82..9a72317 100644 --- a/custom_components/localthings/translations/nl.json +++ b/custom_components/localthings/translations/nl.json @@ -201,6 +201,8 @@ "dryer_cycle_table_03": { "name": "Programma", "state": { + "01": "Normaal", + "06": "Tijdprogramma", "16": "Katoen", "18": "Synthetisch", "19": "Fijne was", @@ -389,10 +391,13 @@ "37": "Air Wash", "38": "Katoen drogen", "39": "Synthetisch drogen", + "52": "Eco koud", "53": "Intensief", + "54": "Handdoeken", "55": "Sportkleding", "57": "Fijn", "5e": "Spoelen+centrifugeren", + "60": "Zelfreinigend+", "65": "Bonte was", "66": "Spijkergoed", "7c": "Witte was", diff --git a/tests/test_translations.py b/tests/test_translations.py index c360ffd..0fa9782 100644 --- a/tests/test_translations.py +++ b/tests/test_translations.py @@ -168,3 +168,18 @@ def test_all_entity_state_translation_keys_are_lowercase(): for translation in platform.values(): for state_key in translation.get("state", {}): assert state_key == state_key.lower() + + +def test_issue_80_cycle_codes_are_labelled(): + """Confirmed by the reporter selecting each cycle on the physical + appliance and reading back the raw code from the entity's state -- + regression-lock those five mappings against accidental removal.""" + select_strings = _load("en")["entity"]["select"] + washer_state = select_strings["washer_cycle_table_02"]["state"] + assert washer_state["52"] == "Eco Cold" + assert washer_state["54"] == "Towels" + assert washer_state["60"] == "Self Clean+" + + dryer_state = select_strings["dryer_cycle_table_03"]["state"] + assert dryer_state["01"] == "Normal" + assert dryer_state["06"] == "Time dry"