feat(homeassistant): advertise both hs and xy color modes when a light exposes both - #33025
Mihonarium wants to merge 1 commit into
Conversation
|
This change is quite risky, I think it's better to expose only the "best" color mode to HA. |
|
Related thought: |
I'm not sure, I think most light work good with XY, and very few work better with HS. |
|
(tbh i just really want the new IKEA Matter bulbs in Zigbee mode to show me red instead of pink. I imagine there are many people with the same problem. Unsure what’s the best way to solve this.) |
|
If it does not work with the |
What
Home Assistant discovery currently advertises only one of
xy/hsper light:xywins unless the device definition listscolor_hsbeforecolor_xy(thepreferHSpath). This PR advertises both whenever the light exposes both, and removespreferHS(nothing else used it). Ordering stays deterministic:["xy", "hs", "color_temp"]filtered by what is present. Single-mode lights are unchanged.Groups go through the same code path, so group discovery is fixed too.
Why
Repro (IKEA KAJPLATS CWS, Koenkk/zigbee-herdsman-converters#13100 has details): ask HA for
rgb_color: [255, 0, 0]. HA converts it toxy ≈ (0.7006, 0.2993), which is outside the bulb's LED gamut; the firmware clamps it silently and the bulb is pink. ThecurrentX/currentYreadback echoes the requested values, so Zigbee2MQTT logs and the HA state look correct; only the bulb shows the problem. Publishing{"color":{"hue":0,"saturation":100}}tozigbee2mqtt/<device>/setgives correct red, becausehsis device-relative and cannot be clamped.HA behaviour when both are advertised (verified empirically with a discovery override, and in HA core
light/__init__.py): anrgb_color/hs_colorrequest lands incolor_mode: "hs"(HA prefershsoverxywhen converting), while an explicitxy_colorrequest passes through asxy. The MQTT JSON light schema (mqtt/light/schema_json.py,_update_color) readscolor_modefrom every state message and validates it againstsupported_color_modes, so a state flipping between"xy"and"hs"is handled per message.History. The XOR dates from #6402 (Feb 2021), when HA's
color_modesupport was new: @jasperro reported that after switching an Osram bulb tohs, HA "prioritizes XY coloring" when both were present, and @Koenkk deferred it to home-assistant/architecture#519, which is exactly thecolor_modemechanism HA has shipped since 2021.4.preferHSwas then added in 8e72b3b as a per-device escape hatch. In #22905 (2024) Koenkk noted "Z2M only exposes eitherhsorxyto Home Assistant since HA cannot handle bothhsandxyat the same time (from what I remember)"; that limitation no longer exists.Advertising both also removes the
Invalid color mode 'hs' received for entity ...warning that HA logs today whenever Zigbee2MQTT publishes acolor_mode: "hs"state (e.g. after a remote or a group set hue/saturation) for a light that was discovered withxyonly (#7736, #22905, #25733).Before / after
KAJPLATS GU10 CWS 470lm (
LED2410R5),homeassistant/light/<ieee>/light/config, unchanged keys omitted:Group of one Hue Go (
7146060PH, exposescolor_xy+color_hs) and one TRADFRI WS bulb (color_temponly),homeassistant/light/<group>/light/config, from the updated test fixture:Things I checked
color_syncis a set-time option in zigbee-herdsman-converters (toZigbee.light_color*) and does not touch discovery.xy/hsin its discovery payload (supported_color_modesis only written here). Thehue→h,saturation→sstate copy stays as is.test/extensions/homeassistant.test.tsadd"hs"to a dual-mode entity; nothing is removed or reordered for single-mode lights. Added a test covering xy+hs in both expose orders, xy only, hs only, color_temp only, brightness only.pnpm run check,pnpm run test:coverage(827 tests, 100% coverage) pass.Open question for maintainers
This changes the discovery payload for every light that exposes both
xyandhs(Hue, IKEA, most modern RGB bulbs), so HA's default colour path for those switches fromxytohs. For bulbs whosehsimplementation is poor (some early Innr/tint, per the #6402 discussion) that could be a regression, though HA users can still callxy_colorexplicitly. Should this be gated behind a config option (e.g.homeassistant.legacy_color_modes: truekeeping the old XOR), or is the unconditional change acceptable? Happy to add the option if preferred.Follow-up (out of scope here)
The real fix for gamut clamping is gamut-aware conversion: read ZCL Color Control
numberOfPrimaries(0x0010) andprimaryN X/Y/Intensity(0x0011…) at configure time and, in zhctoZigbee.light_color, sendMoveToHueAndSaturationinstead of a clampedxywhen the target is out of gamut and the device supportshs. Alternatively publish the gamut in discovery, which needs an HA MQTT schema change.Related: Koenkk/zigbee-herdsman-converters#13100 (lists
hsfirst for the KAJPLATS/VARMBLIXT definitions so the current XOR pickshson Zigbee2MQTT versions without this change).Generated with Claude Code, reviewed and tested by me.