{% if ... elif ... else %} with no else - what do you do?

There is another thread [Automation - right usage of trigger event data for conditions] which has been ever so slightly derailed by the realisation that every clause in an

ifelifelseendif

must be valid. i.e you cannot leave the else empty to do nothing.

It looks like in cases where there genuinely is never (ha! ha!) gong to be an else condition the suggested way round it is to have a dummy script which does something .

Has anyone found another cleaner way to get around this and if not what do you put in your dummy script (or is there a trivial and inconsequential service that could called)?


For example:

 - service_template: >
     {% if (now().month == 1 and now().day == 2) or
           (now().month == 3 and now().day == 4)  %}
        script.birthday_greeting
      {% else %}
      {% endif %}

Seems to give:

Log Details (ERROR)

Tue Sep 25 2018 08:15:38 GMT+0100 (British Summer Time)

Template rendered invalid service:

This is what I do:

  action:
    service: script.turn_on
    data_template:
      entity_id: >-
        {% if states('sensor.aeotec_lounge_light_level') | float > 70 %}
          script.lounge_rd_lights_off
        {% elif 41 > states('sensor.aeotec_lounge_light_level') | float > 30 %}
          script.lounge_rd_lights_25
        {% elif 31 > states('sensor.aeotec_lounge_light_level') | float > 20 %}
          script.lounge_rd_lights_50
        {% elif 20 > states('sensor.aeotec_lounge_light_level') | float %}
          script.lounge_rd_lights_75
        {% else %}
          script.noop
        {% endif %}

script.noop looks like this:

noop:
  sequence:
    delay: 00:00:00
4 Likes

In my setup, the last option becomes the default if no condition fits. (Ie I just have else and then the last one)

That should work for my example above, as I have eliminated all other possibilities. Not sure this will always be the case though.

Clearly in my example this is not possible and there are many cases to have an if where nothing happens if it is not true

I guess you can’t get much more trivial and inconsequential than that. Thanks!

Yeah sorry - I was looking at Toms example not yours…

Typically, I use a condition prior to the service template. But remember, if you use a condition, all services beyond the condition will not run. So in your example, this is what it owuld look like:

  - condition: template
    value_template: >
      #Easily expandable.  just add ", (month, day)" inside square brackets.
      {% set birthdays = [ (1, 2), (3, 4) ] %} 
      {% set today = ( now().month, now().day ) %}
      {{ today in birthdays }}
    #everything beyond this point will not run if the previous condition hasn't been met.
  - service: script.birthday_greeting
3 Likes

Thanks, once again not just an answer but an overall improvement.

A small typo kept me thinking for a minute though… expendable had me looking for something that was not necessary :stuck_out_tongue_winking_eye:

hah! i’ll edit it.

Also… if you’re feeling up to it. You can customize the birthday greeting based on the day.

birthday_greeting:
  sequence:
    - service: notify.notify
      data_template:
        entity_id: x.x
        message: "Happy Birthday {{ name }}"
  - condition: template
    value_template: >
      #Easily expandable.  just add ", (month, day)" inside square brackets.
      {% set birthdays = [ (1, 2), (3, 4), (9, 25) ] %} 
      {% set today = ( now().month, now().day ) %}
      {{ today in birthdays }}
    #everything beyond this point will not run if the previous condition hasn't been met.
  - service: script.birthday_greeting
    data_template:
      name:
        {% set today = '{}.{}'.format(now().month, now().day) %}
        {% set birthdays = { 
          '1.2':'klogg', 
          '3.4':'klogg2',
          '9.25':'klogg3' } %}
        {{ birthdays[today] }}

3 Likes

“If I’m up to it”?
You’ve done all the hard work!! Thanks :slight_smile:

This is how it should be done really, the dummy script as a catch all is a bit hacky. That said, it is quite an effective and unobtrusive hack.

I agree but do you have an alternative for cases where there really isn’t an else but there are further steps in the automation?

The only other way I have come up with is to always call a separate script which performs one function and let that script have the condition. Probably slightly more correct but in my opinion slightly less maintainable. YAML is bad enough without having tiny bits of code all over the place just to deal with a logic problem.

Of course, feel free to disagree :slight_smile:

Agreed. Tonight I have actually been able to remove it from the few templates I was using it in by using either David’s suggestion to put the last option in the else case or petro’s condition suggestion. e.g.

  condition:
  - condition: template # Only if currently running any heat mode
    value_template: "{{ 'Heat' in states.input_select.lounge_ac_mode.state }}"
  action:
    service_template: >
      {% if is_state('input_select.lounge_ac_mode', 'Powerful Heat') %} shell_command.lounge_ac_powerful_heat
      {% elif is_state('input_select.lounge_ac_mode', 'Normal Heat') %} shell_command.lounge_ac_normal_heat
      {% elif is_state('input_select.lounge_ac_mode', 'Silent Heat') %} shell_command.lounge_ac_silent_heat
      {% endif %}

Put the if/else template bit as the last action. After the condition. You can put conditions in the action section.

Show me an example, and I’ll let @petro beat me to the answer :smile:

Ha! You already beat me to my answer though. I’d use a dummy script if it needs to run first in the sequence.

1 Like

@anon43302295 I thought my original example covered it!

But between you and @petro you’ve pretty much answered everything so no need to fight over it :stuck_out_tongue_winking_eye:

However @tom_l wins the prize for being first to point out the obvious trivial and inconsequential,

delay: 00:00:00

I still don’t like that you can’t have an empty else but, hey ho. (EDIT: although it has been adequately explained to me now - Automation - right usage of trigger event data for conditions)
Thanks everyone

If it’s just that, it would be

  - condition: template
    value_template: "{{ (now().month == 1 and now().day == 2) or (now().month == 3 and now().day == 4) }}" 
  - service: script.birthday_greeting

And @tom_l 's would be…

action:
    service: script.turn_on
    data_template:
      entity_id: >-
        {% if states('sensor.aeotec_lounge_light_level') | float > 70 %}
          script.lounge_rd_lights_off
        {% elif 41 > states('sensor.aeotec_lounge_light_level') | float > 30 %}
          script.lounge_rd_lights_25
        {% elif 31 > states('sensor.aeotec_lounge_light_level') | float > 20 %}
          script.lounge_rd_lights_50
        {% else %}
          script.lounge_rd_lights_75
        {% endif %}