From 40b561ea699a5e026ac31031c636c05aa99f334d Mon Sep 17 00:00:00 2001 From: Markus Jacobsen Date: Mon, 28 Oct 2024 13:39:49 +0100 Subject: [PATCH] Add shuffle media controls to Bang & Olufsen (#129325) --- .../components/bang_olufsen/media_player.py | 10 ++++ .../bang_olufsen/test_media_player.py | 47 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/bang_olufsen/media_player.py b/homeassistant/components/bang_olufsen/media_player.py index 81190613c3b..31f821683d4 100644 --- a/homeassistant/components/bang_olufsen/media_player.py +++ b/homeassistant/components/bang_olufsen/media_player.py @@ -95,6 +95,7 @@ BANG_OLUFSEN_FEATURES = ( | MediaPlayerEntityFeature.PREVIOUS_TRACK | MediaPlayerEntityFeature.REPEAT_SET | MediaPlayerEntityFeature.SELECT_SOURCE + | MediaPlayerEntityFeature.SHUFFLE_SET | MediaPlayerEntityFeature.STOP | MediaPlayerEntityFeature.TURN_OFF | MediaPlayerEntityFeature.VOLUME_MUTE @@ -239,6 +240,9 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): if queue_settings.repeat is not None: self._attr_repeat = BANG_OLUFSEN_REPEAT_TO_HA[queue_settings.repeat] + if queue_settings.shuffle is not None: + self._attr_shuffle = queue_settings.shuffle + async def _async_update_sources(self) -> None: """Get sources for the specific product.""" @@ -663,6 +667,12 @@ class BangOlufsenMediaPlayer(BangOlufsenEntity, MediaPlayerEntity): ) ) + async def async_set_shuffle(self, shuffle: bool) -> None: + """Set playback queues to shuffle.""" + await self._client.set_settings_queue( + play_queue_settings=PlayQueueSettings(shuffle=shuffle), + ) + async def async_select_source(self, source: str) -> None: """Select an input source.""" if source not in self._sources.values(): diff --git a/tests/components/bang_olufsen/test_media_player.py b/tests/components/bang_olufsen/test_media_player.py index 5cf2a9654bf..844e9bfe61b 100644 --- a/tests/components/bang_olufsen/test_media_player.py +++ b/tests/components/bang_olufsen/test_media_player.py @@ -36,6 +36,7 @@ from homeassistant.components.media_player import ( ATTR_MEDIA_POSITION_UPDATED_AT, ATTR_MEDIA_REPEAT, ATTR_MEDIA_SEEK_POSITION, + ATTR_MEDIA_SHUFFLE, ATTR_MEDIA_TITLE, ATTR_MEDIA_TRACK, ATTR_MEDIA_VOLUME_LEVEL, @@ -59,7 +60,7 @@ from homeassistant.components.media_player import ( MediaType, RepeatMode, ) -from homeassistant.const import ATTR_ENTITY_ID, SERVICE_REPEAT_SET +from homeassistant.const import ATTR_ENTITY_ID, SERVICE_REPEAT_SET, SERVICE_SHUFFLE_SET from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.setup import async_setup_component @@ -1476,3 +1477,47 @@ async def test_async_set_repeat( # Test the BANG_OLUFSEN_REPEAT_TO_HA dict by checking property value assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID)) assert states.attributes[ATTR_MEDIA_REPEAT] == repeat + + +@pytest.mark.parametrize( + ("shuffle"), + [ + # Shuffle on + (True), + # Shuffle off + (False), + ], +) +async def test_async_set_shuffle( + hass: HomeAssistant, + mock_mozart_client: AsyncMock, + mock_config_entry: MockConfigEntry, + shuffle: bool, +) -> None: + """Test async_set_shuffle.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + + assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID)) + assert ATTR_MEDIA_SHUFFLE not in states.attributes + + # Set the return value of the shuffle endpoint to match service call + mock_mozart_client.get_settings_queue.return_value = PlayQueueSettings( + shuffle=shuffle + ) + + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, + SERVICE_SHUFFLE_SET, + { + ATTR_ENTITY_ID: TEST_MEDIA_PLAYER_ENTITY_ID, + ATTR_MEDIA_SHUFFLE: shuffle, + }, + blocking=True, + ) + mock_mozart_client.set_settings_queue.assert_called_once_with( + play_queue_settings=PlayQueueSettings(shuffle=shuffle) + ) + + assert (states := hass.states.get(TEST_MEDIA_PLAYER_ENTITY_ID)) + assert states.attributes[ATTR_MEDIA_SHUFFLE] == shuffle