"{%- IF -%}" - if, else, endif logic in automations?

In some of my scripts, I use the IF, THEN, ELSE logic to build a notification message.
I can’t seem to find the right syntax for using them in automations.
Is it possible? Can someone share an example?

This is what I have in my script - but pasting it into an automation causes errors. This is the “message:” portion of a text-to-speech service call.

>   message: >
>     {%- if is_state('device_tracker.kelly_iphone', 'dads_house') -%}
>     Preparing the house for bedtime.  Good night Bill and Kelly.
>     The weather is currently {{ states.sensor.pws_weather.state }}.  Tonight will be {{ states.sensor.pws_weather_1n_metric.state }}.
>     {%- else -%}
>     Preparing the house for bedtime.  Good night Bill.  Kelly is at {{ states.device_tracker.kelly_iphone.state }}.  The weather is currently {{ states.sensor.pws_weather.state }}.  Tonight will be {{ states.sensor.pws_weather_1n_metric.state }}.
>     {%- endif %}
1 Like

You certainly can use templates in automations, I’ve moved all my notifications to an engine, which does use the concept but slightly differently, the engine is here…

link removed

Or there are some simpler examples, like my one that sets the interface theme depending on the time of day, or the status of the system, which is here…

link removed

Hope this helps.

1 Like

Thanks for your reply and for sharing your yaml files. Very impressive and will take me some time to figure them out. Is the spelling mistake in “macro bye()” intentional?

So - are you saying that the {% IF} construct should work in automations? Like I said, it works fine for me in scripts - but every time I’ve tried to add it to an automation, it’s caused compile errors.

I also noticed that sometimes your script uses “{%- IF … -%}” and sometimes the “-” (dash) is omitted. Can you tell me what the difference is between the two syntaxes and when each one should be used?

Ha, no, well spotted, I’ll correct that :smile:

Yeah, definitely working in automations here, maybe post the full automation and the error you’re getting?

I’ve been going through removing the dashes from most things in my config tbh, it’s something to do with removing whitespace from the output and in most cases they’re completely irrelevant.

@tenly yes the - is to remove white space. There are times it’s needed, but for the most part you probably won’t need it. The reason you are probably getting errors is it can only be used in places that allow templating. For example, these are both incorrect.

- service: light.turn_on 
  entity_id: light.living_room 
  data: 
    brightness: '{% if is_state("sun.sun", "below_horizon")%}255{%else%}120{%endif%}'

In this case you would have to use data_template and not data.

- service: '{% if is_state("sun.sun", "below_horizon")%}light.turn_on{%else%}light.turn_off{%endif%}'
  entity_id: light.living_room

This would also result in an error because service doesn’t use templating.

Hope that helps understand Jinja templating a bit more.

Actually, you could do the second one too, using service_template.

1 Like

I stand corrected. Actually I can use this in some of my automations. Thanks @anon43302295

1 Like

Thanks for the replies. I’m going to try some of your suggestions over the weekend.
I’ll post back here if I have any problems.

So… using your suggestions and examples, I was able to get a simple IF ELSE working in a test automation - but I’m still unable to get the one I need to work. Maybe you can help?

I’m building the body of an e-mail message and I have a line that ‘sometimes’ needs to be included and other times not. Here is a description of the logic I need:

There is an attribute (not a State) in a (custom component) sensor named “Session Time” which will be either “12:15 PM”, “3:30 PM”, “7:00 PM”, “10:00 PM” or “10:15 PM”.

I need my “if” to evaluate “True” when the “Session Time” is “7:00 PM”.

Here’s what I tried:

 {% if {{ states.mysensor.attributes["Session Time"].split(":")[0] }} == "7" %}
 This is the message I need to display for the 7pm session
 {% endif %}

and also….

 {% if states.mysensor.attributes["Session Time"].split(":")[0] == "7" %}
 This is the message I need to display for the 7pm session
 {% endif %}

Both of the above syntaxes result in the Automations component not loading.
Any ideas how to make this work?

>   - service: notify.mailgun
>     data_template:
>        title: MyTitle
>        message: |-
>        This is the first line of my message (should display all the time)
>        This is the conditional line of my message (should ONLY display for 7PM session)
>        This is the last line of my message (should display all the time)

I’d have to experiment a bit, but I’d start with…

- service: notify.mailgun
  data_template:
     title: MyTitle
     message: >
      This is the first line of my message (should display all the time)

      {% if 7PM_LOGIC %}This is the conditional line of my message (should ONLY display for 7PM session){% endif %}

      This is the last line of my message (should display all the time)

That’s great - and it’s essentially what I’ve tried (except I split my IF/ENDIF over multiple lines).

The piece I’m having trouble with is what to put in the “7PM_LOGIC”.
If I use a straightforward “is_state()” statement, the IF will work. But I don’t have a “state” to use for this.

I just can’t seem to find the right syntax for pulling an attribute instead of a state and then running a function on it to use just the hour portion of the time. The same syntax I used in my first example works for substitution in the message - just not in the 7PM_LOGIC.

I use the “message: |-” instead of “message: >” to preserve the blank lines and linefeeds in my message.

Yeah, not sure on what the exact template would be without experimenting tbh.

Try this:

{% set hour = states.mysensor.attributes["Session Time"].split(":")[0] %}
{% if hour == "7" %}
   This is the message I need to display for the 7pm session
{% endif %}
1 Like

I’m out for the evening - but that looks promising!
Will try it first thing tomorrow!

Thanks!

Hey! Thanks very much. This “mostly” worked.
The only problem I’m running into is that if I put it on 4 separate lines as in your example - then I have 3 extra blank lines in my message output. I can (and did) condense them all to a single really, really long line - but it’s now working properly.

I do have a follow-up question. I wasn’t aware that I could set a variable like this and then refer to it later. This is going to be very handy in some of my other automations. My questions are:

  1. Can I do this in scripts also? (I’m assuming yes)
  2. What is the scope/lifetime of the variable I create?

Very interested in the answer to question #2 above - and here’s why…

The automation I’ve been working with triggers off of my sensors state change event.
I have 3 notify actions that take place:

  • an on-screen notify to Android TV
  • an iOS notify to the Home Assistant app
  • an e-mail message using mailgun

So - I’m wondering - if I want to create and use the ‘hour’ variable in all 3 actions (using {% set hour = %} syntax), do I have to do that in the “message:” for each notify action? Or can I do it in the first one - and then just use it in the others? Can I do it outside of the “message:” area? If I don’t overwrite it, can I use it in other scripts and automations without defining it again? I guess this is what I mean by “what is the scope” of the variable… :slight_smile:

Where would one normally learn how to do this without using the forum? Is there some documentation on this sort of thing that you could point me to?

Thanks again. I’ve been struggling with this for a couple of weeks already. Feels good to finally get it resolved.

@tenly This is one of those cases you’d want to control the whitespace then. Try this…

{%- set hour = states.mysensor.attributes["Session Time"].split(":")[0] -%}
{%- if hour == "7" -%}
   This is the message I need to display for the 7pm session
{%- endif -%} 

To answer your questions above.

1 - Yes, you can use these in scripts just like automations. Actually you can use it anywhere templating is allowed. I use it a lot in template sensors or icon templates etc.

2 - I haven’t used variables globally, but I have ran across some people that have for Sonos TTS. I’ll try to make one work and post an example later this week when I get some time. I’m in the midst of simplfying my yaml code lately. One thing you can do, is make a template sensor and that could act as a variable. Here’s a quick example using your mysensor above:

This is a sensor that gets the hour from your “sensor.mysensor”

sensor:
  platform: template
    sensors:
      my_time_sensor:
        entity_id: sensor.mysensor
        value_template: '{% set hour = states.mysensor.attributes["Session Time"].split(":")[0] %}'

Then here’s an automation for notifications all combined into one, with a condition that will only happen if the sensor is greater than 6, and sends a message to both the Android TV and Home Assistant. These are two different ways to use the “variable” we created with the template sensor.

  - alias: 'Notifications'
    initial_state: on
    trigger:
      platform: state
      entity_id: sensor.my_time_sensor
    condition:
      condition: and
      conditions:
        - condition: template
          value_template: '{% if states.sensor.my_time_sensor.state|int > 6 %}true{%endif%}'
    action:
      - service: notify.android_tv
        data:
          title: "Time is Up"
          message: "It is {{states.sensor.my_time_sensor.state}} oClock"
      - service: persistent_notification.create
        data:
          message: "Time is Up"
          title: 'It was {{trigger.from_state}} and now it is {{trigger.to_state}}'

