mirror of
https://github.com/home-assistant/core.git
synced 2025-07-10 06:47:09 +00:00
Add active_child_template
to universal media player (#88816)
* Add active_children_template in universal * handle multiple updates * edit docstring * Rename parameter to active_child_template
This commit is contained in:
parent
acb7b1fe3b
commit
c14a2dd912
@ -95,6 +95,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
|
|||||||
|
|
||||||
ATTR_ACTIVE_CHILD = "active_child"
|
ATTR_ACTIVE_CHILD = "active_child"
|
||||||
|
|
||||||
|
CONF_ACTIVE_CHILD_TEMPLATE = "active_child_template"
|
||||||
CONF_ATTRS = "attributes"
|
CONF_ATTRS = "attributes"
|
||||||
CONF_CHILDREN = "children"
|
CONF_CHILDREN = "children"
|
||||||
CONF_COMMANDS = "commands"
|
CONF_COMMANDS = "commands"
|
||||||
@ -128,6 +129,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
vol.Optional(CONF_BROWSE_MEDIA_ENTITY): cv.string,
|
vol.Optional(CONF_BROWSE_MEDIA_ENTITY): cv.string,
|
||||||
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
vol.Optional(CONF_UNIQUE_ID): cv.string,
|
||||||
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
|
||||||
|
vol.Optional(CONF_ACTIVE_CHILD_TEMPLATE): cv.template,
|
||||||
vol.Optional(CONF_STATE_TEMPLATE): cv.template,
|
vol.Optional(CONF_STATE_TEMPLATE): cv.template,
|
||||||
},
|
},
|
||||||
extra=vol.REMOVE_EXTRA,
|
extra=vol.REMOVE_EXTRA,
|
||||||
@ -161,6 +163,8 @@ class UniversalMediaPlayer(MediaPlayerEntity):
|
|||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._name = config.get(CONF_NAME)
|
self._name = config.get(CONF_NAME)
|
||||||
self._children = config.get(CONF_CHILDREN)
|
self._children = config.get(CONF_CHILDREN)
|
||||||
|
self._active_child_template = config.get(CONF_ACTIVE_CHILD_TEMPLATE)
|
||||||
|
self._active_child_template_result = None
|
||||||
self._cmds = config.get(CONF_COMMANDS)
|
self._cmds = config.get(CONF_COMMANDS)
|
||||||
self._attrs = {}
|
self._attrs = {}
|
||||||
for key, val in config.get(CONF_ATTRS).items():
|
for key, val in config.get(CONF_ATTRS).items():
|
||||||
@ -186,23 +190,35 @@ class UniversalMediaPlayer(MediaPlayerEntity):
|
|||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_on_template_update(event, updates):
|
def _async_on_template_update(event, updates):
|
||||||
"""Update ha state when dependencies update."""
|
"""Update state when template state changes."""
|
||||||
result = updates.pop().result
|
for data in updates:
|
||||||
|
template = data.template
|
||||||
|
result = data.result
|
||||||
|
|
||||||
if isinstance(result, TemplateError):
|
if template == self._state_template:
|
||||||
self._state_template_result = None
|
self._state_template_result = (
|
||||||
else:
|
None if isinstance(result, TemplateError) else result
|
||||||
self._state_template_result = result
|
)
|
||||||
|
if template == self._active_child_template:
|
||||||
|
self._active_child_template_result = (
|
||||||
|
None if isinstance(result, TemplateError) else result
|
||||||
|
)
|
||||||
|
|
||||||
if event:
|
if event:
|
||||||
self.async_set_context(event.context)
|
self.async_set_context(event.context)
|
||||||
|
|
||||||
self.async_schedule_update_ha_state(True)
|
self.async_schedule_update_ha_state(True)
|
||||||
|
|
||||||
if self._state_template is not None:
|
track_templates: list[TrackTemplate] = []
|
||||||
|
if self._state_template:
|
||||||
|
track_templates.append(TrackTemplate(self._state_template, None))
|
||||||
|
if self._active_child_template:
|
||||||
|
track_templates.append(TrackTemplate(self._active_child_template, None))
|
||||||
|
|
||||||
|
if track_templates:
|
||||||
result = async_track_template_result(
|
result = async_track_template_result(
|
||||||
self.hass,
|
self.hass,
|
||||||
[TrackTemplate(self._state_template, None)],
|
track_templates,
|
||||||
_async_on_template_update,
|
_async_on_template_update,
|
||||||
)
|
)
|
||||||
self.hass.bus.async_listen_once(
|
self.hass.bus.async_listen_once(
|
||||||
@ -644,6 +660,9 @@ class UniversalMediaPlayer(MediaPlayerEntity):
|
|||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
"""Update state in HA."""
|
"""Update state in HA."""
|
||||||
|
if self._active_child_template_result:
|
||||||
|
self._child_state = self.hass.states.get(self._active_child_template_result)
|
||||||
|
return
|
||||||
self._child_state = None
|
self._child_state = None
|
||||||
for child_name in self._children:
|
for child_name in self._children:
|
||||||
if (child_state := self.hass.states.get(child_name)) and (
|
if (child_state := self.hass.states.get(child_name)) and (
|
||||||
|
@ -1278,6 +1278,56 @@ async def test_master_state_with_template(hass: HomeAssistant) -> None:
|
|||||||
assert events[0].context == context
|
assert events[0].context == context
|
||||||
|
|
||||||
|
|
||||||
|
async def test_invalid_active_child_template(hass: HomeAssistant) -> None:
|
||||||
|
"""Test invalid active child template."""
|
||||||
|
hass.states.async_set("media_player.mock1", STATE_PLAYING)
|
||||||
|
hass.states.async_set("media_player.mock2", STATE_PAUSED)
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"media_player",
|
||||||
|
{
|
||||||
|
"media_player": {
|
||||||
|
"platform": "universal",
|
||||||
|
"name": "tv",
|
||||||
|
"children": ["media_player.mock1", "media_player.mock2"],
|
||||||
|
"active_child_template": "{{invalid.invalid}}!invalid",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.tv").state == STATE_PLAYING
|
||||||
|
|
||||||
|
|
||||||
|
async def test_active_child_template(hass: HomeAssistant) -> None:
|
||||||
|
"""Test override active child with template."""
|
||||||
|
hass.states.async_set("media_player.mock1", STATE_PLAYING)
|
||||||
|
hass.states.async_set("media_player.mock2", STATE_PAUSED)
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"media_player",
|
||||||
|
{
|
||||||
|
"media_player": {
|
||||||
|
"platform": "universal",
|
||||||
|
"name": "tv",
|
||||||
|
"children": ["media_player.mock1", "media_player.mock2"],
|
||||||
|
"active_child_template": "{{ 'media_player.mock2' }}",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
|
||||||
|
hass.states.async_set("media_player.mock2", STATE_ON)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.tv").state == STATE_ON
|
||||||
|
|
||||||
|
|
||||||
async def test_reload(hass: HomeAssistant) -> None:
|
async def test_reload(hass: HomeAssistant) -> None:
|
||||||
"""Test reloading the media player from yaml."""
|
"""Test reloading the media player from yaml."""
|
||||||
hass.states.async_set("input_boolean.test", STATE_OFF)
|
hass.states.async_set("input_boolean.test", STATE_OFF)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user