Could use some help with wait_template

I’m trying to get a script to invoke another script depending on the value of an input_select. That part is working, but then I want the first script to wait until the script it invokes has finished. That part is hanging. I think the issue is it’s not able to automatically determine the entities involved due to the way I constructed the template. The template works ok when I test it on the Templates page of the front end, but I think that’s because it just evaluates it and doesn’t need to extract the entities for waiting on corresponding state changes.

Here are the two templates in my script:

      - service_template: >
          {% set map = {"Off":                 "lr_ipc_off",
                        "Stream":              "lr_ipc_stream",
                        "Record":              "lr_ipc_record",
                        "Auto Off":            "lr_ipc_auto_off",
                        "Auto Detect Outside": "lr_ipc_auto_detect",
                        "Auto Record All":     "lr_ipc_auto_record" } %}
          script.{{ map[states("input_select.lr_ipc_op")] }}
      - wait_template: >
          {% set map = {"Off":                 "lr_ipc_off",
                        "Stream":              "lr_ipc_stream",
                        "Record":              "lr_ipc_record",
                        "Auto Off":            "lr_ipc_auto_off",
                        "Auto Detect Outside": "lr_ipc_auto_detect",
                        "Auto Record All":     "lr_ipc_auto_record" } %}
          {{ is_state("script."+map[states("input_select.lr_ipc_op")], "off") }}

I also tried this so that the full names of the scripts can be seen, but it still doesn’t work:

      - service_template: >
          {% set map = {"Off":                 "script.lr_ipc_off",
                        "Stream":              "script.lr_ipc_stream",
                        "Record":              "script.lr_ipc_record",
                        "Auto Off":            "script.lr_ipc_auto_off",
                        "Auto Detect Outside": "script.lr_ipc_auto_detect",
                        "Auto Record All":     "script.lr_ipc_auto_record" } %}
          {{ map[states("input_select.lr_ipc_op")] }}
      - wait_template: >
          {% set map = {"Off":                 "script.lr_ipc_off",
                        "Stream":              "script.lr_ipc_stream",
                        "Record":              "script.lr_ipc_record",
                        "Auto Off":            "script.lr_ipc_auto_off",
                        "Auto Detect Outside": "script.lr_ipc_auto_detect",
                        "Auto Record All":     "script.lr_ipc_auto_record" } %}
          {{ is_state(map[states("input_select.lr_ipc_op")], "off") }}

Any ideas? I know in some cases (such as template sensors) it let’s you list the entities explicitly in case “the automatic analysis fails to find all relevant entities.” Apparently wait_template doesn’t have this feature. (I even tried adding entity_id but it doesn’t accept it.)

And to complete the picture, this is what I had before that works, it’s just a bit messier:

      - wait_template: >
          {% if   is_state("input_select.lr_ipc_op", "Off") %}
            {{ is_state("script.lr_ipc_off", "off") }}
          {% elif is_state("input_select.lr_ipc_op", "Stream") %}
            {{ is_state("script.lr_ipc_stream", "off") }}
          {% elif is_state("input_select.lr_ipc_op", "Record") %}
            {{ is_state("script.lr_ipc_record", "off") }}
          {% elif is_state("input_select.lr_ipc_op", "Auto Off") %}
            {{ is_state("script.lr_ipc_auto_off", "off") }}
          {% elif is_state("input_select.lr_ipc_op", "Auto Detect Outside") %}
            {{ is_state("script.lr_ipc_auto_detect", "off") }}
          {% else %}
            {{ is_state("script.lr_ipc_auto_record", "off") }}
          {% endif %}

I don’t see why this doesn’t work.

I’m assuming you don’t mean the last one. :wink:

Well, it doesn’t. It just sits there forever, even though all the script’s states are ‘off’. I’m assuming because it couldn’t figure out what the entities are, and hence never wakes up when any of their states change. But that’s just a guess. All I know is it never passes the wait.

I mean, all of the methods should work. The only thing I can think of is maybe you need to delay the wait_template by like a second. I’m not sure how the threading is handling this.

I have a few places where a script or automation starts a script and then waits for it to finish. (They don’t all wait, but sometimes it’s necessary.) I had a similar thought of adding a delay between starting the script and doing the wait, just to make sure the script’s state had enough time to change to ‘on’ before the wait for it to be ‘off’. (I.e., could it skip past the wait because it got there too soon?) But then nothing worked. I haven’t verified by looking at the code in sufficient detail, but I assumed the wait_template must need to see a state change before being evaluated. I.e., If the script went from ‘off’ to ‘on’ and back to ‘off’ before getting to the wait_template, will that prevent it from “seeing” the ‘off’ because there were no more state changes???

I mean that could be the case. I mean, you could add to the end of all your scripts an event. Then have your wait template look for that event. Seems painful though.

Have you tried firing another script that has the wait template in it?

I have 8 different scripts that contain wait_template’s, and all but this one work just fine. Granted, none of the rest are this complicated.

Maybe I could try a different tack, such as just simply waiting for all the scripts (in this set of scripts) to be ‘off’. Mainly the one script just invokes one of the others based on the input_select, and they don’t get invoked by anything else (except that one of the called scripts does call one of the others - i.e., nested.)

Oh well. I have a working solution (the last wait_template in the OP.) I was just hoping to find a more elegant/manageable solution, and learn something in the process. :slight_smile: Thanks for your thoughts!

ok for shits and giggles before you give up try this:

      - service_template: >
          {% set map = {"Off":                 "lr_ipc_off",
                        "Stream":              "lr_ipc_stream",
                        "Record":              "lr_ipc_record",
                        "Auto Off":            "lr_ipc_auto_off",
                        "Auto Detect Outside": "lr_ipc_auto_detect",
                        "Auto Record All":     "lr_ipc_auto_record" } %}
          script.{{ map[states("input_select.lr_ipc_op")] }}
      - wait_template: >
          {% set map = {"Off":                 "lr_ipc_off",
                        "Stream":              "lr_ipc_stream",
                        "Record":              "lr_ipc_record",
                        "Auto Off":            "lr_ipc_auto_off",
                        "Auto Detect Outside": "lr_ipc_auto_detect",
                        "Auto Record All":     "lr_ipc_auto_record" } %}
          {% set selection = states("input_select.lr_ipc_op") %}
          {{ is_state("script."+map[selection], "off") }}

I’m wondering if the call in the call is causing problems.

@petro, @pnbruckner,

I have been banging my head against a wall with wait_template for weeks (months?) and I think I can now confirm that it doesn’t work exactly as described.

Unless the template is as literal as it can be.

I have tried countless things including delays (sometimes works, sometimes not, depends on random internal processing factors) and branching out to separate scripts to do the waiting and waiting for that script to end but nothing seems to be reliable except a template with literals.

So for example I wanted to do this:

- wait_template: "{{ is_state('media_player.' ~ states('input_select.announce_room'), 'playing') }}"
  timeout: '00:00:15'

which never worked (for me)

- wait_template: >
    {{ is_state('media_player.' ~ room, 'playing') }}
  timeout: '00:00:15'

Which worked but only sometimes.

Now I have resorted to this, which seems to work every time (today :roll_eyes:) but is a less than ideal solution hardcoding entities when an entire notification system has been built using variables.

- wait_template: >
    {% if is_state('input_select.announce_room', 'kitchen') %}
      {{ is_state('media_player.kitchen', 'playing') }}
    {% elif is_state('input_select.announce_room', 'dining_room') %}
      {{ is_state('media_player.dining_room', 'playing') }}
    {% elif is_state('input_select.announce_room', 'pool_room') %}
      {{ is_state('media_player.pool_room', 'playing') }}     
    {% else %}
      {{ is_state('media_player.tv_room', 'playing') }}
    {% endif %}

I think the documentation for wait_template could be improved to describe how it really works (internally) so that we can work around it’s problems without spending days and days chasing shadows.

But hey, ho. Maybe someone will stumble upon this in future and find it useful.

So I have done a bit of digging to see how this stuff works, and I think the issue is this. (It’s somewhat related to the relatively recent change in template sensors and how they determine what to watch for changes.) The template is searched for entity_ids (i.e., domain.object_id.) It does this using a fairly complicated regex, but normally it comes down to finding these types of patterns:

states('domain.object_id
state_attr('domain.object_id
is_state('domain.object_id
is_state_attr('domain.object_id
states.domain.object_id

The quote characters can be single or double quotes.

If it finds any match, then it will only watch for entity_ids it finds to change. If it does not find any match, then it reacts to all state changes in the system.

So, in your first example it finds input_select.announce_room, so it only watches for changes in that entity. Since it doesn’t find any media_player.xxx entity_ids (because the search pattern isn’t satisfied), it doesn’t watch for any of those to change.

In your second example, it doesn’t find any entity_ids, so (I think, but I guess I’m not 100% sure) it reacts to any and all state changes in the system, re-evaluating the template each time.

The last example works because it finds an entity_id for each entity it needs to react to.

2 Likes

This is excellent, thank you.

I don’t mind things not working (as expected) so long as they don’t work in consistent and explainable way.
It was starting to feel to me that wait_template was too dependent on ‘random’, deep, obscure system events.

Having an idea of what might be going on is very useful.
Thanks again.

And incidentally this explains why it all worked so well a while ago but then stopped. Unfortunately that was at about the same time I made some quite big changes so I would never have made the connection and attributed it to the way template sensors had changed their behaviour.

Seems odd that it was done this way but it makes sense because it’s similar to a template sensor. Nice work figuring that out.