Correct zone state (#65040)

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Erik Montnemery 2022-01-27 19:01:09 +01:00 committed by Paulus Schoutsen
parent 25ffda7cd4
commit a768de51c0
3 changed files with 72 additions and 67 deletions

View file

@ -224,6 +224,7 @@ class TrackerEntity(BaseTrackerEntity):
"""Return the device state attributes."""
attr: dict[str, StateType] = {}
attr.update(super().state_attributes)
if self.latitude is not None and self.longitude is not None:
attr[ATTR_LATITUDE] = self.latitude
attr[ATTR_LONGITUDE] = self.longitude

View file

@ -10,6 +10,7 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import (
ATTR_EDITABLE,
ATTR_GPS_ACCURACY,
ATTR_LATITUDE,
ATTR_LONGITUDE,
CONF_ICON,
@ -22,14 +23,7 @@ from homeassistant.const import (
SERVICE_RELOAD,
STATE_UNAVAILABLE,
)
from homeassistant.core import (
Event,
HomeAssistant,
ServiceCall,
State,
callback,
split_entity_id,
)
from homeassistant.core import Event, HomeAssistant, ServiceCall, State, callback
from homeassistant.helpers import (
collection,
config_validation as cv,
@ -346,10 +340,20 @@ class Zone(entity.Entity):
@callback
def _person_state_change_listener(self, evt: Event) -> None:
object_id = split_entity_id(self.entity_id)[1]
person_entity_id = evt.data["entity_id"]
cur_count = len(self._persons_in_zone)
if evt.data["new_state"] and evt.data["new_state"].state == object_id:
if (
(state := evt.data["new_state"])
and (latitude := state.attributes.get(ATTR_LATITUDE)) is not None
and (longitude := state.attributes.get(ATTR_LONGITUDE)) is not None
and (accuracy := state.attributes.get(ATTR_GPS_ACCURACY)) is not None
and (
zone_state := async_active_zone(
self.hass, latitude, longitude, accuracy
)
)
and zone_state.entity_id == self.entity_id
):
self._persons_in_zone.add(person_entity_id)
elif person_entity_id in self._persons_in_zone:
self._persons_in_zone.remove(person_entity_id)
@ -362,10 +366,17 @@ class Zone(entity.Entity):
await super().async_added_to_hass()
person_domain = "person" # avoid circular import
persons = self.hass.states.async_entity_ids(person_domain)
object_id = split_entity_id(self.entity_id)[1]
for person in persons:
state = self.hass.states.get(person)
if state and state.state == object_id:
if (
state is None
or (latitude := state.attributes.get(ATTR_LATITUDE)) is None
or (longitude := state.attributes.get(ATTR_LONGITUDE)) is None
or (accuracy := state.attributes.get(ATTR_GPS_ACCURACY)) is None
):
continue
zone_state = async_active_zone(self.hass, latitude, longitude, accuracy)
if zone_state is not None and zone_state.entity_id == self.entity_id:
self._persons_in_zone.add(person)
self.async_on_remove(

View file

@ -512,7 +512,7 @@ async def test_state(hass):
"latitude": 32.880837,
"longitude": -117.237561,
"radius": 250,
"passive": True,
"passive": False,
}
assert await setup.async_setup_component(hass, zone.DOMAIN, {"zone": info})
@ -521,28 +521,40 @@ async def test_state(hass):
assert state.state == "0"
# Person entity enters zone
hass.states.async_set("person.person1", "test_zone")
hass.states.async_set(
"person.person1",
"Test Zone",
{"latitude": 32.880837, "longitude": -117.237561, "gps_accuracy": 0},
)
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "1"
assert hass.states.get("zone.test_zone").state == "1"
assert hass.states.get("zone.home").state == "0"
# Person entity enters zone
hass.states.async_set("person.person2", "test_zone")
hass.states.async_set(
"person.person2",
"Test Zone",
{"latitude": 32.880837, "longitude": -117.237561, "gps_accuracy": 0},
)
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "2"
assert hass.states.get("zone.test_zone").state == "2"
assert hass.states.get("zone.home").state == "0"
# Person entity enters another zone
hass.states.async_set("person.person1", "home")
hass.states.async_set(
"person.person1",
"home",
{"latitude": 32.87336, "longitude": -117.22743, "gps_accuracy": 0},
)
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "1"
assert hass.states.get("zone.test_zone").state == "1"
assert hass.states.get("zone.home").state == "1"
# Person entity removed
hass.states.async_remove("person.person2")
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "0"
assert hass.states.get("zone.test_zone").state == "0"
assert hass.states.get("zone.home").state == "1"
async def test_state_2(hass):
@ -555,7 +567,7 @@ async def test_state_2(hass):
"latitude": 32.880837,
"longitude": -117.237561,
"radius": 250,
"passive": True,
"passive": False,
}
assert await setup.async_setup_component(hass, zone.DOMAIN, {"zone": info})
@ -564,56 +576,37 @@ async def test_state_2(hass):
assert state.state == "0"
# Person entity enters zone
hass.states.async_set("person.person1", "test_zone")
hass.states.async_set(
"person.person1",
"Test Zone",
{"latitude": 32.880837, "longitude": -117.237561, "gps_accuracy": 0},
)
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "1"
assert hass.states.get("zone.test_zone").state == "1"
assert hass.states.get("zone.home").state == "0"
# Person entity enters zone
hass.states.async_set("person.person2", "test_zone")
hass.states.async_set(
"person.person2",
"Test Zone",
{"latitude": 32.880837, "longitude": -117.237561, "gps_accuracy": 0},
)
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "2"
assert hass.states.get("zone.test_zone").state == "2"
assert hass.states.get("zone.home").state == "0"
# Person entity enters another zone
hass.states.async_set("person.person1", "home")
hass.states.async_set(
"person.person1",
"home",
{"latitude": 32.87336, "longitude": -117.22743, "gps_accuracy": 0},
)
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "1"
assert hass.states.get("zone.test_zone").state == "1"
assert hass.states.get("zone.home").state == "1"
# Person entity removed
hass.states.async_remove("person.person2")
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "0"
async def test_state_3(hass):
"""Test the state of a zone."""
hass.states.async_set("person.person1", "test_zone")
hass.states.async_set("person.person2", "test_zone")
info = {
"name": "Test Zone",
"latitude": 32.880837,
"longitude": -117.237561,
"radius": 250,
"passive": True,
}
assert await setup.async_setup_component(hass, zone.DOMAIN, {"zone": info})
assert len(hass.states.async_entity_ids("zone")) == 2
state = hass.states.get("zone.test_zone")
assert state.state == "2"
# Person entity enters another zone
hass.states.async_set("person.person1", "home")
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "1"
# Person entity removed
hass.states.async_remove("person.person2")
await hass.async_block_till_done()
state = hass.states.get("zone.test_zone")
assert state.state == "0"
assert hass.states.get("zone.test_zone").state == "0"
assert hass.states.get("zone.home").state == "1"