Understanding of the Use of Script Variables in If Statement

Hi All,

I am having difficulty on understanding the use of variables in an if statement.

If I have a script that has a variable section as follows:

- variables:
    alexa_area: "{{ area_name(states('sensor.last_alexa')) }}"

How do I create an if statement that basically says if alexa_area is equal to ‘bedroom’, run this section of the script, else run another.

Thanks in advance for any input. :slight_smile:

A variable just stores some data for reuse. The actual logic goes under the script sequence or automation actions. You’d keep the value as you have done, and then use that with an if or choose statement.

Automation Example 1

action:
- variables:
    alexa_area: "{{ area_name(states('sensor.last_alexa')) }}"
- if: "{{ alexa_area == 'bedroom' }}"
  then:
    ... your "then" actions go here ...
  else:
    ... your "else" actions go here ...

Automation Example 2

action:
- if: "{{ area_name(states('sensor.last_alexa')) == 'bedroom') }}"
  then:
    ... your "then" actions go here ...
  else:
    ... your "else" actions go here ...
1 Like

Thank you for the examples. It makes more sense now.

One question I have is how do you include elseif’s?

If then / else works fine, but if I try adding a elseif’s, I get the following error when clicking the ‘Check Configuration button’:

Invalid config for [script]: Unable to determine action @ data[‘sequence’][3]. Got None Unable to determine action @ data[‘sequence’][4]. Got None.

Below is my current script:

turn_off_tv:
  alias: Turn Off TV
  sequence:
  - delay:
      seconds: 4
  - variables:
      alexa_area: "{{ area_name(states('sensor.last_alexa')) }}"
      tvs:
        Bedroom: 'bedroom_tv'
        Guest Room: 'guest_room_tv'
        Living Room: 'living_room_tv'
      active_tv: '{{ tvs.get(alexa_area) }}'
  - if: "{{ alexa_area == 'Bedroom' }}"
    then:
      - service: remote.send_command
        data:
          command: power
          device: '{{ active_tv }}'
        target:
          entity_id: remote.bedroom_broadlink_rm4_pro_remote
  - elif: 
      "{{ alexa_area == 'Living Room' }}"
    then:
      - service: remote.send_command
        data:
          command: power
          device: '{{ active_tv }}'
        target:
          entity_id: remote.living_room_broadlink
  - elif: 
      "{{ alexa_area == 'Guest Room' }}"
    then:
      - service: media_player.turn_off
        target:
          device_id: '{{ active_tv }}'
  mode: single

The If/Then action does not support “elif”… you need to use a series of If/Thens or a Choose action instead.

You could instead use a list as the value for your dictionary, so you have both the device and entity information.

turn_off_tv:
  alias: Turn Off TV
  sequence:
  - delay:
      seconds: 4
  - variables:
      alexa_area: "{{ area_name(states('sensor.last_alexa')) }}"
      tvs:
        Bedroom: ['bedroom_tv', 'bedroom_broadlink_rm4_pro_remote']
        Living Room: ['living_room_tv', 'living_room_broadlink' ]
      active_tv: |-
        {{ iif(alexa_area in tvs.keys(), tvs.get(alexa_area), 'guest_room_tv') }}
  - if: "{{ alexa_area in tvs.keys() }}"
    then:
      - service: remote.send_command
        data:
          command: power
          device: '{{ active_tv[0] }}'
        target:
          entity_id: 'remote.{{ active_tv[1] }}'
    else:
      - service: media_player.turn_off
        target:
          device_id: '{{ active_tv }}'
  mode: single

You don’t.

Refer to the documentation for how if-then is used in Home Assistant’s scripting.

The equivalent of a long chain of if-elif-elif-else is, as mentioned by Didgeridrew, to use choose.

Variables can be defined with templates, so is it possible to define a variable with a if statement like what I show bellow?

I need this do change a delay to charge my car (and have it ready at a define time according to the actual SoC.

My if statement in the variable context bellow don’ t work… I don’t know how to make it work…

variables:
  soc: "{{ states('sensor.eco2_soc') }}"
  soc_pretendido: "{{ states('input_number.eco2_soc_pretendido') }}"
  soc_calculo: "{{ soc + 100 - soc_pretendido }}"
  tempo:
    - if: "{{ soc < 20 }}"
      then: "{{ ( soc_calculo * 10 ) }}"
      else: "{{ ( soc_calculo * 100 ) }}"
  tempo_horas: "{{ tempo / 60 }}"
  tempo_minutos: "{{ tempo_horas - ( tempo_horas | int ) }}"
tempo: "{{( soc_calculo * 10 ) if soc < 20 else ( soc_calculo * 100 ) }}"
1 Like

Oh my god… it worked!!! I’ve been trying this alike all day!!!

Thank you very much @Didgeridrew!!!

Now a more difficult one… And If I wanted to use “choose” instead of “If”?

Is that possible? I need it because I have a lot of condition to test and some of them are true even if I just want to use the first one.

Imagine I have my car with a 40% soc…

If “soc” is <20 is false
If “soc” is <60 is true… but If “soc” is <70 or <80 and so on is also true and because of that I need to use the “choose” function instead of If…

“If” was just the first step to understand how can I create this action…

Can you help me? Do you think it’s possible (I mean in the variable definition to use it as a global variable in the automation template)?

This is commonly called a “switch case”.

Yes, you can use a either an if/elif construct or a dictionary. In both methods you need to take care with the order of options based on the comparison type you are using. The cases are rendered from top to bottom and the first one to render true will be returned. You can avoid some problems by using chained comparisons and <= instead of < where appropriate:

tempo: |
  {% if soc <= 20 %}
    {{ soc_calculo * 10 }}
  {% elif 20 < soc <= 40 %}
    {{ soc_calculo * 50 }}
  {% elif 40 < soc <= 60 %}
    {{ soc_calculo * 70 }}
  {% else %}
    {{ soc_calculo * 100 }}
  {% endif %}

In a dictionary, you use the same type of pattern but different methods to find the correct value.

{% set dict = { soc <= 20: 10, 20 < soc <= 40: 50, 40 < soc <= 60: 70 } %}
{{soc_calculo * (  100 if true not in dict.keys() else dict.get(true)) }}
1 Like

Well @Didgeridrew, I manage to do what I show bellow. It’s not pretty programing but it seams to do the work and only use the fist formula that it’s true…

variables:
  soc: "{{ states('sensor.eco2_soc') }}"
  soc_pretendido: "{{ states('input_number.eco2_soc_pretendido') }}"
  soc_calculo: "{{ soc + 100 - soc_pretendido }}"
  tempo: >-
    {{( soc_calculo * 3.98 ) if soc < 20 else ( soc_calculo * 3.99 ) if soc < 50
    else ( soc_calculo * 4.00 ) if soc < 80 else ( soc_calculo * 4.01 )}}
  tempo_horas: "{{ tempo / 60 }}"
  tempo_minutos: "{{ tempo_horas - ( tempo_horas | int ) }}"

I need to do this small variation in the formula because the charging ratio it’s not linear and the %/hour change with the initial SoC of the car…

This gave me an error (I think just a syntax one, but I’m not fiding the correct way to emend it)

Message malformed: invalid template (TemplateSyntaxError: Unexpected end of template. Jinja was looking for the following tags: ‘elif’ or ‘else’ or ‘endif’. The innermost block that needs to be closed is ‘if’.) for dictionary value @ data[‘variables’][‘tempo’]

Double check that line 5 is elif… I accidentally had it as just if and you may have copied it before I made the correction.

I recommend you use Didgeridrew’s suggestion to employ a dictionary. It’s neater than using a long if-elif-else-endif chain.

tempo: >
  {% set dict = {soc <= 20: 10, 20 < soc <= 40: 50, 40 < soc <= 60: 70} %}
  {{ soc_calculo * dict.get(true, 100) }}

It can also be reduced to this (but it might make it a bit more difficult to understand):

tempo: >
  {{ soc_calculo * {soc <= 20: 10, 20 < soc <= 40: 50, 40 < soc <= 60: 70}.get(true, 100) }}
2 Likes

I also had a problem that I wanted to solve by having the script decide based on the value of a variable.
Finally, after a little investigation and quite a few tests, this solution worked for me:

notify_alexa:
  alias: "Notify Alexa"
  sequence:
    - choose: 
      - conditions: 
          - condition: template
            value_template: "{{  (priority) == 'alert'  }}"
        sequence:

Where ‘priority’ is a variable that comes from an automation and if it’s “normal” it won’t talk after 9pm (e.g. “Your phone is charged”), but if ‘priority’ = alarm, it won’t check the time, always speaks (e.g. smoke or leak alarm)