Service validation for media_player component
parent
5c262753d4
commit
afd1e6a5cc
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue