mirror of
https://github.com/home-assistant/core.git
synced 2026-09-24 07:25:52 -05:00
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
156 lines
5.5 KiB
Python
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
|