diff --git a/custom_components/localthings/registry/capabilities/operational.py b/custom_components/localthings/registry/capabilities/operational.py index 440cc8d..e54db0c 100644 --- a/custom_components/localthings/registry/capabilities/operational.py +++ b/custom_components/localthings/registry/capabilities/operational.py @@ -67,11 +67,14 @@ def _new_cycle_running(rep): early once a new cycle is genuinely running. Gated on `state == 'active'`, unlike _just_finished's arm condition - above: issue #358's dryer replays a running stage ('Drying') for a few - seconds after Finish while `state` already reads idle, and a bypass - keyed on the progress code alone read that tail as a new cycle and - republished it. Releasing late costs nothing -- an unreleased hold - still expires on its own -- so this side takes the stronger signal.""" + above: issue #358's dryer resets `progress` to its course's first + stage ('Drying') in the same moment `state` goes idle, ~4s before + settling to 'None' -- confirmed by the reporter's machine_state + history, which flips to idle on the exact second progress reads + 'Drying', in both captured cycles. A bypass keyed on the progress + code alone read that as a new cycle and republished it. Releasing + late costs nothing -- an unreleased hold still expires on its own -- + so this side takes the stronger signal.""" v = rep.get("x.com.samsung.da.progress") return _state_is_active(rep) and v is not None and v not in ("None", "Finish") diff --git a/tests/test_sensor_sticky.py b/tests/test_sensor_sticky.py index 962f0eb..0627a9b 100644 --- a/tests/test_sensor_sticky.py +++ b/tests/test_sensor_sticky.py @@ -166,12 +166,13 @@ def test_a_new_cycle_starting_overrides_the_hold(): def test_a_running_stage_after_finish_does_not_break_the_hold(): - """Issue #358: the reporting dryer replays a running stage after - Finish -- observed twice, identically, as Cooling -> +60s Finish -> - +24s 'Drying' -> +4s settled, with `state` already idle throughout the - tail. The hold must survive it, so the cycle still reads Drying, - Cooling, Finish, Idle rather than the reported Drying, Cooling, - Finish, Drying, Idle.""" + """Issue #358: the reporting dryer resets `progress` to its course's + first stage in the same moment `state` goes idle -- observed twice, + identically, as Cooling -> +60s Finish -> +24s 'Drying' -> +4s + settled, with the reporter's machine_state history flipping to idle on + the exact second progress reads 'Drying'. The hold must survive that, + so the cycle still reads Drying, Cooling, Finish, Idle rather than the + reported Drying, Cooling, Finish, Drying, Idle.""" desc = replace(_PROGRESS_DESC, sticky_seconds=0.2) sensor, coordinator = _sensor(desc)