diff --git a/homeassistant/components/bluesound/media_player.py b/homeassistant/components/bluesound/media_player.py index 97985a74300..38ef78fad3a 100644 --- a/homeassistant/components/bluesound/media_player.py +++ b/homeassistant/components/bluesound/media_player.py @@ -292,14 +292,6 @@ class BluesoundPlayer(MediaPlayerEntity): self._last_status_update = dt_util.utcnow() self._status = status - group_name = status.group_name - if group_name != self._group_name: - _LOGGER.debug("Group name change detected on device: %s", self.id) - self._group_name = group_name - - # rebuild ordered list of entity_ids that are in the group, master is first - self._group_list = self.rebuild_bluesound_group() - self.async_write_ha_state() except PlayerUnreachableError: self._attr_available = False @@ -323,6 +315,8 @@ class BluesoundPlayer(MediaPlayerEntity): self._sync_status = sync_status + self._group_list = self.rebuild_bluesound_group() + if sync_status.master is not None: self._is_master = False master_id = f"{sync_status.master.ip}:{sync_status.master.port}" @@ -619,21 +613,32 @@ class BluesoundPlayer(MediaPlayerEntity): def rebuild_bluesound_group(self) -> list[str]: """Rebuild the list of entities in speaker group.""" - if self._group_name is None: + if self.sync_status.master is None and self.sync_status.slaves is None: return [] - device_group = self._group_name.split("+") + player_entities: list[BluesoundPlayer] = self.hass.data[DATA_BLUESOUND] - sorted_entities: list[BluesoundPlayer] = sorted( - self.hass.data[DATA_BLUESOUND], - key=lambda entity: entity.is_master, - reverse=True, - ) - return [ - entity.sync_status.name - for entity in sorted_entities - if entity.bluesound_device_name in device_group + leader_sync_status: SyncStatus | None = None + if self.sync_status.master is None: + leader_sync_status = self.sync_status + else: + required_id = f"{self.sync_status.master.ip}:{self.sync_status.master.port}" + for x in player_entities: + if x.sync_status.id == required_id: + leader_sync_status = x.sync_status + break + + if leader_sync_status is None or leader_sync_status.slaves is None: + return [] + + follower_ids = [f"{x.ip}:{x.port}" for x in leader_sync_status.slaves] + follower_names = [ + x.sync_status.name + for x in player_entities + if x.sync_status.id in follower_ids ] + follower_names.insert(0, leader_sync_status.name) + return follower_names async def async_unjoin(self) -> None: """Unjoin the player from a group.""" diff --git a/tests/components/bluesound/test_media_player.py b/tests/components/bluesound/test_media_player.py index 0bf615de3da..217225628f2 100644 --- a/tests/components/bluesound/test_media_player.py +++ b/tests/components/bluesound/test_media_player.py @@ -325,17 +325,17 @@ async def test_attr_bluesound_group( setup_config_entry_secondary: None, player_mocks: PlayerMocks, ) -> None: - """Test the media player grouping.""" + """Test the media player grouping for leader.""" attr_bluesound_group = hass.states.get( "media_player.player_name1111" ).attributes.get("bluesound_group") assert attr_bluesound_group is None - updated_status = dataclasses.replace( - player_mocks.player_data.status_long_polling_mock.get(), - group_name="player-name1111+player-name2222", + updated_sync_status = dataclasses.replace( + player_mocks.player_data.sync_status_long_polling_mock.get(), + slaves=[PairedPlayer("2.2.2.2", 11000)], ) - player_mocks.player_data.status_long_polling_mock.set(updated_status) + player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status) # give the long polling loop a chance to update the state; this could be any async call await hass.async_block_till_done() @@ -347,6 +347,45 @@ async def test_attr_bluesound_group( assert attr_bluesound_group == ["player-name1111", "player-name2222"] +async def test_attr_bluesound_group_for_follower( + hass: HomeAssistant, + setup_config_entry: None, + setup_config_entry_secondary: None, + player_mocks: PlayerMocks, +) -> None: + """Test the media player grouping for follower.""" + attr_bluesound_group = hass.states.get( + "media_player.player_name2222" + ).attributes.get("bluesound_group") + assert attr_bluesound_group is None + + updated_sync_status = dataclasses.replace( + player_mocks.player_data.sync_status_long_polling_mock.get(), + slaves=[PairedPlayer("2.2.2.2", 11000)], + ) + player_mocks.player_data.sync_status_long_polling_mock.set(updated_sync_status) + + # give the long polling loop a chance to update the state; this could be any async call + await hass.async_block_till_done() + + updated_sync_status = dataclasses.replace( + player_mocks.player_data_secondary.sync_status_long_polling_mock.get(), + master=PairedPlayer("1.1.1.1", 11000), + ) + player_mocks.player_data_secondary.sync_status_long_polling_mock.set( + updated_sync_status + ) + + # give the long polling loop a chance to update the state; this could be any async call + await hass.async_block_till_done() + + attr_bluesound_group = hass.states.get( + "media_player.player_name2222" + ).attributes.get("bluesound_group") + + assert attr_bluesound_group == ["player-name1111", "player-name2222"] + + async def test_volume_up_from_6_to_7( hass: HomeAssistant, setup_config_entry: None,