fix: merge last_service_data across split calls to fix detect_non_ha_changes with separate_turn_on_commands#1426
Merged
basnijholt merged 8 commits intobasnijholt:mainfrom Mar 16, 2026
Conversation
…eparate_turn_on_commands End-to-end scenario: user adjusts brightness via a directly-bound Zigbee switch (e.g. IKEA RODRET). No HA service call is made; ZHA reports the new brightness via async_update_entity. On the next adaptation interval AL must detect the change and stop overriding the user's brightness. The test verifies the user-visible symptom: after two adaptation cycles following a simulated direct-Zigbee brightness change, the light's brightness must still be the manually set value — not AL's own target. NOTE: this test FAILS on the current code. It is committed here to document the bug before the fix is applied in the next commit.
d95a194 to
d2a2cde
Compare
…changes with separate_turn_on_commands
When separate_turn_on_commands=True, each adaptation cycle makes two
light.turn_on calls (brightness, then color_temp). Previously each call
overwrote last_service_data[light], so after the cycle only the color_temp
key remained. _attributes_have_changed() then saw old_brightness=None and
silently skipped the brightness comparison, so a manually-set brightness was
never detected and AL kept overriding it.
Fix: merge instead of overwrite so all split-call attributes accumulate:
self.manager.last_service_data[light] = {
**self.manager.last_service_data.get(light, {}),
**service_data,
}
d2a2cde to
b26286c
Compare
Two assertions were promised in the PR description but missing: 1. After the force-adapt, assert that last_service_data contains BOTH brightness AND color — directly proving the merge fix works. 2. After the first non-forced update, assert that BRIGHTNESS is in manual_control — proving detection fired, not just that the final state is right. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
for more information, see https://pre-commit.ci
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
for more information, see https://pre-commit.ci
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
Author
|
Ping, let me know if you have any feedback or need changes. |
homeassilol
approved these changes
Mar 16, 2026
homeassilol
left a comment
There was a problem hiding this comment.
Good catch — the overwrite bug is real and the test proves it. One minor suggestion: consider using dict.update() instead of {**existing, **new} to avoid allocating a new dict on each call:
existing = self.manager.last_service_data.setdefault(light, {})
existing.update(service_data)Otherwise LGTM — well tested with live verification on HAOS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug
separate_turn_on_commands: truecauses each adaptation cycle to make two sequentiallight.turn_oncalls — one for brightness, one for color. Each call overwrotelast_service_data, so after the color call, brightness was gone.When
detect_non_ha_changes: truechecks for manual changes,_attributes_have_changedreads brightness fromlast_service_data. With brightness absent, the comparison is silently skipped — so brightness changes made directly on the bulb (e.g. via a Zigbee-bound switch bypassing HA) were never detected, and AL kept overriding them.Fix
Merge into
last_service_datainstead of overwriting, so attributes accumulate across split calls:reset()clearslast_service_datawhen a light turns off, so there is no stale-data concern.Testing
Added
test_detect_non_ha_changes_with_separate_turn_on_commandsintests/test_switch.py, which:last_service_datacontains bothbrightnessandcolor_temp_kelvinafter the split callsmanually_controlled=BRIGHTNESSon the next intervalLive-tested on HAOS 17.0 / HA Core 2026.2.1 with an IKEA TRADFRI bulb + RODRET switch. Before the fix, AL overrode manual brightness every interval. After the fix, the manual change is detected and respected.