Hue handle device update (#60612)

pull/59736/head^2
Marcel van der Veldt 2021-11-30 19:14:51 +01:00 committed by GitHub
parent de9e48174f
commit 19b4cc7119
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 52 additions and 17 deletions

View File

@ -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,

View File

@ -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

View File

@ -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"},

View File

@ -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

View File

@ -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()