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
1 changed files with 36 additions and 26 deletions

View File

@ -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