Script sequence with wait_template not waiting for other script to complete

In the following script, media_player.play_media is executed while script script.kodi_on is running.
Even though I have configured a wait_template to wait for script.kodi_on to finish.

Can anybody explain why this might be the case? Is this by design or should I try to workaround with flipping an input_bool.kodi_on_running and configuring a wait_template for the input_bool instead of the script.kodi_on state?


script:
  youtube_playlist_play:
    sequence:
    - service: script.turn_on
      entity_id: script.kodi_on
    - delay: 00:00:01
    - wait_template: "{{ is_state('script.kodi_on', 'off') }}"
      timeout: '00:01:00'
    - service: media_player.play_media
      data:
        entity_id: media_player.kodi
        media_content_type: playlist 
        media_content_id: plugin://plugin.video.youtube/play/some/url
     
  kodi_on:
    sequence:
    - condition: template
      value_template: "{{ state_attr('remote.woonkamer', 'current_activity') != 'Kodi' }}"
    - service: remote.turn_on
      entity_id: remote.woonkamer
      data:
        activity: Kodi
    - delay: 00:00:03
    - wait_template: "{{ state_attr('remote.woonkamer', 'current_activity') == 'Kodi' }}"
      timeout: '00:00:10'
    - wait_template: "{{ not is_state('media_player.kodi', 'off') }}"
      timeout: '00:00:30'
    - delay: 00:00:15

Ok, so I managed to solve this with some trial and error. Apparently a scripts state is not set to on after being started with a service: script.turn_on call.

So I found a way to set a scripts state to ‘on’ prior to actually starting it with this python script.

The new automation is now:

youtube_playlist_play:
    sequence:
    - service: python_script.set_state
      data_template:
        entity_id: script.kodi_on
        state: on
    - service: script.turn_on
      entity_id: script.kodi_on
    - wait_template: "{{ is_state('script.kodi_on', 'off') }}"
      timeout: '00:01:00'
    - service: media_player.play_media
      data: <etc....>

The sequence now, finally, actually waits for script.kodi_on to complete before proceeding. Effectively enabling me to re-use scripts by starting sub-scripts in blocking mode instead of asynchronous.

FYI, a script’s state is only changed (to on) once it executes a delay step or wait_template (that actually waits), and even then there may be a small delay before the state actually updates in the state machine. There is work on-going to fix that problem.

I was going to suggest adding a delay step (with zero length) as the first step of the script. That will cause its state to change to on more quickly, but unfortunately, not instantaneously. Given the current nature of scripts it seems you came up with a better work around. :slightly_smiling_face:

2 Likes

Something like this would also be good to have in the future:

    - service: script.turn_on
      entity_id: script.kodi_on
      mode: async or sync

Wouldn’t need a wait template then.

imho it’s a bit too much and also things sometimes change their state back after using this script.
do you think input_boolean way is worse?

Well that was indeed the approach I tried first.

However, the first step in subscript script.kodi_on is a condition: [only execute further sequence if kodi is not already running].

If further sequence steps aren’t executed because of the condition, where would I then set the input_boolean.kodi_on_script_running to false again? Can’t do that in the calling script.youtube_playlist_play because that’ll run asynchronously

so you’re basically saying that in your case it’s impossible to use input_boolean approach?

With more nested scripts in script.kodi_on in order to avoid having to use a condition: it’d probably work. Maybe something like the sample below, haven’t tested that though. Didn’t think this approach made the code easier to read or write.

script:
  kodi_on
  sequence:
    service: script.turn_on
    data_template:
      entity_id: >
        {% if state_attr('remote.woonkamer', 'current_activity') != 'Kodi') %} script.script_to_start_kodi_and_then_set_script_running_bool_false
        {% else %} script.script_to_just_set_script_running_bool_false
        {% endif %}

well, my point is set_state approach is more risky that input_boolean as I mentioned above so I wanted to know why you decided not to go for the latter.
if I personally have a choice to have a reliable code or easier to read/write one, I’d opt for the former but it’s a personal choice.

Yeah to be honest I didn’t think of the sub-subscript with tenplate, instead of the condition approach, until I really thought about it when you asked.

I think I just wanted the script status wait template to work, in as few lines of code as possible (python excluded), maybe not a rational reason. :upside_down_face:

Anyway, seems to work really good now

I’m working on it, but it’s going kind of slow, for various reasons.

3 Likes

take your time. we’ve been waiting for so long so we can wait a little bit more :wink:
quality is key here and I believe you’ll deliver it.
thanks a lot for doing that for the community!

Yeah sure is good to see a code contributor replying in my first post on the user forums. I checked out the PR on scripts in GitHub with the blocking param. Looking good :slight_smile:

I was thinking about your solution for a while and it boils down to this difference

youtube_playlist_play:
  sequence:
  - service: script.turn_on
    entity_id: script.kodi_on
  - delay: 00:00:01
  - wait_template: "{{ is_state('script.kodi_on', 'off') }}"

youtube_playlist_play:
    sequence:
    - service: python_script.set_state
      data_template:
        entity_id: script.kodi_on
        state: on
    - service: script.turn_on
      entity_id: script.kodi_on
    - wait_template: "{{ is_state('script.kodi_on', 'off') }}"

What was the reason of adding a delay before wait_template in your original code?
Considering phil’s note about script’s state I’d expect that it will change state at - delay: 00:00:03 point i.e pretty soon taking into account the delay after turning the script on so it should be picked up by wait_template.
Are you saying that media_player.play_media is executed while script script.kodi_on is running because it takes kodi_on more than 1 second to complete?
Is it wait_template finished by timeout or straight away?

I think I tried the delay of 1 sec for the very reason Phil mentioned, to give the state some time to kick in. And that didn’t work. play_media was indeed executed while the script kodi_on was running.

When that didn’t work, I assumed the on state wasn’t being set at all. In computer time, the time between 1 and 3 seconds is ages. So I assumed there wasn’t any race condition going one here regarding the on state. Also, if 3 secs works and 1 sec doesn’t, that does seem kind of arbitrary and not very reliable to me. Who knows it won’t take 5 seconds next time? And also it’s slow.

Much of the scripting approach for me is based on intuition and best practices I picked up in other projects/languages. In this case:

But lets not get too philosophical or code purist on this :wink: For now I’m just happy it works!

cool. I’m sorry but from your answer I didn’t get if wait_template finished by timeout or straight away, could you clarify? you should see the difference because it it was a timeout, you had to wait for a minute.

it’s absolutely technical now, believe me. I use similar approach and wanted to drill a bit down as you have a clear case here (can’t say I have one atm).

Play_media executed instantly so it didn’t wait for the timeout. That’s because the script state was already ‘off’, it had never turned to ‘on’. Hence the python script to do just that. Hope that helps you!

1 Like

Ok, thanks for confirming :wink:

FYI, unless a timeout is specified using the optional timeout parameter, there is no timeout – i.e., it would wait forever. Since the wait_template in the script did not have the timeout parameter specified it could not have timed out.

Phil, I do know that :wink:

There are 2 scripts and I was asking about youtube_playlist_play, which has a timeout specified.

It might be not important in the light of your work on rewriting script’s internals but I have a feeling that the reason it didn’t work for the TS is still unclear as I mentioned

and wait_template didn’t wait for a minute, how can it be? It’s only possible if the script didn’t change its state to on at all despite having a delay in it. But that contradicts your statement.
I’m confused