Define a different response_variable in conditionals doesn't work

I have a called script that may stop or continue at different points, depending on some conditions, and return some information to the calling script whenever it stops, using the response_variable. But the problem is that if the stop command is within a conditional if, the calling script doesn’t get the response_variable, although it works perfectly when the stop command is on the the first level, not within a conditional.

I know it sounds like and XY problem, but I really want to understand this, as working around this limitation may make what I want to do much more complex. Is this a bug?

Here’s a simplified example of what I am talking about:

Calling script:

alias: test 1
sequence:
  - service: script.test_2
    data: {}
    response_variable: test
  - service: notify.mobile_app_myphone
    data:
      message: "{{ test.context_id }} {{ test.resultat }}"
mode: single

Called script:

alias: test 2
sequence:
  - variables:
      test:
        context_id: asdlfkj1234lj
        resultat: success
  - if:
      - condition: time
        after: "10:00:00"
    then:
      - variables:
          test:
            context_id: asdlfkj1234lj
            resultat: fail
      - stop: ""
        response_variable: test
  - stop: ""
    response_variable: test
mode: single

Is there a way to return the response_variable when the script is stopped in a conditional?

I believe thats because a variable, when defined inside a loop or an if, is local in scope to just that statement.

I understand that, but since the stop command is within the conditional, on the same level where the variable test.resultat: fail is defined, it should be able to see it.

The scope of the variable test defined inside of the if statement is limited to the if statement.

I understand that. What I don’t understand is why the stop command that is inside the if statement doesn’t have access to that variable.

Apparently not because then you say this

It’s not an issue of “access” to the variable, the issue is it’s attempting to pass a variable whose scope is limited to the if statement.

1 Like

From here:
Script Syntax - Home Assistant (home-assistant.io)

Try:

response_variable: "test"

Is the suggestion that the variable’s name needs to be wrapped in double quotes?

If you refer to the first post, it reports that the final stop works (and test is not wrapped in quotes). It’s the stop inside the if that is unable to pass the variable test and that’s due to scope constraints.

That was my suggestion.

Sorry if I missed what you described.

I must have read too fast. I’ll slow down moving forward!

The workaround I have found for my problem consists in the called script to trigger a manual event that will include whatever information and variables I want, followed by the STOP command (with no response in that one).

In the calling script, I call the other in parallel, altogether with a wait for trigger - event that will capture the information sent by the called script. Note that whatever command following the wait for trigger must be at the same level of sequence than the wait for trigger (at least for my use case).

Here is a model of what I did:

  - parallel:
      - service: script.example
        data:
          some_variable: some information
      - sequence:
          - wait_for_trigger:
              - platform: event
                event_type: my_personal_event
                event_data:
                  success: true
                id: is_finished
          - some other stuff etc:

In the called script, it looks like this:

      - event: my_personal_event
        event_data:
          success: "{{ boolean_variable }}"

It works. If it was only a matter of variable scope it wouldn’t work.
That’s a workaround I dislike, but that’s the best I found so far.

I noticed other people are facing the same kind of challenge here.

1 Like

Scoping rules don’t apply here because it’s passing a variable to a script which posts it as a custom event.

I think there is a potential race condition here which might result in your solution unpredictably failing to work as expected.

In particular, you are not necessarily guaranteed that the wait_for_trigger will execute before script.example completes. The doc about “parallelizing actions” says that “There is no order guarantee. The actions will be started in parallel, but there is no guaranteed that they will be completed in the same order.”

So, it’s theoretically possible here that my_personal_event will fire before your wait_for_trigger can catch it, in which case the code will just hang waiting for the event. It’s like throwing the ball before your receiver is ready to catch it.

I don’t know how LIKELY it is in practice that you would hit that situation. But as I understand how a “parallel” block works, this example is not guaranteed to work the way you report it’s working for you in practice.

I hate to poke holes because I’m trying to find a solution for the same exact “can’t use response_variable from within a nested block” issue. I haven’t found one so far. But I point this out because race conditions can manifest unpredictably and be difficult to reproduce–which means that unless you are aware for the potential of a race condition, you might have a very hard time debugging the problem when it shows up.

1 Like

I’ve just run into the same issue after refactoring some stuff and creating a script with a return value…

I guess there’s still no better solution than using custom events?

I’ve got another solution for which may be of use to some. I’ve got a script to send a yes/no question to my smartphone and since this is always the same except for message and mapping IDs, I’ve created this script. If you don’t need to stop the script in some nested action and use wait_for_trigger you can do this:

sequence:
  - alias: send yes/no question to mobile
    service: notify.mobile_app_smartphone
    data:
      message: "{{ message }}"
      data:
        ttl: 0
        priority: high
        actions:
          - title: "Yes"
            action: "{{ action_id_yes }}"

          - title: "No"
            action: "{{ action_id_no }}"

  - alias: wait for response
    wait_for_trigger:
      - alias: button 'yes' was pressed
        platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: "{{ action_id_yes }}"

      - alias: button 'no' was pressed
        platform: event
        event_type: mobile_app_notification_action
        event_data:
          action: "{{ action_id_no }}"
    timeout: "00:15:00"

  - alias: set response variable
    variables:
      response: >-
        {% if wait.trigger is not none and wait.trigger.event.data.action == action_id_yes %}
          {{ {"id": action_id_yes} }}
        {% else %}
          {{ {"id": action_id_no} }}
        {% endif %}

  - stop: return answer
    response_variable: response

2 Likes

It’s worse than that. The response variable isn’t return AT ALL.
Frustrating!

1 Like