From 8b63e22c993ab365fbb966a5d871ac78f2ef24a3 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 14 Nov 2020 10:46:24 -1000 Subject: [PATCH] Bypass the slow update warning for group updates (#43209) --- homeassistant/components/group/__init__.py | 11 +++++-- homeassistant/components/group/cover.py | 8 +++++ tests/components/group/test_cover.py | 38 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/group/__init__.py b/homeassistant/components/group/__init__.py index 4a0050868d9..32a9bd41014 100644 --- a/homeassistant/components/group/__init__.py +++ b/homeassistant/components/group/__init__.py @@ -1,4 +1,5 @@ """Provide the functionality to group entities.""" +from abc import abstractmethod import asyncio from contextvars import ContextVar import logging @@ -398,7 +399,8 @@ class GroupEntity(Entity): assert self.hass is not None async def _update_at_start(_): - await self.async_update_ha_state(True) + await self.async_update() + self.async_write_ha_state() self.hass.bus.async_listen_once(EVENT_HOMEASSISTANT_START, _update_at_start) @@ -409,7 +411,12 @@ class GroupEntity(Entity): if self.hass.state != CoreState.running: return - await self.async_update_ha_state(True) + await self.async_update() + self.async_write_ha_state() + + @abstractmethod + async def async_update(self) -> None: + """Abstract method to update the entity.""" class Group(Entity): diff --git a/homeassistant/components/group/cover.py b/homeassistant/components/group/cover.py index 25a8665db9f..b52546c48d7 100644 --- a/homeassistant/components/group/cover.py +++ b/homeassistant/components/group/cover.py @@ -150,6 +150,8 @@ class CoverGroup(GroupEntity, CoverEntity): """Register listeners.""" for entity_id in self._entities: new_state = self.hass.states.get(entity_id) + if new_state is None: + continue await self.async_update_supported_features( entity_id, new_state, update_state=False ) @@ -307,6 +309,8 @@ class CoverGroup(GroupEntity, CoverEntity): self._cover_position = 0 if self.is_closed else 100 for entity_id in self._covers[KEY_POSITION]: state = self.hass.states.get(entity_id) + if state is None: + continue pos = state.attributes.get(ATTR_CURRENT_POSITION) if position == -1: position = pos @@ -323,6 +327,8 @@ class CoverGroup(GroupEntity, CoverEntity): self._tilt_position = 100 for entity_id in self._tilts[KEY_POSITION]: state = self.hass.states.get(entity_id) + if state is None: + continue pos = state.attributes.get(ATTR_CURRENT_TILT_POSITION) if position == -1: position = pos @@ -351,6 +357,8 @@ class CoverGroup(GroupEntity, CoverEntity): if not self._assumed_state: for entity_id in self._entities: state = self.hass.states.get(entity_id) + if state is None: + continue if state and state.attributes.get(ATTR_ASSUMED_STATE): self._assumed_state = True break diff --git a/tests/components/group/test_cover.py b/tests/components/group/test_cover.py index 2ffe02570c9..59bde36b46b 100644 --- a/tests/components/group/test_cover.py +++ b/tests/components/group/test_cover.py @@ -63,6 +63,16 @@ CONFIG_POS = { ] } +CONFIG_TILT_ONLY = { + DOMAIN: [ + {"platform": "demo"}, + { + "platform": "group", + CONF_ENTITIES: [DEMO_COVER_TILT, DEMO_TILT], + }, + ] +} + CONFIG_ATTRIBUTES = { DOMAIN: { "platform": "group", @@ -211,6 +221,34 @@ async def test_attributes(hass, setup_comp): assert state.attributes[ATTR_ASSUMED_STATE] is True +@pytest.mark.parametrize("config_count", [(CONFIG_TILT_ONLY, 2)]) +async def test_cover_that_only_supports_tilt_removed(hass, setup_comp): + """Test removing a cover that support tilt.""" + hass.states.async_set( + DEMO_COVER_TILT, + STATE_OPEN, + {ATTR_SUPPORTED_FEATURES: 128, ATTR_CURRENT_TILT_POSITION: 60}, + ) + hass.states.async_set( + DEMO_TILT, + STATE_OPEN, + {ATTR_SUPPORTED_FEATURES: 128, ATTR_CURRENT_TILT_POSITION: 60}, + ) + state = hass.states.get(COVER_GROUP) + assert state.state == STATE_OPEN + assert state.attributes[ATTR_FRIENDLY_NAME] == DEFAULT_NAME + assert state.attributes[ATTR_ENTITY_ID] == [ + DEMO_COVER_TILT, + DEMO_TILT, + ] + assert ATTR_ASSUMED_STATE not in state.attributes + assert ATTR_CURRENT_TILT_POSITION in state.attributes + + hass.states.async_remove(DEMO_COVER_TILT) + hass.states.async_set(DEMO_TILT, STATE_CLOSED) + await hass.async_block_till_done() + + @pytest.mark.parametrize("config_count", [(CONFIG_ALL, 2)]) async def test_open_covers(hass, setup_comp): """Test open cover function."""