Setting variables in 'choose'-blocks of automations

Hi,
I am cleaning up my code and try to combine multiple similar automations into one. For that, I want to use the new ‘Variables’ feature (v0.115).
The following…

automation:
  - id: test1
    trigger:
      #... some trigger
    variables: 
      messagetext: '--'
    action:
      - variables:
          messagetext: 'start'
      - service: notify.max
        data:
          title: 'Automation Test1'
          message: "{{ messagetext }}"

…works, I get a notification with text ‘start’.
But, if I put the setting of the variable inside a chooser block and use that variable later on:

automation:
  - id: test2
    trigger:
      #... some trigger
    variables: 
      messagetext: '--'
    action:
      - choose:
        - conditions:
          #do something Mondays
          - condition: time
            weekday:
              - mon
          sequence:
            - variables:
                messagetext: 'a Monday'
        default:
          #do something else 
          - variables:
              messagetext: 'another day'        
      - service: notify.max
        data:
          title: 'Automation Test2'
          message: "{{ messagetext }}"

…I get the notification message ‘–’.
In Jinja templates variables are always local or a namespace has to be set.
But how is that done here in automation actions?
In my understanding the defined variable should be accessible throughout the whole automation.

Thanks in advance for your input.
Max

1 Like

Did you ever get this working? I have the same issue

In brief, you can’t redefine the value of a variable like in the posted example.

The variable’s scope is constrained by where it’s defined in the automation. The assumption maxl67 made is that no matter where the variable is defined, it’s scope is always global (available everywhere within the ,action. However, that’s not how it works.

In the example, the variable messagetext is defined not just once but three times. The first time is outside of action and represents the one whose scope is global for the entire automation.

The second and third definitions are made within the conditions of a choose so their scope is constrained to the conditions.

Outside of conditions, like in the service call, the value of messagetext is determined by its first (global) definition.

1 Like

@Rob: no, I haven’t.
@Taras: Thanks for the good explanation.

It’s a pity, it would be useful to be able to alter a variable depending on a condition. For example I’d like to use today’s energy consumption value in an automation run before midnight, but use yesterday’s value if its before 1 AM:

  sequence:
    - variables:
        consumption: "{{ states('sensor.energy_today') | round(1) }}"
    - if:
        - condition: time
          before: "01:00:00"
      then:
        - variables:
            consumption: "{{ states('sensor.energy_yesterday') | round(1) }}"

very easy, nice to read - but it won’t work, cannot use the changed variable later, as its scope limits it to the then: branch…

Because of this, I have to use jinja template to set the variable dependig on the time, but it is much less friendly:

    - variables:
        consumption: >-
          {% if now().strftime("%H")+now().strftime("%M") < "0100"  %}
            {{ states('sensor.power_kwh_yesterday') | round(1) }}
          {% else %}
            {{ states('sensor.daily_energy') | round(1) }}
          {% endif %}

Especially so, if I have to change several variables on the same condition, like the word “today” or “yesterday” in another variable: then the only way to double the whole Jinja template rows for that variable…

1 Like
- variables:
    consumption: >-
      {{ states(iif(now() < today_at('01:00'), 'sensor.power_kwh_yesterday', 'sensor.daily_energy')) | round(1) }}
1 Like

I came across this issue while searching for the same problem as the OP. So I wanted to add to this discussion where I’m at on this, and see if anyone has any better ideas.

I was also trying to use a variable set by a complicated choose automation, and then use the variable later in the automation. It is unfortunate there doesn’t seem to be a way to do this with variables.

I suppose I can do this by setting an input_text helper, but I would then have to set that up separately, which is less clean. I would prefer a variable scoped for the automation as whole. I could also try and write my whole choose action as a template, but that is not clean either.

Another option is using one of the variable integrations from HACS, but I would prefer to used HA core functionality as much as possible to ensure long term stability.

Does anyone else think one of these is better than the other? Why?

You can put all your logic in the variable. Jinja is much more flexible than normal conditions. So just post the logic and we can help you write the template.

I have multiple variables that need to be set depending on the choose conditions. So I’d have to repeat the same if/else logic for every single variable.

No, you can put the logic into a variable and then use that variable in other variables.

All of the variables are independent of one another, so I can’t use the text of any of them in the others.

Post your code and I’ll show you.

Thanks @petro. I’ll take you up on this offer. I agree with @jimjames, especially this part:

I suppose I can do this by setting an input_text helper, but I would then have to set that up separately, which is less clean. I would prefer a variable scoped for the automation as whole.

I have a very simple use case, where I want to store the current position of my blinds (number between 0 and 100). Then change the blind position and then 1 minute later revert to the original blind position. Please note the pseudo-service local_input_number.set_value. This doesn’t exist but I’m looking for something like it:

- service: local_input_number.set_value
  data:
    name: prev_position
    value: state_attr('cover.kitchen_smart_blind', 'position')
- service: cover.set_cover_position
  data:
    position: 50
  target:
    entity_id: cover.kitchen_smart_blind
- delay:
    hours: 0
    minutes: 0
    seconds: 10
    milliseconds: 0
- service: cover.set_cover_position
  data:
    position: "{{prev_position}}"
  target:
    entity_id: cover.kitchen_smart_blind

How can I write this automation in a simple manner that doesn’t rely on globally accessible variables?

- variables:
    prev_position: >
      {{ state_attr('cover.kitchen_smart_blind', 'position') }}
- service: cover.set_cover_position
  data:
    position: 50
  target:
    entity_id: cover.kitchen_smart_blind
- delay:
    hours: 0
    minutes: 0
    seconds: 10
    milliseconds: 0
- service: cover.set_cover_position
  data:
    position: "{{prev_position}}"
  target:
    entity_id: cover.kitchen_smart_blind
1 Like

Awesome! I must have been using it wrong all along. Thank you!