From 800bf926aa196cc077f90aba5a6c6a88200f0264 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 11 Apr 2022 08:36:40 +0200 Subject: [PATCH] Add attribute to zone indicating persons in zone (#69767) Co-authored-by: Paulus Schoutsen --- homeassistant/components/zone/__init__.py | 6 ++- homeassistant/const.py | 2 + tests/components/zone/test_init.py | 60 +++++++++++++++++++---- 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/zone/__init__.py b/homeassistant/components/zone/__init__.py index ebde3328c02..9dac47eaafb 100644 --- a/homeassistant/components/zone/__init__.py +++ b/homeassistant/components/zone/__init__.py @@ -13,6 +13,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_LATITUDE, ATTR_LONGITUDE, + ATTR_PERSONS, CONF_ICON, CONF_ID, CONF_LATITUDE, @@ -292,8 +293,8 @@ class Zone(entity.Entity): self.editable = True self._attrs: dict | None = None self._remove_listener: Callable[[], None] | None = None - self._generate_attrs() self._persons_in_zone: set[str] = set() + self._generate_attrs() @classmethod def from_yaml(cls, config: dict) -> Zone: @@ -346,6 +347,7 @@ class Zone(entity.Entity): self._persons_in_zone.remove(person_entity_id) if len(self._persons_in_zone) != cur_count: + self._generate_attrs() self.async_write_ha_state() async def async_added_to_hass(self) -> None: @@ -356,6 +358,7 @@ class Zone(entity.Entity): for person in persons: if self._state_is_in_zone(self.hass.states.get(person)): self._persons_in_zone.add(person) + self._generate_attrs() self.async_on_remove( event.async_track_state_change_filtered( @@ -373,6 +376,7 @@ class Zone(entity.Entity): ATTR_LONGITUDE: self._config[CONF_LONGITUDE], ATTR_RADIUS: self._config[CONF_RADIUS], ATTR_PASSIVE: self._config[CONF_PASSIVE], + ATTR_PERSONS: sorted(self._persons_in_zone), ATTR_EDITABLE: self.editable, } diff --git a/homeassistant/const.py b/homeassistant/const.py index 5f837c70597..765b7b0077a 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -456,6 +456,8 @@ ATTR_DEVICE_CLASS: Final = "device_class" # Temperature attribute ATTR_TEMPERATURE: Final = "temperature" +# Persons attribute +ATTR_PERSONS: Final = "persons" # #### UNITS OF MEASUREMENT #### # Apparent power units diff --git a/tests/components/zone/test_init.py b/tests/components/zone/test_init.py index 1e0c069e8ff..7a65d5c22dc 100644 --- a/tests/components/zone/test_init.py +++ b/tests/components/zone/test_init.py @@ -11,6 +11,7 @@ from homeassistant.const import ( ATTR_FRIENDLY_NAME, ATTR_ICON, ATTR_NAME, + ATTR_PERSONS, SERVICE_RELOAD, ) from homeassistant.core import Context @@ -519,6 +520,7 @@ async def test_state(hass): assert len(hass.states.async_entity_ids("zone")) == 2 state = hass.states.get("zone.test_zone") assert state.state == "0" + assert state.attributes[ATTR_PERSONS] == [] # Person entity enters zone hass.states.async_set( @@ -526,8 +528,16 @@ async def test_state(hass): "Test Zone", ) await hass.async_block_till_done() - assert hass.states.get("zone.test_zone").state == "1" - assert hass.states.get("zone.home").state == "0" + + state = hass.states.get("zone.test_zone") + assert state + assert state.state == "1" + assert state.attributes[ATTR_PERSONS] == ["person.person1"] + + state = hass.states.get("zone.home") + assert state + assert state.state == "0" + assert state.attributes[ATTR_PERSONS] == [] # Person entity enters zone (case insensitive) hass.states.async_set( @@ -535,8 +545,19 @@ async def test_state(hass): "TEST zone", ) await hass.async_block_till_done() - assert hass.states.get("zone.test_zone").state == "2" - assert hass.states.get("zone.home").state == "0" + + state = hass.states.get("zone.test_zone") + assert state + assert state.state == "2" + assert sorted(state.attributes[ATTR_PERSONS]) == [ + "person.person1", + "person.person2", + ] + + state = hass.states.get("zone.home") + assert state + assert state.state == "0" + assert state.attributes[ATTR_PERSONS] == [] # Person entity enters another zone hass.states.async_set( @@ -544,8 +565,16 @@ async def test_state(hass): "home", ) await hass.async_block_till_done() - assert hass.states.get("zone.test_zone").state == "1" - assert hass.states.get("zone.home").state == "1" + + state = hass.states.get("zone.test_zone") + assert state + assert state.state == "1" + assert state.attributes[ATTR_PERSONS] == ["person.person2"] + + state = hass.states.get("zone.home") + assert state + assert state.state == "1" + assert state.attributes[ATTR_PERSONS] == ["person.person1"] # Person entity enters not_home hass.states.async_set( @@ -553,11 +582,22 @@ async def test_state(hass): "not_home", ) await hass.async_block_till_done() - assert hass.states.get("zone.test_zone").state == "1" - assert hass.states.get("zone.home").state == "0" + + state = hass.states.get("zone.test_zone") + assert state + assert state.state == "1" + assert state.attributes[ATTR_PERSONS] == ["person.person2"] # Person entity removed hass.states.async_remove("person.person2") await hass.async_block_till_done() - assert hass.states.get("zone.test_zone").state == "0" - assert hass.states.get("zone.home").state == "0" + + state = hass.states.get("zone.test_zone") + assert state + assert state.state == "0" + assert state.attributes[ATTR_PERSONS] == [] + + state = hass.states.get("zone.home") + assert state + assert state.state == "0" + assert state.attributes[ATTR_PERSONS] == []