Automatically update the entity propery when a member created, updated or deleted

This commit is contained in:
jbouwh
2025-09-15 17:47:48 +00:00
parent 07c5cbbcce
commit 003c8feae7
2 changed files with 95 additions and 2 deletions

View File

@@ -33,7 +33,13 @@ from homeassistant.const import (
CONF_URL,
CONF_VALUE_TEMPLATE,
)
from homeassistant.core import Event, HassJobType, HomeAssistant, callback
from homeassistant.core import (
CALLBACK_TYPE,
Event,
HassJobType,
HomeAssistant,
callback,
)
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers.device_registry import (
DeviceEntry,
@@ -476,12 +482,41 @@ class MqttAttributesMixin(Entity):
[MessageCallbackType, set[str] | None, ReceiveMessage], None
]
_process_update_extra_state_attributes: Callable[[dict[str, Any]], None]
_monitor_member_updates_callback: CALLBACK_TYPE
def __init__(self, config: ConfigType) -> None:
"""Initialize the JSON attributes mixin."""
self._attributes_sub_state: dict[str, EntitySubscription] = {}
self._attributes_config = config
def _monitor_member_updates(self) -> None:
"""Update the group members if the entity registry is updated."""
entity_registry = er.async_get(self.hass)
async def _handle_entity_registry_updated(event: Event[Any]) -> None:
"""Handle registry update event."""
if (
event.data["action"] in {"create", "update"}
and (entry := entity_registry.async_get(event.data["entity_id"]))
and entry.unique_id in self._attributes_config[CONF_GROUP]
) or (
event.data["action"] == "remove"
and self._group_entity_ids is not None
and event.data["entity_id"] in self._group_entity_ids
):
self._update_group_entity_ids()
self._attr_extra_state_attributes[ATTR_ENTITY_ID] = (
self._group_entity_ids
)
self.async_write_ha_state()
self.async_on_remove(
self.hass.bus.async_listen(
er.EVENT_ENTITY_REGISTRY_UPDATED,
_handle_entity_registry_updated,
)
)
def _update_group_entity_ids(self) -> None:
"""Set the entity_id property if the entity represents a group of entities.
@@ -506,6 +541,7 @@ class MqttAttributesMixin(Entity):
await super().async_added_to_hass()
self._update_group_entity_ids()
if self._group_entity_ids is not None:
self._monitor_member_updates()
self._attr_extra_state_attributes = {ATTR_ENTITY_ID: self._group_entity_ids}
self._attributes_prepare_subscribe_topics()

View File

@@ -101,6 +101,7 @@ from homeassistant.const import (
STATE_UNKNOWN,
)
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers import entity_registry as er
from homeassistant.util.json import json_loads
from .common import (
@@ -1893,7 +1894,7 @@ async def test_white_scale(
assert state.attributes.get("brightness") == 129
async def test_light_group_discovery_members(
async def test_light_group_discovery_members_before_group(
hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator
) -> None:
"""Test the discovery of a light group and linked entity IDs.
@@ -1919,6 +1920,62 @@ async def test_light_group_discovery_members(
assert group_state.attributes.get("icon") == "mdi:lightbulb-group"
async def test_light_group_discovery_group_before_members(
hass: HomeAssistant,
mqtt_mock_entry: MqttMockHAClientGenerator,
entity_registry: er.EntityRegistry,
) -> None:
"""Test the discovery of a light group and linked entity IDs.
The group is discovered first, so the group members are
not (all) known yet in the entity registry.
The entity property should be updates as soon as member entities
are discovered, updated or removed.
"""
await mqtt_mock_entry()
# Discover group
async_fire_mqtt_message(hass, GROUP_TOPIC, GROUP_DISCOVERY_LIGHT_GROUP_CONFIG)
await hass.async_block_till_done()
# Discover light group members
async_fire_mqtt_message(hass, GROUP_MEMBER_1_TOPIC, GROUP_DISCOVERY_MEMBER_1_CONFIG)
async_fire_mqtt_message(hass, GROUP_MEMBER_2_TOPIC, GROUP_DISCOVERY_MEMBER_2_CONFIG)
await hass.async_block_till_done()
assert hass.states.get("light.member1") is not None
assert hass.states.get("light.member2") is not None
group_state = hass.states.get("light.group")
assert group_state is not None
assert group_state.attributes.get("entity_id") == ["light.member1", "light.member2"]
assert group_state.attributes.get("icon") == "mdi:lightbulb-group"
# Remove member 1
async_fire_mqtt_message(hass, GROUP_MEMBER_1_TOPIC, "")
await hass.async_block_till_done()
assert hass.states.get("light.member1") is None
assert hass.states.get("light.member2") is not None
group_state = hass.states.get("light.group")
assert group_state is not None
assert group_state.attributes.get("entity_id") == ["light.member2"]
# Rename member 2
entity_registry.async_update_entity(
"light.member2", new_entity_id="light.member2_updated"
)
await hass.async_block_till_done()
group_state = hass.states.get("light.group")
assert group_state is not None
assert group_state.attributes.get("entity_id") == ["light.member2_updated"]
@pytest.mark.parametrize(
"hass_config",
[