Variable Scope and Scripting

Good morning!
Trying to put together a Notifier script that will handle all my notification needs. I’ve found that I’ve been embedding logic for notifications in different automations and it’s getting annoying. My intent is to have one subroutine-style script I can call from automations, with a set of options, that will handle my needs - notify me, my wife, when we’re home, or away, or away but only if we’ve just left, etc etc.

I’m running into a logical problem that I think has to do with variable scope. It appears variables don’t propagate back up out of loops? I’m using a set of Repeat/Choose blocks to iterate over our devices and the settings, evaluate, and if need be, notify.The loops set a “Actually Do It” flag, with the intent that I’d catch the flag at the end.

But that doesn’t seem to work. I initialize the variables up top as false and even when set true later on, it still gets evaluated as false later on. Is there no way to define a “Global” within a script?

Full code is below for anyone who wants to pick it apart. Thanks!

alias: Notifier New
sequence:
  - variables:
      SEND_CPG_PH: false
      SEND_CPG_TB: false
      SEND_ESG_PH: false
      SEND_ESG_TB: false
      SEND_TVS: false
  - alias: Check Time Range
    if:
      - condition: template
        value_template: >-
          {% set current_date_string = now().strftime("%Y-%m-%d ") %}

          {% set current_time = now().timestamp() %} 

          {% set start_timestamp =
          strptime(current_date_string+input_start_time, '%Y-%m-%d
          %H:%M:%S').timestamp() %}

          {% set end_timestamp = strptime(current_date_string+input_end_time,
          '%Y-%m-%d %H:%M:%S').timestamp() %}

          {{ not (start_timestamp <= current_time  <= end_timestamp) }}
        alias: Test if time is within bounds.
    then:
      - stop: Not in allowed time range.
  - alias: Check Targets for Reach
    repeat:
      sequence:
        - variables:
            TARGET: |
              {{ repeat.item }}
            TARGET_PRESENCE: |
              {% if repeat.item == 'cpg_phone' %}
                {{ states('device_tracker.starfury') }}
              {% elif repeat.item == 'esg_phone' %}
                {{ states('device_tracker.canary') }}
              {% endif %}
            SINCE_CHANGE: |
              {% if repeat.item == 'cpg_phone' %}
                {{ as_timestamp(now()) - as_timestamp(states.device_tracker['starfury'].last_changed) }}
              {% elif repeat.item == 'esg_phone' %}
                {{ as_timestamp(now()) - as_timestamp(states.device_tracker['canary'].last_changed) }}
              {% endif %}
          alias: Save the working target
        - alias: Check Reach against each Target
          repeat:
            sequence:
              - choose:
                  - conditions:
                      - condition: template
                        value_template: "{{ repeat.item == 'H' }}"
                        alias: Home
                    sequence:
                      - if:
                          - alias: Home Set
                            condition: template
                            value_template: "{{ TARGET_PRESENCE == 'home' }}"
                        then:
                          - choose:
                              - conditions:
                                  - condition: template
                                    value_template: "{{ TARGET == 'cpg_phone' }}"
                                sequence:
                                  - variables:
                                      SEND_CPG_PH: true
                              - conditions:
                                  - condition: template
                                    value_template: "{{ TARGET == 'esg_phone' }}"
                                sequence:
                                  - variables:
                                      SEND_ESG_PH: true
                            alias: Set correct Send variable
                    alias: Home
                  - conditions:
                      - condition: template
                        value_template: "{{ repeat.item == 'ARD' }}"
                        alias: Away, Recently Departed Set
                    sequence:
                      - alias: Check Occupancy, Away Time, and Set Variable
                        choose:
                          - conditions:
                              - condition: template
                                value_template: "{{ TARGET == 'cpg_phone' }}"
                                alias: Target is Chris
                              - condition: not
                                conditions:
                                  - condition: state
                                    entity_id: person.chris
                                    state: home
                                alias: Chris Not Home
                              - condition: template
                                value_template: "{{ SINCE_CHANGE <= ( input_ard_time * 60 ) }}"
                                alias: Away within ARD time
                            sequence:
                              - variables:
                                  SEND_CPG_PH: true
                            alias: Target is Chris
                          - conditions:
                              - alias: Target is Chris
                                condition: template
                                value_template: "{{ TARGET == 'esg_phone' }}"
                              - alias: Chris Not Home
                                condition: not
                                conditions:
                                  - condition: state
                                    entity_id: person.emily
                                    state: home
                              - condition: template
                                value_template: "{{ SINCE_CHANGE <= ( input_ard_time * 60 ) }}"
                                alias: Away within ARD time
                            sequence:
                              - variables:
                                  SEND_ESG_PH: true
                            alias: Target is Emily
                  - conditions:
                      - condition: template
                        value_template: "{{ repeat.item == 'ANH' }}"
                    sequence:
                      - alias: Check Occupancy and Set Variable
                        choose:
                          - conditions:
                              - condition: template
                                value_template: "{{ TARGET == 'cpg_phone' }}"
                                alias: Target is Chris
                              - condition: numeric_state
                                entity_id: zone.home
                                below: 1
                                alias: Home is Vacant
                            sequence:
                              - variables:
                                  SEND_CPG_PH: true
                            alias: Target is Chris
                          - conditions:
                              - alias: Target is Emily
                                condition: template
                                value_template: "{{ TARGET == 'esg_phone' }}"
                              - condition: numeric_state
                                entity_id: zone.home
                                below: 1
                                alias: Home is Vacant
                            sequence:
                              - variables:
                                  SEND_ESG_PH: true
                            alias: Target is Emily
                    alias: Away, if Nobody is Home
                  - conditions:
                      - condition: template
                        value_template: "{{ repeat.item == 'OOT' }}"
                        alias: Out of Town Set
                    sequence:
                      - alias: Check Proximity and Set Variable
                        choose:
                          - conditions:
                              - condition: template
                                value_template: "{{ TARGET == 'cpg_phone' }}"
                                alias: Target is Chris
                              - condition: numeric_state
                                entity_id: sensor.home_chris_distance
                                above: 528000
                                alias: Chris > 100mi
                            sequence:
                              - variables:
                                  SEND_CPG_PH: true
                            alias: Target is Chris
                          - conditions:
                              - alias: Target is Emily
                                condition: template
                                value_template: "{{ TARGET == 'esg_phone' }}"
                              - alias: Emily > 100mi
                                condition: numeric_state
                                entity_id: sensor.home_emily_distance
                                above: 528000
                            sequence:
                              - variables:
                                  SEND_ESG_PH: true
                            alias: Target is Emily
                    alias: Out of Town
            for_each: "{{ input_reach }}"
      for_each: "{{ input_targets }}"
  - alias: Send to Chris' Phone
    if:
      - alias: Send flag is True
        condition: template
        value_template: "{{ SEND_CPG_PH }}"
    then:
      - metadata: {}
        data:
          message: "{{ input_message }}"
          title: "{{ input_title }}"
        action: notify.mobile_app_starfury
mode: parallel
icon: mdi:bullhorn
description: Standardized Notifier for all targets.
fields:
  input_targets:
    name: Target
    description: Target to notify
    selector:
      select:
        multiple: true
        mode: dropdown
        options:
          - label: Chris' Phone
            value: cpg_phone
          - label: Chris' Tablet
            value: cpg_tablet
          - label: Emily's Phone
            value: esg_phone
          - label: Emily's Tablet
            value: esg_tablet
          - label: TVs
            value: tvs
    required: true
  input_reach:
    name: Reach
    description: Will this notification go to people at home, away or out of town
    default:
      - S
      - H
      - ANH
      - ARD
    selector:
      select:
        multiple: true
        options:
          - label: Out of Town (>100 mi)
            value: OOT
          - label: Away
            value: A
          - label: Away, Nobody Home
            value: ANH
          - label: Away, Recently Departed
            value: ARD
          - label: Home
            value: H
  input_title:
    selector:
      template: {}
    name: Title
    description: Title to show in the notification (Mobile Only)
    required: false
  input_message:
    selector:
      template: {}
    name: Message
    description: The message to send
    required: true
  input_notify_settings:
    name: Settings for Notify
    selector:
      template: null
    description: Additional to attach as part of the data to the notify.
    required: false
  input_start_time:
    name: Start Time
    description: When notifications should start being allowed
    default: "07:30:00"
    selector:
      time: null
    required: true
  input_end_time:
    name: End Time
    description: When notifications should stop being allowed
    default: "23:00:00"
    selector:
      time: null
    required: true
  input_ard_time:
    selector:
      number:
        min: 1
        max: 10
        step: 1
    name: Away Time
    description: >-
      When using 'Away, Recently Departed', how much time counts for 'Recent'.
      (In Minutes)
    default: 2
max: 100

variables only have local scope. and you can’t really change a variable… ie, variables don’t vary… they’re essentially const.

Hi Platonicsolid,

You would need to use something global to store stuff from a lower scope.
A helper would work.
This would work:
Trigger based template sensor to store global variables.

Here’s a string you can plug into your search engine to get more examples:

site:community.home-assistant.io automation global variable

Well boo.
I don’t know how I got it into my head that such a thing was possible. That’s honestly pretty annoying and limiting, but I should have known.
I think I’ll have to try it with multiple notify invocations. I don’t want to use a helper so I can support concurrent runs.
Thanks.

looking at your code, it looks to me like it boils down to a pretty simple loop that might call notify once each time… might. everything else is a calc of values, and no service calls (unless i missed something)

you could reduce all of that calc into a single template.
that template, albeit long, could also be half the length of the current yaml you have.

the key is that since everything is just calculating w/o invoking services, it looks like it can all be a jinja template.

Thanks all. I may give that a try, @armedad. I’ve gotten into some trouble with overly complex templates but it may be worth a shot.

i can understand that. to help solve for that i’d encourage you to do it one part by part. in the example you gave, it looks to me like you kinda wrote the whole thing then tested it and then realized the use of variables like that doesn’t work…

i’d encourage you to do it part by part. e.g. step 1… just have the template firgure out who to send to. don’t worry about getting the message right.

overly complex templates often come about by trying to solve the whole problem all at once…

Belatedly, thanks. I’ve been busy and traveling, I’ll update once I’ve had a chance to dig in and take a swing on this.