From 6bfd39f0942cd013b64ed01d1c50ad5ef9d73c91 Mon Sep 17 00:00:00 2001 From: Andrew Sayre <6730289+andrewsayre@users.noreply.github.com> Date: Wed, 26 Mar 2025 15:47:10 -0500 Subject: [PATCH] Add play queue item to HEOS (#141480) Add ability to play specific queue item --- homeassistant/components/heos/media_player.py | 9 ++++ tests/components/heos/__init__.py | 1 + tests/components/heos/test_media_player.py | 45 +++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/homeassistant/components/heos/media_player.py b/homeassistant/components/heos/media_player.py index 9cd01051b95..81d997ba44f 100644 --- a/homeassistant/components/heos/media_player.py +++ b/homeassistant/components/heos/media_player.py @@ -387,6 +387,15 @@ class HeosMediaPlayer(CoordinatorEntity[HeosCoordinator], MediaPlayerEntity): await self._player.play_preset_station(index) return + if media_type == "queue": + # media_id must be an int + try: + queue_id = int(media_id) + except ValueError: + raise ValueError(f"Invalid queue id '{media_id}'") from None + await self._player.play_queue(queue_id) + return + raise ValueError(f"Unsupported media type '{media_type}'") @catch_action_error("select source") diff --git a/tests/components/heos/__init__.py b/tests/components/heos/__init__.py index 34eba8a9c76..1fb67bd114f 100644 --- a/tests/components/heos/__init__.py +++ b/tests/components/heos/__init__.py @@ -41,6 +41,7 @@ class MockHeos(Heos): self.player_get_quick_selects: AsyncMock = AsyncMock() self.player_play_next: AsyncMock = AsyncMock() self.player_play_previous: AsyncMock = AsyncMock() + self.player_play_queue: AsyncMock = AsyncMock() self.player_play_quick_select: AsyncMock = AsyncMock() self.player_set_mute: AsyncMock = AsyncMock() self.player_set_play_mode: AsyncMock = AsyncMock() diff --git a/tests/components/heos/test_media_player.py b/tests/components/heos/test_media_player.py index 474d606b5b1..5bc4f2bae30 100644 --- a/tests/components/heos/test_media_player.py +++ b/tests/components/heos/test_media_player.py @@ -1321,6 +1321,51 @@ async def test_play_media_music_source_url( controller.play_url.assert_called_once() +async def test_play_media_queue( + hass: HomeAssistant, + config_entry: MockConfigEntry, + controller: MockHeos, +) -> None: + """Test the play media service with type queue.""" + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, + SERVICE_PLAY_MEDIA, + { + ATTR_ENTITY_ID: "media_player.test_player", + ATTR_MEDIA_CONTENT_TYPE: "queue", + ATTR_MEDIA_CONTENT_ID: "2", + }, + blocking=True, + ) + controller.player_play_queue.assert_called_once_with(1, 2) + + +async def test_play_media_queue_invalid( + hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos +) -> None: + """Test the play media service with an invalid queue id.""" + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + with pytest.raises( + HomeAssistantError, + match=re.escape("Unable to play media: Invalid queue id 'Invalid'"), + ): + await hass.services.async_call( + MEDIA_PLAYER_DOMAIN, + SERVICE_PLAY_MEDIA, + { + ATTR_ENTITY_ID: "media_player.test_player", + ATTR_MEDIA_CONTENT_TYPE: "queue", + ATTR_MEDIA_CONTENT_ID: "Invalid", + }, + blocking=True, + ) + assert controller.player_play_queue.call_count == 0 + + async def test_browse_media_root( hass: HomeAssistant, config_entry: MockConfigEntry,