Add unique ID support to light, cover and media player groups (#53225)
parent
51dd95ce35
commit
b4a50f5459
|
@ -36,6 +36,7 @@ from homeassistant.const import (
|
|||
ATTR_SUPPORTED_FEATURES,
|
||||
CONF_ENTITIES,
|
||||
CONF_NAME,
|
||||
CONF_UNIQUE_ID,
|
||||
STATE_CLOSING,
|
||||
STATE_OPEN,
|
||||
STATE_OPENING,
|
||||
|
@ -57,8 +58,9 @@ DEFAULT_NAME = "Cover Group"
|
|||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Required(CONF_ENTITIES): cv.entities_domain(DOMAIN),
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -70,7 +72,13 @@ async def async_setup_platform(
|
|||
discovery_info: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
"""Set up the Group Cover platform."""
|
||||
async_add_entities([CoverGroup(config[CONF_NAME], config[CONF_ENTITIES])])
|
||||
async_add_entities(
|
||||
[
|
||||
CoverGroup(
|
||||
config.get(CONF_UNIQUE_ID), config[CONF_NAME], config[CONF_ENTITIES]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class CoverGroup(GroupEntity, CoverEntity):
|
||||
|
@ -82,7 +90,7 @@ class CoverGroup(GroupEntity, CoverEntity):
|
|||
_attr_current_cover_position: int | None = 100
|
||||
_attr_assumed_state: bool = True
|
||||
|
||||
def __init__(self, name: str, entities: list[str]) -> None:
|
||||
def __init__(self, unique_id: str | None, name: str, entities: list[str]) -> None:
|
||||
"""Initialize a CoverGroup entity."""
|
||||
self._entities = entities
|
||||
self._covers: dict[str, set[str]] = {
|
||||
|
@ -98,6 +106,7 @@ class CoverGroup(GroupEntity, CoverEntity):
|
|||
|
||||
self._attr_name = name
|
||||
self._attr_extra_state_attributes = {ATTR_ENTITY_ID: entities}
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
async def _update_supported_features_event(self, event: Event) -> None:
|
||||
self.async_set_context(event.context)
|
||||
|
|
|
@ -39,6 +39,7 @@ from homeassistant.const import (
|
|||
ATTR_SUPPORTED_FEATURES,
|
||||
CONF_ENTITIES,
|
||||
CONF_NAME,
|
||||
CONF_UNIQUE_ID,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
|
@ -55,6 +56,7 @@ DEFAULT_NAME = "Light Group"
|
|||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
vol.Required(CONF_ENTITIES): cv.entities_domain(light.DOMAIN),
|
||||
}
|
||||
)
|
||||
|
@ -72,7 +74,11 @@ async def async_setup_platform(
|
|||
) -> None:
|
||||
"""Initialize light.group platform."""
|
||||
async_add_entities(
|
||||
[LightGroup(cast(str, config.get(CONF_NAME)), config[CONF_ENTITIES])]
|
||||
[
|
||||
LightGroup(
|
||||
config.get(CONF_UNIQUE_ID), config[CONF_NAME], config[CONF_ENTITIES]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
@ -86,13 +92,14 @@ class LightGroup(GroupEntity, light.LightEntity):
|
|||
_attr_min_mireds = 154
|
||||
_attr_should_poll = False
|
||||
|
||||
def __init__(self, name: str, entity_ids: list[str]) -> None:
|
||||
def __init__(self, unique_id: str | None, name: str, entity_ids: list[str]) -> None:
|
||||
"""Initialize a light group."""
|
||||
self._entity_ids = entity_ids
|
||||
self._white_value: int | None = None
|
||||
|
||||
self._attr_name = name
|
||||
self._attr_extra_state_attributes = {ATTR_ENTITY_ID: entity_ids}
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Register callbacks."""
|
||||
|
|
|
@ -48,6 +48,7 @@ from homeassistant.const import (
|
|||
ATTR_SUPPORTED_FEATURES,
|
||||
CONF_ENTITIES,
|
||||
CONF_NAME,
|
||||
CONF_UNIQUE_ID,
|
||||
STATE_OFF,
|
||||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
|
@ -71,8 +72,9 @@ DEFAULT_NAME = "Media Group"
|
|||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||
{
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Required(CONF_ENTITIES): cv.entities_domain(DOMAIN),
|
||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -84,17 +86,24 @@ async def async_setup_platform(
|
|||
discovery_info: DiscoveryInfoType | None = None,
|
||||
) -> None:
|
||||
"""Set up the Media Group platform."""
|
||||
async_add_entities([MediaGroup(config[CONF_NAME], config[CONF_ENTITIES])])
|
||||
async_add_entities(
|
||||
[
|
||||
MediaGroup(
|
||||
config.get(CONF_UNIQUE_ID), config[CONF_NAME], config[CONF_ENTITIES]
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
class MediaGroup(MediaPlayerEntity):
|
||||
"""Representation of a Media Group."""
|
||||
|
||||
def __init__(self, name: str, entities: list[str]) -> None:
|
||||
def __init__(self, unique_id: str | None, name: str, entities: list[str]) -> None:
|
||||
"""Initialize a Media Group entity."""
|
||||
self._name = name
|
||||
self._state: str | None = None
|
||||
self._supported_features: int = 0
|
||||
self._attr_unique_id = unique_id
|
||||
|
||||
self._entities = entities
|
||||
self._features: dict[str, set[str]] = {
|
||||
|
|
|
@ -17,6 +17,7 @@ from homeassistant.const import (
|
|||
ATTR_FRIENDLY_NAME,
|
||||
ATTR_SUPPORTED_FEATURES,
|
||||
CONF_ENTITIES,
|
||||
CONF_UNIQUE_ID,
|
||||
SERVICE_CLOSE_COVER,
|
||||
SERVICE_CLOSE_COVER_TILT,
|
||||
SERVICE_OPEN_COVER,
|
||||
|
@ -32,6 +33,7 @@ from homeassistant.const import (
|
|||
STATE_OPEN,
|
||||
STATE_OPENING,
|
||||
)
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
|
@ -77,6 +79,7 @@ CONFIG_ATTRIBUTES = {
|
|||
DOMAIN: {
|
||||
"platform": "group",
|
||||
CONF_ENTITIES: [DEMO_COVER, DEMO_COVER_POS, DEMO_COVER_TILT, DEMO_TILT],
|
||||
CONF_UNIQUE_ID: "unique_identifier",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -220,6 +223,11 @@ async def test_attributes(hass, setup_comp):
|
|||
state = hass.states.get(COVER_GROUP)
|
||||
assert state.attributes[ATTR_ASSUMED_STATE] is True
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
entry = entity_registry.async_get(COVER_GROUP)
|
||||
assert entry
|
||||
assert entry.unique_id == "unique_identifier"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("config_count", [(CONFIG_TILT_ONLY, 2)])
|
||||
async def test_cover_that_only_supports_tilt_removed(hass, setup_comp):
|
||||
|
|
|
@ -44,6 +44,7 @@ from homeassistant.const import (
|
|||
STATE_ON,
|
||||
STATE_UNAVAILABLE,
|
||||
)
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
||||
|
@ -58,6 +59,7 @@ async def test_default_state(hass):
|
|||
"platform": DOMAIN,
|
||||
"entities": ["light.kitchen", "light.bedroom"],
|
||||
"name": "Bedroom Group",
|
||||
"unique_id": "unique_identifier",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -77,6 +79,11 @@ async def test_default_state(hass):
|
|||
assert state.attributes.get(ATTR_EFFECT_LIST) is None
|
||||
assert state.attributes.get(ATTR_EFFECT) is None
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
entry = entity_registry.async_get("light.bedroom_group")
|
||||
assert entry
|
||||
assert entry.unique_id == "unique_identifier"
|
||||
|
||||
|
||||
async def test_state_reporting(hass):
|
||||
"""Test the state reporting."""
|
||||
|
@ -1064,7 +1071,7 @@ async def test_invalid_service_calls(hass):
|
|||
"""Test invalid service call arguments get discarded."""
|
||||
add_entities = MagicMock()
|
||||
await group.async_setup_platform(
|
||||
hass, {"entities": ["light.test1", "light.test2"]}, add_entities
|
||||
hass, {"name": "test", "entities": ["light.test1", "light.test2"]}, add_entities
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
await hass.async_start()
|
||||
|
|
|
@ -49,6 +49,7 @@ from homeassistant.const import (
|
|||
STATE_UNAVAILABLE,
|
||||
STATE_UNKNOWN,
|
||||
)
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
|
||||
|
@ -73,6 +74,7 @@ async def test_default_state(hass):
|
|||
"platform": DOMAIN,
|
||||
"entities": ["media_player.player_1", "media_player.player_2"],
|
||||
"name": "Media group",
|
||||
"unique_id": "unique_identifier",
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -89,6 +91,11 @@ async def test_default_state(hass):
|
|||
"media_player.player_2",
|
||||
]
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
entry = entity_registry.async_get("media_player.media_group")
|
||||
assert entry
|
||||
assert entry.unique_id == "unique_identifier"
|
||||
|
||||
|
||||
async def test_state_reporting(hass):
|
||||
"""Test the state reporting."""
|
||||
|
|
Loading…
Reference in New Issue