Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions homeassistant/components/media_player/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@

SERVICE_PLAY_MEDIA = 'play_media'
SERVICE_SELECT_SOURCE = 'select_source'
SERVICE_SELECT_SOUND_MODE = 'select_sound_mode'
SERVICE_CLEAR_PLAYLIST = 'clear_playlist'

ATTR_MEDIA_VOLUME_LEVEL = 'volume_level'
Expand All @@ -81,6 +82,8 @@
ATTR_APP_NAME = 'app_name'
ATTR_INPUT_SOURCE = 'source'
ATTR_INPUT_SOURCE_LIST = 'source_list'
ATTR_SOUND_MODE = 'sound_mode'
ATTR_SOUND_MODE_LIST = 'sound_mode_list'
ATTR_MEDIA_ENQUEUE = 'enqueue'
ATTR_MEDIA_SHUFFLE = 'shuffle'

Expand Down Expand Up @@ -109,6 +112,7 @@
SUPPORT_CLEAR_PLAYLIST = 8192
SUPPORT_PLAY = 16384
SUPPORT_SHUFFLE_SET = 32768
SUPPORT_SELECT_SOUND_MODE = 65536

# Service call validation schemas
MEDIA_PLAYER_SCHEMA = vol.Schema({
Expand All @@ -132,6 +136,10 @@
vol.Required(ATTR_INPUT_SOURCE): cv.string,
})

MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_SOUND_MODE): cv.string,
})

MEDIA_PLAYER_PLAY_MEDIA_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_MEDIA_CONTENT_TYPE): cv.string,
vol.Required(ATTR_MEDIA_CONTENT_ID): cv.string,
Expand Down Expand Up @@ -167,6 +175,9 @@
SERVICE_SELECT_SOURCE: {
'method': 'async_select_source',
'schema': MEDIA_PLAYER_SELECT_SOURCE_SCHEMA},
SERVICE_SELECT_SOUND_MODE: {
'method': 'async_select_sound_mode',
'schema': MEDIA_PLAYER_SELECT_SOUND_MODE_SCHEMA},
SERVICE_PLAY_MEDIA: {
'method': 'async_play_media',
'schema': MEDIA_PLAYER_PLAY_MEDIA_SCHEMA},
Expand Down Expand Up @@ -197,6 +208,8 @@
ATTR_APP_NAME,
ATTR_INPUT_SOURCE,
ATTR_INPUT_SOURCE_LIST,
ATTR_SOUND_MODE,
ATTR_SOUND_MODE_LIST,
ATTR_MEDIA_SHUFFLE,
]

Expand Down Expand Up @@ -346,6 +359,17 @@ def select_source(hass, source, entity_id=None):
hass.services.call(DOMAIN, SERVICE_SELECT_SOURCE, data)


@bind_hass
def select_sound_mode(hass, sound_mode, entity_id=None):
"""Send the media player the command to select sound mode."""
data = {ATTR_SOUND_MODE: sound_mode}

if entity_id:
data[ATTR_ENTITY_ID] = entity_id

hass.services.call(DOMAIN, SERVICE_SELECT_SOUND_MODE, data)


@bind_hass
def clear_playlist(hass, entity_id=None):
"""Send the media player the command for clear playlist."""
Expand Down Expand Up @@ -399,6 +423,8 @@ async def async_service_handler(service):
params['position'] = service.data.get(ATTR_MEDIA_SEEK_POSITION)
elif service.service == SERVICE_SELECT_SOURCE:
params['source'] = service.data.get(ATTR_INPUT_SOURCE)
elif service.service == SERVICE_SELECT_SOUND_MODE:
params['sound_mode'] = service.data.get(ATTR_SOUND_MODE)
elif service.service == SERVICE_PLAY_MEDIA:
params['media_type'] = \
service.data.get(ATTR_MEDIA_CONTENT_TYPE)
Expand Down Expand Up @@ -580,6 +606,16 @@ def source_list(self):
"""List of available input sources."""
return None

@property
def sound_mode(self):
"""Name of the current sound mode."""
return None

@property
def sound_mode_list(self):
"""List of available sound modes."""
return None

@property
def shuffle(self):
"""Boolean if shuffle is enabled."""
Expand Down Expand Up @@ -723,6 +759,17 @@ def async_select_source(self, source):
"""
return self.hass.async_add_job(self.select_source, source)

def select_sound_mode(self, sound_mode):
"""Select sound mode."""
raise NotImplementedError()

def async_select_sound_mode(self, sound_mode):
"""Select sound mode.

