From c1962a4895d2e3f96d48ffa60e9720b148bebc12 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Fri, 10 Apr 2020 23:19:17 -0400 Subject: [PATCH] Read min and max mireds from ZHA lights (#33983) * implement min and max mireds * remove unnecessary else * additional light test * add test to appease the codecov god * change defaults --- .../components/zha/core/channels/lighting.py | 24 ++++++++++++++++--- homeassistant/components/zha/light.py | 17 +++++++++++-- tests/components/zha/test_discover.py | 9 +++++++ tests/components/zha/test_light.py | 9 +++++++ 4 files changed, 54 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/zha/core/channels/lighting.py b/homeassistant/components/zha/core/channels/lighting.py index 9721bee9014..2b80a1092bb 100644 --- a/homeassistant/components/zha/core/channels/lighting.py +++ b/homeassistant/components/zha/core/channels/lighting.py @@ -41,6 +41,18 @@ class ColorChannel(ZigbeeChannel): """Initialize ColorChannel.""" super().__init__(cluster, ch_pool) self._color_capabilities = None + self._min_mireds = 153 + self._max_mireds = 500 + + @property + def min_mireds(self): + """Return the coldest color_temp that this channel supports.""" + return self._min_mireds + + @property + def max_mireds(self): + """Return the warmest color_temp that this channel supports.""" + return self._max_mireds def get_color_capabilities(self): """Return the color capabilities.""" @@ -59,9 +71,15 @@ class ColorChannel(ZigbeeChannel): async def fetch_color_capabilities(self, from_cache): """Get the color configuration.""" - capabilities = await self.get_attribute_value( - "color_capabilities", from_cache=from_cache - ) + attributes = [ + "color_temp_physical_min", + "color_temp_physical_max", + "color_capabilities", + ] + results = await self.get_attributes(attributes, from_cache=from_cache) + capabilities = results.get("color_capabilities") + self._min_mireds = results.get("color_temp_physical_min", 153) + self._max_mireds = results.get("color_temp_physical_max", 500) if capabilities is None: # ZCL Version 4 devices don't support the color_capabilities diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index c6ec5c2ccf9..b05e4b7bee0 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -108,7 +108,7 @@ class BaseLight(LogMixin, light.Light): self._off_brightness: Optional[int] = None self._hs_color: Optional[Tuple[float, float]] = None self._color_temp: Optional[int] = None - self._min_mireds: Optional[int] = 154 + self._min_mireds: Optional[int] = 153 self._max_mireds: Optional[int] = 500 self._white_value: Optional[int] = None self._effect_list: Optional[List[str]] = None @@ -138,6 +138,16 @@ class BaseLight(LogMixin, light.Light): """Return the brightness of this light.""" return self._brightness + @property + def min_mireds(self): + """Return the coldest color_temp that this light supports.""" + return self._min_mireds + + @property + def max_mireds(self): + """Return the warmest color_temp that this light supports.""" + return self._max_mireds + def set_level(self, value): """Set the brightness of this light between 0..254. @@ -316,6 +326,9 @@ class Light(BaseLight, ZhaEntity): self._level_channel = self.cluster_channels.get(CHANNEL_LEVEL) self._color_channel = self.cluster_channels.get(CHANNEL_COLOR) self._identify_channel = self.zha_device.channels.identify_ch + if self._color_channel: + self._min_mireds: Optional[int] = self._color_channel.min_mireds + self._max_mireds: Optional[int] = self._color_channel.max_mireds self._cancel_refresh_handle = None effect_list = [] @@ -501,7 +514,7 @@ class LightGroup(BaseLight, ZhaGroupEntity): self._color_temp = helpers.reduce_attribute(on_states, ATTR_COLOR_TEMP) self._min_mireds = helpers.reduce_attribute( - states, ATTR_MIN_MIREDS, default=154, reduce=min + states, ATTR_MIN_MIREDS, default=153, reduce=min ) self._max_mireds = helpers.reduce_attribute( states, ATTR_MAX_MIREDS, default=500, reduce=max diff --git a/tests/components/zha/test_discover.py b/tests/components/zha/test_discover.py index 5996ca467f7..8b1ce502a78 100644 --- a/tests/components/zha/test_discover.py +++ b/tests/components/zha/test_discover.py @@ -392,3 +392,12 @@ async def test_device_override(hass, zigpy_device_mock, setup_zha, override, ent await zha_gateway.async_device_initialized(zigpy_device) await hass.async_block_till_done() assert hass.states.get(entity_id) is not None + + +async def test_group_probe_cleanup_called(hass, setup_zha, config_entry): + """Test cleanup happens when zha is unloaded.""" + await setup_zha() + disc.GROUP_PROBE.cleanup = mock.Mock(wraps=disc.GROUP_PROBE.cleanup) + await config_entry.async_unload(hass) + await hass.async_block_till_done() + disc.GROUP_PROBE.cleanup.assert_called() diff --git a/tests/components/zha/test_light.py b/tests/components/zha/test_light.py index f297bfa5bf0..03c29283c20 100644 --- a/tests/components/zha/test_light.py +++ b/tests/components/zha/test_light.py @@ -552,6 +552,15 @@ async def async_test_zha_group_light_entity( await dev3_cluster_on_off.on() assert hass.states.get(entity_id).state == STATE_ON + # add a 3rd member and ensure we still have an entity and we track the new one + await dev1_cluster_on_off.off() + await dev3_cluster_on_off.off() + assert hass.states.get(entity_id).state == STATE_OFF + # this will test that _reprobe_group is used correctly + await zha_group.async_add_members([device_light_2.ieee]) + await dev2_cluster_on_off.on() + assert hass.states.get(entity_id).state == STATE_ON + # remove the group and ensure that there is no entity and that the entity registry is cleaned up assert zha_gateway.ha_entity_registry.async_get(entity_id) is not None await zha_gateway.async_remove_zigpy_group(zha_group.group_id)