mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 08:17:08 +00:00
Add repeat feature to HEOS media player (#136180)
This commit is contained in:
parent
a3cc68754f
commit
f4d6cb45e5
@ -4,7 +4,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Awaitable, Callable, Coroutine
|
from collections.abc import Awaitable, Callable, Coroutine
|
||||||
from functools import reduce, wraps
|
from functools import reduce, wraps
|
||||||
import logging
|
|
||||||
from operator import ior
|
from operator import ior
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -14,6 +13,7 @@ from pyheos import (
|
|||||||
HeosError,
|
HeosError,
|
||||||
HeosPlayer,
|
HeosPlayer,
|
||||||
PlayState,
|
PlayState,
|
||||||
|
RepeatType,
|
||||||
const as heos_const,
|
const as heos_const,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,6 +26,7 @@ from homeassistant.components.media_player import (
|
|||||||
MediaPlayerEntityFeature,
|
MediaPlayerEntityFeature,
|
||||||
MediaPlayerState,
|
MediaPlayerState,
|
||||||
MediaType,
|
MediaType,
|
||||||
|
RepeatMode,
|
||||||
async_process_play_media_url,
|
async_process_play_media_url,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
@ -48,7 +49,6 @@ BASE_SUPPORTED_FEATURES = (
|
|||||||
| MediaPlayerEntityFeature.VOLUME_SET
|
| MediaPlayerEntityFeature.VOLUME_SET
|
||||||
| MediaPlayerEntityFeature.VOLUME_STEP
|
| MediaPlayerEntityFeature.VOLUME_STEP
|
||||||
| MediaPlayerEntityFeature.CLEAR_PLAYLIST
|
| MediaPlayerEntityFeature.CLEAR_PLAYLIST
|
||||||
| MediaPlayerEntityFeature.SHUFFLE_SET
|
|
||||||
| MediaPlayerEntityFeature.SELECT_SOURCE
|
| MediaPlayerEntityFeature.SELECT_SOURCE
|
||||||
| MediaPlayerEntityFeature.PLAY_MEDIA
|
| MediaPlayerEntityFeature.PLAY_MEDIA
|
||||||
| MediaPlayerEntityFeature.GROUPING
|
| MediaPlayerEntityFeature.GROUPING
|
||||||
@ -78,7 +78,12 @@ HA_HEOS_ENQUEUE_MAP = {
|
|||||||
MediaPlayerEnqueue.PLAY: AddCriteriaType.PLAY_NOW,
|
MediaPlayerEnqueue.PLAY: AddCriteriaType.PLAY_NOW,
|
||||||
}
|
}
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
HEOS_HA_REPEAT_TYPE_MAP = {
|
||||||
|
RepeatType.OFF: RepeatMode.OFF,
|
||||||
|
RepeatType.ON_ALL: RepeatMode.ALL,
|
||||||
|
RepeatType.ON_ONE: RepeatMode.ONE,
|
||||||
|
}
|
||||||
|
HA_HEOS_REPEAT_TYPE_MAP = {v: k for k, v in HEOS_HA_REPEAT_TYPE_MAP.items()}
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -293,6 +298,13 @@ class HeosMediaPlayer(MediaPlayerEntity):
|
|||||||
"""Select input source."""
|
"""Select input source."""
|
||||||
await self._source_manager.play_source(source, self._player)
|
await self._source_manager.play_source(source, self._player)
|
||||||
|
|
||||||
|
@catch_action_error("set repeat")
|
||||||
|
async def async_set_repeat(self, repeat: RepeatMode) -> None:
|
||||||
|
"""Set repeat mode."""
|
||||||
|
await self._player.set_play_mode(
|
||||||
|
HA_HEOS_REPEAT_TYPE_MAP[repeat], self._player.shuffle
|
||||||
|
)
|
||||||
|
|
||||||
@catch_action_error("set shuffle")
|
@catch_action_error("set shuffle")
|
||||||
async def async_set_shuffle(self, shuffle: bool) -> None:
|
async def async_set_shuffle(self, shuffle: bool) -> None:
|
||||||
"""Enable/disable shuffle mode."""
|
"""Enable/disable shuffle mode."""
|
||||||
@ -305,11 +317,17 @@ class HeosMediaPlayer(MediaPlayerEntity):
|
|||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
"""Update supported features of the player."""
|
"""Update supported features of the player."""
|
||||||
|
self._attr_repeat = HEOS_HA_REPEAT_TYPE_MAP[self._player.repeat]
|
||||||
controls = self._player.now_playing_media.supported_controls
|
controls = self._player.now_playing_media.supported_controls
|
||||||
current_support = [CONTROL_TO_SUPPORT[control] for control in controls]
|
current_support = [CONTROL_TO_SUPPORT[control] for control in controls]
|
||||||
self._attr_supported_features = reduce(
|
self._attr_supported_features = reduce(
|
||||||
ior, current_support, BASE_SUPPORTED_FEATURES
|
ior, current_support, BASE_SUPPORTED_FEATURES
|
||||||
)
|
)
|
||||||
|
if self.support_next_track and self.support_previous_track:
|
||||||
|
self._attr_supported_features |= (
|
||||||
|
MediaPlayerEntityFeature.REPEAT_SET
|
||||||
|
| MediaPlayerEntityFeature.SHUFFLE_SET
|
||||||
|
)
|
||||||
|
|
||||||
@catch_action_error("unjoin player")
|
@catch_action_error("unjoin player")
|
||||||
async def async_unjoin_player(self) -> None:
|
async def async_unjoin_player(self) -> None:
|
||||||
|
@ -19,13 +19,14 @@
|
|||||||
'media_station': 'Station Name',
|
'media_station': 'Station Name',
|
||||||
'media_title': 'Song',
|
'media_title': 'Song',
|
||||||
'media_type': 'Station',
|
'media_type': 'Station',
|
||||||
|
'repeat': <RepeatMode.OFF: 'off'>,
|
||||||
'shuffle': False,
|
'shuffle': False,
|
||||||
'source_list': list([
|
'source_list': list([
|
||||||
"Today's Hits Radio",
|
"Today's Hits Radio",
|
||||||
'Classical MPR (Classical Music)',
|
'Classical MPR (Classical Music)',
|
||||||
'HEOS Drive - Line In 1',
|
'HEOS Drive - Line In 1',
|
||||||
]),
|
]),
|
||||||
'supported_features': <MediaPlayerEntityFeature: 2817597>,
|
'supported_features': <MediaPlayerEntityFeature: 3079741>,
|
||||||
'volume_level': 0.25,
|
'volume_level': 0.25,
|
||||||
}),
|
}),
|
||||||
'entity_id': 'media_player.test_player',
|
'entity_id': 'media_player.test_player',
|
||||||
|
@ -11,6 +11,7 @@ from pyheos import (
|
|||||||
MediaItem,
|
MediaItem,
|
||||||
PlayerUpdateResult,
|
PlayerUpdateResult,
|
||||||
PlayState,
|
PlayState,
|
||||||
|
RepeatType,
|
||||||
SignalHeosEvent,
|
SignalHeosEvent,
|
||||||
SignalType,
|
SignalType,
|
||||||
const,
|
const,
|
||||||
@ -30,6 +31,7 @@ from homeassistant.components.media_player import (
|
|||||||
ATTR_MEDIA_ENQUEUE,
|
ATTR_MEDIA_ENQUEUE,
|
||||||
ATTR_MEDIA_POSITION,
|
ATTR_MEDIA_POSITION,
|
||||||
ATTR_MEDIA_POSITION_UPDATED_AT,
|
ATTR_MEDIA_POSITION_UPDATED_AT,
|
||||||
|
ATTR_MEDIA_REPEAT,
|
||||||
ATTR_MEDIA_SHUFFLE,
|
ATTR_MEDIA_SHUFFLE,
|
||||||
ATTR_MEDIA_VOLUME_LEVEL,
|
ATTR_MEDIA_VOLUME_LEVEL,
|
||||||
ATTR_MEDIA_VOLUME_MUTED,
|
ATTR_MEDIA_VOLUME_MUTED,
|
||||||
@ -40,6 +42,7 @@ from homeassistant.components.media_player import (
|
|||||||
SERVICE_SELECT_SOURCE,
|
SERVICE_SELECT_SOURCE,
|
||||||
SERVICE_UNJOIN,
|
SERVICE_UNJOIN,
|
||||||
MediaType,
|
MediaType,
|
||||||
|
RepeatMode,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
@ -48,6 +51,7 @@ from homeassistant.const import (
|
|||||||
SERVICE_MEDIA_PLAY,
|
SERVICE_MEDIA_PLAY,
|
||||||
SERVICE_MEDIA_PREVIOUS_TRACK,
|
SERVICE_MEDIA_PREVIOUS_TRACK,
|
||||||
SERVICE_MEDIA_STOP,
|
SERVICE_MEDIA_STOP,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
SERVICE_SHUFFLE_SET,
|
SERVICE_SHUFFLE_SET,
|
||||||
SERVICE_VOLUME_MUTE,
|
SERVICE_VOLUME_MUTE,
|
||||||
SERVICE_VOLUME_SET,
|
SERVICE_VOLUME_SET,
|
||||||
@ -563,6 +567,46 @@ async def test_shuffle_set_error(
|
|||||||
player.set_play_mode.assert_called_once_with(player.repeat, True)
|
player.set_play_mode.assert_called_once_with(player.repeat, True)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_repeat_set(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
||||||
|
) -> None:
|
||||||
|
"""Test the repeat set service."""
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
player = controller.players[1]
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player", ATTR_MEDIA_REPEAT: RepeatMode.ONE},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
player.set_play_mode.assert_called_once_with(RepeatType.ON_ONE, player.shuffle)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_repeat_set_error(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
||||||
|
) -> None:
|
||||||
|
"""Test the repeat set service raises error."""
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
player = controller.players[1]
|
||||||
|
player.set_play_mode.side_effect = CommandFailedError(None, "Failure", 1)
|
||||||
|
with pytest.raises(
|
||||||
|
HomeAssistantError,
|
||||||
|
match=re.escape("Unable to set repeat: Failure (1)"),
|
||||||
|
):
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_REPEAT: RepeatMode.ALL,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
player.set_play_mode.assert_called_once_with(RepeatType.ON_ALL, player.shuffle)
|
||||||
|
|
||||||
|
|
||||||
async def test_volume_set(
|
async def test_volume_set(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
||||||
) -> None:
|
) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user