LinkPlay group members should return the entity ids (#141791)

This commit is contained in:
Simon Lamon 2025-04-29 20:28:08 +02:00 committed by GitHub
parent d3745d2519
commit cd104dc08c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 54 additions and 41 deletions

View File

@ -13,7 +13,7 @@ from homeassistant.const import CONF_HOST
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from .const import CONTROLLER, CONTROLLER_KEY, DOMAIN, PLATFORMS from .const import DOMAIN, PLATFORMS, SHARED_DATA, LinkPlaySharedData
from .utils import async_get_client_session from .utils import async_get_client_session
@ -44,11 +44,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: LinkPlayConfigEntry) ->
# setup the controller and discover multirooms # setup the controller and discover multirooms
controller: LinkPlayController | None = None controller: LinkPlayController | None = None
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
if CONTROLLER not in hass.data[DOMAIN]: if SHARED_DATA not in hass.data[DOMAIN]:
controller = LinkPlayController(session) controller = LinkPlayController(session)
hass.data[DOMAIN][CONTROLLER_KEY] = controller hass.data[DOMAIN][SHARED_DATA] = LinkPlaySharedData(controller, {})
else: else:
controller = hass.data[DOMAIN][CONTROLLER_KEY] controller = hass.data[DOMAIN][SHARED_DATA].controller
await controller.add_bridge(bridge) await controller.add_bridge(bridge)
await controller.discover_multirooms() await controller.discover_multirooms()
@ -62,4 +62,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: LinkPlayConfigEntry) ->
async def async_unload_entry(hass: HomeAssistant, entry: LinkPlayConfigEntry) -> bool: async def async_unload_entry(hass: HomeAssistant, entry: LinkPlayConfigEntry) -> bool:
"""Unload a config entry.""" """Unload a config entry."""
# remove the bridge from the controller and discover multirooms
bridge: LinkPlayBridge | None = entry.runtime_data.bridge
controller: LinkPlayController = hass.data[DOMAIN][SHARED_DATA].controller
await controller.remove_bridge(bridge)
await controller.discover_multirooms()
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

View File

@ -1,12 +1,23 @@
"""LinkPlay constants.""" """LinkPlay constants."""
from dataclasses import dataclass
from linkplay.controller import LinkPlayController from linkplay.controller import LinkPlayController
from homeassistant.const import Platform from homeassistant.const import Platform
from homeassistant.util.hass_dict import HassKey from homeassistant.util.hass_dict import HassKey
@dataclass
class LinkPlaySharedData:
"""Shared data for LinkPlay."""
controller: LinkPlayController
entity_to_bridge: dict[str, str]
DOMAIN = "linkplay" DOMAIN = "linkplay"
CONTROLLER = "controller" SHARED_DATA = "shared_data"
CONTROLLER_KEY: HassKey[LinkPlayController] = HassKey(CONTROLLER) SHARED_DATA_KEY: HassKey[LinkPlaySharedData] = HassKey(SHARED_DATA)
PLATFORMS = [Platform.BUTTON, Platform.MEDIA_PLAYER] PLATFORMS = [Platform.BUTTON, Platform.MEDIA_PLAYER]
DATA_SESSION = "session" DATA_SESSION = "session"

View File

@ -23,19 +23,14 @@ from homeassistant.components.media_player import (
RepeatMode, RepeatMode,
async_process_play_media_url, async_process_play_media_url,
) )
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import ( from homeassistant.helpers import config_validation as cv, entity_platform
config_validation as cv,
entity_platform,
entity_registry as er,
)
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
from . import LinkPlayConfigEntry, LinkPlayData from . import SHARED_DATA, LinkPlayConfigEntry
from .const import CONTROLLER_KEY, DOMAIN from .const import DOMAIN
from .entity import LinkPlayBaseEntity, exception_wrap from .entity import LinkPlayBaseEntity, exception_wrap
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -163,6 +158,13 @@ class LinkPlayMediaPlayerEntity(LinkPlayBaseEntity, MediaPlayerEntity):
mode.value for mode in bridge.player.available_equalizer_modes mode.value for mode in bridge.player.available_equalizer_modes
] ]
async def async_added_to_hass(self) -> None:
"""Handle common setup when added to hass."""
await super().async_added_to_hass()
self.hass.data[DOMAIN][SHARED_DATA].entity_to_bridge[self.entity_id] = (
self._bridge.device.uuid
)
@exception_wrap @exception_wrap
async def async_update(self) -> None: async def async_update(self) -> None:
"""Update the state of the media player.""" """Update the state of the media player."""
@ -276,62 +278,56 @@ class LinkPlayMediaPlayerEntity(LinkPlayBaseEntity, MediaPlayerEntity):
async def async_join_players(self, group_members: list[str]) -> None: async def async_join_players(self, group_members: list[str]) -> None:
"""Join `group_members` as a player group with the current player.""" """Join `group_members` as a player group with the current player."""
controller: LinkPlayController = self.hass.data[DOMAIN][CONTROLLER_KEY] controller: LinkPlayController = self.hass.data[DOMAIN][SHARED_DATA].controller
multiroom = self._bridge.multiroom multiroom = self._bridge.multiroom
if multiroom is None: if multiroom is None:
multiroom = LinkPlayMultiroom(self._bridge) multiroom = LinkPlayMultiroom(self._bridge)
for group_member in group_members: for group_member in group_members:
bridge = self._get_linkplay_bridge(group_member) bridge = await self._get_linkplay_bridge(group_member)
if bridge: if bridge:
await multiroom.add_follower(bridge) await multiroom.add_follower(bridge)
await controller.discover_multirooms() await controller.discover_multirooms()
def _get_linkplay_bridge(self, entity_id: str) -> LinkPlayBridge: async def _get_linkplay_bridge(self, entity_id: str) -> LinkPlayBridge:
"""Get linkplay bridge from entity_id.""" """Get linkplay bridge from entity_id."""
entity_registry = er.async_get(self.hass) shared_data = self.hass.data[DOMAIN][SHARED_DATA]
controller = shared_data.controller
bridge_uuid = shared_data.entity_to_bridge.get(entity_id, None)
bridge = await controller.find_bridge(bridge_uuid)
# Check for valid linkplay media_player entity if bridge is None:
entity_entry = entity_registry.async_get(entity_id)
if (
entity_entry is None
or entity_entry.domain != Platform.MEDIA_PLAYER
or entity_entry.platform != DOMAIN
or entity_entry.config_entry_id is None
):
raise ServiceValidationError( raise ServiceValidationError(
translation_domain=DOMAIN, translation_domain=DOMAIN,
translation_key="invalid_grouping_entity", translation_key="invalid_grouping_entity",
translation_placeholders={"entity_id": entity_id}, translation_placeholders={"entity_id": entity_id},
) )
config_entry = self.hass.config_entries.async_get_entry( return bridge
entity_entry.config_entry_id
)
assert config_entry
# Return bridge
data: LinkPlayData = config_entry.runtime_data
return data.bridge
@property @property
def group_members(self) -> list[str]: def group_members(self) -> list[str]:
"""List of players which are grouped together.""" """List of players which are grouped together."""
multiroom = self._bridge.multiroom multiroom = self._bridge.multiroom
if multiroom is not None: if multiroom is None:
return [multiroom.leader.device.uuid] + [ return []
follower.device.uuid for follower in multiroom.followers
]
return [] shared_data = self.hass.data[DOMAIN][SHARED_DATA]
return [
entity_id
for entity_id, bridge in shared_data.entity_to_bridge.items()
if bridge
in [multiroom.leader.device.uuid]
+ [follower.device.uuid for follower in multiroom.followers]
]
@exception_wrap @exception_wrap
async def async_unjoin_player(self) -> None: async def async_unjoin_player(self) -> None:
"""Remove this player from any group.""" """Remove this player from any group."""
controller: LinkPlayController = self.hass.data[DOMAIN][CONTROLLER_KEY] controller: LinkPlayController = self.hass.data[DOMAIN][SHARED_DATA].controller
multiroom = self._bridge.multiroom multiroom = self._bridge.multiroom
if multiroom is not None: if multiroom is not None: