diff --git a/homeassistant/components/switch_as_x/cover.py b/homeassistant/components/switch_as_x/cover.py index b7f8e5bf971e99b540c0c349b7732a896948f268..7df3b17721736633cb7271c3777154fc169b6268 100644 --- a/homeassistant/components/switch_as_x/cover.py +++ b/homeassistant/components/switch_as_x/cover.py @@ -3,7 +3,11 @@ from __future__ import annotations from typing import Any -from homeassistant.components.cover import CoverEntity, CoverEntityFeature +from homeassistant.components.cover import ( + DOMAIN as COVER_DOMAIN, + CoverEntity, + CoverEntityFeature, +) from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( @@ -36,6 +40,7 @@ async def async_setup_entry( CoverSwitch( hass, config_entry.title, + COVER_DOMAIN, entity_id, config_entry.entry_id, ) diff --git a/homeassistant/components/switch_as_x/entity.py b/homeassistant/components/switch_as_x/entity.py index 8432c46f856a605232da95cf7f90eb4f700eb6b7..21a7b882442094ac0aa2393d70d9f4ed98d9730a 100644 --- a/homeassistant/components/switch_as_x/entity.py +++ b/homeassistant/components/switch_as_x/entity.py @@ -23,13 +23,15 @@ class BaseEntity(Entity): """Represents a Switch as an X.""" _attr_should_poll = False + _is_new_entity: bool def __init__( self, hass: HomeAssistant, config_entry_title: str, + domain: str, switch_entity_id: str, - unique_id: str | None, + unique_id: str, ) -> None: """Initialize Switch as an X.""" registry = er.async_get(hass) @@ -41,7 +43,7 @@ class BaseEntity(Entity): name: str | None = config_entry_title if wrapped_switch: - name = wrapped_switch.name or wrapped_switch.original_name + name = wrapped_switch.original_name self._device_id = device_id if device_id and (device := device_registry.async_get(device_id)): @@ -55,6 +57,10 @@ class BaseEntity(Entity): self._attr_unique_id = unique_id self._switch_entity_id = switch_entity_id + self._is_new_entity = ( + registry.async_get_entity_id(domain, SWITCH_AS_X_DOMAIN, unique_id) is None + ) + @callback def async_state_changed_listener(self, event: Event | None = None) -> None: """Handle child updates.""" @@ -67,7 +73,7 @@ class BaseEntity(Entity): self._attr_available = True async def async_added_to_hass(self) -> None: - """Register callbacks.""" + """Register callbacks and copy the wrapped entity's custom name if set.""" @callback def _async_state_changed_listener(event: Event | None = None) -> None: @@ -93,6 +99,15 @@ class BaseEntity(Entity): {"entity_id": self._switch_entity_id}, ) + if not self._is_new_entity: + return + + wrapped_switch = registry.async_get(self._switch_entity_id) + if not wrapped_switch or wrapped_switch.name is None: + return + + registry.async_update_entity(self.entity_id, name=wrapped_switch.name) + class BaseToggleEntity(BaseEntity, ToggleEntity): """Represents a Switch as a ToggleEntity.""" diff --git a/homeassistant/components/switch_as_x/fan.py b/homeassistant/components/switch_as_x/fan.py index 87a6c3872958e4ff0dfed0d04403c6b1e4abd634..d8c43cfe38191870ceed766003bee22cd2729cb7 100644 --- a/homeassistant/components/switch_as_x/fan.py +++ b/homeassistant/components/switch_as_x/fan.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Any -from homeassistant.components.fan import FanEntity +from homeassistant.components.fan import DOMAIN as FAN_DOMAIN, FanEntity from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_ENTITY_ID from homeassistant.core import HomeAssistant @@ -29,6 +29,7 @@ async def async_setup_entry( FanSwitch( hass, config_entry.title, + FAN_DOMAIN, entity_id, config_entry.entry_id, ) diff --git a/homeassistant/components/switch_as_x/light.py b/homeassistant/components/switch_as_x/light.py index 7bcdb659e9ce967b3a5d7d6bd6e25f3b7d39d79f..e6183c95d91bf64f79946fc19ebd42674f57a008 100644 --- a/homeassistant/components/switch_as_x/light.py +++ b/homeassistant/components/switch_as_x/light.py @@ -1,7 +1,11 @@ """Light support for switch entities.""" from __future__ import annotations -from homeassistant.components.light import ColorMode, LightEntity +from homeassistant.components.light import ( + DOMAIN as LIGHT_DOMAIN, + ColorMode, + LightEntity, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_ENTITY_ID from homeassistant.core import HomeAssistant @@ -27,6 +31,7 @@ async def async_setup_entry( LightSwitch( hass, config_entry.title, + LIGHT_DOMAIN, entity_id, config_entry.entry_id, ) diff --git a/homeassistant/components/switch_as_x/lock.py b/homeassistant/components/switch_as_x/lock.py index e3c29a1cf424fd3ae8774131789b407c7ae40a2c..9778caf8e600aeaf7972a01e751367f58d2e18e3 100644 --- a/homeassistant/components/switch_as_x/lock.py +++ b/homeassistant/components/switch_as_x/lock.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Any -from homeassistant.components.lock import LockEntity +from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN, LockEntity from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( @@ -36,6 +36,7 @@ async def async_setup_entry( LockSwitch( hass, config_entry.title, + LOCK_DOMAIN, entity_id, config_entry.entry_id, ) diff --git a/homeassistant/components/switch_as_x/siren.py b/homeassistant/components/switch_as_x/siren.py index 88ff9a322d305fee0e87a5e663673b9ee54d19ff..c9981b17cfe6f270b4180da0bf63fda6037e16a2 100644 --- a/homeassistant/components/switch_as_x/siren.py +++ b/homeassistant/components/switch_as_x/siren.py @@ -1,7 +1,11 @@ """Siren support for switch entities.""" from __future__ import annotations -from homeassistant.components.siren import SirenEntity, SirenEntityFeature +from homeassistant.components.siren import ( + DOMAIN as SIREN_DOMAIN, + SirenEntity, + SirenEntityFeature, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_ENTITY_ID from homeassistant.core import HomeAssistant @@ -27,6 +31,7 @@ async def async_setup_entry( SirenSwitch( hass, config_entry.title, + SIREN_DOMAIN, entity_id, config_entry.entry_id, ) diff --git a/tests/components/switch_as_x/test_init.py b/tests/components/switch_as_x/test_init.py index 2d63ce9617b64f4d9be3c72ff49c328bff479c65..87cc291a59998b3f928fbdeb5fc09cba2e87cd19 100644 --- a/tests/components/switch_as_x/test_init.py +++ b/tests/components/switch_as_x/test_init.py @@ -534,7 +534,143 @@ async def test_entity_name( assert entity_entry assert entity_entry.device_id == switch_entity_entry.device_id assert entity_entry.has_entity_name is True + assert entity_entry.name is None assert entity_entry.original_name is None assert entity_entry.options == { DOMAIN: {"entity_id": switch_entity_entry.entity_id} } + + +@pytest.mark.parametrize("target_domain", PLATFORMS_TO_TEST) +async def test_custom_name_1( + hass: HomeAssistant, + target_domain: Platform, +) -> None: + """Test the source entity has a custom name.""" + registry = er.async_get(hass) + device_registry = dr.async_get(hass) + + switch_config_entry = MockConfigEntry() + + device_entry = device_registry.async_get_or_create( + config_entry_id=switch_config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + name="Device name", + ) + + switch_entity_entry = registry.async_get_or_create( + "switch", + "test", + "unique", + device_id=device_entry.id, + has_entity_name=True, + original_name="Original entity name", + ) + switch_entity_entry = registry.async_update_entity( + switch_entity_entry.entity_id, + config_entry_id=switch_config_entry.entry_id, + name="Custom entity name", + ) + + # Add the config entry + switch_as_x_config_entry = MockConfigEntry( + data={}, + domain=DOMAIN, + options={ + CONF_ENTITY_ID: switch_entity_entry.id, + CONF_TARGET_DOMAIN: target_domain, + }, + title="ABC", + ) + switch_as_x_config_entry.add_to_hass(hass) + + assert await hass.config_entries.async_setup(switch_as_x_config_entry.entry_id) + await hass.async_block_till_done() + + entity_entry = registry.async_get( + f"{target_domain}.device_name_original_entity_name" + ) + assert entity_entry + assert entity_entry.device_id == switch_entity_entry.device_id + assert entity_entry.has_entity_name is True + assert entity_entry.name == "Custom entity name" + assert entity_entry.original_name == "Original entity name" + assert entity_entry.options == { + DOMAIN: {"entity_id": switch_entity_entry.entity_id} + } + + +@pytest.mark.parametrize("target_domain", PLATFORMS_TO_TEST) +async def test_custom_name_2( + hass: HomeAssistant, + target_domain: Platform, +) -> None: + """Test the source entity has a custom name. + + This tests the custom name is only copied from the source device when the config + switch_as_x config entry is setup the first time. + """ + registry = er.async_get(hass) + device_registry = dr.async_get(hass) + + switch_config_entry = MockConfigEntry() + + device_entry = device_registry.async_get_or_create( + config_entry_id=switch_config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + name="Device name", + ) + + switch_entity_entry = registry.async_get_or_create( + "switch", + "test", + "unique", + device_id=device_entry.id, + has_entity_name=True, + original_name="Original entity name", + ) + switch_entity_entry = registry.async_update_entity( + switch_entity_entry.entity_id, + config_entry_id=switch_config_entry.entry_id, + name="New custom entity name", + ) + + # Add the config entry + switch_as_x_config_entry = MockConfigEntry( + data={}, + domain=DOMAIN, + options={ + CONF_ENTITY_ID: switch_entity_entry.id, + CONF_TARGET_DOMAIN: target_domain, + }, + title="ABC", + ) + switch_as_x_config_entry.add_to_hass(hass) + + switch_as_x_entity_entry = registry.async_get_or_create( + target_domain, + "switch_as_x", + switch_as_x_config_entry.entry_id, + suggested_object_id="device_name_original_entity_name", + ) + switch_as_x_entity_entry = registry.async_update_entity( + switch_as_x_entity_entry.entity_id, + config_entry_id=switch_config_entry.entry_id, + name="Old custom entity name", + ) + + assert await hass.config_entries.async_setup(switch_as_x_config_entry.entry_id) + await hass.async_block_till_done() + + entity_entry = registry.async_get( + f"{target_domain}.device_name_original_entity_name" + ) + assert entity_entry + assert entity_entry.entity_id == switch_as_x_entity_entry.entity_id + assert entity_entry.device_id == switch_entity_entry.device_id + assert entity_entry.has_entity_name is True + assert entity_entry.name == "Old custom entity name" + assert entity_entry.original_name == "Original entity name" + assert entity_entry.options == { + DOMAIN: {"entity_id": switch_entity_entry.entity_id} + }