Fix light polling trusting unsupported color_mode#707
Fix light polling trusting unsupported color_mode#707TheJulianJES merged 8 commits intozigpy:devfrom
color_mode#707Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #707 +/- ##
==========================================
+ Coverage 97.51% 97.62% +0.11%
==========================================
Files 62 62
Lines 10946 10951 +5
==========================================
+ Hits 10674 10691 +17
+ Misses 272 260 -12 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR hardens ZHA light polling and state restoration against devices that incorrectly report an unsupported Zigbee color_mode (e.g., reporting XY even though the light only supports color temperature), aligning runtime updates with the already-established capability recomputation logic.
Changes:
- Ignore restored/persisted
color_modevalues that are not present in the entity’s_supported_color_modes. - During polling (
async_update), derive an “effective”color_modefrom_supported_color_modes(especially for single-mode lights), so color temperature updates aren’t dropped when devices misreportcolor_mode. - Add tests covering restoration and polling behavior for color-temp-only lights and dual-mode lights.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
zha/application/platforms/light/__init__.py |
Validates restored color_mode against supported modes; derives an effective polled color mode to keep updates consistent with capabilities. |
tests/test_light.py |
Adds regression tests for restoring unsupported color_mode and for polling behavior when devices misreport color_mode. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (color_mode := results.get("color_mode")) is not None: | ||
| if color_mode == Color.ColorMode.Color_temperature: | ||
| self._color_mode = ColorMode.COLOR_TEMP | ||
| # Determine the effective color mode: if only one mode is | ||
| # supported, use it regardless of what the device reports | ||
| if len(self._supported_color_modes) == 1: | ||
| effective_mode = next(iter(self._supported_color_modes)) |
There was a problem hiding this comment.
The new comment says to use the only supported mode “regardless of what the device reports”, but this logic only runs when results.get("color_mode") is not None. If the color_mode read fails/returns no value while other attributes (e.g., color_temperature) do, polling will currently skip updating state entirely; either adjust the comment to reflect the guard, or consider deriving effective_mode from _supported_color_modes even when color_mode is missing so polling can still apply updates.
There was a problem hiding this comment.
Hmm, I guess this is valid somewhat...
I guess this also brings into question if there's a non-functional Color cluster on the device. Instead of having XY and/or COLOR_TEMP as supported modes, we'd just have ONOFF or BRIGHTNESS.
This would still work with the current logic, we would just re-set the color_mode to ONOFF or BRIGHTNESS during every poll. Shouldn't matter..
There was a problem hiding this comment.
Honestly, I think current behavior is fine. A light with color_mode being unsupported somehow still supporting color/temp is something we don't need to care about when polling IMO.
|
@puddly What do you think of this for the patch release tomorrow? |
|
I think it's fine. I played around more with #703 but it's a dead end for now and your PR here fixes the actual runtime issue, since we can't assume these devices aren't sending bad data anyways. |
|
#703 is still something to look at (or a different but kinda similar approach?), as we do seem to incorrectly identify some lights as supporting XY or color temperature. #572 is also still open to fix the color temperature issue. With both of those PRs, I worry that there's more lights out in the real world that "work fine" now, without any quirks, but later break when we fix our behavior. I think we'll just need to add logging at some point (with requests to report these devices), then implement quirks for them, and merge ZHA change(s). |
|
Yeah, fundamentally there is no way to handle all of these weird devices with a generic ZCL |
Proposed change
This works around an issue in lights that report
color_mode=XYduring polling, even though they only support color temperature. This PR effectively clones the logic used to determine the color mode inrecompute_capabilities:zha/zha/application/platforms/light/__init__.py
Lines 928 to 938 in c51efa5
This has the advantage that even if a color temperature light reports
color_mode=XY, we still update the color temp values during polling, as_supported_color_modesonly containsCOLOR_TEMP.We can also consider polling out that logic into a
_determine_color_modemethod, for example.Additional information
HA Core recently introduced stricter validation of the set
color_mode, which seems to have exposed this issue. See:Related PR
device_typeover cluster/attribute values for Light #703A bigger change is tried in the PR linked above, where the endpoint's
device_typeis used and trusted to determine the color capabilities of a light. However, it seems like we already have one device that doesn't follow those rules either...There's also a difference in how that PR handles
color_modewhen polling: If the device responds with an incorrectcolor_mode(e.g.XY), even though we know from_supported_color_modesthat it only supportsCOLOR_TEMP, that PR ignores the updates it got from polling. With this PR, we update color temper values, even if the light reportscolor_mode=XYwhen our_supported_color_modesonly includeCOLOR_TEMP.Future
We do need to have a more robust solution for this in the future. For a patch release, I think this is the easiest solution that should fix the issue and not introduce new ones.
Notes for me later (for a proper long-term solution):
current_xandcurrent_yare unsupported?0then, causing log warnings, as device shouldn't show color temp in first place