Small cleanup to zone async_active_zone (#108629)

This commit is contained in:
J. Nick Koston 2024-01-21 19:33:05 -10:00 committed by GitHub
parent 8d4a1f475e
commit 4ee6735cbb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,9 +1,10 @@
"""Support for the definition of zones.""" """Support for the definition of zones."""
from __future__ import annotations from __future__ import annotations
from collections.abc import Callable from collections.abc import Callable, Iterable
import logging import logging
from operator import attrgetter from operator import attrgetter
import sys
from typing import Any, Self, cast from typing import Any, Self, cast
import voluptuous as vol import voluptuous as vol
@ -109,40 +110,49 @@ def async_active_zone(
This method must be run in the event loop. This method must be run in the event loop.
""" """
# Sort entity IDs so that we are deterministic if equal distance to 2 zones # Sort entity IDs so that we are deterministic if equal distance to 2 zones
min_dist = None min_dist: float = sys.maxsize
closest = None closest: State | None = None
# This can be called before async_setup by device tracker # 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: for entity_id in zone_entity_ids:
zone = hass.states.get(entity_id)
if ( if (
not zone not (zone := hass.states.get(entity_id))
# Skip unavailable zones
or zone.state == STATE_UNAVAILABLE 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 continue
zone_dist = distance( # If have a closest and its not closer than the closest skip it
latitude, if closest and not (
longitude, zone_dist < min_dist
zone.attributes[ATTR_LATITUDE], or (
zone.attributes[ATTR_LONGITUDE], # If same distance, prefer smaller zone
) zone_dist == min_dist and radius < closest.attributes[ATTR_RADIUS]
)
if zone_dist is None: ):
continue continue
within_zone = zone_dist - radius < zone.attributes[ATTR_RADIUS] # We got here which means it closer than the previous known closest
closer_zone = closest is None or zone_dist < min_dist # type: ignore[unreachable] # or equal distance but this one is smaller.
smaller_zone = ( min_dist = zone_dist
zone_dist == min_dist closest = zone
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
return closest return closest