Add attribute to zone indicating persons in zone (#69767)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
32a10648a5
commit
800bf926aa
3 changed files with 57 additions and 11 deletions
|
@ -13,6 +13,7 @@ from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
ATTR_LATITUDE,
|
ATTR_LATITUDE,
|
||||||
ATTR_LONGITUDE,
|
ATTR_LONGITUDE,
|
||||||
|
ATTR_PERSONS,
|
||||||
CONF_ICON,
|
CONF_ICON,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
|
@ -292,8 +293,8 @@ class Zone(entity.Entity):
|
||||||
self.editable = True
|
self.editable = True
|
||||||
self._attrs: dict | None = None
|
self._attrs: dict | None = None
|
||||||
self._remove_listener: Callable[[], None] | None = None
|
self._remove_listener: Callable[[], None] | None = None
|
||||||
self._generate_attrs()
|
|
||||||
self._persons_in_zone: set[str] = set()
|
self._persons_in_zone: set[str] = set()
|
||||||
|
self._generate_attrs()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_yaml(cls, config: dict) -> Zone:
|
def from_yaml(cls, config: dict) -> Zone:
|
||||||
|
@ -346,6 +347,7 @@ class Zone(entity.Entity):
|
||||||
self._persons_in_zone.remove(person_entity_id)
|
self._persons_in_zone.remove(person_entity_id)
|
||||||
|
|
||||||
if len(self._persons_in_zone) != cur_count:
|
if len(self._persons_in_zone) != cur_count:
|
||||||
|
self._generate_attrs()
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
async def async_added_to_hass(self) -> None:
|
async def async_added_to_hass(self) -> None:
|
||||||
|
@ -356,6 +358,7 @@ class Zone(entity.Entity):
|
||||||
for person in persons:
|
for person in persons:
|
||||||
if self._state_is_in_zone(self.hass.states.get(person)):
|
if self._state_is_in_zone(self.hass.states.get(person)):
|
||||||
self._persons_in_zone.add(person)
|
self._persons_in_zone.add(person)
|
||||||
|
self._generate_attrs()
|
||||||
|
|
||||||
self.async_on_remove(
|
self.async_on_remove(
|
||||||
event.async_track_state_change_filtered(
|
event.async_track_state_change_filtered(
|
||||||
|
@ -373,6 +376,7 @@ class Zone(entity.Entity):
|
||||||
ATTR_LONGITUDE: self._config[CONF_LONGITUDE],
|
ATTR_LONGITUDE: self._config[CONF_LONGITUDE],
|
||||||
ATTR_RADIUS: self._config[CONF_RADIUS],
|
ATTR_RADIUS: self._config[CONF_RADIUS],
|
||||||
ATTR_PASSIVE: self._config[CONF_PASSIVE],
|
ATTR_PASSIVE: self._config[CONF_PASSIVE],
|
||||||
|
ATTR_PERSONS: sorted(self._persons_in_zone),
|
||||||
ATTR_EDITABLE: self.editable,
|
ATTR_EDITABLE: self.editable,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -456,6 +456,8 @@ ATTR_DEVICE_CLASS: Final = "device_class"
|
||||||
# Temperature attribute
|
# Temperature attribute
|
||||||
ATTR_TEMPERATURE: Final = "temperature"
|
ATTR_TEMPERATURE: Final = "temperature"
|
||||||
|
|
||||||
|
# Persons attribute
|
||||||
|
ATTR_PERSONS: Final = "persons"
|
||||||
|
|
||||||
# #### UNITS OF MEASUREMENT ####
|
# #### UNITS OF MEASUREMENT ####
|
||||||
# Apparent power units
|
# Apparent power units
|
||||||
|
|
|
@ -11,6 +11,7 @@ from homeassistant.const import (
|
||||||
ATTR_FRIENDLY_NAME,
|
ATTR_FRIENDLY_NAME,
|
||||||
ATTR_ICON,
|
ATTR_ICON,
|
||||||
ATTR_NAME,
|
ATTR_NAME,
|
||||||
|
ATTR_PERSONS,
|
||||||
SERVICE_RELOAD,
|
SERVICE_RELOAD,
|
||||||
)
|
)
|
||||||
from homeassistant.core import Context
|
from homeassistant.core import Context
|
||||||
|
@ -519,6 +520,7 @@ async def test_state(hass):
|
||||||
assert len(hass.states.async_entity_ids("zone")) == 2
|
assert len(hass.states.async_entity_ids("zone")) == 2
|
||||||
state = hass.states.get("zone.test_zone")
|
state = hass.states.get("zone.test_zone")
|
||||||
assert state.state == "0"
|
assert state.state == "0"
|
||||||
|
assert state.attributes[ATTR_PERSONS] == []
|
||||||
|
|
||||||
# Person entity enters zone
|
# Person entity enters zone
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -526,8 +528,16 @@ async def test_state(hass):
|
||||||
"Test Zone",
|
"Test Zone",
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
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)
|
# Person entity enters zone (case insensitive)
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -535,8 +545,19 @@ async def test_state(hass):
|
||||||
"TEST zone",
|
"TEST zone",
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
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
|
# Person entity enters another zone
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -544,8 +565,16 @@ async def test_state(hass):
|
||||||
"home",
|
"home",
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
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
|
# Person entity enters not_home
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
|
@ -553,11 +582,22 @@ async def test_state(hass):
|
||||||
"not_home",
|
"not_home",
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
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
|
# Person entity removed
|
||||||
hass.states.async_remove("person.person2")
|
hass.states.async_remove("person.person2")
|
||||||
await hass.async_block_till_done()
|
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] == []
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue