Resolve zones and return state in find_coordinates (#66081)

This commit is contained in:
Kevin Stillhammer
2022-02-09 10:43:20 +01:00
committed by GitHub
parent bc9ccf0e47
commit a0119f7ed0
2 changed files with 55 additions and 31 deletions

View File

@@ -4,8 +4,6 @@ from __future__ import annotations
from collections.abc import Iterable
import logging
import voluptuous as vol
from homeassistant.const import ATTR_LATITUDE, ATTR_LONGITUDE
from homeassistant.core import HomeAssistant, State
from homeassistant.util import location as loc_util
@@ -48,29 +46,42 @@ def closest(latitude: float, longitude: float, states: Iterable[State]) -> State
def find_coordinates(
hass: HomeAssistant, entity_id: str, recursion_history: list | None = None
hass: HomeAssistant, name: str, recursion_history: list | None = None
) -> str | None:
"""Find the gps coordinates of the entity in the form of '90.000,180.000'."""
if (entity_state := hass.states.get(entity_id)) is None:
_LOGGER.error("Unable to find entity %s", entity_id)
return None
"""Try to resolve the a location from a supplied name or entity_id.
# Check if the entity has location attributes
Will recursively resolve an entity if pointed to by the state of the supplied entity.
Returns coordinates in the form of '90.000,180.000', an address or the state of the last resolved entity.
"""
# Check if a friendly name of a zone was supplied
if (zone_coords := resolve_zone(hass, name)) is not None:
return zone_coords
# Check if an entity_id was supplied.
if (entity_state := hass.states.get(name)) is None:
_LOGGER.debug("Unable to find entity %s", name)
return name
# Check if the entity_state has location attributes
if has_location(entity_state):
return _get_location_from_attributes(entity_state)
# Check if device is in a zone
# Check if entity_state is a zone
zone_entity = hass.states.get(f"zone.{entity_state.state}")
if has_location(zone_entity): # type: ignore
_LOGGER.debug(
"%s is in %s, getting zone location", entity_id, zone_entity.entity_id # type: ignore
"%s is in %s, getting zone location", name, zone_entity.entity_id # type: ignore
)
return _get_location_from_attributes(zone_entity) # type: ignore
# Resolve nested entity
# Check if entity_state is a friendly name of a zone
if (zone_coords := resolve_zone(hass, entity_state.state)) is not None:
return zone_coords
# Check if entity_state is an entity_id
if recursion_history is None:
recursion_history = []
recursion_history.append(entity_id)
recursion_history.append(name)
if entity_state.state in recursion_history:
_LOGGER.error(
"Circular reference detected while trying to find coordinates of an entity. The state of %s has already been checked",
@@ -83,21 +94,18 @@ def find_coordinates(
_LOGGER.debug("Resolving nested entity_id: %s", entity_state.state)
return find_coordinates(hass, entity_state.state, recursion_history)
# Check if state is valid coordinate set
try:
# Import here, not at top-level to avoid circular import
from . import config_validation as cv # pylint: disable=import-outside-toplevel
# Might be an address, coordinates or anything else. This has to be checked by the caller.
return entity_state.state
cv.gps(entity_state.state.split(","))
except vol.Invalid:
_LOGGER.error(
"Entity %s does not contain a location and does not point at an entity that does: %s",
entity_id,
entity_state.state,
)
return None
else:
return entity_state.state
def resolve_zone(hass: HomeAssistant, zone_name: str) -> str | None:
"""Get a lat/long from a zones friendly_name or None if no zone is found by that friendly_name."""
states = hass.states.async_all("zone")
for state in states:
if state.name == zone_name:
return _get_location_from_attributes(state)
return None
def _get_location_from_attributes(entity_state: State) -> str: