From 8ec436423fdc7014a10c74c761206194fcb66787 Mon Sep 17 00:00:00 2001 From: Paul Bottein Date: Mon, 14 Apr 2025 14:30:00 +0200 Subject: [PATCH] Add template function: device_name (#142683) --- homeassistant/helpers/template.py | 25 +++++++++++++ tests/helpers/test_template.py | 60 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 9468eb6bf49..424cd3d978e 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -1413,6 +1413,28 @@ def device_id(hass: HomeAssistant, entity_id_or_device_name: str) -> str | None: ) +def device_name(hass: HomeAssistant, lookup_value: str) -> str | None: + """Get the device name from an device id, or entity id.""" + device_reg = device_registry.async_get(hass) + if device := device_reg.async_get(lookup_value): + return device.name_by_user or device.name + + ent_reg = entity_registry.async_get(hass) + # Import here, not at top-level to avoid circular import + from . import config_validation as cv # pylint: disable=import-outside-toplevel + + try: + cv.entity_id(lookup_value) + except vol.Invalid: + pass + else: + if entity := ent_reg.async_get(lookup_value): + if entity.device_id and (device := device_reg.async_get(entity.device_id)): + return device.name_by_user or device.name + + return None + + def device_attr(hass: HomeAssistant, device_or_entity_id: str, attr_name: str) -> Any: """Get the device specific attribute.""" device_reg = device_registry.async_get(hass) @@ -3230,6 +3252,9 @@ class TemplateEnvironment(ImmutableSandboxedEnvironment): # Device extensions + self.globals["device_name"] = hassfunction(device_name) + self.filters["device_name"] = self.globals["device_name"] + self.globals["device_attr"] = hassfunction(device_attr) self.filters["device_attr"] = self.globals["device_attr"] diff --git a/tests/helpers/test_template.py b/tests/helpers/test_template.py index 89d1c307fd7..43efe79e96f 100644 --- a/tests/helpers/test_template.py +++ b/tests/helpers/test_template.py @@ -3887,6 +3887,66 @@ async def test_device_id( assert info.rate_limit is None +async def test_device_name( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test device_name function.""" + config_entry = MockConfigEntry(domain="light") + config_entry.add_to_hass(hass) + + # Test non existing entity id + info = render_to_info(hass, "{{ device_name('sensor.fake') }}") + assert_result_info(info, None) + assert info.rate_limit is None + + # Test non existing device id + info = render_to_info(hass, "{{ device_name('1234567890') }}") + assert_result_info(info, None) + assert info.rate_limit is None + + # Test wrong value type + info = render_to_info(hass, "{{ device_name(56) }}") + assert_result_info(info, None) + assert info.rate_limit is None + + # Test device with single entity + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + name="A light", + ) + entity_entry = entity_registry.async_get_or_create( + "light", + "hue", + "5678", + config_entry=config_entry, + device_id=device_entry.id, + ) + info = render_to_info(hass, f"{{{{ device_name('{device_entry.id}') }}}}") + assert_result_info(info, device_entry.name) + assert info.rate_limit is None + + info = render_to_info(hass, f"{{{{ device_name('{entity_entry.entity_id}') }}}}") + assert_result_info(info, device_entry.name) + assert info.rate_limit is None + + # Test device after renaming + device_entry = device_registry.async_update_device( + device_entry.id, + name_by_user="My light", + ) + + info = render_to_info(hass, f"{{{{ device_name('{device_entry.id}') }}}}") + assert_result_info(info, device_entry.name_by_user) + assert info.rate_limit is None + + info = render_to_info(hass, f"{{{{ device_name('{entity_entry.entity_id}') }}}}") + assert_result_info(info, device_entry.name_by_user) + assert info.rate_limit is None + + async def test_device_attr( hass: HomeAssistant, device_registry: dr.DeviceRegistry,