Add media_player.repeat_set service (#41435)
parent
a6393fb36c
commit
d00655810f
|
@ -4,12 +4,14 @@ from homeassistant.components.media_player.const import (
|
||||||
MEDIA_TYPE_MOVIE,
|
MEDIA_TYPE_MOVIE,
|
||||||
MEDIA_TYPE_MUSIC,
|
MEDIA_TYPE_MUSIC,
|
||||||
MEDIA_TYPE_TVSHOW,
|
MEDIA_TYPE_TVSHOW,
|
||||||
|
REPEAT_MODE_OFF,
|
||||||
SUPPORT_CLEAR_PLAYLIST,
|
SUPPORT_CLEAR_PLAYLIST,
|
||||||
SUPPORT_NEXT_TRACK,
|
SUPPORT_NEXT_TRACK,
|
||||||
SUPPORT_PAUSE,
|
SUPPORT_PAUSE,
|
||||||
SUPPORT_PLAY,
|
SUPPORT_PLAY,
|
||||||
SUPPORT_PLAY_MEDIA,
|
SUPPORT_PLAY_MEDIA,
|
||||||
SUPPORT_PREVIOUS_TRACK,
|
SUPPORT_PREVIOUS_TRACK,
|
||||||
|
SUPPORT_REPEAT_SET,
|
||||||
SUPPORT_SEEK,
|
SUPPORT_SEEK,
|
||||||
SUPPORT_SELECT_SOUND_MODE,
|
SUPPORT_SELECT_SOUND_MODE,
|
||||||
SUPPORT_SELECT_SOURCE,
|
SUPPORT_SELECT_SOURCE,
|
||||||
|
@ -73,6 +75,7 @@ MUSIC_PLAYER_SUPPORT = (
|
||||||
| SUPPORT_CLEAR_PLAYLIST
|
| SUPPORT_CLEAR_PLAYLIST
|
||||||
| SUPPORT_PLAY
|
| SUPPORT_PLAY
|
||||||
| SUPPORT_SHUFFLE_SET
|
| SUPPORT_SHUFFLE_SET
|
||||||
|
| SUPPORT_REPEAT_SET
|
||||||
| SUPPORT_VOLUME_STEP
|
| SUPPORT_VOLUME_STEP
|
||||||
| SUPPORT_PREVIOUS_TRACK
|
| SUPPORT_PREVIOUS_TRACK
|
||||||
| SUPPORT_NEXT_TRACK
|
| SUPPORT_NEXT_TRACK
|
||||||
|
@ -319,6 +322,7 @@ class DemoMusicPlayer(AbstractDemoPlayer):
|
||||||
"""Initialize the demo device."""
|
"""Initialize the demo device."""
|
||||||
super().__init__("Walkman")
|
super().__init__("Walkman")
|
||||||
self._cur_track = 0
|
self._cur_track = 0
|
||||||
|
self._repeat = REPEAT_MODE_OFF
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_content_id(self):
|
def media_content_id(self):
|
||||||
|
@ -360,6 +364,11 @@ class DemoMusicPlayer(AbstractDemoPlayer):
|
||||||
"""Return the track number of current media (Music track only)."""
|
"""Return the track number of current media (Music track only)."""
|
||||||
return self._cur_track + 1
|
return self._cur_track + 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def repeat(self):
|
||||||
|
"""Return current repeat mode."""
|
||||||
|
return self._repeat
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag media player features that are supported."""
|
"""Flag media player features that are supported."""
|
||||||
|
@ -384,6 +393,11 @@ class DemoMusicPlayer(AbstractDemoPlayer):
|
||||||
self._player_state = STATE_OFF
|
self._player_state = STATE_OFF
|
||||||
self.schedule_update_ha_state()
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
|
def set_repeat(self, repeat):
|
||||||
|
"""Enable/disable repeat mode."""
|
||||||
|
self._repeat = repeat
|
||||||
|
self.schedule_update_ha_state()
|
||||||
|
|
||||||
|
|
||||||
class DemoTVShowPlayer(AbstractDemoPlayer):
|
class DemoTVShowPlayer(AbstractDemoPlayer):
|
||||||
"""A Demo media player that only supports YouTube."""
|
"""A Demo media player that only supports YouTube."""
|
||||||
|
|
|
@ -35,6 +35,7 @@ from homeassistant.const import (
|
||||||
SERVICE_MEDIA_PREVIOUS_TRACK,
|
SERVICE_MEDIA_PREVIOUS_TRACK,
|
||||||
SERVICE_MEDIA_SEEK,
|
SERVICE_MEDIA_SEEK,
|
||||||
SERVICE_MEDIA_STOP,
|
SERVICE_MEDIA_STOP,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
SERVICE_SHUFFLE_SET,
|
SERVICE_SHUFFLE_SET,
|
||||||
SERVICE_TOGGLE,
|
SERVICE_TOGGLE,
|
||||||
SERVICE_TURN_OFF,
|
SERVICE_TURN_OFF,
|
||||||
|
@ -76,6 +77,7 @@ from .const import (
|
||||||
ATTR_MEDIA_PLAYLIST,
|
ATTR_MEDIA_PLAYLIST,
|
||||||
ATTR_MEDIA_POSITION,
|
ATTR_MEDIA_POSITION,
|
||||||
ATTR_MEDIA_POSITION_UPDATED_AT,
|
ATTR_MEDIA_POSITION_UPDATED_AT,
|
||||||
|
ATTR_MEDIA_REPEAT,
|
||||||
ATTR_MEDIA_SEASON,
|
ATTR_MEDIA_SEASON,
|
||||||
ATTR_MEDIA_SEEK_POSITION,
|
ATTR_MEDIA_SEEK_POSITION,
|
||||||
ATTR_MEDIA_SERIES_TITLE,
|
ATTR_MEDIA_SERIES_TITLE,
|
||||||
|
@ -88,6 +90,7 @@ from .const import (
|
||||||
ATTR_SOUND_MODE_LIST,
|
ATTR_SOUND_MODE_LIST,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
MEDIA_CLASS_DIRECTORY,
|
MEDIA_CLASS_DIRECTORY,
|
||||||
|
REPEAT_MODES,
|
||||||
SERVICE_CLEAR_PLAYLIST,
|
SERVICE_CLEAR_PLAYLIST,
|
||||||
SERVICE_PLAY_MEDIA,
|
SERVICE_PLAY_MEDIA,
|
||||||
SERVICE_SELECT_SOUND_MODE,
|
SERVICE_SELECT_SOUND_MODE,
|
||||||
|
@ -99,6 +102,7 @@ from .const import (
|
||||||
SUPPORT_PLAY,
|
SUPPORT_PLAY,
|
||||||
SUPPORT_PLAY_MEDIA,
|
SUPPORT_PLAY_MEDIA,
|
||||||
SUPPORT_PREVIOUS_TRACK,
|
SUPPORT_PREVIOUS_TRACK,
|
||||||
|
SUPPORT_REPEAT_SET,
|
||||||
SUPPORT_SEEK,
|
SUPPORT_SEEK,
|
||||||
SUPPORT_SELECT_SOUND_MODE,
|
SUPPORT_SELECT_SOUND_MODE,
|
||||||
SUPPORT_SELECT_SOURCE,
|
SUPPORT_SELECT_SOURCE,
|
||||||
|
@ -167,6 +171,7 @@ ATTR_TO_PROPERTY = [
|
||||||
ATTR_INPUT_SOURCE,
|
ATTR_INPUT_SOURCE,
|
||||||
ATTR_SOUND_MODE,
|
ATTR_SOUND_MODE,
|
||||||
ATTR_MEDIA_SHUFFLE,
|
ATTR_MEDIA_SHUFFLE,
|
||||||
|
ATTR_MEDIA_REPEAT,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -325,6 +330,13 @@ async def async_setup(hass, config):
|
||||||
[SUPPORT_SHUFFLE_SET],
|
[SUPPORT_SHUFFLE_SET],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
component.async_register_entity_service(
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
|
{vol.Required(ATTR_MEDIA_REPEAT): vol.In(REPEAT_MODES)},
|
||||||
|
"async_set_repeat",
|
||||||
|
[SUPPORT_REPEAT_SET],
|
||||||
|
)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -508,6 +520,11 @@ class MediaPlayerEntity(Entity):
|
||||||
"""Boolean if shuffle is enabled."""
|
"""Boolean if shuffle is enabled."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def repeat(self):
|
||||||
|
"""Return current repeat mode."""
|
||||||
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_features(self):
|
def supported_features(self):
|
||||||
"""Flag media player features that are supported."""
|
"""Flag media player features that are supported."""
|
||||||
|
@ -635,6 +652,14 @@ class MediaPlayerEntity(Entity):
|
||||||
"""Enable/disable shuffle mode."""
|
"""Enable/disable shuffle mode."""
|
||||||
await self.hass.async_add_executor_job(self.set_shuffle, shuffle)
|
await self.hass.async_add_executor_job(self.set_shuffle, shuffle)
|
||||||
|
|
||||||
|
def set_repeat(self, repeat):
|
||||||
|
"""Set repeat mode."""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
async def async_set_repeat(self, repeat):
|
||||||
|
"""Set repeat mode."""
|
||||||
|
await self.hass.async_add_job(self.set_repeat, repeat)
|
||||||
|
|
||||||
# No need to overwrite these.
|
# No need to overwrite these.
|
||||||
@property
|
@property
|
||||||
def support_play(self):
|
def support_play(self):
|
||||||
|
|
|
@ -17,6 +17,7 @@ ATTR_MEDIA_EPISODE = "media_episode"
|
||||||
ATTR_MEDIA_PLAYLIST = "media_playlist"
|
ATTR_MEDIA_PLAYLIST = "media_playlist"
|
||||||
ATTR_MEDIA_POSITION = "media_position"
|
ATTR_MEDIA_POSITION = "media_position"
|
||||||
ATTR_MEDIA_POSITION_UPDATED_AT = "media_position_updated_at"
|
ATTR_MEDIA_POSITION_UPDATED_AT = "media_position_updated_at"
|
||||||
|
ATTR_MEDIA_REPEAT = "repeat"
|
||||||
ATTR_MEDIA_SEASON = "media_season"
|
ATTR_MEDIA_SEASON = "media_season"
|
||||||
ATTR_MEDIA_SEEK_POSITION = "seek_position"
|
ATTR_MEDIA_SEEK_POSITION = "seek_position"
|
||||||
ATTR_MEDIA_SERIES_TITLE = "media_series_title"
|
ATTR_MEDIA_SERIES_TITLE = "media_series_title"
|
||||||
|
@ -78,6 +79,11 @@ SERVICE_PLAY_MEDIA = "play_media"
|
||||||
SERVICE_SELECT_SOUND_MODE = "select_sound_mode"
|
SERVICE_SELECT_SOUND_MODE = "select_sound_mode"
|
||||||
SERVICE_SELECT_SOURCE = "select_source"
|
SERVICE_SELECT_SOURCE = "select_source"
|
||||||
|
|
||||||
|
REPEAT_MODE_ALL = "all"
|
||||||
|
REPEAT_MODE_OFF = "off"
|
||||||
|
REPEAT_MODE_ONE = "one"
|
||||||
|
REPEAT_MODES = [REPEAT_MODE_ALL, REPEAT_MODE_OFF, REPEAT_MODE_ONE]
|
||||||
|
|
||||||
SUPPORT_PAUSE = 1
|
SUPPORT_PAUSE = 1
|
||||||
SUPPORT_SEEK = 2
|
SUPPORT_SEEK = 2
|
||||||
SUPPORT_VOLUME_SET = 4
|
SUPPORT_VOLUME_SET = 4
|
||||||
|
@ -96,3 +102,4 @@ SUPPORT_PLAY = 16384
|
||||||
SUPPORT_SHUFFLE_SET = 32768
|
SUPPORT_SHUFFLE_SET = 32768
|
||||||
SUPPORT_SELECT_SOUND_MODE = 65536
|
SUPPORT_SELECT_SOUND_MODE = 65536
|
||||||
SUPPORT_BROWSE_MEDIA = 131072
|
SUPPORT_BROWSE_MEDIA = 131072
|
||||||
|
SUPPORT_REPEAT_SET = 262144
|
||||||
|
|
|
@ -156,3 +156,13 @@ shuffle_set:
|
||||||
shuffle:
|
shuffle:
|
||||||
description: True/false for enabling/disabling shuffle.
|
description: True/false for enabling/disabling shuffle.
|
||||||
example: true
|
example: true
|
||||||
|
|
||||||
|
repeat_set:
|
||||||
|
description: Set repeat mode.
|
||||||
|
fields:
|
||||||
|
entity_id:
|
||||||
|
description: Name(s) of entities to set.
|
||||||
|
example: "media_player.sonos"
|
||||||
|
repeat:
|
||||||
|
description: Repeat mode to set (off, all, one).
|
||||||
|
example: "off"
|
||||||
|
|
|
@ -532,6 +532,7 @@ SERVICE_MEDIA_STOP = "media_stop"
|
||||||
SERVICE_MEDIA_NEXT_TRACK = "media_next_track"
|
SERVICE_MEDIA_NEXT_TRACK = "media_next_track"
|
||||||
SERVICE_MEDIA_PREVIOUS_TRACK = "media_previous_track"
|
SERVICE_MEDIA_PREVIOUS_TRACK = "media_previous_track"
|
||||||
SERVICE_MEDIA_SEEK = "media_seek"
|
SERVICE_MEDIA_SEEK = "media_seek"
|
||||||
|
SERVICE_REPEAT_SET = "repeat_set"
|
||||||
SERVICE_SHUFFLE_SET = "shuffle_set"
|
SERVICE_SHUFFLE_SET = "shuffle_set"
|
||||||
|
|
||||||
SERVICE_ALARM_DISARM = "alarm_disarm"
|
SERVICE_ALARM_DISARM = "alarm_disarm"
|
||||||
|
|
|
@ -60,6 +60,27 @@ async def test_source_select(hass):
|
||||||
assert state.attributes.get(mp.ATTR_INPUT_SOURCE) == "xbox"
|
assert state.attributes.get(mp.ATTR_INPUT_SOURCE) == "xbox"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_repeat_set(hass):
|
||||||
|
"""Test the repeat set service."""
|
||||||
|
entity_id = "media_player.walkman"
|
||||||
|
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass, mp.DOMAIN, {"media_player": {"platform": "demo"}}
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state.attributes.get(mp.ATTR_MEDIA_REPEAT) == mp.const.REPEAT_MODE_OFF
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
mp.DOMAIN,
|
||||||
|
mp.SERVICE_REPEAT_SET,
|
||||||
|
{ATTR_ENTITY_ID: entity_id, mp.ATTR_MEDIA_REPEAT: mp.const.REPEAT_MODE_ALL},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
state = hass.states.get(entity_id)
|
||||||
|
assert state.attributes.get(mp.ATTR_MEDIA_REPEAT) == mp.const.REPEAT_MODE_ALL
|
||||||
|
|
||||||
|
|
||||||
async def test_clear_playlist(hass):
|
async def test_clear_playlist(hass):
|
||||||
"""Test clear playlist."""
|
"""Test clear playlist."""
|
||||||
assert await async_setup_component(
|
assert await async_setup_component(
|
||||||
|
|
Loading…
Reference in New Issue