Files
2026-05-14 16:31:01 -04:00

156 lines
5.5 KiB
Python

"""Floor functions for Home Assistant templates."""
from collections.abc import Iterable
from typing import TYPE_CHECKING, Any
from homeassistant.helpers import (
area_registry as ar,
device_registry as dr,
entity_registry as er,
floor_registry as fr,
)
from homeassistant.helpers.template.helpers import resolve_area_id
from .base import BaseTemplateExtension, TemplateFunction
if TYPE_CHECKING:
from homeassistant.helpers.template import TemplateEnvironment
class FloorExtension(BaseTemplateExtension):
"""Extension for floor-related template functions."""
def __init__(self, environment: TemplateEnvironment) -> None:
"""Initialize the floor extension."""
super().__init__(
environment,
functions=[
TemplateFunction(
"floors",
self.floors,
as_global=True,
requires_hass=True,
),
TemplateFunction(
"floor_id",
self.floor_id,
as_global=True,
as_filter=True,
requires_hass=True,
limited_ok=False,
),
TemplateFunction(
"floor_name",
self.floor_name,
as_global=True,
as_filter=True,
requires_hass=True,
limited_ok=False,
),
TemplateFunction(
"floor_areas",
self.floor_areas,
as_global=True,
as_filter=True,
requires_hass=True,
),
TemplateFunction(
"floor_entities",
self.floor_entities,
as_global=True,
as_filter=True,
requires_hass=True,
),
],
)
def floors(self) -> Iterable[str | None]:
"""Return all floors."""
floor_registry = fr.async_get(self.hass)
return [floor.floor_id for floor in floor_registry.async_list_floors()]
def floor_id(self, lookup_value: Any) -> str | None:
"""Get the floor ID from a floor/area name, alias, device/entity id."""
floor_registry = fr.async_get(self.hass)
lookup_str = str(lookup_value)
# Check if it's a floor name or alias
if floor := floor_registry.async_get_floor_by_name(lookup_str):
return floor.floor_id
floors_list = floor_registry.async_get_floors_by_alias(lookup_str)
if floors_list:
return floors_list[0].floor_id
# Resolve to area ID and get floor from area
if aid := resolve_area_id(self.hass, lookup_value):
area_reg = ar.async_get(self.hass)
if area := area_reg.async_get_area(aid):
return area.floor_id
return None
def floor_name(self, lookup_value: str) -> str | None:
"""Get the floor name from a floor id."""
floor_registry = fr.async_get(self.hass)
# Check if it's a floor ID
if floor := floor_registry.async_get_floor(lookup_value):
return floor.name
# Resolve to area ID and get floor name from area's floor
if aid := resolve_area_id(self.hass, lookup_value):
area_reg = ar.async_get(self.hass)
if (
(area := area_reg.async_get_area(aid))
and area.floor_id
and (floor := floor_registry.async_get_floor(area.floor_id))
):
return floor.name
return None
def _floor_id_or_name(self, floor_id_or_name: str) -> str | None:
"""Get the floor ID from a floor name or ID."""
# If floor_name returns a value, we know the input was an ID, otherwise we
# assume it's a name, and if it's neither, we return early.
if self.floor_name(floor_id_or_name) is not None:
return floor_id_or_name
return self.floor_id(floor_id_or_name)
def floor_areas(self, floor_id_or_name: str) -> Iterable[str]:
"""Return area IDs for a given floor ID or name."""
if (_floor_id := self._floor_id_or_name(floor_id_or_name)) is None:
return []
area_reg = ar.async_get(self.hass)
entries = ar.async_entries_for_floor(area_reg, _floor_id)
return [entry.id for entry in entries if entry.id]
def floor_entities(self, floor_id_or_name: str) -> Iterable[str]:
"""Return entity_ids for a given floor ID or name."""
ent_reg = er.async_get(self.hass)
dev_reg = dr.async_get(self.hass)
entity_ids = []
for area_id in self.floor_areas(floor_id_or_name):
# Get entities directly assigned to the area
entity_ids.extend(
[
entry.entity_id
for entry in er.async_entries_for_area(ent_reg, area_id)
]
)
# Also add entities tied to a device in the area that don't themselves
# have an area specified since they inherit the area from the device
entity_ids.extend(
[
entity.entity_id
for device in dr.async_entries_for_area(dev_reg, area_id)
for entity in er.async_entries_for_device(ent_reg, device.id)
if entity.area_id is None
]
)
return entity_ids