Service validation for media_player component
parent
5c262753d4
commit
afd1e6a5cc
|
@ -7,11 +7,14 @@ https://home-assistant.io/components/media_player/
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components import discovery
|
from homeassistant.components import discovery
|
||||||
from homeassistant.config import load_yaml_config_file
|
from homeassistant.config import load_yaml_config_file
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.helpers.entity_component import EntityComponent
|
from homeassistant.helpers.entity_component import EntityComponent
|
||||||
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
|
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
STATE_OFF, STATE_UNKNOWN, STATE_PLAYING, STATE_IDLE,
|
STATE_OFF, STATE_UNKNOWN, STATE_PLAYING, STATE_IDLE,
|
||||||
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON,
|
ATTR_ENTITY_ID, SERVICE_TURN_OFF, SERVICE_TURN_ON,
|
||||||
|
@ -78,6 +81,7 @@ SUPPORT_PLAY_MEDIA = 512
|
||||||
SUPPORT_VOLUME_STEP = 1024
|
SUPPORT_VOLUME_STEP = 1024
|
||||||
SUPPORT_SELECT_SOURCE = 2048
|
SUPPORT_SELECT_SOURCE = 2048
|
||||||
|
|
||||||
|
# simple services that only take entity_id(s) as optional argument
|
||||||
SERVICE_TO_METHOD = {
|
SERVICE_TO_METHOD = {
|
||||||
SERVICE_TURN_ON: 'turn_on',
|
SERVICE_TURN_ON: 'turn_on',
|
||||||
SERVICE_TURN_OFF: 'turn_off',
|
SERVICE_TURN_OFF: 'turn_off',
|
||||||
|
@ -89,8 +93,6 @@ SERVICE_TO_METHOD = {
|
||||||
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_PLAY_MEDIA: 'play_media',
|
|
||||||
SERVICE_SELECT_SOURCE: 'select_source',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ATTR_TO_PROPERTY = [
|
ATTR_TO_PROPERTY = [
|
||||||
|
@ -115,6 +117,33 @@ ATTR_TO_PROPERTY = [
|
||||||
ATTR_INPUT_SOURCE,
|
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):
|
def is_on(hass, entity_id=None):
|
||||||
"""
|
"""
|
||||||
|
@ -258,18 +287,13 @@ def setup(hass, config):
|
||||||
|
|
||||||
for service in SERVICE_TO_METHOD:
|
for service in SERVICE_TO_METHOD:
|
||||||
hass.services.register(DOMAIN, service, media_player_service_handler,
|
hass.services.register(DOMAIN, service, media_player_service_handler,
|
||||||
descriptions.get(service))
|
descriptions.get(service),
|
||||||
|
schema=MEDIA_PLAYER_SCHEMA)
|
||||||
|
|
||||||
def volume_set_service(service):
|
def volume_set_service(service):
|
||||||
"""Set specified volume on the media player."""
|
"""Set specified volume on the media player."""
|
||||||
volume = service.data.get(ATTR_MEDIA_VOLUME_LEVEL)
|
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):
|
for player in component.extract_from_service(service):
|
||||||
player.set_volume_level(volume)
|
player.set_volume_level(volume)
|
||||||
|
|
||||||
|
@ -277,18 +301,13 @@ def setup(hass, config):
|
||||||
player.update_ha_state(True)
|
player.update_ha_state(True)
|
||||||
|
|
||||||
hass.services.register(DOMAIN, SERVICE_VOLUME_SET, volume_set_service,
|
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):
|
def volume_mute_service(service):
|
||||||
"""Mute (true) or unmute (false) the media player."""
|
"""Mute (true) or unmute (false) the media player."""
|
||||||
mute = service.data.get(ATTR_MEDIA_VOLUME_MUTED)
|
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):
|
for player in component.extract_from_service(service):
|
||||||
player.mute_volume(mute)
|
player.mute_volume(mute)
|
||||||
|
|
||||||
|
@ -296,18 +315,13 @@ def setup(hass, config):
|
||||||
player.update_ha_state(True)
|
player.update_ha_state(True)
|
||||||
|
|
||||||
hass.services.register(DOMAIN, SERVICE_VOLUME_MUTE, volume_mute_service,
|
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):
|
def media_seek_service(service):
|
||||||
"""Seek to a position."""
|
"""Seek to a position."""
|
||||||
position = service.data.get(ATTR_MEDIA_SEEK_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):
|
for player in component.extract_from_service(service):
|
||||||
player.media_seek(position)
|
player.media_seek(position)
|
||||||
|
|
||||||
|
@ -315,18 +329,13 @@ def setup(hass, config):
|
||||||
player.update_ha_state(True)
|
player.update_ha_state(True)
|
||||||
|
|
||||||
hass.services.register(DOMAIN, SERVICE_MEDIA_SEEK, media_seek_service,
|
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):
|
def select_source_service(service):
|
||||||
"""Change input to selected source."""
|
"""Change input to selected source."""
|
||||||
input_source = service.data.get(ATTR_INPUT_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):
|
for player in component.extract_from_service(service):
|
||||||
player.select_source(input_source)
|
player.select_source(input_source)
|
||||||
|
|
||||||
|
@ -335,30 +344,23 @@ def setup(hass, config):
|
||||||
|
|
||||||
hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE,
|
hass.services.register(DOMAIN, SERVICE_SELECT_SOURCE,
|
||||||
select_source_service,
|
select_source_service,
|
||||||
descriptions.get(SERVICE_SELECT_SOURCE))
|
descriptions.get(SERVICE_SELECT_SOURCE),
|
||||||
|
schema=MEDIA_PLAYER_SELECT_SOURCE_SCHEMA)
|
||||||
|
|
||||||
def play_media_service(service):
|
def play_media_service(service):
|
||||||
"""Play specified media_id on the media player."""
|
"""Play specified media_id on the media player."""
|
||||||
media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE)
|
media_type = service.data.get(ATTR_MEDIA_CONTENT_TYPE)
|
||||||
media_id = service.data.get(ATTR_MEDIA_CONTENT_ID)
|
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):
|
for player in component.extract_from_service(service):
|
||||||
player.play_media(media_type, media_id)
|
player.play_media(media_type, media_id)
|
||||||
|
|
||||||
if player.should_poll:
|
if player.should_poll:
|
||||||
player.update_ha_state(True)
|
player.update_ha_state(True)
|
||||||
|
|
||||||
hass.services.register(
|
hass.services.register(DOMAIN, SERVICE_PLAY_MEDIA, play_media_service,
|
||||||
DOMAIN, SERVICE_PLAY_MEDIA, play_media_service,
|
descriptions.get(SERVICE_PLAY_MEDIA),
|
||||||
descriptions.get(SERVICE_PLAY_MEDIA))
|
schema=MEDIA_PLAYER_PLAY_MEDIA_SCHEMA)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,13 @@ def icon(value):
|
||||||
raise vol.Invalid('Icons should start with prefix "mdi:"')
|
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):
|
def temperature_unit(value):
|
||||||
"""Validate and transform temperature unit."""
|
"""Validate and transform temperature unit."""
|
||||||
if isinstance(value, str):
|
if isinstance(value, str):
|
||||||
|
|
Loading…
Reference in New Issue