diff --git a/homeassistant/components/music_assistant/media_player.py b/homeassistant/components/music_assistant/media_player.py index d1d707c92e1..fdf3a0c0c48 100644 --- a/homeassistant/components/music_assistant/media_player.py +++ b/homeassistant/components/music_assistant/media_player.py @@ -400,13 +400,13 @@ class MusicAssistantPlayer(MusicAssistantEntity, MediaPlayerEntity): async def async_join_players(self, group_members: list[str]) -> None: """Join `group_members` as a player group with the current player.""" player_ids: list[str] = [] + entity_registry = er.async_get(self.hass) for child_entity_id in group_members: # resolve HA entity_id to MA player_id - if (hass_state := self.hass.states.get(child_entity_id)) is None: - continue - if (mass_player_id := hass_state.attributes.get("mass_player_id")) is None: - continue - player_ids.append(mass_player_id) + if not (entity_reg_entry := entity_registry.async_get(child_entity_id)): + raise HomeAssistantError(f"Entity {child_entity_id} not found") + # unique id is the MA player_id + player_ids.append(entity_reg_entry.unique_id) await self.mass.players.player_command_group_many(self.player_id, player_ids) @catch_musicassistant_error diff --git a/tests/components/music_assistant/test_media_player.py b/tests/components/music_assistant/test_media_player.py index 26ed5d1e538..13716b6a479 100644 --- a/tests/components/music_assistant/test_media_player.py +++ b/tests/components/music_assistant/test_media_player.py @@ -8,6 +8,7 @@ import pytest from syrupy import SnapshotAssertion from homeassistant.components.media_player import ( + ATTR_GROUP_MEMBERS, ATTR_MEDIA_ENQUEUE, ATTR_MEDIA_REPEAT, ATTR_MEDIA_SEEK_POSITION, @@ -16,6 +17,8 @@ from homeassistant.components.media_player import ( ATTR_MEDIA_VOLUME_MUTED, DOMAIN as MEDIA_PLAYER_DOMAIN, SERVICE_CLEAR_PLAYLIST, + SERVICE_JOIN, + SERVICE_UNJOIN, ) from homeassistant.components.music_assistant.const import DOMAIN as MASS_DOMAIN from homeassistant.components.music_assistant.media_player import ( @@ -269,6 +272,71 @@ async def test_media_player_repeat_set_action( ) +async def test_media_player_join_players_action( + hass: HomeAssistant, + music_assistant_client: MagicMock, +) -> None: + """Test media_player entity join_players action.""" + await setup_integration_from_fixtures(hass, music_assistant_client) + entity_id = "media_player.test_player_1" + mass_player_id = "00:00:00:00:00:01" + state = hass.states.get(entity_id) + assert state + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, + SERVICE_JOIN, + { + ATTR_ENTITY_ID: entity_id, + ATTR_GROUP_MEMBERS: ["media_player.my_super_test_player_2"], + }, + blocking=True, + ) + assert music_assistant_client.send_command.call_count == 1 + assert music_assistant_client.send_command.call_args == call( + "players/cmd/group_many", + target_player=mass_player_id, + child_player_ids=["00:00:00:00:00:02"], + ) + # test again with invalid source player + music_assistant_client.send_command.reset_mock() + with pytest.raises( + HomeAssistantError, match="Entity media_player.blah_blah not found" + ): + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, + SERVICE_JOIN, + { + ATTR_ENTITY_ID: entity_id, + ATTR_GROUP_MEMBERS: ["media_player.blah_blah"], + }, + blocking=True, + ) + + +async def test_media_player_unjoin_player_action( + hass: HomeAssistant, + music_assistant_client: MagicMock, +) -> None: + """Test media_player entity unjoin player action.""" + await setup_integration_from_fixtures(hass, music_assistant_client) + entity_id = "media_player.test_player_1" + mass_player_id = "00:00:00:00:00:01" + state = hass.states.get(entity_id) + assert state + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, + SERVICE_UNJOIN, + { + ATTR_ENTITY_ID: entity_id, + }, + blocking=True, + ) + assert music_assistant_client.send_command.call_count == 1 + assert music_assistant_client.send_command.call_args == call( + "players/cmd/ungroup", player_id=mass_player_id + ) + + async def test_media_player_clear_playlist_action( hass: HomeAssistant, music_assistant_client: MagicMock,