diff --git a/homeassistant/components/universal/media_player.py b/homeassistant/components/universal/media_player.py index fd73ad33e16..68ce8e9b96c 100644 --- a/homeassistant/components/universal/media_player.py +++ b/homeassistant/components/universal/media_player.py @@ -95,6 +95,7 @@ from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType ATTR_ACTIVE_CHILD = "active_child" +CONF_ACTIVE_CHILD_TEMPLATE = "active_child_template" CONF_ATTRS = "attributes" CONF_CHILDREN = "children" CONF_COMMANDS = "commands" @@ -128,6 +129,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( vol.Optional(CONF_BROWSE_MEDIA_ENTITY): cv.string, vol.Optional(CONF_UNIQUE_ID): cv.string, vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA, + vol.Optional(CONF_ACTIVE_CHILD_TEMPLATE): cv.template, vol.Optional(CONF_STATE_TEMPLATE): cv.template, }, extra=vol.REMOVE_EXTRA, @@ -161,6 +163,8 @@ class UniversalMediaPlayer(MediaPlayerEntity): self.hass = hass self._name = config.get(CONF_NAME) 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._attrs = {} for key, val in config.get(CONF_ATTRS).items(): @@ -186,23 +190,35 @@ class UniversalMediaPlayer(MediaPlayerEntity): @callback def _async_on_template_update(event, updates): - """Update ha state when dependencies update.""" - result = updates.pop().result + """Update state when template state changes.""" + for data in updates: + template = data.template + result = data.result - if isinstance(result, TemplateError): - self._state_template_result = None - else: - self._state_template_result = result + if template == self._state_template: + self._state_template_result = ( + None if isinstance(result, TemplateError) else result + ) + if template == self._active_child_template: + self._active_child_template_result = ( + None if isinstance(result, TemplateError) else result + ) if event: self.async_set_context(event.context) 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( self.hass, - [TrackTemplate(self._state_template, None)], + track_templates, _async_on_template_update, ) self.hass.bus.async_listen_once( @@ -644,6 +660,9 @@ class UniversalMediaPlayer(MediaPlayerEntity): async def async_update(self) -> None: """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 for child_name in self._children: if (child_state := self.hass.states.get(child_name)) and ( diff --git a/tests/components/universal/test_media_player.py b/tests/components/universal/test_media_player.py index a6cf342eeb3..e31cab59358 100644 --- a/tests/components/universal/test_media_player.py +++ b/tests/components/universal/test_media_player.py @@ -1278,6 +1278,56 @@ async def test_master_state_with_template(hass: HomeAssistant) -> None: 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: """Test reloading the media player from yaml.""" hass.states.async_set("input_boolean.test", STATE_OFF)