diff --git a/homeassistant/components/hue/scene.py b/homeassistant/components/hue/scene.py index 55807ad0f2f..7335d2a048e 100644 --- a/homeassistant/components/hue/scene.py +++ b/homeassistant/components/hue/scene.py @@ -60,6 +60,19 @@ class HueSceneEntity(HueBaseEntity, SceneEntity): super().__init__(bridge, controller, resource) self.resource = resource self.controller = controller + self.group = self.controller.get_group(self.resource.id) + + async def async_added_to_hass(self) -> None: + """Call when entity is added.""" + await super().async_added_to_hass() + # Add value_changed callback for group to catch name changes. + self.async_on_remove( + self.bridge.api.groups.subscribe( + self._handle_event, + self.group.id, + (EventType.RESOURCE_UPDATED), + ) + ) @property def name(self) -> str: @@ -96,7 +109,6 @@ class HueSceneEntity(HueBaseEntity, SceneEntity): @property def extra_state_attributes(self) -> dict[str, Any] | None: """Return the optional state attributes.""" - group = self.controller.get_group(self.resource.id) brightness = None if palette := self.resource.palette: if palette.dimming: @@ -108,8 +120,8 @@ class HueSceneEntity(HueBaseEntity, SceneEntity): brightness = action.action.dimming.brightness break return { - "group_name": group.metadata.name, - "group_type": group.type.value, + "group_name": self.group.metadata.name, + "group_type": self.group.type.value, "name": self.resource.metadata.name, "speed": self.resource.speed, "brightness": brightness, diff --git a/homeassistant/components/hue/v2/entity.py b/homeassistant/components/hue/v2/entity.py index 9bb81c16fa5..368a6cfe9d0 100644 --- a/homeassistant/components/hue/v2/entity.py +++ b/homeassistant/components/hue/v2/entity.py @@ -56,11 +56,11 @@ class HueBaseEntity(Entity): # creating a pretty name for device-less entities (e.g. groups/scenes) # should be handled in the platform instead return self.resource.type.value - dev_name = self.device.metadata.name - # if resource is a light, use the device name + # if resource is a light, use the name from metadata if self.resource.type == ResourceTypes.LIGHT: - return dev_name + return self.resource.name # for sensors etc, use devicename + pretty name of type + dev_name = self.device.metadata.name type_title = RESOURCE_TYPE_NAMES.get( self.resource.type, self.resource.type.value.replace("_", " ").title() ) @@ -76,6 +76,23 @@ class HueBaseEntity(Entity): (EventType.RESOURCE_UPDATED, EventType.RESOURCE_DELETED), ) ) + # also subscribe to device update event to catch devicer changes (e.g. name) + if self.device is None: + return + self.async_on_remove( + self.bridge.api.devices.subscribe( + self._handle_event, + self.device.id, + EventType.RESOURCE_UPDATED, + ) + ) + # subscribe to zigbee_connectivity to catch availability changes + if zigbee := self.bridge.api.devices.get_zigbee_connectivity(self.device.id): + self.bridge.api.sensors.zigbee_connectivity.subscribe( + self._handle_event, + zigbee.id, + EventType.RESOURCE_UPDATED, + ) @property def available(self) -> bool: @@ -98,7 +115,7 @@ class HueBaseEntity(Entity): @callback def _handle_event(self, event_type: EventType, resource: CLIPResource) -> None: - """Handle status event for this resource.""" + """Handle status event for this resource (or it's parent).""" if event_type == EventType.RESOURCE_DELETED and resource.id == self.resource.id: self.logger.debug("Received delete for %s", self.entity_id) # non-device bound entities like groups and scenes need to be removed here diff --git a/tests/components/hue/const.py b/tests/components/hue/const.py index 84b342c73be..03b2f1947cf 100644 --- a/tests/components/hue/const.py +++ b/tests/components/hue/const.py @@ -32,7 +32,7 @@ FAKE_LIGHT = { }, "id": "fake_light_id_1", "id_v1": "/lights/1", - "metadata": {"archetype": "unknown", "name": "Hue fake light 1"}, + "metadata": {"archetype": "unknown", "name": "Hue fake light"}, "mode": "normal", "on": {"on": False}, "owner": {"rid": "fake_device_id_1", "rtype": "device"}, diff --git a/tests/components/hue/test_light_v2.py b/tests/components/hue/test_light_v2.py index e608ef00e26..7843cab1574 100644 --- a/tests/components/hue/test_light_v2.py +++ b/tests/components/hue/test_light_v2.py @@ -173,7 +173,7 @@ async def test_light_added(hass, mock_bridge_v2): await setup_platform(hass, mock_bridge_v2, "light") - test_entity_id = "light.hue_mocked_device" + test_entity_id = "light.hue_fake_light" # verify entity does not exist before we start assert hass.states.get(test_entity_id) is None @@ -186,7 +186,7 @@ async def test_light_added(hass, mock_bridge_v2): test_entity = hass.states.get(test_entity_id) assert test_entity is not None assert test_entity.state == "off" - assert test_entity.attributes["friendly_name"] == FAKE_DEVICE["metadata"]["name"] + assert test_entity.attributes["friendly_name"] == FAKE_LIGHT["metadata"]["name"] async def test_light_availability(hass, mock_bridge_v2, v2_resources_test_data): @@ -212,13 +212,6 @@ async def test_light_availability(hass, mock_bridge_v2, v2_resources_test_data): "type": "zigbee_connectivity", }, ) - mock_bridge_v2.api.emit_event( - "update", - { - "id": "02cba059-9c2c-4d45-97e4-4f79b1bfbaa1", - "type": "light", - }, - ) await hass.async_block_till_done() # the entity should now be available only when zigbee is connected diff --git a/tests/components/hue/test_scene.py b/tests/components/hue/test_scene.py index 15684eb7e56..0f3d6255e86 100644 --- a/tests/components/hue/test_scene.py +++ b/tests/components/hue/test_scene.py @@ -118,6 +118,19 @@ async def test_scene_updates(hass, mock_bridge_v2, v2_resources_test_data): assert test_entity is not None assert test_entity.attributes["brightness"] == 35.0 + # test entity name changes on group name change + mock_bridge_v2.api.emit_event( + "update", + { + "type": "room", + "id": "6ddc9066-7e7d-4a03-a773-c73937968296", + "metadata": {"name": "Test Room 2"}, + }, + ) + await hass.async_block_till_done() + test_entity = hass.states.get(test_entity_id) + assert test_entity.name == "Test Room 2 - Mocked Scene" + # test delete mock_bridge_v2.api.emit_event("delete", updated_resource) await hass.async_block_till_done()