From 4ee6735cbbf13c130ee7cf2ca99274141fafc0fc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 21 Jan 2024 19:33:05 -1000 Subject: [PATCH] Small cleanup to zone async_active_zone (#108629) --- homeassistant/components/zone/__init__.py | 62 +++++++++++++---------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/homeassistant/components/zone/__init__.py b/homeassistant/components/zone/__init__.py index bfc9c2fce09..01ec041e9d8 100644 --- a/homeassistant/components/zone/__init__.py +++ b/homeassistant/components/zone/__init__.py @@ -1,9 +1,10 @@ """Support for the definition of zones.""" from __future__ import annotations -from collections.abc import Callable +from collections.abc import Callable, Iterable import logging from operator import attrgetter +import sys from typing import Any, Self, cast import voluptuous as vol @@ -109,40 +110,49 @@ def async_active_zone( This method must be run in the event loop. """ # Sort entity IDs so that we are deterministic if equal distance to 2 zones - min_dist = None - closest = None + min_dist: float = sys.maxsize + closest: State | None = None + # This can be called before async_setup by device tracker - zone_entity_ids: list[str] = hass.data.get(ZONE_ENTITY_IDS, []) + zone_entity_ids: Iterable[str] = hass.data.get(ZONE_ENTITY_IDS, ()) + for entity_id in zone_entity_ids: - zone = hass.states.get(entity_id) if ( - not zone + not (zone := hass.states.get(entity_id)) + # Skip unavailable zones or zone.state == STATE_UNAVAILABLE - or zone.attributes.get(ATTR_PASSIVE) + # Skip passive zones + or (zone_attrs := zone.attributes).get(ATTR_PASSIVE) + # Skip zones where we cannot calculate distance + or ( + zone_dist := distance( + latitude, + longitude, + zone_attrs[ATTR_LATITUDE], + zone_attrs[ATTR_LONGITUDE], + ) + ) + is None + # Skip zone that are outside the radius aka the + # lat/long is outside the zone + or not (zone_dist - (radius := zone_attrs[ATTR_RADIUS]) < radius) ): continue - zone_dist = distance( - latitude, - longitude, - zone.attributes[ATTR_LATITUDE], - zone.attributes[ATTR_LONGITUDE], - ) - - if zone_dist is None: + # If have a closest and its not closer than the closest skip it + if closest and not ( + zone_dist < min_dist + or ( + # If same distance, prefer smaller zone + zone_dist == min_dist and radius < closest.attributes[ATTR_RADIUS] + ) + ): continue - within_zone = zone_dist - radius < zone.attributes[ATTR_RADIUS] - closer_zone = closest is None or zone_dist < min_dist # type: ignore[unreachable] - smaller_zone = ( - zone_dist == min_dist - and zone.attributes[ATTR_RADIUS] - < cast(State, closest).attributes[ATTR_RADIUS] - ) - - if within_zone and (closer_zone or smaller_zone): - min_dist = zone_dist - closest = zone + # We got here which means it closer than the previous known closest + # or equal distance but this one is smaller. + min_dist = zone_dist + closest = zone return closest