Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions tests/data/devices/ericsity-gl-c-009p-0x25013001.json
Original file line number Diff line number Diff line change
Expand Up @@ -371,16 +371,15 @@
"on": false,
"brightness": 254,
"xy_color": null,
"color_temp": 500,
"color_temp": null,
"effect_list": [
"off"
],
"effect": "off",
"supported_features": 40,
"color_mode": "color_temp",
"color_mode": "brightness",
"supported_color_modes": [
"brightness",
"color_temp",
"onoff"
],
"off_with_transition": false,
Expand Down
5 changes: 2 additions & 3 deletions tests/data/devices/gledopto-gl-c-009p-0x17013001.json
Original file line number Diff line number Diff line change
Expand Up @@ -340,16 +340,15 @@
"on": false,
"brightness": 143,
"xy_color": null,
"color_temp": 158,
"color_temp": null,
"effect_list": [
"off"
],
"effect": "off",
"supported_features": 40,
"color_mode": "color_temp",
"color_mode": "brightness",
"supported_color_modes": [
"brightness",
"color_temp",
"onoff"
],
"off_with_transition": false,
Expand Down
5 changes: 2 additions & 3 deletions tests/data/devices/gledopto-gl-sd-301p-0x26013001.json
Original file line number Diff line number Diff line change
Expand Up @@ -340,16 +340,15 @@
"on": true,
"brightness": 254,
"xy_color": null,
"color_temp": 495,
"color_temp": null,
"effect_list": [
"off"
],
"effect": "off",
"supported_features": 40,
"color_mode": "color_temp",
"color_mode": "brightness",
"supported_color_modes": [
"brightness",
"color_temp",
"onoff"
],
"off_with_transition": false,
Expand Down
3 changes: 1 addition & 2 deletions tests/data/devices/homr-hrmsn01.json
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@
0.0,
0.0
],
"color_temp": 0,
"color_temp": null,
"effect_list": [
"off"
],
Expand All @@ -497,7 +497,6 @@
"color_mode": "xy",
"supported_color_modes": [
"brightness",
"color_temp",
"onoff",
"xy"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,16 +350,15 @@
0.16398870832379644,
0.13199053940642405
],
"color_temp": 1901,
"color_temp": null,
"effect_list": [
"off"
],
"effect": "off",
"supported_features": 40,
"color_mode": "color_temp",
"color_mode": "xy",
"supported_color_modes": [
"brightness",
"color_temp",
"onoff",
"xy"
],
Expand Down
5 changes: 2 additions & 3 deletions tests/data/devices/sonoff-dongle-e-r.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,16 +472,15 @@
"on": false,
"brightness": 51,
"xy_color": null,
"color_temp": 17476,
"color_temp": null,
"effect_list": [
"off"
],
"effect": "off",
"supported_features": 40,
"color_mode": "color_temp",
"color_mode": "brightness",
"supported_color_modes": [
"brightness",
"color_temp",
"onoff"
],
"off_with_transition": false,
Expand Down
92 changes: 92 additions & 0 deletions tests/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -2248,6 +2248,98 @@ async def test_poll_updates_color_mode_on_dual_mode_light(
assert entity.state.color_temp is None


_ZHA_COLOR = (zha.PROFILE_ID, zha.DeviceType.COLOR_DIMMABLE_LIGHT)
_ZHA_EXTENDED = (zha.PROFILE_ID, zha.DeviceType.EXTENDED_COLOR_LIGHT)
_ZCL_CT: lighting.ColorMode = lighting.ColorMode.Color_temperature


def _create_color_light(
zha_gateway: Gateway,
*,
endpoint: tuple[int, int] = _ZHA_COLOR,
color_attributes: dict[str, Any] | None = None,
) -> tuple[Any, Any]:
profile_id, device_type = endpoint
zigpy_device = create_mock_zigpy_device(
zha_gateway,
{
1: {
**LIGHT_COLOR[1],
SIG_EP_PROFILE: profile_id,
SIG_EP_TYPE: device_type,
}
},
)
color_cluster = zigpy_device.endpoints[1].light_color
color_cluster.PLUGGED_ATTR_READS = color_attributes or {}
update_attribute_cache(color_cluster)
return zigpy_device, color_cluster


async def test_explicit_negative_color_capability_suppresses_color_temperature(
zha_gateway: Gateway,
) -> None:
"""Test an explicit bitmap without CT overrides fallback signals."""
zigpy_device, color_cluster = _create_color_light(
zha_gateway,
endpoint=_ZHA_EXTENDED,
color_attributes={
"color_capabilities": lighting.ColorCapabilities.XY_attributes,
"color_mode": _ZCL_CT,
"color_temperature": 250,
},
)
level_cluster = zigpy_device.endpoints[1].level
zha_device = await join_zigpy_device(zha_gateway, zigpy_device)
entity = get_entity(zha_device, platform=Platform.LIGHT)

assert entity.supported_color_modes == {ColorMode.XY}
assert entity.state.color_temp is None

level_cluster.PLUGGED_ATTR_READS = {"current_level": 180}
color_cluster.PLUGGED_ATTR_READS = {
"color_mode": lighting.ColorMode.X_and_Y,
"color_temperature": 275,
"current_x": 30000,
"current_y": 25000,
}
color_cluster.read_attributes.reset_mock()
await entity.async_update()

polled_attributes = color_cluster.read_attributes.await_args.args[0]
assert "color_temperature" not in polled_attributes
assert entity.state.color_mode == ColorMode.XY
assert entity.state.xy_color == (30000 / 65535, 25000 / 65535)
assert entity.state.brightness == 180


async def test_recompute_capabilities_clears_unsupported_color_temperature(
zha_gateway: Gateway,
) -> None:
"""Test recomputing capabilities clears stale color temperature state."""
zigpy_device, color_cluster = _create_color_light(
zha_gateway,
color_attributes={
"color_mode": _ZCL_CT,
"color_temperature": 250,
},
)
zha_device = await join_zigpy_device(zha_gateway, zigpy_device)
entity = get_entity(zha_device, platform=Platform.LIGHT)

assert entity.supported_color_modes == {ColorMode.COLOR_TEMP, ColorMode.XY}
assert entity.state.color_temp == 250

color_cluster._attr_cache.set_value(
lighting.Color.AttributeDefs.color_capabilities,
lighting.ColorCapabilities.XY_attributes,
)
entity.recompute_capabilities()

assert entity.supported_color_modes == {ColorMode.XY}
assert entity.state.color_temp is None


async def test_turn_on_cancellation_cleans_up_transition_flag(
zha_gateway: Gateway,
) -> None:
Expand Down
16 changes: 13 additions & 3 deletions zha/application/platforms/light/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,18 @@ def _color_xy_supported(self) -> bool:

@property
def _color_temp_supported(self) -> bool:
return (
Color.ColorCapabilities.Color_temperature in self._color_capabilities
) or self._color_temperature is not None
assert self._color_cluster is not None
capability_name = Color.AttributeDefs.color_capabilities.name
capabilities = self._color_cluster.get(capability_name)
if capabilities is None or self._color_cluster.is_attribute_unsupported(
capability_name
):
# Older lights may not implement the capability bitmap. Preserve
# their existing attribute-based detection in that case.
return self._color_temperature is not None
return Color.ColorCapabilities.Color_temperature in Color.ColorCapabilities(
capabilities
)

@property
def _color_loop_supported(self) -> bool:
Expand Down Expand Up @@ -1057,6 +1066,7 @@ def recompute_capabilities(self) -> None:
self._min_mireds: int = self._color_min_mireds
self._max_mireds: int = self._color_max_mireds

self._color_temp = None
if self._color_temp_supported:
self._internal_supported_color_modes.add(ColorMode.COLOR_TEMP)
self._color_temp = self._color_temperature
Expand Down
Loading