Add included_entities attribute to base Entity class

This commit is contained in:
jbouwh
2025-09-18 19:51:12 +00:00
parent 42a9d5d4e3
commit ee24acf52a
2 changed files with 56 additions and 2 deletions

View File

@@ -25,6 +25,7 @@ from homeassistant.const import (
ATTR_ASSUMED_STATE, ATTR_ASSUMED_STATE,
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_ENTITY_PICTURE, ATTR_ENTITY_PICTURE,
ATTR_FRIENDLY_NAME, ATTR_FRIENDLY_NAME,
ATTR_ICON, ATTR_ICON,
@@ -535,6 +536,7 @@ class Entity(
_attr_device_info: DeviceInfo | None = None _attr_device_info: DeviceInfo | None = None
_attr_entity_category: EntityCategory | None _attr_entity_category: EntityCategory | None
_attr_has_entity_name: bool _attr_has_entity_name: bool
_attr_included_entities: list[str] | None
_attr_entity_picture: str | None = None _attr_entity_picture: str | None = None
_attr_entity_registry_enabled_default: bool _attr_entity_registry_enabled_default: bool
_attr_entity_registry_visible_default: bool _attr_entity_registry_visible_default: bool
@@ -765,6 +767,16 @@ class Entity(
""" """
return self._attr_capability_attributes return self._attr_capability_attributes
@property
def included_entities(self) -> list[str] | None:
"""Return a list of entity IDs if the entity represents a group.
Included entities will be shown as members in the UI.
"""
if hasattr(self, "_attr_included_entities"):
return self._attr_included_entities
return None
def get_initial_entity_options(self) -> er.EntityOptionsType | None: def get_initial_entity_options(self) -> er.EntityOptionsType | None:
"""Return initial entity options. """Return initial entity options.
@@ -793,9 +805,18 @@ class Entity(
Implemented by platform classes. Convention for attribute names Implemented by platform classes. Convention for attribute names
is lowercase snake_case. is lowercase snake_case.
""" """
entity_ids = (
None
if self.included_entities is None
else {ATTR_ENTITY_ID: self.included_entities}
)
if hasattr(self, "_attr_extra_state_attributes"): if hasattr(self, "_attr_extra_state_attributes"):
return self._attr_extra_state_attributes return (
return None self._attr_extra_state_attributes
if entity_ids is None
else self._attr_extra_state_attributes | entity_ids
)
return None or entity_ids
@cached_property @cached_property
def device_info(self) -> DeviceInfo | None: def device_info(self) -> DeviceInfo | None:

View File

@@ -20,6 +20,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_ATTRIBUTION, ATTR_ATTRIBUTION,
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME, ATTR_FRIENDLY_NAME,
STATE_UNAVAILABLE, STATE_UNAVAILABLE,
STATE_UNKNOWN, STATE_UNKNOWN,
@@ -926,6 +927,38 @@ async def test_attribution_attribute(hass: HomeAssistant) -> None:
assert state.attributes.get(ATTR_ATTRIBUTION) == "Home Assistant" assert state.attributes.get(ATTR_ATTRIBUTION) == "Home Assistant"
async def test_included_entities_attribute(hass: HomeAssistant) -> None:
"""Test included_entities attribute."""
mock_entity = entity.Entity()
mock_entity.hass = hass
mock_entity.entity_id = "hello.world"
mock_entity._attr_included_entities = ["hello.oceans", "hello.continents"]
mock_entity.async_schedule_update_ha_state(True)
await hass.async_block_till_done()
state = hass.states.get(mock_entity.entity_id)
assert state.attributes.get(ATTR_ENTITY_ID) == ["hello.oceans", "hello.continents"]
async def test_included_entities_attribute_with_extra_state_attributes(
hass: HomeAssistant,
) -> None:
"""Test included_entities attribute."""
mock_entity = entity.Entity()
mock_entity.hass = hass
mock_entity.entity_id = "hello.world"
mock_entity._attr_included_entities = ["hello.oceans", "hello.continents"]
mock_entity._attr_extra_state_attributes = {"demo": "Home Assistant"}
mock_entity.async_schedule_update_ha_state(True)
await hass.async_block_till_done()
state = hass.states.get(mock_entity.entity_id)
assert state.attributes.get(ATTR_ENTITY_ID) == ["hello.oceans", "hello.continents"]
assert state.attributes.get("demo") == "Home Assistant"
async def test_entity_category_property(hass: HomeAssistant) -> None: async def test_entity_category_property(hass: HomeAssistant) -> None:
"""Test entity category property.""" """Test entity category property."""
mock_entity1 = entity.Entity() mock_entity1 = entity.Entity()