This method must be run in the event loop and returns a coroutine.
"""
return self.hass.async_add_job(self.select_sound_mode, sound_mode)

def clear_playlist(self):
"""Clear players playlist."""
raise NotImplementedError()
Expand Down Expand Up @@ -796,6 +843,11 @@ def support_select_source(self):
"""Boolean if select source command supported."""
return bool(self.supported_features & SUPPORT_SELECT_SOURCE)

@property
def support_select_sound_mode(self):
"""Boolean if select sound mode command supported."""
return bool(self.supported_features & SUPPORT_SELECT_SOUND_MODE)

@property
def support_clear_playlist(self):
"""Boolean if clear playlist command supported."""
Expand Down
31 changes: 26 additions & 5 deletions homeassistant/components/media_player/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
MEDIA_TYPE_MUSIC, MEDIA_TYPE_TVSHOW, MEDIA_TYPE_MOVIE, SUPPORT_NEXT_TRACK,
SUPPORT_PAUSE, SUPPORT_PLAY_MEDIA, SUPPORT_PREVIOUS_TRACK,
SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
SUPPORT_SELECT_SOURCE, SUPPORT_CLEAR_PLAYLIST, SUPPORT_PLAY,
SUPPORT_SHUFFLE_SET, MediaPlayerDevice)
SUPPORT_SELECT_SOURCE, SUPPORT_SELECT_SOUND_MODE, SUPPORT_CLEAR_PLAYLIST,
SUPPORT_PLAY, SUPPORT_SHUFFLE_SET, MediaPlayerDevice)
from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING
import homeassistant.util.dt as dt_util

Expand All @@ -28,22 +28,26 @@ def setup_platform(hass, config, add_devices, discovery_info=None):


YOUTUBE_COVER_URL_FORMAT = 'https://img.youtube.com/vi/{}/hqdefault.jpg'
SOUND_MODE_LIST = ['Dummy Music', 'Dummy Movie']
DEFAULT_SOUND_MODE = 'Dummy Music'

YOUTUBE_PLAYER_SUPPORT = \
SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PLAY_MEDIA | SUPPORT_PLAY | \
SUPPORT_SHUFFLE_SET
SUPPORT_SHUFFLE_SET | SUPPORT_SELECT_SOUND_MODE

MUSIC_PLAYER_SUPPORT = \
SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_CLEAR_PLAYLIST | \
SUPPORT_PLAY | SUPPORT_SHUFFLE_SET | \
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | \
SUPPORT_SELECT_SOUND_MODE

NETFLIX_PLAYER_SUPPORT = \
SUPPORT_PAUSE | SUPPORT_TURN_ON | SUPPORT_TURN_OFF | \
SUPPORT_SELECT_SOURCE | SUPPORT_PLAY | SUPPORT_SHUFFLE_SET | \
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK
SUPPORT_PREVIOUS_TRACK | SUPPORT_NEXT_TRACK | \
SUPPORT_SELECT_SOUND_MODE


class AbstractDemoPlayer(MediaPlayerDevice):
Expand All @@ -58,6 +62,8 @@ def __init__(self, name):
self._volume_level = 1.0
self._volume_muted = False
self._shuffle = False
self._sound_mode_list = SOUND_MODE_LIST
self._sound_mode = DEFAULT_SOUND_MODE

@property
def should_poll(self):
Expand Down Expand Up @@ -89,6 +95,16 @@ def shuffle(self):
"""Boolean if shuffling is enabled."""
return self._shuffle

@property
def sound_mode(self):
"""Return the current sound mode."""
return self._sound_mode

@property
def sound_mode_list(self):
"""Return a list of available sound modes."""
return self._sound_mode_list

def turn_on(self):
"""Turn the media player on."""
self._player_state = STATE_PLAYING
Expand Down Expand Up @@ -124,6 +140,11 @@ def set_shuffle(self, shuffle):
self._shuffle = shuffle
self.schedule_update_ha_state()

def select_sound_mode(self, sound_mode):
"""Select sound mode."""
self._sound_mode = sound_mode
self.schedule_update_ha_state()


class DemoYoutubePlayer(AbstractDemoPlayer):
"""A Demo media player that only supports YouTube."""
Expand Down
10 changes: 10 additions & 0 deletions homeassistant/components/media_player/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ select_source:
description: Name of the source to switch to. Platform dependent.
example: 'video1'

select_sound_mode:
description: Send the media player the command to change sound mode.
fields:
entity_id:
description: Name(s) of entities to change sound mode on.
example: 'media_player.marantz'
sound_mode:
description: Name of the sound mode to switch to.
example: 'Music'

clear_playlist:
description: Send the media player the command to clear players playlist.
fields:
Expand Down