Variables scope involving IF statement

Hello,

If have read in some messages of this forum that apparently variables used within an IF statement are not visible outside the IF statement.
I would like to create a script where I would initialise a string with a given value via such a statement:

variable:
mystring: toto

Then with several IF statements I would like to add some text to mystring based on the tests made by IF statements.

But I have seen that I cannot modify my string mystring within the IF statement.

Is there an other mechanism of is it possible to modify the default scope of a variable to achieve what I would like to so ?

Thank you

Eric

If it works like variable scope does in most other languages, just define the variable outside the if, then it should have global scope in the script, then just assign it inside your IF statement.

The variable inside the if is local to the if even if it has the same name as a variable defined outside the if. Therefore changes to the value of variable x defined inside the if donā€™t appear in variable x defined outside the if.

Or at least thatā€™s how it worked the last time I checked ā€¦

Is there no way to define it outside and just assign it inside ?

Currently, the only way to assign a value to a script variable is when you define the variable.

This is also what I experienced .

I finally found the solution to keep track of variables even within IF statement by using the custom component variables:

Yes this is true. The documentation explains it this way Script Syntax - Home Assistant.

I hope there is a plan to update this in the future. To adhere to this logic will just require more actions within a Script.

The simple below does not work because the IF statement does not change the variable value.

alias: TTS - Washing Machine
sequence:
  - variables:
      ttsm: Placeholder
      ttsm1: >-
        Good morning team, the clothes washer is complete.
      ttsm2: >-
        The clothes washer is complete.  Have a great day!
  - if:
      - condition: time
        before: "12:00:00"
    then:
      - variables:
          ttsm: "{{ ttsm1 }}"
    else:
      - variables:
          ttsm: "{{ ttsm2 }}"
  - service: tts.google_translate_say
    data:
      cache: false
      entity_id: media_player.mpd3
      message: "{{ ttsm }}"
  - wait_for_trigger:
      - platform: state
        entity_id:
          - media_player.mpd3
        to: "off"
    continue_on_timeout: false
mode: single

For me, Iā€™d rather not install a custom component to work around this BUT you can just use the built in service input_text.set_value for an input_text helper. The variable then will be GLOBAL to your entire app though.

For example in your config

input_text:
  #tts washing machine global message
  ttsm:
    name: TTS Message

Your new Script would be

alias: TTS - Washing Machine
sequence:
  - if:
      - condition: time
        before: "12:00:00"
    then:
      - service: input_text.set_value
        target:
          entity_id: input_text.ttsm
        data:
          value: "Good morning team, the clothes washer is complete."
    else:
      - service: input_text.set_value
        target:
          entity_id: input_text.ttsm
        data:
          value: "The clothes washer is complete.  Have a great day!"
  - service: tts.google_translate_say
    data:
      cache: false
      entity_id: media_player.mpd3
      message: "{{ states('input_text.ttsm') }}"
  - wait_for_trigger:
      - platform: state
        entity_id:
          - media_player.mpd3
        to: "off"
    continue_on_timeout: false
mode: single

Thereā€™s no obligation to compute a variableā€™s value via a scriptā€™s if - then. It can be done when the variable is defined, using a template. It requires less code and no custom integration.

Your first example revised:

alias: TTS - Washing Machine
sequence:
  - variables:
      ttsm1: >-
        Good morning team, the clothes washer is complete.
      ttsm2: >-
        The clothes washer is complete.  Have a great day!
      ttsm: "{{ iif(now().hour < 12, ttsm1, ttsm2) }}"
  - service: tts.google_translate_say
    data:
      cache: false
      entity_id: media_player.mpd3
      message: "{{ ttsm }}"
  - wait_for_trigger:
      - platform: state
        entity_id:
          - media_player.mpd3
        to: "off"
    continue_on_timeout: false
mode: single
1 Like

Amazing! I need to get better with Jinja syntax in Home Assistant.

Amazing?
Thatā€™s still a if statement but a more complicated and much less intuitive one. I really donā€™t understand why I canā€™t define a variable in a in normal if-then block. I lost almost an hour trying to figure why my automation was not working. There is maybe a ā€˜technicalā€™ reason but thatā€™s not a good reason from a userfriendlyness standpoint, which should always be the mindset to adopt.

Itā€™s an Immediate If and is documented here.

The documentation also shows two other ways to create an if statement in Jinja2. Perhaps one of the two other ones is more familiar to you.

You can but its scope will be constrained to the if-then block. Thatā€™s explained here.

Yeah I saw that. By that I meant ā€œImmediate Ifā€ vs ā€œIf-then blockā€. In the end Iā€™ll get the same result but I will have had to take the complicated way.

Again, I read that and thatā€™s what I meant by ā€œcanā€™t defineā€, or should I have said ā€œcanā€™t define in way so itā€™s really usefulā€. The whole point of defining the variable was to be used in some later part of the automation to avoid duplication of code. As many people mentioned, here variables are more constants.

Anywaysā€¦

A script variableā€™s scope is the limiting factor.

  • You can redefine a script variableā€™s value provided itā€™s performed within its scope.

  • You cannot redefine its value outside its scope.

In practice, the solution is to simply restructure the sequence of variables and actions (like I demonstrated in my post nine months ago).

1 Like