From a768de51c08a93064e05c8b1470af7f12480fb93 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Thu, 27 Jan 2022 19:01:09 +0100 Subject: [PATCH] Correct zone state (#65040) Co-authored-by: Franck Nijhof --- .../components/device_tracker/config_entry.py | 1 + homeassistant/components/zone/__init__.py | 35 ++++-- tests/components/zone/test_init.py | 103 ++++++++---------- 3 files changed, 72 insertions(+), 67 deletions(-) diff --git a/homeassistant/components/device_tracker/config_entry.py b/homeassistant/components/device_tracker/config_entry.py index 096268c8fed..18d769df07f 100644 --- a/homeassistant/components/device_tracker/config_entry.py +++ b/homeassistant/components/device_tracker/config_entry.py @@ -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 diff --git a/homeassistant/components/zone/__init__.py b/homeassistant/components/zone/__init__.py index 21f7363695e..41fdd8c32d3 100644 --- a/homeassistant/components/zone/__init__.py +++ b/homeassistant/components/zone/__init__.py @@ -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( diff --git a/tests/components/zone/test_init.py b/tests/components/zone/test_init.py index 399afd480c7..54cb87aa772 100644 --- a/tests/components/zone/test_init.py +++ b/tests/components/zone/test_init.py @@ -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"