Initial update of cast device to MediaPlayerDevice. Added media_seek command and service to MediaPlayerDevice.

This commit is contained in:
Hans Bakker 2015-06-04 00:17:03 +02:00
parent 7f788d6be1
commit 66024e5059
3 changed files with 158 additions and 77 deletions

View file

@ -15,7 +15,7 @@ from homeassistant.const import (
SERVICE_VOLUME_UP, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_SET, SERVICE_VOLUME_UP, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_SET,
SERVICE_VOLUME_MUTE, SERVICE_VOLUME_MUTE,
SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PAUSE,
SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREVIOUS_TRACK) SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK)
DOMAIN = 'media_player' DOMAIN = 'media_player'
DEPENDENCIES = [] DEPENDENCIES = []
@ -31,6 +31,7 @@ SERVICE_YOUTUBE_VIDEO = 'play_youtube_video'
ATTR_MEDIA_VOLUME_LEVEL = 'volume_level' ATTR_MEDIA_VOLUME_LEVEL = 'volume_level'
ATTR_MEDIA_VOLUME_MUTED = 'volume_muted' ATTR_MEDIA_VOLUME_MUTED = 'volume_muted'
ATTR_MEDIA_SEEK_POSITION = 'seek_position'
ATTR_MEDIA_CONTENT_ID = 'media_content_id' ATTR_MEDIA_CONTENT_ID = 'media_content_id'
ATTR_MEDIA_CONTENT_TYPE = 'media_content_type' ATTR_MEDIA_CONTENT_TYPE = 'media_content_type'
ATTR_MEDIA_DURATION = 'media_duration' ATTR_MEDIA_DURATION = 'media_duration'
@ -246,6 +247,26 @@ def setup(hass, config):
volume_mute_service( volume_mute_service(
service, )) service, ))
def media_seek_service(service):
""" Seek to a position. """
target_players = component.extract_from_service(service)
if ATTR_MEDIA_SEEK_POSITION not in service.data:
return
position = service.data[ATTR_MEDIA_SEEK_POSITION]
for player in target_players:
player.seek(position)
if player.should_poll:
player.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK,
lambda service:
media_seek_service(
service, ))
def play_youtube_video_service(service, media_id): def play_youtube_video_service(service, media_id):
""" Plays specified media_id on the media player. """ """ Plays specified media_id on the media player. """
target_players = component.extract_from_service(service) target_players = component.extract_from_service(service)
@ -401,6 +422,10 @@ class MediaPlayerDevice(Entity):
""" Send next track command. """ """ Send next track command. """
raise NotImplementedError() raise NotImplementedError()
def media_seek(self, position):
""" Send seek command. """
raise NotImplementedError()
def play_youtube(self, media_id): def play_youtube(self, media_id):
""" Plays a YouTube media. """ """ Plays a YouTube media. """
raise NotImplementedError() raise NotImplementedError()

View file

@ -14,16 +14,16 @@ try:
except ImportError: except ImportError:
pychromecast = None pychromecast = None
from homeassistant.const import ATTR_ENTITY_PICTURE from homeassistant.const import (
STATE_PLAYING, STATE_PAUSED, STATE_IDLE, STATE_OFF,
STATE_UNKNOWN)
# ATTR_MEDIA_ALBUM, ATTR_MEDIA_IMAGE_URL,
# ATTR_MEDIA_ARTIST,
from homeassistant.components.media_player import ( from homeassistant.components.media_player import (
MediaPlayerDevice, STATE_NO_APP, ATTR_MEDIA_STATE, ATTR_MEDIA_TITLE, MediaPlayerDevice,
ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_DURATION, SUPPORT_PAUSE, SUPPORT_VOLUME_SET, SUPPORT_VOLUME_MUTE,
ATTR_MEDIA_VOLUME, ATTR_MEDIA_IS_VOLUME_MUTED, SUPPORT_YOUTUBE,
MEDIA_STATE_PLAYING, MEDIA_STATE_PAUSED, MEDIA_STATE_STOPPED, SUPPORT_TURN_ON, SUPPORT_TURN_OFF,
MEDIA_STATE_UNKNOWN) SUPPORT_PREVIOUS_TRACK, SUPPORT_NEXT_TRACK)
CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png' CAST_SPLASH = 'https://home-assistant.io/images/cast/splash.png'
@ -73,6 +73,8 @@ class CastDevice(MediaPlayerDevice):
self.cast_status = self.cast.status self.cast_status = self.cast.status
self.media_status = self.cast.media_controller.status self.media_status = self.cast.media_controller.status
"""Entity properties and methods"""
@property @property
def should_poll(self): def should_poll(self):
return False return False
@ -82,57 +84,122 @@ class CastDevice(MediaPlayerDevice):
""" Returns the name of the device. """ """ Returns the name of the device. """
return self.cast.device.friendly_name return self.cast.device.friendly_name
@property """MediaPlayerDevice properties and methods"""
def state(self):
""" Returns the state of the device. """
if self.cast.is_idle:
return STATE_NO_APP
else:
return self.cast.app_display_name
@property @property
def media_state(self): def state(self):
""" Returns the media state. """ """ State of the player. """
media_controller = self.cast.media_controller media_controller = self.cast.media_controller
if media_controller.is_playing: if media_controller.is_playing:
return MEDIA_STATE_PLAYING return STATE_PLAYING
elif media_controller.is_paused: elif media_controller.is_paused:
return MEDIA_STATE_PAUSED return STATE_PAUSED
elif media_controller.is_idle: elif media_controller.is_idle:
return MEDIA_STATE_STOPPED return STATE_IDLE
elif self.cast.is_idle:
return STATE_OFF
else: else:
return MEDIA_STATE_UNKNOWN return STATE_UNKNOWN
@property @property
def state_attributes(self): def volume_level(self):
""" Returns the state attributes. """ """ Volume level of the media player (0..1). """
cast_status = self.cast_status if self.cast_status is None:
media_status = self.media_status return None
media_controller = self.cast.media_controller else:
return self.cast_status.volume_level
state_attr = { @property
ATTR_MEDIA_STATE: self.media_state, def is_volume_muted(self):
'application_id': self.cast.app_id, """ Boolean if volume is currently muted. """
} if self.cast_status is None:
return None
else:
return self.cast_status.volume_muted
if cast_status: @property
state_attr[ATTR_MEDIA_VOLUME] = cast_status.volume_level def media_content_id(self):
state_attr[ATTR_MEDIA_IS_VOLUME_MUTED] = cast_status.volume_muted """ Content ID of current playing media. """
if self.media_status is None:
return None
else:
return self.media_status.content_id
if media_status.content_id: @property
state_attr[ATTR_MEDIA_CONTENT_ID] = media_status.content_id def media_content_type(self):
""" Content type of current playing media. """
return None
if media_status.duration: @property
state_attr[ATTR_MEDIA_DURATION] = media_status.duration def media_duration(self):
""" Duration of current playing media in seconds. """
if self.media_status is None:
return None
else:
return self.media_status.duration
if media_controller.title: @property
state_attr[ATTR_MEDIA_TITLE] = media_controller.title def media_image_url(self):
""" Image url of current playing media. """
return self.cast.media_controller.thumbnail
if media_controller.thumbnail: @property
state_attr[ATTR_ENTITY_PICTURE] = media_controller.thumbnail def media_title(self):
""" Title of current playing media. """
return self.cast.media_controller.title
return state_attr @property
def media_artist(self):
""" Artist of current playing media. (Music track only) """
return None
@property
def media_album(self):
""" Album of current playing media. (Music track only) """
return None
@property
def media_track(self):
""" Track number of current playing media. (Music track only) """
return None
@property
def media_series_title(self):
""" Series title of current playing media. (TV Show only)"""
return None
@property
def media_season(self):
""" Season of current playing media. (TV Show only) """
return None
@property
def media_episode(self):
""" Episode of current playing media. (TV Show only) """
return None
@property
def app_id(self):
""" ID of the current running app. """
return self.cast.app_id
@property
def app_name(self):
""" Name of the current running app. """
return self.cast.app_display_name
@property
def supported_media_commands(self):
""" Flags of media commands that are supported. """
return SUPPORT_PAUSE | SUPPORT_VOLUME_SET | SUPPORT_VOLUME_MUTE | \
SUPPORT_TURN_ON | SUPPORT_TURN_OFF | SUPPORT_PREVIOUS_TRACK | \
SUPPORT_NEXT_TRACK
@property
def device_state_attributes(self):
""" Extra attributes a device wants to expose. """
return None
def turn_on(self): def turn_on(self):
""" Turns on the ChromeCast. """ """ Turns on the ChromeCast. """
@ -144,58 +211,46 @@ class CastDevice(MediaPlayerDevice):
self.cast.play_media( self.cast.play_media(
CAST_SPLASH, pychromecast.STREAM_TYPE_BUFFERED) CAST_SPLASH, pychromecast.STREAM_TYPE_BUFFERED)
def turn_off(self): def turn_off(self):
""" Service to exit any running app on the specimedia player ChromeCast and """ Service to exit any running app on the specimedia player ChromeCast and
shows idle screen. Will quit all ChromeCasts if nothing specified. shows idle screen. Will quit all ChromeCasts if nothing specified.
""" """
self.cast.quit_app() self.cast.quit_app()
def volume_up(self): def mute_volume(self, mute):
""" Service to send the chromecast the command for volume up. """ """ mute the volume. """
self.cast.volume_up()
def volume_down(self):
""" Service to send the chromecast the command for volume down. """
self.cast.volume_down()
def volume_mute(self, mute):
""" Set media player to mute volume. """
self.cast.set_volume_muted(mute) self.cast.set_volume_muted(mute)
def volume_set(self, volume): def set_volume_level(self, volume):
""" Set media player volume, range of volume 0..1 """ """ set volume level, range 0..1. """
self.cast.set_volume(volume) self.cast.set_volume(volume)
def media_play_pause(self):
""" Service to send the chromecast the command for play/pause. """
media_state = self.media_state
if media_state in (MEDIA_STATE_STOPPED, MEDIA_STATE_PAUSED):
self.cast.media_controller.play()
elif media_state == MEDIA_STATE_PLAYING:
self.cast.media_controller.pause()
def media_play(self): def media_play(self):
""" Service to send the chromecast the command for play/pause. """ """ Send play commmand. """
if self.media_state in (MEDIA_STATE_STOPPED, MEDIA_STATE_PAUSED): self.cast.media_controller.play()
self.cast.media_controller.play()
def media_pause(self): def media_pause(self):
""" Service to send the chromecast the command for play/pause. """ """ Send pause command. """
if self.media_state == MEDIA_STATE_PLAYING: self.cast.media_controller.pause()
self.cast.media_controller.pause()
def media_prev_track(self): def media_previous_track(self):
""" media_prev_track media player. """ """ Send previous track command. """
self.cast.media_controller.rewind() self.cast.media_controller.rewind()
def media_next_track(self): def media_next_track(self):
""" media_next_track media player. """ """ Send next track command. """
self.cast.media_controller.skip() self.cast.media_controller.skip()
def play_youtube_video(self, video_id): def media_seek(self, position):
""" Plays specified video_id on the Chromecast's YouTube channel. """ """ Seek the media to a specific location. """
self.youtube.play_video(video_id) self.case.media_controller.seek(position)
def play_youtube(self, media_id):
""" Plays a YouTube media. """
self.youtube.play_video(media_id)
"""implementation of chromecast status_listener methods"""
def new_cast_status(self, status): def new_cast_status(self, status):
""" Called when a new cast status is received. """ """ Called when a new cast status is received. """
@ -205,4 +260,4 @@ class CastDevice(MediaPlayerDevice):
def new_media_status(self, status): def new_media_status(self, status):
""" Called when a new media status is received. """ """ Called when a new media status is received. """
self.media_status = status self.media_status = status
self.update_ha_state() self.update_ha_state()

View file

@ -108,6 +108,7 @@ SERVICE_MEDIA_PLAY = "media_play"
SERVICE_MEDIA_PAUSE = "media_pause" SERVICE_MEDIA_PAUSE = "media_pause"
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"
# #### API / REMOTE #### # #### API / REMOTE ####
SERVER_PORT = 8123 SERVER_PORT = 8123