mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Upgraded to use new version of pychromecast
This commit is contained in:
parent
28389f6c39
commit
75a0498080
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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 = {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
if not bus.has_service(DOMAIN, components.SERVICE_TURN_OFF):
|
status = chromecast.app
|
||||||
def turn_off_service(service):
|
|
||||||
""" Service to exit any running app on the specified ChromeCast and
|
|
||||||
shows idle screen. Will quit all ChromeCasts if nothing specified.
|
|
||||||
"""
|
|
||||||
entity_id = service.data.get(components.ATTR_ENTITY_ID)
|
|
||||||
|
|
||||||
entity_ids = [entity_id] if entity_id \
|
state_attr = {ATTR_HOST: chromecast.host,
|
||||||
else util.filter_entity_ids(statemachine.entity_ids, DOMAIN)
|
ATTR_FRIENDLY_NAME: chromecast.device.friendly_name}
|
||||||
|
|
||||||
for entity_id in entity_ids:
|
if status and status.app_id != pychromecast.APP_ID['HOME']:
|
||||||
state = statemachine.get_state(entity_id)
|
state = status.app_id
|
||||||
|
|
||||||
try:
|
ramp = chromecast.get_protocol(pychromecast.PROTOCOL_RAMP)
|
||||||
pychromecast.quit_app(state.attributes[ATTR_HOST])
|
|
||||||
except (AttributeError, KeyError):
|
|
||||||
# AttributeError: state returned None
|
|
||||||
# KeyError: ATTR_HOST did not exist
|
|
||||||
pass
|
|
||||||
|
|
||||||
bus.register_service(DOMAIN, components.SERVICE_TURN_OFF,
|
if ramp and ramp.state != pychromecast.RAMP_STATE_UNKNOWN:
|
||||||
turn_off_service)
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def turn_off_service(service):
|
||||||
|
""" Service to exit any running app on the specified ChromeCast and
|
||||||
|
shows idle screen. Will quit all ChromeCasts if nothing specified.
|
||||||
|
"""
|
||||||
|
for entity_id, cast in _service_to_entities(service):
|
||||||
|
cast.quit_app()
|
||||||
|
update_chromecast_state(entity_id, cast)
|
||||||
|
|
||||||
|
def volume_up_service(service):
|
||||||
|
""" Service to send the chromecast the command for volume up. """
|
||||||
|
for _, cast in _service_to_entities(service):
|
||||||
|
ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)
|
||||||
|
|
||||||
|
if ramp:
|
||||||
|
ramp.volume_up()
|
||||||
|
|
||||||
|
def volume_down_service(service):
|
||||||
|
""" Service to send the chromecast the command for volume down. """
|
||||||
|
for _, cast in _service_to_entities(service):
|
||||||
|
ramp = cast.get_protocol(pychromecast.PROTOCOL_RAMP)
|
||||||
|
|
||||||
|
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,
|
||||||
|
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
|
||||||
|
@ -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
homeassistant/external/pychromecast
vendored
1
homeassistant/external/pychromecast
vendored
@ -1 +0,0 @@
|
|||||||
Subproject commit 3d697b56a4a9178b9970e0596340a5e507ffd67c
|
|
Loading…
x
Reference in New Issue
Block a user