mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Add move queue item HEOS entity service (#142301)
This commit is contained in:
parent
52143155e7
commit
660cbc136f
@ -2,6 +2,7 @@
|
||||
|
||||
ATTR_PASSWORD = "password"
|
||||
ATTR_USERNAME = "username"
|
||||
ATTR_DESTINATION_POSITION = "destination_position"
|
||||
ATTR_QUEUE_IDS = "queue_ids"
|
||||
DOMAIN = "heos"
|
||||
ENTRY_TITLE = "HEOS System"
|
||||
@ -9,6 +10,7 @@ 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_MOVE_QUEUE_ITEM = "move_queue_item"
|
||||
SERVICE_REMOVE_FROM_QUEUE = "remove_from_queue"
|
||||
SERVICE_SIGN_IN = "sign_in"
|
||||
SERVICE_SIGN_OUT = "sign_out"
|
||||
|
@ -6,6 +6,9 @@
|
||||
"remove_from_queue": {
|
||||
"service": "mdi:playlist-remove"
|
||||
},
|
||||
"move_queue_item": {
|
||||
"service": "mdi:playlist-edit"
|
||||
},
|
||||
"group_volume_set": {
|
||||
"service": "mdi:volume-medium"
|
||||
},
|
||||
|
@ -479,6 +479,13 @@ class HeosMediaPlayer(CoordinatorEntity[HeosCoordinator], MediaPlayerEntity):
|
||||
"""Remove items from the queue."""
|
||||
await self._player.remove_from_queue(queue_ids)
|
||||
|
||||
@catch_action_error("move queue item")
|
||||
async def async_move_queue_item(
|
||||
self, queue_ids: list[int], destination_position: int
|
||||
) -> None:
|
||||
"""Move items in the queue."""
|
||||
await self._player.move_queue_item(queue_ids, destination_position)
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return True if the device is available."""
|
||||
|
@ -19,6 +19,7 @@ from homeassistant.helpers import (
|
||||
from homeassistant.helpers.typing import VolDictType, VolSchemaType
|
||||
|
||||
from .const import (
|
||||
ATTR_DESTINATION_POSITION,
|
||||
ATTR_PASSWORD,
|
||||
ATTR_QUEUE_IDS,
|
||||
ATTR_USERNAME,
|
||||
@ -27,6 +28,7 @@ from .const import (
|
||||
SERVICE_GROUP_VOLUME_DOWN,
|
||||
SERVICE_GROUP_VOLUME_SET,
|
||||
SERVICE_GROUP_VOLUME_UP,
|
||||
SERVICE_MOVE_QUEUE_ITEM,
|
||||
SERVICE_REMOVE_FROM_QUEUE,
|
||||
SERVICE_SIGN_IN,
|
||||
SERVICE_SIGN_OUT,
|
||||
@ -87,6 +89,16 @@ REMOVE_FROM_QUEUE_SCHEMA: Final[VolDictType] = {
|
||||
GROUP_VOLUME_SET_SCHEMA: Final[VolDictType] = {
|
||||
vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float
|
||||
}
|
||||
MOVE_QEUEUE_ITEM_SCHEMA: Final[VolDictType] = {
|
||||
vol.Required(ATTR_QUEUE_IDS): vol.All(
|
||||
cv.ensure_list,
|
||||
[vol.All(vol.Coerce(int), vol.Range(min=1, max=1000))],
|
||||
vol.Unique(),
|
||||
),
|
||||
vol.Required(ATTR_DESTINATION_POSITION): vol.All(
|
||||
vol.Coerce(int), vol.Range(min=1, max=1000)
|
||||
),
|
||||
}
|
||||
|
||||
MEDIA_PLAYER_ENTITY_SERVICES: Final = (
|
||||
# Player queue services
|
||||
@ -96,6 +108,9 @@ MEDIA_PLAYER_ENTITY_SERVICES: Final = (
|
||||
EntityServiceDescription(
|
||||
SERVICE_REMOVE_FROM_QUEUE, "async_remove_from_queue", REMOVE_FROM_QUEUE_SCHEMA
|
||||
),
|
||||
EntityServiceDescription(
|
||||
SERVICE_MOVE_QUEUE_ITEM, "async_move_queue_item", MOVE_QEUEUE_ITEM_SCHEMA
|
||||
),
|
||||
# Group volume services
|
||||
EntityServiceDescription(
|
||||
SERVICE_GROUP_VOLUME_SET,
|
||||
|
@ -17,6 +17,26 @@ remove_from_queue:
|
||||
multiple: true
|
||||
type: number
|
||||
|
||||
move_queue_item:
|
||||
target:
|
||||
entity:
|
||||
integration: heos
|
||||
domain: media_player
|
||||
fields:
|
||||
queue_ids:
|
||||
required: true
|
||||
selector:
|
||||
text:
|
||||
multiple: true
|
||||
type: number
|
||||
destination_position:
|
||||
required: true
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
max: 1000
|
||||
step: 1
|
||||
|
||||
group_volume_set:
|
||||
target:
|
||||
entity:
|
||||
|
@ -100,6 +100,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"move_queue_item": {
|
||||
"name": "Move queue item",
|
||||
"description": "Move one or more items within the play queue.",
|
||||
"fields": {
|
||||
"queue_ids": {
|
||||
"name": "Queue IDs",
|
||||
"description": "The IDs (indexes) of the items in the queue to move."
|
||||
},
|
||||
"destination_position": {
|
||||
"name": "Destination position",
|
||||
"description": "The position index in the queue to move the items to."
|
||||
}
|
||||
}
|
||||
},
|
||||
"group_volume_down": {
|
||||
"name": "Turn down group volume",
|
||||
"description": "Turns down the group volume."
|
||||
|
@ -39,6 +39,7 @@ class MockHeos(Heos):
|
||||
self.player_clear_queue: AsyncMock = AsyncMock()
|
||||
self.player_get_queue: AsyncMock = AsyncMock()
|
||||
self.player_get_quick_selects: AsyncMock = AsyncMock()
|
||||
self.player_move_queue_item: AsyncMock = AsyncMock()
|
||||
self.player_play_next: AsyncMock = AsyncMock()
|
||||
self.player_play_previous: AsyncMock = AsyncMock()
|
||||
self.player_play_queue: AsyncMock = AsyncMock()
|
||||
|
@ -27,12 +27,14 @@ from syrupy.assertion import SnapshotAssertion
|
||||
from syrupy.filters import props
|
||||
|
||||
from homeassistant.components.heos.const import (
|
||||
ATTR_DESTINATION_POSITION,
|
||||
ATTR_QUEUE_IDS,
|
||||
DOMAIN,
|
||||
SERVICE_GET_QUEUE,
|
||||
SERVICE_GROUP_VOLUME_DOWN,
|
||||
SERVICE_GROUP_VOLUME_SET,
|
||||
SERVICE_GROUP_VOLUME_UP,
|
||||
SERVICE_MOVE_QUEUE_ITEM,
|
||||
SERVICE_REMOVE_FROM_QUEUE,
|
||||
)
|
||||
from homeassistant.components.media_player import (
|
||||
@ -1784,3 +1786,45 @@ async def test_remove_from_queue(
|
||||
blocking=True,
|
||||
)
|
||||
controller.player_remove_from_queue.assert_called_once_with(1, [1, 2])
|
||||
|
||||
|
||||
async def test_move_queue_item_queue(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||
) -> None:
|
||||
"""Test the move 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_MOVE_QUEUE_ITEM,
|
||||
{
|
||||
ATTR_ENTITY_ID: "media_player.test_player",
|
||||
ATTR_QUEUE_IDS: [1, "2"],
|
||||
ATTR_DESTINATION_POSITION: 10,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
controller.player_move_queue_item.assert_called_once_with(1, [1, 2], 10)
|
||||
|
||||
|
||||
async def test_move_queue_item_queue_error_raises(
|
||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||
) -> None:
|
||||
"""Test move queue raises error when failed."""
|
||||
config_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
controller.player_move_queue_item.side_effect = HeosError("error")
|
||||
with pytest.raises(
|
||||
HomeAssistantError,
|
||||
match=re.escape("Unable to move queue item: error"),
|
||||
):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_MOVE_QUEUE_ITEM,
|
||||
{
|
||||
ATTR_ENTITY_ID: "media_player.test_player",
|
||||
ATTR_QUEUE_IDS: [1, "2"],
|
||||
ATTR_DESTINATION_POSITION: 10,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user