Skip to content

feat(homeassistant): advertise both hs and xy color modes when a light exposes both - #33025

Open
Mihonarium wants to merge 1 commit into
Koenkk:devfrom
Mihonarium:feat/ha-advertise-hs-and-xy
Open

Mihonarium wants to merge 1 commit into
Koenkk:devfrom
Mihonarium:feat/ha-advertise-hs-and-xy

Conversation

@Mihonarium

Copy link
Copy Markdown
Contributor

What

Home Assistant discovery currently advertises only one of xy/hs per light: xy wins unless the device definition lists color_hs before color_xy (the preferHS path). This PR advertises both whenever the light exposes both, and removes preferHS (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 to xy ≈ (0.7006, 0.2993), which is outside the bulb's LED gamut; the firmware clamps it silently and the bulb is pink. The currentX/currentY readback 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}} to zigbee2mqtt/<device>/set gives correct red, because hs is 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): an rgb_color/hs_color request lands in color_mode: "hs" (HA prefers hs over xy when converting), while an explicit xy_color request passes through as xy. The MQTT JSON light schema (mqtt/light/schema_json.py, _update_color) reads color_mode from every state message and validates it against supported_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_mode support was new: @jasperro reported that after switching an Osram bulb to hs, HA "prioritizes XY coloring" when both were present, and @Koenkk deferred it to home-assistant/architecture#519, which is exactly the color_mode mechanism HA has shipped since 2021.4. preferHS was then added in 8e72b3b as a per-device escape hatch. In #22905 (2024) Koenkk noted "Z2M only exposes either hs or xy to Home Assistant since HA cannot handle both hs and xy at 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 a color_mode: "hs" state (e.g. after a remote or a group set hue/saturation) for a light that was discovered with xy only (#7736, #22905, #25733).

Before / after

KAJPLATS GU10 CWS 470lm (LED2410R5), homeassistant/light/<ieee>/light/config, unchanged keys omitted:

-  "supported_color_modes": ["xy", "color_temp"],
+  "supported_color_modes": ["xy", "hs", "color_temp"],

Group of one Hue Go (7146060PH, exposes color_xy + color_hs) and one TRADFRI WS bulb (color_temp only), homeassistant/light/<group>/light/config, from the updated test fixture:

-  "supported_color_modes": ["xy", "color_temp"],
+  "supported_color_modes": ["xy", "hs", "color_temp"],

Things I checked

  • color_sync is a set-time option in zigbee-herdsman-converters (toZigbee.light_color*) and does not touch discovery.
  • No other place in the repo assumes a light has exactly one of xy/hs in its discovery payload (supported_color_modes is only written here). The hueh, saturations state copy stays as is.
  • All fixture changes in test/extensions/homeassistant.test.ts add "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 xy and hs (Hue, IKEA, most modern RGB bulbs), so HA's default colour path for those switches from xy to hs. For bulbs whose hs implementation is poor (some early Innr/tint, per the #6402 discussion) that could be a regression, though HA users can still call xy_color explicitly. Should this be gated behind a config option (e.g. homeassistant.legacy_color_modes: true keeping 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) and primaryN X/Y/Intensity (0x0011…) at configure time and, in zhc toZigbee.light_color, send MoveToHueAndSaturation instead of a clamped xy when the target is out of gamut and the device supports hs. Alternatively publish the gamut in discovery, which needs an HA MQTT schema change.

Related: Koenkk/zigbee-herdsman-converters#13100 (lists hs first for the KAJPLATS/VARMBLIXT definitions so the current XOR picks hs on Zigbee2MQTT versions without this change).


Generated with Claude Code, reviewed and tested by me.

@Koenkk

Koenkk commented Sep 4, 2026

Copy link
Copy Markdown
Owner

This change is quite risky, I think it's better to expose only the "best" color mode to HA.

@luar123

luar123 commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Related thought:
If modern lights work better with hs (do they? I am not sure) it should be the default in generateDefinitions:
https://github.com/Koenkk/zigbee-herdsman-converters/blob/e2aa7143427f423c5a8ebe0d8abd1adbd6bf26c7/src/lib/generateDefinition.ts#L423

@Koenkk

Koenkk commented Sep 6, 2026

Copy link
Copy Markdown
Owner

If modern lights work better with hs (do they? I am not sure)

I'm not sure, I think most light work good with XY, and very few work better with HS.

@Mihonarium

Copy link
Copy Markdown
Contributor Author

(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.)

@Koenkk

Koenkk commented Sep 8, 2026

Copy link
Copy Markdown
Owner

If it does not work with the applyRedFix, than we should put hs as first in the list in the zigbee-herdsman-converters definition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants