Upgraded to use new version of pychromecast

This commit is contained in:
Paulus Schoutsen 2014-03-11 22:45:05 -07:00
parent 28389f6c39
commit 75a0498080
6 changed files with 246 additions and 68 deletions

View File

@ -20,7 +20,6 @@ username=admin
password=PASSWORD password=PASSWORD
[chromecast] [chromecast]
host=192.168.1.3
[downloader] [downloader]
download_dir=downloads download_dir=downloads

View File

@ -119,11 +119,10 @@ def from_config_file(config_path):
sun = None sun = None
# Chromecast # Chromecast
if has_opt("chromecast", "host"): if has_section("chromecast"):
chromecast = load_module('chromecast') chromecast = load_module('chromecast')
chromecast_started = chromecast.setup(bus, statemachine, chromecast_started = chromecast.setup(bus, statemachine)
get_opt("chromecast", "host"))
add_status("Chromecast", chromecast_started) add_status("Chromecast", chromecast_started)
else: else:

View File

@ -30,6 +30,13 @@ STATE_HOME = 'home'
SERVICE_TURN_ON = 'turn_on' SERVICE_TURN_ON = 'turn_on'
SERVICE_TURN_OFF = 'turn_off' SERVICE_TURN_OFF = 'turn_off'
SERVICE_VOLUME_UP = "volume_up"
SERVICE_VOLUME_DOWN = "volume_down"
SERVICE_VOLUME_MUTE = "volume_mute"
SERVICE_MEDIA_PLAY_PAUSE = "media_play_pause"
SERVICE_MEDIA_NEXT_TRACK = "media_next_track"
SERVICE_MEDIA_PREV_TRACK = "media_prev_track"
_LOADED_MOD = {} _LOADED_MOD = {}

View File

@ -21,6 +21,18 @@ ATTR_FRIENDLY_NAME = 'friendly_name'
ATTR_HOST = 'host' ATTR_HOST = 'host'
ATTR_STATE = 'state' ATTR_STATE = 'state'
ATTR_OPTIONS = 'options' ATTR_OPTIONS = 'options'
ATTR_MEDIA_STATE = 'media_state'
ATTR_MEDIA_CONTENT_ID = 'media_content_id'
ATTR_MEDIA_TITLE = 'media_title'
ATTR_MEDIA_ARTIST = 'media_artist'
ATTR_MEDIA_ALBUM = 'media_album'
ATTR_MEDIA_IMAGE_URL = 'media_image_url'
ATTR_MEDIA_VOLUME = 'media_volume'
ATTR_MEDIA_DURATION = 'media_duration'
MEDIA_STATE_UNKNOWN = 'unknown'
MEDIA_STATE_PLAYING = 'playing'
MEDIA_STATE_STOPPED = 'stopped'
def is_on(statemachine, entity_id=None): def is_on(statemachine, entity_id=None):
@ -34,83 +46,220 @@ def is_on(statemachine, entity_id=None):
for entity_id in entity_ids) for entity_id in entity_ids)
def setup(bus, statemachine, host): def volume_up(bus, entity_id=None):
""" Send the chromecast the command for volume up. """
data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
bus.call_service(DOMAIN, components.SERVICE_VOLUME_UP, data)
def volume_down(bus, entity_id=None):
""" Send the chromecast the command for volume down. """
data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
bus.call_service(DOMAIN, components.SERVICE_VOLUME_DOWN, data)
def media_play_pause(bus, entity_id=None):
""" Send the chromecast the command for play/pause. """
data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
bus.call_service(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE, data)
def media_next_track(bus, entity_id=None):
""" Send the chromecast the command for next track. """
data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
bus.call_service(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK, data)
def media_prev_track(bus, entity_id=None):
""" Send the chromecast the command for prev track. """
data = {components.ATTR_ENTITY_ID: entity_id} if entity_id else {}
bus.call_service(DOMAIN, components.SERVICE_MEDIA_PREV_TRACK, data)
# pylint: disable=too-many-locals, too-many-branches
def setup(bus, statemachine):
""" Listen for chromecast events. """ """ Listen for chromecast events. """
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
try: try:
from homeassistant.external import pychromecast import pychromecast
except ImportError: except ImportError:
logger.exception(("Failed to import pychromecast. " logger.exception(("Failed to import pychromecast. "
"Did you maybe not cloned the git submodules?")) "Did you maybe not install the 'pychromecast' "
"dependency?"))
return False return False
logger.info("Getting device status") logger.info("Scanning for Chromecasts")
device = pychromecast.get_device_status(host) hosts = pychromecast.discover_chromecasts()
if not device: casts = {}
logger.error("Could not find Chromecast")
for host in hosts:
try:
cast = pychromecast.PyChromecast(host)
entity_id = ENTITY_ID_FORMAT.format(
util.slugify(cast.device.friendly_name))
casts[entity_id] = cast
except pychromecast.ConnectionError:
pass
if not casts:
logger.error("Could not find Chromecasts")
return False return False
entity = ENTITY_ID_FORMAT.format(util.slugify(device.friendly_name)) def update_chromecast_state(entity_id, chromecast):
""" Retrieve state of Chromecast and update statemachine. """
chromecast.refresh()
status = chromecast.app
state_attr = {ATTR_HOST: chromecast.host,
ATTR_FRIENDLY_NAME: chromecast.device.friendly_name}
if status and status.app_id != pychromecast.APP_ID['HOME']:
state = status.app_id
ramp = chromecast.get_protocol(pychromecast.PROTOCOL_RAMP)
if ramp and ramp.state != pychromecast.RAMP_STATE_UNKNOWN:
if ramp.state == pychromecast.RAMP_STATE_PLAYING:
state_attr[ATTR_MEDIA_STATE] = MEDIA_STATE_PLAYING
else:
state_attr[ATTR_MEDIA_STATE] = MEDIA_STATE_STOPPED
if ramp.content_id:
state_attr[ATTR_MEDIA_CONTENT_ID] = ramp.content_id
if ramp.title:
state_attr[ATTR_MEDIA_TITLE] = ramp.title
if ramp.artist:
state_attr[ATTR_MEDIA_ARTIST] = ramp.artist
if ramp.album:
state_attr[ATTR_MEDIA_ALBUM] = ramp.album
if ramp.image_url:
state_attr[ATTR_MEDIA_IMAGE_URL] = ramp.image_url
if ramp.duration:
state_attr[ATTR_MEDIA_DURATION] = ramp.duration
state_attr[ATTR_MEDIA_VOLUME] = ramp.volume
else:
state = STATE_NO_APP
statemachine.set_state(entity_id, state, state_attr)
def update_chromecast_states(time): # pylint: disable=unused-argument
""" Updates all chromecast states. """
logger.info("Updating Chromecast status")
for entity_id, cast in casts.items():
update_chromecast_state(entity_id, cast)
def _service_to_entities(service):
""" Helper method to get entities from service. """
entity_id = service.data.get(components.ATTR_ENTITY_ID)
if entity_id:
cast = casts.get(entity_id)
if cast:
yield entity_id, cast
else:
for item in casts.items():
yield item
if not bus.has_service(DOMAIN, components.SERVICE_TURN_OFF):
def turn_off_service(service): def turn_off_service(service):
""" Service to exit any running app on the specified ChromeCast and """ Service to exit any running app on the specified ChromeCast and
shows idle screen. Will quit all ChromeCasts if nothing specified. shows idle screen. Will quit all ChromeCasts if nothing specified.
""" """
entity_id = service.data.get(components.ATTR_ENTITY_ID) for entity_id, cast in _service_to_entities(service):
cast.quit_app()
update_chromecast_state(entity_id, cast)
entity_ids = [entity_id] if entity_id \ def volume_up_service(service):
else util.filter_entity_ids(statemachine.entity_ids, DOMAIN) """ Service to send the chromecast the command for volume up. """
for _, cast in _service_to_entities(service):
ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)
for entity_id in entity_ids: if ramp:
state = statemachine.get_state(entity_id) ramp.volume_up()
try: def volume_down_service(service):
pychromecast.quit_app(state.attributes[ATTR_HOST]) """ Service to send the chromecast the command for volume down. """
except (AttributeError, KeyError): for _, cast in _service_to_entities(service):
# AttributeError: state returned None ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)
# KeyError: ATTR_HOST did not exist
pass if ramp:
ramp.volume_down()
def media_play_pause_service(service):
""" Service to send the chromecast the command for play/pause. """
for _, cast in _service_to_entities(service):
ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)
if ramp:
ramp.playpause()
def media_next_track_service(service):
""" Service to send the chromecast the command for next track. """
for entity_id, cast in _service_to_entities(service):
ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)
if ramp:
ramp.next()
update_chromecast_state(entity_id, cast)
def play_youtube_video_service(service, video_id):
""" Plays specified video_id on the Chromecast's YouTube channel. """
if video_id: # if service.data.get('video') returned None
for entity_id, cast in _service_to_entities(service):
pychromecast.play_youtube_video(video_id, cast.host)
update_chromecast_state(entity_id, cast)
ha.track_time_change(bus, update_chromecast_states)
bus.register_service(DOMAIN, components.SERVICE_TURN_OFF, bus.register_service(DOMAIN, components.SERVICE_TURN_OFF,
turn_off_service) turn_off_service)
bus.register_service(DOMAIN, components.SERVICE_VOLUME_UP,
volume_up_service)
bus.register_service(DOMAIN, components.SERVICE_VOLUME_DOWN,
volume_down_service)
bus.register_service(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE,
media_play_pause_service)
bus.register_service(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK,
media_next_track_service)
bus.register_service(DOMAIN, "start_fireplace", bus.register_service(DOMAIN, "start_fireplace",
lambda service: lambda service:
pychromecast.play_youtube_video(host, "eyU3bRy2x44")) play_youtube_video_service(service, "eyU3bRy2x44"))
bus.register_service(DOMAIN, "start_epic_sax", bus.register_service(DOMAIN, "start_epic_sax",
lambda service: lambda service:
pychromecast.play_youtube_video(host, "kxopViU98Xo")) play_youtube_video_service(service, "kxopViU98Xo"))
bus.register_service(DOMAIN, SERVICE_YOUTUBE_VIDEO, bus.register_service(DOMAIN, SERVICE_YOUTUBE_VIDEO,
lambda service: lambda service:
pychromecast.play_youtube_video( play_youtube_video_service(service,
host, service.data['video'])) service.data.get('video')))
def update_chromecast_state(time): # pylint: disable=unused-argument update_chromecast_states(None)
""" Retrieve state of Chromecast and update statemachine. """
logger.info("Updating app status")
status = pychromecast.get_app_status(host)
if status:
state = STATE_NO_APP if status.name == pychromecast.APP_ID_HOME \
else status.name
statemachine.set_state(entity, state,
{ATTR_FRIENDLY_NAME:
pychromecast.get_friendly_name(
status.name),
ATTR_HOST: host,
ATTR_STATE: status.state,
ATTR_OPTIONS: status.options})
else:
statemachine.set_state(entity, STATE_NO_APP, {ATTR_HOST: host})
ha.track_time_change(bus, update_chromecast_state)
update_chromecast_state(None)
return True return True

View File

@ -6,14 +6,39 @@ Provides functionality to emulate keyboard presses on host machine.
""" """
import logging import logging
import homeassistant.components as components
DOMAIN = "keyboard" DOMAIN = "keyboard"
SERVICE_KEYBOARD_VOLUME_UP = "volume_up"
SERVICE_KEYBOARD_VOLUME_DOWN = "volume_down" def volume_up(bus):
SERVICE_KEYBOARD_VOLUME_MUTE = "volume_mute" """ Press the keyboard button for volume up. """
SERVICE_KEYBOARD_MEDIA_PLAY_PAUSE = "media_play_pause" bus.call_service(DOMAIN, components.SERVICE_VOLUME_UP)
SERVICE_KEYBOARD_MEDIA_NEXT_TRACK = "media_next_track"
SERVICE_KEYBOARD_MEDIA_PREV_TRACK = "media_prev_track"
def volume_down(bus):
""" Press the keyboard button for volume down. """
bus.call_service(DOMAIN, components.SERVICE_VOLUME_DOWN)
def volume_mute(bus):
""" Press the keyboard button for muting volume. """
bus.call_service(DOMAIN, components.SERVICE_VOLUME_MUTE)
def media_play_pause(bus):
""" Press the keyboard button for play/pause. """
bus.call_service(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE)
def media_next_track(bus):
""" Press the keyboard button for next track. """
bus.call_service(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK)
def media_prev_track(bus):
""" Press the keyboard button for prev track. """
bus.call_service(DOMAIN, components.SERVICE_MEDIA_PREV_TRACK)
def setup(bus): def setup(bus):
@ -29,27 +54,27 @@ def setup(bus):
keyboard = pykeyboard.PyKeyboard() keyboard = pykeyboard.PyKeyboard()
keyboard.special_key_assignment() keyboard.special_key_assignment()
bus.register_service(DOMAIN, SERVICE_KEYBOARD_VOLUME_UP, bus.register_service(DOMAIN, components.SERVICE_VOLUME_UP,
lambda service: lambda service:
keyboard.tap_key(keyboard.volume_up_key)) keyboard.tap_key(keyboard.volume_up_key))
bus.register_service(DOMAIN, SERVICE_KEYBOARD_VOLUME_DOWN, bus.register_service(DOMAIN, components.SERVICE_VOLUME_DOWN,
lambda service: lambda service:
keyboard.tap_key(keyboard.volume_down_key)) keyboard.tap_key(keyboard.volume_down_key))
bus.register_service(DOMAIN, SERVICE_KEYBOARD_VOLUME_MUTE, bus.register_service(DOMAIN, components.SERVICE_VOLUME_MUTE,
lambda service: lambda service:
keyboard.tap_key(keyboard.volume_mute_key)) keyboard.tap_key(keyboard.volume_mute_key))
bus.register_service(DOMAIN, SERVICE_KEYBOARD_MEDIA_PLAY_PAUSE, bus.register_service(DOMAIN, components.SERVICE_MEDIA_PLAY_PAUSE,
lambda service: lambda service:
keyboard.tap_key(keyboard.media_play_pause_key)) keyboard.tap_key(keyboard.media_play_pause_key))
bus.register_service(DOMAIN, SERVICE_KEYBOARD_MEDIA_NEXT_TRACK, bus.register_service(DOMAIN, components.SERVICE_MEDIA_NEXT_TRACK,
lambda service: lambda service:
keyboard.tap_key(keyboard.media_next_track_key)) keyboard.tap_key(keyboard.media_next_track_key))
bus.register_service(DOMAIN, SERVICE_KEYBOARD_MEDIA_PREV_TRACK, bus.register_service(DOMAIN, components.SERVICE_MEDIA_PREV_TRACK,
lambda service: lambda service:
keyboard.tap_key(keyboard.media_prev_track_key)) keyboard.tap_key(keyboard.media_prev_track_key))

@ -1 +0,0 @@
Subproject commit 3d697b56a4a9178b9970e0596340a5e507ffd67c