diff --git a/homeassistant/components/heos/const.py b/homeassistant/components/heos/const.py index 789fbc12b8e..b83da128c91 100644 --- a/homeassistant/components/heos/const.py +++ b/homeassistant/components/heos/const.py @@ -2,11 +2,13 @@ ATTR_PASSWORD = "password" ATTR_USERNAME = "username" +ATTR_QUEUE_IDS = "queue_ids" DOMAIN = "heos" ENTRY_TITLE = "HEOS System" SERVICE_GET_QUEUE = "get_queue" SERVICE_GROUP_VOLUME_SET = "group_volume_set" SERVICE_GROUP_VOLUME_DOWN = "group_volume_down" SERVICE_GROUP_VOLUME_UP = "group_volume_up" +SERVICE_REMOVE_FROM_QUEUE = "remove_from_queue" SERVICE_SIGN_IN = "sign_in" SERVICE_SIGN_OUT = "sign_out" diff --git a/homeassistant/components/heos/icons.json b/homeassistant/components/heos/icons.json index c957ac1939c..c11b499fc0b 100644 --- a/homeassistant/components/heos/icons.json +++ b/homeassistant/components/heos/icons.json @@ -3,6 +3,9 @@ "get_queue": { "service": "mdi:playlist-music" }, + "remove_from_queue": { + "service": "mdi:playlist-remove" + }, "group_volume_set": { "service": "mdi:volume-medium" }, diff --git a/homeassistant/components/heos/media_player.py b/homeassistant/components/heos/media_player.py index 81d997ba44f..a6bc24099f0 100644 --- a/homeassistant/components/heos/media_player.py +++ b/homeassistant/components/heos/media_player.py @@ -61,11 +61,13 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.util.dt import utcnow from .const import ( + ATTR_QUEUE_IDS, DOMAIN as HEOS_DOMAIN, SERVICE_GET_QUEUE, SERVICE_GROUP_VOLUME_DOWN, SERVICE_GROUP_VOLUME_SET, SERVICE_GROUP_VOLUME_UP, + SERVICE_REMOVE_FROM_QUEUE, ) from .coordinator import HeosConfigEntry, HeosCoordinator @@ -145,6 +147,17 @@ async def async_setup_entry( "async_get_queue", supports_response=SupportsResponse.ONLY, ) + platform.async_register_entity_service( + SERVICE_REMOVE_FROM_QUEUE, + { + vol.Required(ATTR_QUEUE_IDS): vol.All( + cv.ensure_list, + [vol.All(cv.positive_int, vol.Range(min=1))], + vol.Unique(), + ) + }, + "async_remove_from_queue", + ) platform.async_register_entity_service( SERVICE_GROUP_VOLUME_SET, {vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float}, @@ -509,6 +522,10 @@ class HeosMediaPlayer(CoordinatorEntity[HeosCoordinator], MediaPlayerEntity): await self.coordinator.heos.set_group(new_members) return + async def async_remove_from_queue(self, queue_ids: list[int]) -> None: + """Remove items from the queue.""" + await self._player.remove_from_queue(queue_ids) + @property def available(self) -> bool: """Return True if the device is available.""" diff --git a/homeassistant/components/heos/services.yaml b/homeassistant/components/heos/services.yaml index fa79bd03096..fd74b2f90c4 100644 --- a/homeassistant/components/heos/services.yaml +++ b/homeassistant/components/heos/services.yaml @@ -4,6 +4,19 @@ get_queue: integration: heos domain: media_player +remove_from_queue: + target: + entity: + integration: heos + domain: media_player + fields: + queue_ids: + required: true + selector: + text: + multiple: true + type: number + group_volume_set: target: entity: diff --git a/homeassistant/components/heos/strings.json b/homeassistant/components/heos/strings.json index 38e3349b7c0..982d15a06fa 100644 --- a/homeassistant/components/heos/strings.json +++ b/homeassistant/components/heos/strings.json @@ -90,6 +90,16 @@ "name": "Get queue", "description": "Retrieves the queue of the media player." }, + "remove_from_queue": { + "name": "Remove from queue", + "description": "Removes items from the play queue.", + "fields": { + "queue_ids": { + "name": "Queue IDs", + "description": "The IDs (indexes) of the items in the queue to remove." + } + } + }, "group_volume_down": { "name": "Turn down group volume", "description": "Turns down the group volume." diff --git a/tests/components/heos/__init__.py b/tests/components/heos/__init__.py index 1fb67bd114f..cdf93c202f0 100644 --- a/tests/components/heos/__init__.py +++ b/tests/components/heos/__init__.py @@ -43,6 +43,7 @@ class MockHeos(Heos): self.player_play_previous: AsyncMock = AsyncMock() self.player_play_queue: AsyncMock = AsyncMock() self.player_play_quick_select: AsyncMock = AsyncMock() + self.player_remove_from_queue: AsyncMock = AsyncMock() self.player_set_mute: AsyncMock = AsyncMock() self.player_set_play_mode: AsyncMock = AsyncMock() self.player_set_play_state: AsyncMock = AsyncMock() diff --git a/tests/components/heos/test_media_player.py b/tests/components/heos/test_media_player.py index 5bc4f2bae30..085a42337b3 100644 --- a/tests/components/heos/test_media_player.py +++ b/tests/components/heos/test_media_player.py @@ -27,11 +27,13 @@ from syrupy.assertion import SnapshotAssertion from syrupy.filters import props from homeassistant.components.heos.const import ( + ATTR_QUEUE_IDS, DOMAIN, SERVICE_GET_QUEUE, SERVICE_GROUP_VOLUME_DOWN, SERVICE_GROUP_VOLUME_SET, SERVICE_GROUP_VOLUME_UP, + SERVICE_REMOVE_FROM_QUEUE, ) from homeassistant.components.media_player import ( ATTR_GROUP_MEMBERS, @@ -1767,3 +1769,18 @@ async def test_get_queue( ) controller.player_get_queue.assert_called_once_with(1, None, None) assert response == snapshot + + +async def test_remove_from_queue( + hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos +) -> None: + """Test the get queue service.""" + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.services.async_call( + DOMAIN, + SERVICE_REMOVE_FROM_QUEUE, + {ATTR_ENTITY_ID: "media_player.test_player", ATTR_QUEUE_IDS: [1, "2"]}, + blocking=True, + ) + controller.player_remove_from_queue.assert_called_once_with(1, [1, 2])