diff --git a/homeassistant/components/demo/media_player.py b/homeassistant/components/demo/media_player.py index f00f1fb781e..2ea360ebb81 100644 --- a/homeassistant/components/demo/media_player.py +++ b/homeassistant/components/demo/media_player.py @@ -4,12 +4,14 @@ from homeassistant.components.media_player.const import ( MEDIA_TYPE_MOVIE, MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, + REPEAT_MODE_OFF, SUPPORT_CLEAR_PLAYLIST, SUPPORT_NEXT_TRACK, SUPPORT_PAUSE, SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, + SUPPORT_REPEAT_SET, SUPPORT_SEEK, SUPPORT_SELECT_SOUND_MODE, SUPPORT_SELECT_SOURCE, @@ -73,6 +75,7 @@ MUSIC_PLAYER_SUPPORT = ( | SUPPORT_CLEAR_PLAYLIST | SUPPORT_PLAY | SUPPORT_SHUFFLE_SET + | SUPPORT_REPEAT_SET | SUPPORT_VOLUME_STEP | SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK @@ -319,6 +322,7 @@ class DemoMusicPlayer(AbstractDemoPlayer): """Initialize the demo device.""" super().__init__("Walkman") self._cur_track = 0 + self._repeat = REPEAT_MODE_OFF @property def media_content_id(self): @@ -360,6 +364,11 @@ class DemoMusicPlayer(AbstractDemoPlayer): """Return the track number of current media (Music track only).""" return self._cur_track + 1 + @property + def repeat(self): + """Return current repeat mode.""" + return self._repeat + @property def supported_features(self): """Flag media player features that are supported.""" @@ -384,6 +393,11 @@ class DemoMusicPlayer(AbstractDemoPlayer): self._player_state = STATE_OFF 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): """A Demo media player that only supports YouTube.""" diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 52d61339c38..1985fac1c1d 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -35,6 +35,7 @@ from homeassistant.const import ( SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK, SERVICE_MEDIA_STOP, + SERVICE_REPEAT_SET, SERVICE_SHUFFLE_SET, SERVICE_TOGGLE, SERVICE_TURN_OFF, @@ -76,6 +77,7 @@ from .const import ( ATTR_MEDIA_PLAYLIST, ATTR_MEDIA_POSITION, ATTR_MEDIA_POSITION_UPDATED_AT, + ATTR_MEDIA_REPEAT, ATTR_MEDIA_SEASON, ATTR_MEDIA_SEEK_POSITION, ATTR_MEDIA_SERIES_TITLE, @@ -88,6 +90,7 @@ from .const import ( ATTR_SOUND_MODE_LIST, DOMAIN, MEDIA_CLASS_DIRECTORY, + REPEAT_MODES, SERVICE_CLEAR_PLAYLIST, SERVICE_PLAY_MEDIA, SERVICE_SELECT_SOUND_MODE, @@ -99,6 +102,7 @@ from .const import ( SUPPORT_PLAY, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK, + SUPPORT_REPEAT_SET, SUPPORT_SEEK, SUPPORT_SELECT_SOUND_MODE, SUPPORT_SELECT_SOURCE, @@ -167,6 +171,7 @@ ATTR_TO_PROPERTY = [ ATTR_INPUT_SOURCE, ATTR_SOUND_MODE, ATTR_MEDIA_SHUFFLE, + ATTR_MEDIA_REPEAT, ] @@ -325,6 +330,13 @@ async def async_setup(hass, config): [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 @@ -508,6 +520,11 @@ class MediaPlayerEntity(Entity): """Boolean if shuffle is enabled.""" return None + @property + def repeat(self): + """Return current repeat mode.""" + return None + @property def supported_features(self): """Flag media player features that are supported.""" @@ -635,6 +652,14 @@ class MediaPlayerEntity(Entity): """Enable/disable shuffle mode.""" 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. @property def support_play(self): diff --git a/homeassistant/components/media_player/const.py b/homeassistant/components/media_player/const.py index 3db31006341..e170132d48b 100644 --- a/homeassistant/components/media_player/const.py +++ b/homeassistant/components/media_player/const.py @@ -17,6 +17,7 @@ ATTR_MEDIA_EPISODE = "media_episode" ATTR_MEDIA_PLAYLIST = "media_playlist" ATTR_MEDIA_POSITION = "media_position" ATTR_MEDIA_POSITION_UPDATED_AT = "media_position_updated_at" +ATTR_MEDIA_REPEAT = "repeat" ATTR_MEDIA_SEASON = "media_season" ATTR_MEDIA_SEEK_POSITION = "seek_position" 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_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_SEEK = 2 SUPPORT_VOLUME_SET = 4 @@ -96,3 +102,4 @@ SUPPORT_PLAY = 16384 SUPPORT_SHUFFLE_SET = 32768 SUPPORT_SELECT_SOUND_MODE = 65536 SUPPORT_BROWSE_MEDIA = 131072 +SUPPORT_REPEAT_SET = 262144 diff --git a/homeassistant/components/media_player/services.yaml b/homeassistant/components/media_player/services.yaml index 99fdb30b5c5..08637df0745 100644 --- a/homeassistant/components/media_player/services.yaml +++ b/homeassistant/components/media_player/services.yaml @@ -156,3 +156,13 @@ shuffle_set: shuffle: description: True/false for enabling/disabling shuffle. 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" diff --git a/homeassistant/const.py b/homeassistant/const.py index a40df9527f6..8d962aa0d3f 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -532,6 +532,7 @@ SERVICE_MEDIA_STOP = "media_stop" SERVICE_MEDIA_NEXT_TRACK = "media_next_track" SERVICE_MEDIA_PREVIOUS_TRACK = "media_previous_track" SERVICE_MEDIA_SEEK = "media_seek" +SERVICE_REPEAT_SET = "repeat_set" SERVICE_SHUFFLE_SET = "shuffle_set" SERVICE_ALARM_DISARM = "alarm_disarm" diff --git a/tests/components/demo/test_media_player.py b/tests/components/demo/test_media_player.py index 0d4d1d6bbe4..340416f4586 100644 --- a/tests/components/demo/test_media_player.py +++ b/tests/components/demo/test_media_player.py @@ -60,6 +60,27 @@ async def test_source_select(hass): 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): """Test clear playlist.""" assert await async_setup_component(