Comparing trigger attributes in service template

Hi there.

My music player sometimes gets stuck at a song, which I want to (band-aid) fix with home assistant. If a song title is the same for [time] while [playing], this automation should skip a song.

The part that does not work for me is here. It seems to have difficulties comparing the trigger state in the service_template.

  action:
    - service_template: >
        {%-  if trigger.to_state.attributes.media_title == trigger.from_state.attributes.media_title %}media_player.media_next_track
        {%- endif %}
      data_template:
        entity_id: media_player.mpd

A version that does work is listed below:

  action:
    - service_template: >
        {%-  if STRING == STRING %}media_player.media_next_track
        {%- endif %}
      data_template:
        entity_id: media_player.mpd

The full automation is given below:


- alias: 'Release Mopidy from loop if stuck'
  trigger:
    platform: state
    entity_id: media_player.mpd

  condition:
    condition: and
    conditions:
      ## Check if song changed
      - condition: template
        value_template: >
          {{ trigger.from_state and
              trigger.to_state.attributes.media_title !=
              trigger.from_state.attributes.media_title }}
      ## Check if media player is in playing state
      - condition: state
        entity_id: 'media_player.mpd'
        state: 'playing'

  action:
    - data_template:
        message: Mopidy changed song to {{trigger.to_state.attributes.media_title}} .
      service: notify.me
    - delay:
        # minutes: 11
        seconds: 10
    - data_template:
        message: 10 seconds passed
      service: notify.me

    - service_template: >
        {%-  if trigger.to_state.attributes.media_title == trigger.from_state.attributes.media_title %}media_player.media_next_track
        {%- endif %}
      data_template:
        entity_id: media_player.mpd
      # - service_template: >
      #     {%-  if tabel == tabel %}media_player.media_next_track
      #     {%- endif %}

    - service_template: >
        {%-  if trigger.to_state.attributes.media_title == trigger.from_state.attributes.media_title %}notify.me
        {%- endif %}
      data_template:
        message: Mopidy is playing the same song for 10 seconds.

    - data_template:
        message: Checks done
      service: notify.me

This results in the following error of HA Core:

2020-08-18 15:57:15 ERROR (MainThread) [homeassistant.components.automation.release_mopidy_from_loop_if_stuck] Release Mopidy from loop if stuck: Error executing script. Unexpected error for call_service at pos 4: Template rendered invalid service: 
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 115, in async_prepare_call_from_config
    domain_service = cv.service(domain_service)
  File "/usr/src/homeassistant/homeassistant/helpers/config_validation.py", line 418, in service
    raise vol.Invalid(f"Service {value} does not match format <domain>.<name>")
voluptuous.error.Invalid: Service  does not match format <domain>.<name>
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 191, in _async_step
    await getattr(
  File "/usr/src/homeassistant/homeassistant/helpers/script.py", line 352, in _async_call_service_step
    domain, service, service_data = async_prepare_call_from_config(
  File "/usr/src/homeassistant/homeassistant/helpers/service.py", line 121, in async_prepare_call_from_config
    raise HomeAssistantError(
homeassistant.exceptions.HomeAssistantError: Template rendered invalid service: 

Edit: this is not true, it always defaults to true.
I fixed it :+1:

    - service_template: >
        {%-  if '{{ trigger.to_state.attributes.media_title }} == {{trigger.from_state.attributes.media_title}}' %}media_player.media_next_track
        {%- endif %}
      data_template:
        entity_id: media_player.mpd

that’s not correct at all…

when you wrap a characters in quotes, it turns it into a string. if you perform an if statement looking at a string, it returns true if it has characters or false if it doesn’t. Your if statement will always return true because your string has characters.

Also, when the media_player gets stuck on a song, does it update the state in home assistant? If it does not, the likely hood of you being able to capture the event is low.

What media_player do you have?

I believe I’ve got it now:

  action:
    - delay:
      # TODO change to song duration
        minutes: 11
        # seconds: 20

    - condition: and
      conditions:
        - condition: template
          value_template: >
            {{ trigger.to_state.attributes.media_title == state_attr('media_player.mpd', 'media_title') }}
    # TODO check for song duration: media_duration (in seconds, for example 169)
        - condition: template
          value_template: >
            {{ state_attr('media_player.mpd', 'media_duration')|int < 660 }}

    - service: media_player.media_next_track
      data:
        entity_id: media_player.mpd
    - service: notify.me
      data_template:
        message: Mopidy was playing {{trigger.to_state.attributes.media_title}} for 11 minutes.

Hi @petro, you are right, I realized that after my second post. I just now learned of the feature of adding conditions in your actions, so I opted to use those. I believe it is correct now. I am using media_player.mpd for an externally run mopidy instance.

When Mopidy gets stuck on a song (this is not a problem within Home Assistant, it is fully external, but I am bandaging it with HA) it keeps on talking to HA. HA sees that it is still playing the same song and can tell it to skip the current song.

But what’s the trigger? The media player won’t trigger if the state isn’t changing.

The trigger is the initial change from the previous song to the current song. So every time a new song is loaded HA will check after 11 minutes if it got stuck on this song and thus needs to skip it.

  trigger:
    platform: state
    entity_id: media_player.mpd

the main media player state is ‘idle’, ‘playing’, ‘pause’, etc. It does not contain the media title. So this will only trigger when the state changes between those states.

Is it not supposed to trigger when one of its attributes (the media_title) changes? At least for me, it currently does.

My current total setup ensures it is playing and it just skipped a song

- alias: 'Release Mopidy from loop if stuck'
  trigger:
    platform: state
    entity_id: media_player.mpd
  mode: restart

  condition:
    condition: and
    conditions:
      ## Check if song changed
      - condition: template
        value_template: >
          {{ trigger.to_state.attributes.media_title !=
             trigger.from_state.attributes.media_title }}
      ## Check if media player is in playing state
      - condition: state
        entity_id: 'media_player.mpd'
        state: 'playing'


  action:
    - delay:
      # TODO change to song duration
        minutes: 11
        # seconds: 20

    - condition: and
      conditions:
        - condition: template
          value_template: >
            {{ trigger.to_state.attributes.media_title == state_attr('media_player.mpd', 'media_title') }}
    # TODO check for song duration: media_duration (in seconds, for example 169)
        - condition: template
          value_template: >
            {{ state_attr('media_player.mpd', 'media_duration')|int < 660 }}

    - service: media_player.media_next_track
      data:
        entity_id: media_player.mpd
    - service: notify.me
      data_template:
        message: Mopidy was playing {{trigger.to_state.attributes.media_title}} for 11 minutes.

I stand corrected. I was thinking of templates. My mistake. This trigger should work for you.

1 Like