mirror of
https://github.com/home-assistant/core.git
synced 2025-04-28 11:17:53 +00:00
Fix ZHA lighting initial hue/saturation attribute read (#77727)
* Handle the case of `current_hue` being `None` * WIP unit tests
This commit is contained in:
parent
2cfdc15c38
commit
4076f8b94e
@ -612,16 +612,18 @@ class Light(BaseLight, ZhaEntity):
|
|||||||
and self._color_channel.enhanced_current_hue is not None
|
and self._color_channel.enhanced_current_hue is not None
|
||||||
):
|
):
|
||||||
curr_hue = self._color_channel.enhanced_current_hue * 65535 / 360
|
curr_hue = self._color_channel.enhanced_current_hue * 65535 / 360
|
||||||
else:
|
elif self._color_channel.current_hue is not None:
|
||||||
curr_hue = self._color_channel.current_hue * 254 / 360
|
curr_hue = self._color_channel.current_hue * 254 / 360
|
||||||
curr_saturation = self._color_channel.current_saturation
|
|
||||||
if curr_hue is not None and curr_saturation is not None:
|
|
||||||
self._attr_hs_color = (
|
|
||||||
int(curr_hue),
|
|
||||||
int(curr_saturation * 2.54),
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
self._attr_hs_color = (0, 0)
|
curr_hue = 0
|
||||||
|
|
||||||
|
if (curr_saturation := self._color_channel.current_saturation) is None:
|
||||||
|
curr_saturation = 0
|
||||||
|
|
||||||
|
self._attr_hs_color = (
|
||||||
|
int(curr_hue),
|
||||||
|
int(curr_saturation * 2.54),
|
||||||
|
)
|
||||||
|
|
||||||
if self._color_channel.color_loop_supported:
|
if self._color_channel.color_loop_supported:
|
||||||
self._attr_supported_features |= light.LightEntityFeature.EFFECT
|
self._attr_supported_features |= light.LightEntityFeature.EFFECT
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
import math
|
import math
|
||||||
from unittest.mock import AsyncMock, Mock
|
from typing import Any
|
||||||
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
import zigpy.zcl
|
import zigpy.zcl
|
||||||
import zigpy.zcl.foundation as zcl_f
|
import zigpy.zcl.foundation as zcl_f
|
||||||
|
|
||||||
import homeassistant.components.zha.core.const as zha_const
|
import homeassistant.components.zha.core.const as zha_const
|
||||||
|
from homeassistant.components.zha.core.helpers import async_get_zha_config_value
|
||||||
from homeassistant.helpers import entity_registry
|
from homeassistant.helpers import entity_registry
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
@ -243,3 +245,20 @@ async def async_shift_time(hass):
|
|||||||
next_update = dt_util.utcnow() + timedelta(seconds=11)
|
next_update = dt_util.utcnow() + timedelta(seconds=11)
|
||||||
async_fire_time_changed(hass, next_update)
|
async_fire_time_changed(hass, next_update)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
|
def patch_zha_config(component: str, overrides: dict[tuple[str, str], Any]):
|
||||||
|
"""Patch the ZHA custom configuration defaults."""
|
||||||
|
|
||||||
|
def new_get_config(config_entry, section, config_key, default):
|
||||||
|
if (section, config_key) in overrides:
|
||||||
|
return overrides[section, config_key]
|
||||||
|
else:
|
||||||
|
return async_get_zha_config_value(
|
||||||
|
config_entry, section, config_key, default
|
||||||
|
)
|
||||||
|
|
||||||
|
return patch(
|
||||||
|
f"homeassistant.components.zha.{component}.async_get_zha_config_value",
|
||||||
|
side_effect=new_get_config,
|
||||||
|
)
|
||||||
|
@ -14,6 +14,10 @@ from homeassistant.components.light import (
|
|||||||
FLASH_SHORT,
|
FLASH_SHORT,
|
||||||
ColorMode,
|
ColorMode,
|
||||||
)
|
)
|
||||||
|
from homeassistant.components.zha.core.const import (
|
||||||
|
CONF_ALWAYS_PREFER_XY_COLOR_MODE,
|
||||||
|
ZHA_OPTIONS,
|
||||||
|
)
|
||||||
from homeassistant.components.zha.core.group import GroupMember
|
from homeassistant.components.zha.core.group import GroupMember
|
||||||
from homeassistant.components.zha.light import FLASH_EFFECTS
|
from homeassistant.components.zha.light import FLASH_EFFECTS
|
||||||
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, Platform
|
from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, Platform
|
||||||
@ -26,6 +30,7 @@ from .common import (
|
|||||||
async_test_rejoin,
|
async_test_rejoin,
|
||||||
find_entity_id,
|
find_entity_id,
|
||||||
get_zha_gateway,
|
get_zha_gateway,
|
||||||
|
patch_zha_config,
|
||||||
send_attributes_report,
|
send_attributes_report,
|
||||||
)
|
)
|
||||||
from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
|
from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_PROFILE, SIG_EP_TYPE
|
||||||
@ -340,7 +345,11 @@ async def test_light(
|
|||||||
if cluster_identify:
|
if cluster_identify:
|
||||||
await async_test_flash_from_hass(hass, cluster_identify, entity_id, FLASH_SHORT)
|
await async_test_flash_from_hass(hass, cluster_identify, entity_id, FLASH_SHORT)
|
||||||
|
|
||||||
# test turning the lights on and off from the HA
|
# test long flashing the lights from the HA
|
||||||
|
if cluster_identify:
|
||||||
|
await async_test_flash_from_hass(hass, cluster_identify, entity_id, FLASH_LONG)
|
||||||
|
|
||||||
|
# test dimming the lights on and off from the HA
|
||||||
if cluster_level:
|
if cluster_level:
|
||||||
await async_test_level_on_off_from_hass(
|
await async_test_level_on_off_from_hass(
|
||||||
hass, cluster_on_off, cluster_level, entity_id
|
hass, cluster_on_off, cluster_level, entity_id
|
||||||
@ -355,16 +364,82 @@ async def test_light(
|
|||||||
|
|
||||||
# test rejoin
|
# test rejoin
|
||||||
await async_test_off_from_hass(hass, cluster_on_off, entity_id)
|
await async_test_off_from_hass(hass, cluster_on_off, entity_id)
|
||||||
clusters = [cluster_on_off]
|
clusters = [c for c in (cluster_on_off, cluster_level, cluster_color) if c]
|
||||||
if cluster_level:
|
|
||||||
clusters.append(cluster_level)
|
|
||||||
if cluster_color:
|
|
||||||
clusters.append(cluster_color)
|
|
||||||
await async_test_rejoin(hass, zigpy_device, clusters, reporting)
|
await async_test_rejoin(hass, zigpy_device, clusters, reporting)
|
||||||
|
|
||||||
# test long flashing the lights from the HA
|
|
||||||
if cluster_identify:
|
@pytest.mark.parametrize(
|
||||||
await async_test_flash_from_hass(hass, cluster_identify, entity_id, FLASH_LONG)
|
"plugged_attr_reads, config_override, expected_state",
|
||||||
|
[
|
||||||
|
# HS light without cached hue or saturation
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"color_capabilities": (
|
||||||
|
lighting.Color.ColorCapabilities.Hue_and_saturation
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{(ZHA_OPTIONS, CONF_ALWAYS_PREFER_XY_COLOR_MODE): False},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
# HS light with cached hue
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"color_capabilities": (
|
||||||
|
lighting.Color.ColorCapabilities.Hue_and_saturation
|
||||||
|
),
|
||||||
|
"current_hue": 100,
|
||||||
|
},
|
||||||
|
{(ZHA_OPTIONS, CONF_ALWAYS_PREFER_XY_COLOR_MODE): False},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
# HS light with cached saturation
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"color_capabilities": (
|
||||||
|
lighting.Color.ColorCapabilities.Hue_and_saturation
|
||||||
|
),
|
||||||
|
"current_saturation": 100,
|
||||||
|
},
|
||||||
|
{(ZHA_OPTIONS, CONF_ALWAYS_PREFER_XY_COLOR_MODE): False},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
# HS light with both
|
||||||
|
(
|
||||||
|
{
|
||||||
|
"color_capabilities": (
|
||||||
|
lighting.Color.ColorCapabilities.Hue_and_saturation
|
||||||
|
),
|
||||||
|
"current_hue": 100,
|
||||||
|
"current_saturation": 100,
|
||||||
|
},
|
||||||
|
{(ZHA_OPTIONS, CONF_ALWAYS_PREFER_XY_COLOR_MODE): False},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_light_initialization(
|
||||||
|
hass,
|
||||||
|
zigpy_device_mock,
|
||||||
|
zha_device_joined_restored,
|
||||||
|
plugged_attr_reads,
|
||||||
|
config_override,
|
||||||
|
expected_state,
|
||||||
|
):
|
||||||
|
"""Test zha light initialization with cached attributes and color modes."""
|
||||||
|
|
||||||
|
# create zigpy devices
|
||||||
|
zigpy_device = zigpy_device_mock(LIGHT_COLOR)
|
||||||
|
|
||||||
|
# mock attribute reads
|
||||||
|
zigpy_device.endpoints[1].light_color.PLUGGED_ATTR_READS = plugged_attr_reads
|
||||||
|
|
||||||
|
with patch_zha_config("light", config_override):
|
||||||
|
zha_device = await zha_device_joined_restored(zigpy_device)
|
||||||
|
entity_id = await find_entity_id(Platform.LIGHT, zha_device, hass)
|
||||||
|
|
||||||
|
assert entity_id is not None
|
||||||
|
|
||||||
|
# TODO ensure hue and saturation are properly set on startup
|
||||||
|
|
||||||
|
|
||||||
@patch(
|
@patch(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user