fix: prevent transient Zigbee off-state from cancelling adaptation#1460
fix: prevent transient Zigbee off-state from cancelling adaptation#1460florianhorner wants to merge 3 commits intobasnijholt:mainfrom
Conversation
…asnijholt#1449) Three fixes for lights turning off immediately after being turned on: 1. Add is_proactively_adapting guard to the on→off branch in state_changed_event_listener. Previously, a transient off state reported by Zigbee devices (e.g., FUT035Z) during a turn-on transition would unconditionally call reset(), cancelling the in-flight adaptation task. The off→on branch already had this guard; the on→off branch did not. 2. Reorder checks in just_turned_off() so that _off_to_on_state_event_is_from_turn_on runs BEFORE the context-equality check. The context-equality check (added in basnijholt#696 for lights polling as "on" during turn_off transitions) was incorrectly firing for the reverse case where a device briefly reports "off" during a turn_on. Also tighten the context-equality check to require a matching turn_off_event, preventing false positives from inherited Zigbee context IDs. 3. Fix truthiness check in _split_service_call_data that silently dropped brightness=0 values. Changed to explicit None check so that zero values are preserved in split service call data. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Sorry it took me so long to get to this. I've been a bit overwhelmed by the number of AI-assisted PRs opened here recently, and I've also been spending nearly every spare hour on my biggest project so far, MindRoom. I'm very supportive of using AI for coding, but many of these PRs still need careful human review because even plausible-looking changes can introduce subtle breakage. That backlog made me postpone reviewing them for a while. I've now done a batch review with Codex / GPT-5.5 (xhigh). This comment is AI-assisted, but I've reviewed it before posting. This looks like the right direction to me. I do not see a blocking issue in the implementation, and the The one thing I would really like before merging is regression coverage. This PR touches subtle context/cancellation behavior, so tests for the transient off-state case and the zero-brightness split data case would make this much safer to carry forward. |
|
Follow-up from a deeper Codex / GPT-5.5 (xhigh) pass. I re-read the actual context/cancellation change and still do not see a code-level blocker. The ordering change in The missing piece is regression coverage. Could you add tests for:
This is subtle enough that I would be much more comfortable merging it with those cases pinned down. |
…holt#1460) Signed-off-by: jaynis <kranz.jannis@googlemail.com>
…or expectations) Fork main carried tests written against a planned "PR simplification" that never landed: tests asserted that STEP_OPTIONS, ROOM_PRESETS, CONF_ROOM_PRESET, CONF_ENABLE_DIAGNOSTIC_SENSORS, LightStatus, LightStatusInfo, STATUS_PRIORITY, SIGNAL_STATUS_UPDATED, expand_light_groups, and sensor.py had been removed — but the code still ships them. Delete the predicate tests for code that was not removed. The test suite is now a faithful description of what the code actually does. * tests/test_const_and_helpers.py — deleted (entire file was these predicate-removal asserts). * tests/test_config_flow.py — drop seven tests that asserted the single-step options flow (test_options, test_incorrect_options, test_options_single_step_completes, test_options_no_room_preset_field, test_options_no_sleep_step, test_options_sleep_brightness_zero_rejected, test_options_sleep_brightness_one_accepted). * tests/test_adaptation_utils.py — fix the test_split_service_call_data_falsy_values parametrize set to assert PR basnijholt#1460's actual behavior (brightness=0 preserved by `is not None`, not dropped silently). * strings.json + translations/en.json — drop the URL from options.step.init.description. Hassfest forbids URLs in translation strings. Other locale catalogs still carry the URL and will need a Weblate sync. * tests/__init__.py — add minimal package-init with docstring. Ruff INP001 + D104 were blocking every commit because tests/ was an implicit namespace package with no __init__.py. * tests/test_init.py — black formatting drift fixed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Fixes #1449 — lights turning off immediately (~680ms) after being turned on, particularly with Zigbee devices like FUT035Z and
separate_turn_on_commands=True.Root cause
When a Zigbee device briefly reports an
offstate during a turn-on transition (common with MiBoxer/FUT controllers), thestate_changed_event_listener's on→off branch at line 2539 unconditionally calledreset(), which cancelled the in-flight adaptation task. The off→on branch had anis_proactively_adaptingguard (line 2557) but the on→off branch did not.Additionally,
just_turned_off()had a context-equality check (line 2760, added in #696) that fired before_off_to_on_state_event_is_from_turn_on, causing false positives when both events shared a context ID inherited from the same service call chain.Changes
Add
is_proactively_adaptingguard to the on→off branch — Transient off states during proactive adaptation now skipreset()(preserving the adaptation task) while still recordingon_to_off_eventto prevent stale state.Reorder and tighten
just_turned_off()checks —_off_to_on_state_event_is_from_turn_onnow runs before the context-equality check, so reallight.turn_oncalls are never misclassified as phantom events. The context-equality check now also requires a matchingturn_off_event, preventing false positives from inherited Zigbee context IDs while preserving the original Bail adapting if on event equals off event context #696 protection.Fix truthiness bug in
_split_service_call_data— Changedif service_data.get(attribute)toif service_data.get(attribute) is not Nonesobrightness=0is no longer silently dropped from split service data.Analysis
This fix was validated by 8 independent code reviews across 4 different AI models (Claude Opus, OpenAI Codex/o3, Perplexity Deep Research, adversarial agents). The Perplexity thread with the full analysis is available here for reference: https://www.perplexity.ai/search/i-m-analyzing-a-confirmed-bug-UNxwI3FaRouo_nwUM6mymw
How to verify
Users experiencing #1449 should look for this new debug log line when the transient off is handled correctly:
The absence of
Cancelled ongoing brightness adaptation callsafter a turn-on confirms the fix is working.Test plan
separate_turn_on_commands=Trueno longer turn off intermittently after turn-onlight.turn_offcallssleep_brightness=0works correctly withseparate_turn_on_commands=True🤖 Generated with Claude Code