Use a template for the Universal media player state (#10395)
* Implementation of `state_template` for the Universal media_player * add tracking to entities in state template * use normal config_validation * fix tests, use defaults in platform schema, remove extra keys * and test the new option `state_template` * lint fixes * no need to check attributes against None * use `async_added_to_hass` and call `async_track_state_change` from `hass.helpers`
This commit is contained in:
parent
dc6e50c39d
commit
e947e6a143
3 changed files with 155 additions and 177 deletions
|
@ -9,28 +9,30 @@ import logging
|
|||
# pylint: disable=import-error
|
||||
from copy import copy
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.components.media_player import (
|
||||
ATTR_APP_ID, ATTR_APP_NAME, ATTR_MEDIA_ALBUM_ARTIST, ATTR_MEDIA_ALBUM_NAME,
|
||||
ATTR_MEDIA_ARTIST, ATTR_MEDIA_CHANNEL, ATTR_MEDIA_CONTENT_ID,
|
||||
ATTR_MEDIA_CONTENT_TYPE, ATTR_MEDIA_DURATION, ATTR_MEDIA_EPISODE,
|
||||
ATTR_MEDIA_PLAYLIST, ATTR_MEDIA_SEASON, ATTR_MEDIA_SEEK_POSITION,
|
||||
ATTR_MEDIA_SERIES_TITLE, ATTR_MEDIA_TITLE, ATTR_MEDIA_TRACK,
|
||||
ATTR_MEDIA_VOLUME_LEVEL, ATTR_MEDIA_VOLUME_MUTED, ATTR_INPUT_SOURCE_LIST,
|
||||
ATTR_MEDIA_POSITION, ATTR_MEDIA_SHUFFLE,
|
||||
ATTR_MEDIA_POSITION_UPDATED_AT, DOMAIN, SERVICE_PLAY_MEDIA,
|
||||
ATTR_APP_ID, ATTR_APP_NAME, ATTR_INPUT_SOURCE, ATTR_INPUT_SOURCE_LIST,
|
||||
ATTR_MEDIA_ALBUM_ARTIST, ATTR_MEDIA_ALBUM_NAME, ATTR_MEDIA_ARTIST,
|
||||
ATTR_MEDIA_CHANNEL, ATTR_MEDIA_CONTENT_ID, ATTR_MEDIA_CONTENT_TYPE,
|
||||
ATTR_MEDIA_DURATION, ATTR_MEDIA_EPISODE, ATTR_MEDIA_PLAYLIST,
|
||||
ATTR_MEDIA_POSITION, ATTR_MEDIA_POSITION_UPDATED_AT, ATTR_MEDIA_SEASON,
|
||||
ATTR_MEDIA_SEEK_POSITION, ATTR_MEDIA_SERIES_TITLE, ATTR_MEDIA_SHUFFLE,
|
||||
ATTR_MEDIA_TITLE, ATTR_MEDIA_TRACK, ATTR_MEDIA_VOLUME_LEVEL,
|
||||
ATTR_MEDIA_VOLUME_MUTED, DOMAIN, MediaPlayerDevice, PLATFORM_SCHEMA,
|
||||
SERVICE_CLEAR_PLAYLIST, SERVICE_PLAY_MEDIA, SERVICE_SELECT_SOURCE,
|
||||
SUPPORT_CLEAR_PLAYLIST, SUPPORT_SELECT_SOURCE, SUPPORT_SHUFFLE_SET,
|
||||
SUPPORT_TURN_OFF, SUPPORT_TURN_ON, SUPPORT_VOLUME_MUTE, SUPPORT_VOLUME_SET,
|
||||
SUPPORT_VOLUME_STEP, SUPPORT_SELECT_SOURCE, SUPPORT_CLEAR_PLAYLIST,
|
||||
SUPPORT_SHUFFLE_SET, ATTR_INPUT_SOURCE, SERVICE_SELECT_SOURCE,
|
||||
SERVICE_CLEAR_PLAYLIST, MediaPlayerDevice)
|
||||
SUPPORT_VOLUME_STEP)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE, CONF_NAME, SERVICE_MEDIA_NEXT_TRACK,
|
||||
SERVICE_MEDIA_PAUSE, SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PLAY_PAUSE,
|
||||
SERVICE_MEDIA_PREVIOUS_TRACK, SERVICE_MEDIA_SEEK, SERVICE_TURN_OFF,
|
||||
SERVICE_TURN_ON, SERVICE_VOLUME_DOWN, SERVICE_VOLUME_MUTE,
|
||||
SERVICE_VOLUME_SET, SERVICE_VOLUME_UP, SERVICE_SHUFFLE_SET, STATE_IDLE,
|
||||
STATE_OFF, STATE_ON, SERVICE_MEDIA_STOP, ATTR_SUPPORTED_FEATURES)
|
||||
from homeassistant.helpers.event import async_track_state_change
|
||||
ATTR_ENTITY_ID, ATTR_ENTITY_PICTURE, ATTR_SUPPORTED_FEATURES, CONF_NAME,
|
||||
CONF_STATE_TEMPLATE, SERVICE_MEDIA_NEXT_TRACK, SERVICE_MEDIA_PAUSE,
|
||||
SERVICE_MEDIA_PLAY, SERVICE_MEDIA_PLAY_PAUSE, SERVICE_MEDIA_PREVIOUS_TRACK,
|
||||
SERVICE_MEDIA_SEEK, SERVICE_TURN_OFF, SERVICE_TURN_ON, SERVICE_VOLUME_DOWN,
|
||||
SERVICE_VOLUME_MUTE, SERVICE_VOLUME_SET, SERVICE_VOLUME_UP,
|
||||
SERVICE_SHUFFLE_SET, STATE_IDLE, STATE_OFF, STATE_ON, SERVICE_MEDIA_STOP)
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.service import async_call_from_config
|
||||
|
||||
ATTR_ACTIVE_CHILD = 'active_child'
|
||||
|
@ -48,113 +50,75 @@ OFF_STATES = [STATE_IDLE, STATE_OFF]
|
|||
REQUIREMENTS = []
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
ATTRS_SCHEMA = vol.Schema({cv.slug: cv.string})
|
||||
CMD_SCHEMA = vol.Schema({cv.slug: cv.SERVICE_SCHEMA})
|
||||
|
||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_CHILDREN, default=[]): cv.entity_ids,
|
||||
vol.Optional(CONF_COMMANDS, default={}): CMD_SCHEMA,
|
||||
vol.Optional(CONF_ATTRS, default={}):
|
||||
vol.Or(cv.ensure_list(ATTRS_SCHEMA), ATTRS_SCHEMA),
|
||||
vol.Optional(CONF_STATE_TEMPLATE): cv.template
|
||||
}, extra=vol.REMOVE_EXTRA)
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
|
||||
"""Set up the universal media players."""
|
||||
if not validate_config(config):
|
||||
return
|
||||
|
||||
player = UniversalMediaPlayer(
|
||||
hass,
|
||||
config[CONF_NAME],
|
||||
config[CONF_CHILDREN],
|
||||
config[CONF_COMMANDS],
|
||||
config[CONF_ATTRS]
|
||||
config.get(CONF_NAME),
|
||||
config.get(CONF_CHILDREN),
|
||||
config.get(CONF_COMMANDS),
|
||||
config.get(CONF_ATTRS),
|
||||
config.get(CONF_STATE_TEMPLATE)
|
||||
)
|
||||
|
||||
async_add_devices([player])
|
||||
|
||||
|
||||
def validate_config(config):
|
||||
"""Validate universal media player configuration."""
|
||||
del config[CONF_PLATFORM]
|
||||
|
||||
# Validate name
|
||||
if CONF_NAME not in config:
|
||||
_LOGGER.error("Universal Media Player configuration requires name")
|
||||
return False
|
||||
|
||||
validate_children(config)
|
||||
validate_commands(config)
|
||||
validate_attributes(config)
|
||||
|
||||
del_keys = []
|
||||
for key in config:
|
||||
if key not in [CONF_NAME, CONF_CHILDREN, CONF_COMMANDS, CONF_ATTRS]:
|
||||
_LOGGER.warning(
|
||||
"Universal Media Player (%s) unrecognized parameter %s",
|
||||
config[CONF_NAME], key)
|
||||
del_keys.append(key)
|
||||
for key in del_keys:
|
||||
del config[key]
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def validate_children(config):
|
||||
"""Validate children."""
|
||||
if CONF_CHILDREN not in config:
|
||||
_LOGGER.info(
|
||||
"No children under Universal Media Player (%s)", config[CONF_NAME])
|
||||
config[CONF_CHILDREN] = []
|
||||
elif not isinstance(config[CONF_CHILDREN], list):
|
||||
_LOGGER.warning(
|
||||
"Universal Media Player (%s) children not list in config. "
|
||||
"They will be ignored", config[CONF_NAME])
|
||||
config[CONF_CHILDREN] = []
|
||||
|
||||
|
||||
def validate_commands(config):
|
||||
"""Validate commands."""
|
||||
if CONF_COMMANDS not in config:
|
||||
config[CONF_COMMANDS] = {}
|
||||
elif not isinstance(config[CONF_COMMANDS], dict):
|
||||
_LOGGER.warning(
|
||||
"Universal Media Player (%s) specified commands not dict in "
|
||||
"config. They will be ignored", config[CONF_NAME])
|
||||
config[CONF_COMMANDS] = {}
|
||||
|
||||
|
||||
def validate_attributes(config):
|
||||
"""Validate attributes."""
|
||||
if CONF_ATTRS not in config:
|
||||
config[CONF_ATTRS] = {}
|
||||
elif not isinstance(config[CONF_ATTRS], dict):
|
||||
_LOGGER.warning(
|
||||
"Universal Media Player (%s) specified attributes "
|
||||
"not dict in config. They will be ignored", config[CONF_NAME])
|
||||
config[CONF_ATTRS] = {}
|
||||
|
||||
for key, val in config[CONF_ATTRS].items():
|
||||
attr = val.split('|', 1)
|
||||
if len(attr) == 1:
|
||||
attr.append(None)
|
||||
config[CONF_ATTRS][key] = attr
|
||||
|
||||
|
||||
class UniversalMediaPlayer(MediaPlayerDevice):
|
||||
"""Representation of an universal media player."""
|
||||
|
||||
def __init__(self, hass, name, children, commands, attributes):
|
||||
def __init__(self, hass, name, children,
|
||||
commands, attributes, state_template=None):
|
||||
"""Initialize the Universal media device."""
|
||||
self.hass = hass
|
||||
self._name = name
|
||||
self._children = children
|
||||
self._cmds = commands
|
||||
self._attrs = attributes
|
||||
self._attrs = {}
|
||||
for key, val in attributes.items():
|
||||
attr = val.split('|', 1)
|
||||
if len(attr) == 1:
|
||||
attr.append(None)
|
||||
self._attrs[key] = attr
|
||||
self._child_state = None
|
||||
self._state_template = state_template
|
||||
if state_template is not None:
|
||||
self._state_template.hass = hass
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_added_to_hass(self):
|
||||
"""Subscribe to children and template state changes.
|
||||
|
||||
This method must be run in the event loop and returns a coroutine.
|
||||
"""
|
||||
@callback
|
||||
def async_on_dependency_update(*_):
|
||||
"""Update ha state when dependencies update."""
|
||||
self.async_schedule_update_ha_state(True)
|
||||
|
||||
depend = copy(children)
|
||||
for entity in attributes.values():
|
||||
depend = copy(self._children)
|
||||
for entity in self._attrs.values():
|
||||
depend.append(entity[0])
|
||||
if self._state_template is not None:
|
||||
for entity in self._state_template.extract_entities():
|
||||
depend.append(entity)
|
||||
|
||||
async_track_state_change(hass, depend, async_on_dependency_update)
|
||||
self.hass.helpers.event.async_track_state_change(
|
||||
list(set(depend)), async_on_dependency_update)
|
||||
|
||||
def _entity_lkp(self, entity_id, state_attr=None):
|
||||
"""Look up an entity state."""
|
||||
|
@ -211,6 +175,8 @@ class UniversalMediaPlayer(MediaPlayerDevice):
|
|||
@property
|
||||
def master_state(self):
|
||||
"""Return the master state for entity or None."""
|
||||
if self._state_template is not None:
|
||||
return self._state_template.async_render()
|
||||
if CONF_STATE in self._attrs:
|
||||
master_state = self._entity_lkp(
|
||||
self._attrs[CONF_STATE][0], self._attrs[CONF_STATE][1])
|
||||
|
@ -232,8 +198,8 @@ class UniversalMediaPlayer(MediaPlayerDevice):
|
|||
else master state or off
|
||||
"""
|
||||
master_state = self.master_state # avoid multiple lookups
|
||||
if master_state == STATE_OFF:
|
||||
return STATE_OFF
|
||||
if (master_state == STATE_OFF) or (self._state_template is not None):
|
||||
return master_state
|
||||
|
||||
active_child = self._child_state
|
||||
if active_child:
|
||||
|
|
|
@ -126,6 +126,7 @@ CONF_SHOW_ON_MAP = 'show_on_map'
|
|||
CONF_SLAVE = 'slave'
|
||||
CONF_SSL = 'ssl'
|
||||
CONF_STATE = 'state'
|
||||
CONF_STATE_TEMPLATE = 'state_template'
|
||||
CONF_STRUCTURE = 'structure'
|
||||
CONF_SWITCHES = 'switches'
|
||||
CONF_TEMPERATURE_UNIT = 'temperature_unit'
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
from copy import copy
|
||||
import unittest
|
||||
|
||||
from voluptuous.error import MultipleInvalid
|
||||
|
||||
from homeassistant.const import (
|
||||
STATE_OFF, STATE_ON, STATE_UNKNOWN, STATE_PLAYING, STATE_PAUSED)
|
||||
import homeassistant.components.switch as switch
|
||||
|
@ -14,6 +16,13 @@ from homeassistant.util.async import run_coroutine_threadsafe
|
|||
from tests.common import mock_service, get_test_home_assistant
|
||||
|
||||
|
||||
def validate_config(config):
|
||||
"""Use the platform schema to validate configuration."""
|
||||
validated_config = universal.PLATFORM_SCHEMA(config)
|
||||
validated_config.pop('platform')
|
||||
return validated_config
|
||||
|
||||
|
||||
class MockMediaPlayer(media_player.MediaPlayerDevice):
|
||||
"""Mock media player for testing."""
|
||||
|
||||
|
@ -116,9 +125,9 @@ class MockMediaPlayer(media_player.MediaPlayerDevice):
|
|||
"""Mock turn_off function."""
|
||||
self._state = STATE_OFF
|
||||
|
||||
def mute_volume(self):
|
||||
def mute_volume(self, mute):
|
||||
"""Mock mute function."""
|
||||
self._is_volume_muted = ~self._is_volume_muted
|
||||
self._is_volume_muted = mute
|
||||
|
||||
def set_volume_level(self, volume):
|
||||
"""Mock set volume level."""
|
||||
|
@ -210,10 +219,8 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
config_start['commands'] = {}
|
||||
config_start['attributes'] = {}
|
||||
|
||||
response = universal.validate_config(self.config_children_only)
|
||||
|
||||
self.assertTrue(response)
|
||||
self.assertEqual(config_start, self.config_children_only)
|
||||
config = validate_config(self.config_children_only)
|
||||
self.assertEqual(config_start, config)
|
||||
|
||||
def test_config_children_and_attr(self):
|
||||
"""Check config with children and attributes."""
|
||||
|
@ -221,15 +228,16 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
del config_start['platform']
|
||||
config_start['commands'] = {}
|
||||
|
||||
response = universal.validate_config(self.config_children_and_attr)
|
||||
|
||||
self.assertTrue(response)
|
||||
self.assertEqual(config_start, self.config_children_and_attr)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
self.assertEqual(config_start, config)
|
||||
|
||||
def test_config_no_name(self):
|
||||
"""Check config with no Name entry."""
|
||||
response = universal.validate_config({'platform': 'universal'})
|
||||
|
||||
response = True
|
||||
try:
|
||||
validate_config({'platform': 'universal'})
|
||||
except MultipleInvalid:
|
||||
response = False
|
||||
self.assertFalse(response)
|
||||
|
||||
def test_config_bad_children(self):
|
||||
|
@ -238,36 +246,31 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
config_bad_children = {'name': 'test', 'children': {},
|
||||
'platform': 'universal'}
|
||||
|
||||
response = universal.validate_config(config_no_children)
|
||||
self.assertTrue(response)
|
||||
config_no_children = validate_config(config_no_children)
|
||||
self.assertEqual([], config_no_children['children'])
|
||||
|
||||
response = universal.validate_config(config_bad_children)
|
||||
self.assertTrue(response)
|
||||
config_bad_children = validate_config(config_bad_children)
|
||||
self.assertEqual([], config_bad_children['children'])
|
||||
|
||||
def test_config_bad_commands(self):
|
||||
"""Check config with bad commands entry."""
|
||||
config = {'name': 'test', 'commands': [], 'platform': 'universal'}
|
||||
config = {'name': 'test', 'platform': 'universal'}
|
||||
|
||||
response = universal.validate_config(config)
|
||||
self.assertTrue(response)
|
||||
config = validate_config(config)
|
||||
self.assertEqual({}, config['commands'])
|
||||
|
||||
def test_config_bad_attributes(self):
|
||||
"""Check config with bad attributes."""
|
||||
config = {'name': 'test', 'attributes': [], 'platform': 'universal'}
|
||||
config = {'name': 'test', 'platform': 'universal'}
|
||||
|
||||
response = universal.validate_config(config)
|
||||
self.assertTrue(response)
|
||||
config = validate_config(config)
|
||||
self.assertEqual({}, config['attributes'])
|
||||
|
||||
def test_config_bad_key(self):
|
||||
"""Check config with bad key."""
|
||||
config = {'name': 'test', 'asdf': 5, 'platform': 'universal'}
|
||||
|
||||
response = universal.validate_config(config)
|
||||
self.assertTrue(response)
|
||||
config = validate_config(config)
|
||||
self.assertFalse('asdf' in config)
|
||||
|
||||
def test_platform_setup(self):
|
||||
|
@ -281,21 +284,27 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
for dev in new_entities:
|
||||
entities.append(dev)
|
||||
|
||||
setup_ok = True
|
||||
try:
|
||||
run_coroutine_threadsafe(
|
||||
universal.async_setup_platform(self.hass, bad_config, add_devices),
|
||||
universal.async_setup_platform(
|
||||
self.hass, validate_config(bad_config), add_devices),
|
||||
self.hass.loop).result()
|
||||
except MultipleInvalid:
|
||||
setup_ok = False
|
||||
self.assertFalse(setup_ok)
|
||||
self.assertEqual(0, len(entities))
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
universal.async_setup_platform(self.hass, config, add_devices),
|
||||
universal.async_setup_platform(
|
||||
self.hass, validate_config(config), add_devices),
|
||||
self.hass.loop).result()
|
||||
self.assertEqual(1, len(entities))
|
||||
self.assertEqual('test', entities[0].name)
|
||||
|
||||
def test_master_state(self):
|
||||
"""Test master state property."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -303,8 +312,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_master_state_with_attrs(self):
|
||||
"""Test master state property."""
|
||||
config = self.config_children_and_attr
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -312,11 +320,26 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
self.hass.states.set(self.mock_state_switch_id, STATE_ON)
|
||||
self.assertEqual(STATE_ON, ump.master_state)
|
||||
|
||||
def test_master_state_with_template(self):
|
||||
"""Test the state_template option."""
|
||||
config = copy(self.config_children_and_attr)
|
||||
self.hass.states.set('input_boolean.test', STATE_OFF)
|
||||
templ = '{% if states.input_boolean.test.state == "off" %}on' \
|
||||
'{% else %}{{ states.media_player.mock1.state }}{% endif %}'
|
||||
config['state_template'] = templ
|
||||
config = validate_config(config)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
self.assertEqual(STATE_ON, ump.master_state)
|
||||
self.hass.states.set('input_boolean.test', STATE_ON)
|
||||
self.assertEqual(STATE_OFF, ump.master_state)
|
||||
|
||||
def test_master_state_with_bad_attrs(self):
|
||||
"""Test master state property."""
|
||||
config = self.config_children_and_attr
|
||||
config = copy(self.config_children_and_attr)
|
||||
config['attributes']['state'] = 'bad.entity_id'
|
||||
universal.validate_config(config)
|
||||
config = validate_config(config)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -324,8 +347,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_active_child_state(self):
|
||||
"""Test active child state property."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -356,8 +378,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_name(self):
|
||||
"""Test name property."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -365,8 +386,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_polling(self):
|
||||
"""Test should_poll property."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -374,8 +394,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_state_children_only(self):
|
||||
"""Test media player state with only children."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -391,8 +410,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_state_with_children_and_attrs(self):
|
||||
"""Test media player with children and master state."""
|
||||
config = self.config_children_and_attr
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -416,8 +434,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_volume_level(self):
|
||||
"""Test volume level property."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -439,9 +456,8 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_media_image_url(self):
|
||||
"""Test media_image_url property."""
|
||||
TEST_URL = "test_url"
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
test_url = "test_url"
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -450,7 +466,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
self.assertEqual(None, ump.media_image_url)
|
||||
|
||||
self.mock_mp_1._state = STATE_PLAYING
|
||||
self.mock_mp_1._media_image_url = TEST_URL
|
||||
self.mock_mp_1._media_image_url = test_url
|
||||
self.mock_mp_1.schedule_update_ha_state()
|
||||
self.hass.block_till_done()
|
||||
run_coroutine_threadsafe(ump.async_update(), self.hass.loop).result()
|
||||
|
@ -460,8 +476,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_is_volume_muted_children_only(self):
|
||||
"""Test is volume muted property w/ children only."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -483,8 +498,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_source_list_children_and_attr(self):
|
||||
"""Test source list property w/ children and attrs."""
|
||||
config = self.config_children_and_attr
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -495,8 +509,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_source_children_and_attr(self):
|
||||
"""Test source property w/ children and attrs."""
|
||||
config = self.config_children_and_attr
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -507,8 +520,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_volume_level_children_and_attr(self):
|
||||
"""Test volume level property w/ children and attrs."""
|
||||
config = self.config_children_and_attr
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -519,8 +531,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_is_volume_muted_children_and_attr(self):
|
||||
"""Test is volume muted property w/ children and attrs."""
|
||||
config = self.config_children_and_attr
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
|
||||
|
@ -531,8 +542,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_supported_features_children_only(self):
|
||||
"""Test supported media commands with only children."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -549,16 +559,19 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_supported_features_children_and_cmds(self):
|
||||
"""Test supported media commands with children and attrs."""
|
||||
config = self.config_children_and_attr
|
||||
universal.validate_config(config)
|
||||
config['commands']['turn_on'] = 'test'
|
||||
config['commands']['turn_off'] = 'test'
|
||||
config['commands']['volume_up'] = 'test'
|
||||
config['commands']['volume_down'] = 'test'
|
||||
config['commands']['volume_mute'] = 'test'
|
||||
config['commands']['volume_set'] = 'test'
|
||||
config['commands']['select_source'] = 'test'
|
||||
config['commands']['shuffle_set'] = 'test'
|
||||
config = copy(self.config_children_and_attr)
|
||||
excmd = {'service': 'media_player.test', 'data': {'entity_id': 'test'}}
|
||||
config['commands'] = {
|
||||
'turn_on': excmd,
|
||||
'turn_off': excmd,
|
||||
'volume_up': excmd,
|
||||
'volume_down': excmd,
|
||||
'volume_mute': excmd,
|
||||
'volume_set': excmd,
|
||||
'select_source': excmd,
|
||||
'shuffle_set': excmd
|
||||
}
|
||||
config = validate_config(config)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -577,8 +590,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_service_call_no_active_child(self):
|
||||
"""Test a service call to children with no active child."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_and_attr)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -599,8 +611,7 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_service_call_to_child(self):
|
||||
"""Test service calls that should be routed to a child."""
|
||||
config = self.config_children_only
|
||||
universal.validate_config(config)
|
||||
config = validate_config(self.config_children_only)
|
||||
|
||||
ump = universal.UniversalMediaPlayer(self.hass, **config)
|
||||
ump.entity_id = media_player.ENTITY_ID_FORMAT.format(config['name'])
|
||||
|
@ -699,10 +710,10 @@ class TestMediaPlayer(unittest.TestCase):
|
|||
|
||||
def test_service_call_to_command(self):
|
||||
"""Test service call to command."""
|
||||
config = self.config_children_only
|
||||
config = copy(self.config_children_only)
|
||||
config['commands'] = {'turn_off': {
|
||||
'service': 'test.turn_off', 'data': {}}}
|
||||
universal.validate_config(config)
|
||||
config = validate_config(config)
|
||||
|
||||
service = mock_service(self.hass, 'test', 'turn_off')
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue