diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 7866250d658ed..cdf5a17f32150 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -1649,6 +1649,19 @@ def area_devices(hass: HomeAssistant, area_id_or_name: str) -> Iterable[str]: return [entry.id for entry in entries] +def area_attr(hass: HomeAssistant, area_id_or_name: str, attr_name: str) -> Any: + """Get area specific attribute.""" + area_reg = area_registry.async_get(hass) + area = area_reg.async_get_area(area_id_or_name) or area_reg.async_get_area_by_name( + area_id_or_name + ) + + if area is None or not hasattr(area, attr_name): + return None + + return getattr(area, attr_name) + + def labels(hass: HomeAssistant, lookup_value: Any = None) -> Iterable[str | None]: """Return all labels, or those from a area ID, device ID, or entity ID.""" label_reg = label_registry.async_get(hass) @@ -3036,6 +3049,9 @@ def wrapper(_: Any, *args: _P.args, **kwargs: _P.kwargs) -> _R: self.globals["area_devices"] = hassfunction(area_devices) self.filters["area_devices"] = self.globals["area_devices"] + self.globals["area_attr"] = hassfunction(area_attr) + self.filters["area_attr"] = self.globals["area_attr"] + self.globals["floors"] = hassfunction(floors) self.filters["floors"] = self.globals["floors"] diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index b3a30806cbd87..04c05575db6fb 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -20,7 +20,9 @@ from homeassistant import config_entries from homeassistant.components import group +from homeassistant.components.sensor import SensorDeviceClass from homeassistant.const import ( + ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_UNAVAILABLE, @@ -4414,6 +4416,61 @@ async def test_area_devices( assert info.rate_limit is None +async def test_area_attr( + hass: HomeAssistant, + area_registry: ar.AreaRegistry, + device_registry: dr.DeviceRegistry, +) -> None: + """Test area_attr functions.""" + # Test non existing area id (area_attr) + info = render_to_info(hass, "{{ area_attr('deadbeef', 'name') }}") + assert_result_info(info, None) + assert info.rate_limit is None + + # Test non existing area name (area_attr) + info = render_to_info(hass, "{{ area_attr('fake area name', 'name') }}") + assert_result_info(info, None) + assert info.rate_limit is None + + # Test wrong value type (area_attr) + info = render_to_info(hass, "{{ area_attr('56', 'name') }}") + assert_result_info(info, None) + assert info.rate_limit is None + + hass.states.async_set( + "sensor.mock_temperature", + "20", + { + ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE, + ATTR_UNIT_OF_MEASUREMENT: UnitOfTemperature.CELSIUS, + }, + ) + + area_entry = area_registry.async_get_or_create("sensor.fake") + area_registry.async_update( + area_entry.id, temperature_entity_id="sensor.mock_temperature" + ) + + # Test non existent area attribute (area_attr) + info = render_to_info( + hass, f"{{{{ area_attr('{area_entry.id}', 'invalid_attr') }}}}" + ) + assert_result_info(info, None) + assert info.rate_limit is None + + # Test temperature_entity_id area attribute (area_attr) + info = render_to_info( + hass, f"{{{{ area_attr('{area_entry.id}', 'temperature_entity_id') }}}}" + ) + assert_result_info(info, "sensor.mock_temperature") + + # Test temperature_entity_id area attribute (area_attr) + info = render_to_info( + hass, f"{{{{ area_attr('{area_entry.name}', 'temperature_entity_id') }}}}" + ) + assert_result_info(info, "sensor.mock_temperature") + + def test_closest_function_to_coord(hass: HomeAssistant) -> None: """Test closest function to coord.""" hass.states.async_set(