Service validation for media_player component

pull/1687/head
Jan Harkes 2016-04-02 03:51:03 -04:00
parent 5c262753d4
commit afd1e6a5cc
2 changed files with 51 additions and 42 deletions

View File

@ -7,11 +7,14 @@ https://home-assistant.io/components/media_player/
import logging
import os
import voluptuous as vol
from homeassistant.components import discovery
from homeassistant.config import load_yaml_config_file
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
import homeassistant.helpers.config_validation as cv
from homeassistant.const import (
STATE_OFF, STATE_UNKNOWN, STATE_PLAYING, STATE_IDLE,
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON,
@ -78,6 +81,7 @@ SUPPORT_PLAY_MEDIA = 512
SUPPORT_VOLUME_STEP = 1024
SUPPORT_SELECT_SOURCE = 2048
# simple services that only take entity_id(s) as optional argument
SERVICE_TO_METHOD = {
SERVICE_TURN_ON: 'turn_on',
SERVICE_TURN_OFF: 'turn_off',
@ -89,8 +93,6 @@ SERVICE_TO_METHOD = {
SERVICE_MEDIA_PAUSE: 'media_pause',
SERVICE_MEDIA_NEXT_TRACK: 'media_next_track',
SERVICE_MEDIA_PREVIOUS_TRACK: 'media_previous_track',
SERVICE_PLAY_MEDIA: 'play_media',
SERVICE_SELECT_SOURCE: 'select_source',
}
ATTR_TO_PROPERTY = [
@ -115,6 +117,33 @@ ATTR_TO_PROPERTY = [
ATTR_INPUT_SOURCE,
]
# Service call validation schemas
MEDIA_PLAYER_SCHEMA = vol.Schema({
ATTR_ENTITY_ID: cv.entity_ids,
})
MEDIA_PLAYER_MUTE_VOLUME_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_MEDIA_VOLUME_MUTED): vol.Coerce(bool),
})
MEDIA_PLAYER_SET_VOLUME_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_MEDIA_VOLUME_LEVEL): cv.small_float,
})
MEDIA_PLAYER_MEDIA_SEEK_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_MEDIA_SEEK_POSITION):
vol.All(vol.Coerce(float), vol.Range(min=0)),
})
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,
})
MEDIA_PLAYER_SELECT_SOURCE_SCHEMA = MEDIA_PLAYER_SCHEMA.extend({
vol.Required(ATTR_INPUT_SOURCE): cv.string,
})
def is_on(hass, entity_id=None):
"""
@ -258,18 +287,13 @@ def setup(hass, config):
for service in SERVICE_TO_METHOD:
hass.services.register(DOMAIN, service, media_player_service_handler,
descriptions.get(service))
descriptions.get(service),
schema=MEDIA_PLAYER_SCHEMA)
def volume_set_service(service):
"""Set specified volume on the media player."""
volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL)
if volume is None:
_LOGGER.error(
'Received call to %s without attribute %s',
service.service, ATTR_MEDIA_VOLUME_LEVEL)
return
for player in component.extract_from_service(service):
player.set_volume_level(volume)
@ -277,18 +301,13 @@ def setup(hass, config):
player.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service,
descriptions.get(SERVICE_VOLUME_SET))
descriptions.get(SERVICE_VOLUME_SET),
schema=MEDIA_PLAYER_SET_VOLUME_SCHEMA)
def volume_mute_service(service):
"""Mute (true) or unmute (false) the media player."""
mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED)
if mute is None:
_LOGGER.error(
'Received call to %s without attribute %s',
service.service, ATTR_MEDIA_VOLUME_MUTED)
return
for player in component.extract_from_service(service):
player.mute_volume(mute)
@ -296,18 +315,13 @@ def setup(hass, config):
player.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service,
descriptions.get(SERVICE_VOLUME_MUTE))
descriptions.get(SERVICE_VOLUME_MUTE),
schema=MEDIA_PLAYER_MUTE_VOLUME_SCHEMA)
def media_seek_service(service):
"""Seek to a position."""
position = service.data.get(ATTR_MEDIA_SEEK_POSITION)
if position is None:
_LOGGER.error(
'Received call to %s without attribute %s',
service.service, ATTR_MEDIA_SEEK_POSITION)
return
for player in component.extract_from_service(service):
player.media_seek(position)
@ -315,18 +329,13 @@ def setup(hass, config):
player.update_ha_state(True)
hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service,
descriptions.get(SERVICE_MEDIA_SEEK))
descriptions.get(SERVICE_MEDIA_SEEK),
schema=MEDIA_PLAYER_MEDIA_SEEK_SCHEMA)
def select_source_service(service):
"""Change input to selected source."""
input_source = service.data.get(ATTR_INPUT_SOURCE)
if input_source is None:
_LOGGER.error(
'Received call to %s without attribute %s',
service.service, ATTR_INPUT_SOURCE)
return
for player in component.extract_from_service(service):
player.select_source(input_source)
@ -335,30 +344,23 @@ def setup(hass, config):
hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE,
select_source_service,
descriptions.get(SERVICE_SELECT_SOURCE))
descriptions.get(SERVICE_SELECT_SOURCE),
schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA)
def play_media_service(service):
"""Play specified media_id on the media player."""
media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE)
media_id = service.data.get(ATTR_MEDIA_CONTENT_ID)
if media_type is None or media_id is None:
missing_attr = (ATTR_MEDIA_CONTENT_TYPE if media_type is None
else ATTR_MEDIA_CONTENT_ID)
_LOGGER.error(
'Received call to %s without attribute %s',
service.service, missing_attr)
return
for player in component.extract_from_service(service):
player.play_media(media_type, media_id)
if player.should_poll:
player.update_ha_state(True)
hass.services.register(
DOMAIN, SERVICE_PLAY_MEDIA, play_media_service,
descriptions.get(SERVICE_PLAY_MEDIA))
hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service,
descriptions.get(SERVICE_PLAY_MEDIA),
schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA)
return True

View File

@ -47,6 +47,13 @@ def icon(value):
raise vol.Invalid('Icons should start with prefix "mdi:"')
def string(value):
"""Coerce value to string, except for None."""
if value is not None:
return str(value)
raise vol.Invalid('Value should not be None')
def temperature_unit(value):
"""Validate and transform temperature unit."""
if isinstance(value, str):