Because I’m using “message: |-” instead of “message: >”, newlines are preserved in my message body - which I need. That made the “{%- -%}” usage tricky, but after a lot of trial and error, I was able to find something that worked. What I actually wanted was to leave 1 blank line before and after my variable message - and this is what I ended up with:

Balls Jackpot: {{ states.sensor.bingo_world_newmarket.attributes["Balls Jackpot"] }} in {{ states.sensor.bingo_world_newmarket.attributes["Balls Designated Number"] }} #'s
{%- set hour = states.sensor.bingo_world_newmarket.attributes["Session Time"].split(":")[0] %}

{% if hour == "12" or hour == "7" -%}
Turbo Jackpot: {{ states.sensor.bingo_world_newmarket.attributes["Turbo Prize"] }} in {{ states.sensor.bingo_world_newmarket.attributes["Turbo Number"] }} #'s 
{% else %} No Turbo's at this session ({{ hour }} PM) {%- endif %}

Toonie Pot: {{ states.sensor.bingo_world_newmarket.attributes["Toonie Pot"] }}
Rapid Bonus: {{ states.sensor.bingo_world_newmarket.attributes["Shutter Bonus"] }}

If you look closely, you’ll see that I used the “-” on some of the “{%” and not others. Normally, with “message: |-” all of the newlines result in newlines in the output - but adding the “-” to the normal open or close delimiters “{%” or “%}” seems to delete all whitespace - including newlines - before, or after - or both before and after the statement. So, “{% set hour = “12” %}” on a line by itself would create a blank line in the message body (depending on what came next). If my “{% else %}” clause were actually “{%- else %}”, it would end up deleting the blank line that the “{% set hour = ‘12’ %}” had created because it was all whitespace and line breaks right back as far as the last text I printed - and then the alternate text in the else clause would be appended directly to the end of the last line with text on it. (undesirable)

It’s a bit complicated and my explanation is probably not making it any clearer. I guess I just wanted to point out to anyone finding this discussion that the “-” is a modifier and it can be used on either the opening delimiter or the closing delimiter - or both. Up until today, I thought they were part of the open and close delimiters and had to match. No matter what type of “message:” you are composing, if you use the “-” modifier on both the open and close delimiters for your “IF” statement - even on a line by itself with a blank line above and below; as far as the final message is concerned, it will be like all three of those lines ever existed.

One other thing I wanted to call out to people who may find this discussion in the future is that; in my initial example, there is a typo in my syntax. It also appears in some of the replies from others because of copy/paste or quoting my original post. I said I was using ‘states.mysensor.attributes[“Session Time”]’ when in fact, I left out a piece of it. It should have read ‘states.sensor.mysensor.attributes[“Session Time”]’

Thanks Jer78 for your help with this - and for suggesting the “value_template:” as an alternative.

1 Like

I highly recommend that you look at using a Python Script for this kind of automation – it’ll change your life as to how you write automations with complex logic!

I posted a sample Automation and linked Python Script here:

The logic needed, the control over the custom message you want, etc. are all reasons that this is a really good case for use of a Python Script to drive the automation . . . you still have your automation, but the action can just call the python script which can have far more advanced logic! And it’s really not that hard to work with once you get the hang of it, because you do NOT have to re-start HASS to see the changes, you just save the file and try the automation again!

This shows the use of a single Automation that delegates all logic into the script, and shows how variables, and various element can work. You can retrieve the state or attribute of any entity and use that to drive your logic. You can also pass data dynamically from the Automation, but for most use cases it’s more simple to just query Hass for the latest entity state/attribute needed.

The sample linked also shows how you can use a Notify and pass any custom dynamic message… I use them to help debug the script by pushing the values via Pushover notifications (much easier than having to try and look at log outputs).

I hope this helps, and it will likely change your life in how you write automations!

3 Likes