Data_template, ios_notify: loop through group and add text if

Hi,

I’m trying to create an automation that will send a push notification to my ios device if the diesel price dops below a price defined by a input slider.

Right now I have it working, but with everyhing “hard coded”. I’d like to use a for loop and only list the gas stations that are below the slider limit. I googled for the better part of the afternoon, found many examples but nothing worked out so far.

What I’d like to archive:

  • loop through group.all_gas_stations
  • if diesel price is below slider value, add the gas station name and the price to the push notification.

My attempt at this is (loop based) version is a mess, so I think it’s better to add the “static” version here:

automation:
  alias: Diesel Price Monitor
  trigger:
    platform: state
    entity_id: sensor.score_holtland_diesel, sensor.vela24_diesel, sensor.multi_emden_diesel, input_number.slider1

  condition:
    condition: or
    conditions:
      - condition: template
        value_template: "{{ (states('sensor.score_holtland_diesel')|float) < (states('input_number.slider1')|float) }}"
      - condition: template
        value_template: "{{ (states('sensor.vela24_diesel')|float) < (states('input_number.slider1')|float) }}"
      - condition: template
        value_template: "{{ (states('sensor.multi_emden_diesel')|float) < (states('input_number.slider1')|float) }}"
  action:
    service: notify.ios_socrates_iphone
    data_template:
      message: |-
        Current Prices: {{state_attr('sensor.score_holtland_diesel', 'friendly_name')}}: {{ states('sensor.score_holtland_diesel') }} 
        Current Prices: {{state_attr('sensor.vela24_diesel', 'friendly_name')}}: {{ states('sensor.vela24_diesel') }} 
        Current Prices: {{state_attr('sensor.multi_

Could someone point me at some comprehensive documentation or maybe show me how I can remove the hard coded entries in data_template and maybe even in condition?

I know it would be better to post the “not working” version, but since I currently (sadly) lack understanding of the template engine my “not working” version is really only try and error.

Entities (from the web frontend to show value and attributes)

 group.all_gas_stations	unknown	
entity_id: sensor.score_holtland_diesel,sensor.vela24_diesel,sensor.multi_emden_diesel
friendly_name: All Gas Stations
view: true
order: 1
hidden: true
input_number.slider1	1.1	
icon: mdi:currency-eur
friendly_name: Notification Price Diesel
step: 0.01
min: 1.1
initial: null
mode: slider
unit_of_measurement: €
max: 1.5

 sensor.multi_emden_diesel	1.239	
id: 839ec92a-1b5c-4989-82bc-5bebac644742
name: Multi Emden
friendly_name: Multi Emden Diesel
unit_of_measurement: €
icon: mdi:gas-station
sensor.score_holtland_diesel	1.279	
id: 6151509b-91c5-43fe-ed78-a5196b38888c
name: Score Holtland
friendly_name: Score Holtland Diesel
unit_of_measurement: €
icon: mdi:gas-station
sensor.vela24_diesel	1.339	
id: c0c4e510-c7b0-46b4-564b-808a6439cc0d
name: VELA24
friendly_name: VELA24 Diesel
unit_of_measurement: €
icon: mdi:gas-station

Thanks in advance!

Ok, got one step closer to a solution. What I have overlooked so far:

  1. https://www.home-assistant.io/docs/configuration/templating/ as a reference to the “Jinja Templating engine” which helped a lot in understanding: http://jinja.pocoo.org/

  2. HomeAssistant has a template rendering engine under “Developer Tools”. This allows me to not fly completely blind :slight_smile:

One thing I cannot wrap my head around: Either the Jinja2 engine or I have a problem with “greater” or “lesser”:

This is the code I’m currently running in the Template Engine:

{{states.input_number.slider1.state}}
{% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
{% set domain, device = entity_id.split('.') %}
{% if (states.input_number.slider1.state > states[domain][device].state) %}
{{states[domain][device].attributes.friendly_name}} - {{ states[domain][device].state }}
{%endif%}
{%endfor%}

The Output is:

1.5



Score Holtland Diesel - 1.259




VELA24 Diesel - 1.339




Multi Emden Diesel - 1.299

But “Multi Emden Diesel” has a value of “1.299” with is smaller then “1.5” of the input_number.slider1.
But the if statement says:

{% if (states.input_number.slider1.state > states[domain][device].state) %}

and “>” mean greater then, right?

Similar, wenn I change the if statement to the - in my understanding - correct way

{% if (states.input_number.slider1.state < states[domain][device].state) %}

I get all values bigger then input_number.slider1.

What am I making wrong?

Any insight would be greatly appreciated!

If you fill in the values you suggest, the above if-statement becomes:

{% if (1.5 > 1.299) %}

which obviously is true.

I think your thinking-error is that you confuse what variables you used left and right of the > sign :wink:

The thing to remember and the issue that you are having is that all states are strings. Even if they look like a number they are strings. you have to force the strings to a number in order to do the comparison correctly.

example:

{% if (states.input_number.slider1.state | float > states[domain][device].state | float) %}

Hi vloris, finity
Thanks for pointing that out! I just realized it myself. Now I’ve got the message part working (in the template engine, at least):

    message: |-
        {% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
          {% set domain, device = entity_id.split('.') %}
          {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
            {{states[domain][device].attributes.friendly_name}} - {{ states[domain][device].state }}
          {%endif%}
        {%endfor%}

But I’m still struggling with the condition part. Here’s what I have come up with so far:

 condition: template
  value_template: " {% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
                        {% set domain, device = entity_id.split('.') %}
                        {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
                        {# What to put here? return true? #}
                        {%- endif -%}
                      {%endfor%} %}"
  action:

But I’m not sure what to put between the %if% and the %endif%
How do I return “true” here?

Any thought’s ?

Thanks in advance !

true

:wink:

condition: 
  condition: template
  value_template: >
    {% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
      {% set domain, device = entity_id.split('.') %}
      {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
        true
      {% else %}
        false
      {%- endif -%}
    {%endfor%} %}"
action:

Hi,
thanks for your input. It works in the Template renderer but not in the automation itself.

In the template renderer with this code:

{% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
        {% set domain, device = entity_id.split('.') %}
        {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
          true
        {% else %}
          false
        {%- endif -%}
      {%endfor%}

I get this results:

true
        
        
        
          true
        
        
        
          true

I get the push notification if I trigger the automation manually, so the message part is fine. But the automation will not fire.

Here is the Package content:

# RefURL: https://www.panbachi.de/tankerkoenig-component-fuer-home-assistant/
# RefURL: https://github.com/panbachi/homeassistant-tankerkoenig
# find gas stations (ID's: https://creativecommons.tankerkoenig.de/TankstellenFinder/index.html
tankerkoenig:
  api_key: <my_API_key_goes_here>
  monitored_conditions:
    - diesel
    - state
  stations:
    - id: '6151509b-91c5-43fe-ed78-a5196b38888c'
      name: 'Score Holtland'
      street: 'Leeraner Straße'
      brand: SCORE
    - id: 'c0c4e510-c7b0-46b4-564b-808a6439cc0d'
      name: 'VELA24'
      #street: 'Leeraner Straße'
      brand: VELA
    - id: '839ec92a-1b5c-4989-82bc-5bebac644742'
      name: 'Multi Emden'
      #street: 'Leeraner Straße'
      brand: TANKLOGO


input_number:
  slider1:
    name: Notification Price Diesel
    min: 1.10
    max: 1.50
    step: 0.01
    unit_of_measurement: €
    icon: mdi:currency-eur




automation:
  alias: Diesel Price Monitor
  trigger:
    platform: state
    entity_id: sensor.score_holtland_diesel, sensor.vela24_diesel, sensor.multi_emden_diesel, input_number.slider1

  # condition:
    # condition: or
    # conditions:
      # - condition: template
      #   value_template: "{{ (states('sensor.score_holtland_diesel')|float) < (states('input_number.slider1')|float) }}"
      # - condition: template
      #   value_template: "{{ (states('sensor.vela24_diesel')|float) < (states('input_number.slider1')|float) }}"
      # - condition: template
      #   value_template: "{{ (states('sensor.multi_emden_diesel')|float) < (states('input_number.slider1')|float) }}"
  condition: 
    condition: template
    value_template: >
      {% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
        {% set domain, device = entity_id.split('.') %}
        {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
          true
        {% else %}
          false
        {%- endif -%}
      {%endfor%}
  action:
    #service: lock.lock
    #entity_id: lock.my_place
    service: notify.ios_socrates_iphone
    data_template:
      message: |-
        {% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
          {% set domain, device = entity_id.split('.') %}
          {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
            {{states[domain][device].attributes.friendly_name}} - {{ states[domain][device].state }}
          {%endif%}
        {%endfor%}

The groups are defined in group.yaml and look like this:

all_gas_stations:
  name: All Gas Stations
  view: yes
  entities:
    - sensor.score_holtland_diesel
    - sensor.vela24_diesel
    - sensor.multi_emden_diesel

Could the problem be that the value template returns more than one result?
I’ve been playing around with the “reject” filter, trying to build a list of “true” results and check if the size of the list ist >0. But I haven’t figured out how to do that yet.

Yeah, you’re probably correct that it’s failing because of the multiple return values.

I’m not much more help with that unfortunately. I’ve never done anything with “for” loops other than in the template editor and I think I got the same results as you.

Thanks for staying with me so far!

I’m currently thinking about this:

{% set conditionResult = [] %}
  {% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
        {% set domain, device = entity_id.split('.') %}
        {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
{% if 1 == 1 %}          
{% set x = conditionResult.append('True') %}{%endif%}
        {%- endif -%}
        {% if loop.last %}
        {{conditionResult|length >1}}
        {%endif%}

      {%endfor%}
       {# {{resultVar |length >1}} #}

I know the code seems strange, especially the "{% if 1 == 1 %} " part and the line below. But I learned from other posts here that this is required to circument other errors :slight_smile: :man_shrugging:

Problem is, the rendering engine gives me this error, and there is just one google hit on it:

Error rendering template: SecurityError: access to attribute 'append' of 'list' object is unsafe.

I’m also looking into macros to see if there is a way to overcome the limitations of Jinja.

I’ll keep you posted :wink:

Ok, macros are also not a solution. They are compared to as “functions” in Jinja, but suffer the same limitations. I’m afraid I’m stuck at a point where google does not reveal any new information. So I will keep the static condition for now.

But I’ve got one more question to the message part:

This code run in the template renderer:

        {% for entity_id in states.group.all_gas_stations.attributes.entity_id %}
          {% set domain, device = entity_id.split('.') %}
          {% if (states[domain][device].state |float < states.input_number.slider1.state |float) %}
            {{states[domain][device].attributes.friendly_name}} - {{ states[domain][device].state }}
          {%endif%}
        {%endfor%}

yields this output:

Score Holtland Diesel - 1.259
          
        
          
          
            VELA24 Diesel - 1.289
          
        
          
          
            Multi Emden Diesel - 1.229

The same extra newlines appear also in the push notification itself. Does anyone know a way to suppress them? Or even why they appear in the first place?

Thanks in advance!

I kind of do… although I have trouble getting the right output without a lot of trial and error. I’m only answering because no one else has :wink:

The trick is to use ‘{%-’ and ‘-%}
The ‘-’ means ignore preceeeding or following white space.

So something along the lines of

        {%- for entity_id in states.group.all_gas_stations.attributes.entity_id -%}
          {%- set domain, device = entity_id.split('.') -%}
          {%- if (states[domain][device].state |float < states.input_number.slider1.state |float) -%}
            {{states[domain][device].attributes.friendly_name}} - {{ states[domain][device].state }}
          {%- endif -%}
        {%- endfor -%}

Will do what you want. But play with adding and removing the dashes (‘-’).

Hi klogg,

perfect! That did the trick!

I was wondering what the difference between {% %} and {%- -%} was. Thanks for pointing this out!

Do you also know what the difference between the “>” and “|-” symbols in

 value_template: >
 message: |-

is? Is there some documentation about this that I still haven’t found?


FYI my code is now:

action:
    service: notify.ios_socrates_iphone
    data_template:
      message: |-
        {%- for entity_id in states.group.all_gas_stations.attributes.entity_id -%}
          {%- set domain, device = entity_id.split('.') -%}
          {%- if (states[domain][device].state |float < states.input_number.slider1.state |float) -%}
            {{states[domain][device].attributes.friendly_name}} - {{ states[domain][device].state + " €\n"}}
          {%- endif -%}
        {%- endfor -%}

and the output is:

Score Holtland Diesel - 1.269 €
VELA24 Diesel - 1.319 €
Multi Emden Diesel - 1.289 €

As far as I know, no difference. I always use ‘>’.
I don’t know if it is documented here but if you haven’t seen it, this where I look for all my templating information.

https://jinja.palletsprojects.com/en/2.10.x/templates/

Hi,

I’d like to share my (for now) final version. Maybe it’ll help others.

Some remarks:

  1. The Jinja2 template for the condition didn’t work because it generates multiple “return” values. Ref: Data_template, ios_notify: loop through group and add text if

  2. The “clumsy” OR condition I used afterwards also didn’t work out as I expected. Each time one of the “OR” value templates were “TRUE”, a push message was send. So if all three gas stations Diesel price was below the slider value, three push messages with identical content were generated. Ref: Condition part in this post: Data_template, ios_notify: loop through group and add text if

  3. solution for me now was to add a “min_max” sensor, evaluate the lowest price and use this in the condition to compare against the slider.

Here’s the whole package as it is working right now:

# RefURL: https://www.panbachi.de/tankerkoenig-component-fuer-home-assistant/
# RefURL: https://github.com/panbachi/homeassistant-tankerkoenig
# find gas stations (ID's: https://creativecommons.tankerkoenig.de/TankstellenFinder/index.html

## #############################################################################
## How to add a gas station for monitoring
## 1) add gas station under tankerkoenig -> stations
## 2) restart hass, find new sensor name
## 3) add new sensor name under sensor -> min_max -> entify_ids
## 4) add new sensor name under group -> all_gas_stations
### ############################################################################



tankerkoenig:
  api_key: <my_API_key_goes_here>
  monitored_conditions:
    - diesel
    - state
  stations:
    - id: '6151509b-91c5-43fe-ed78-a5196b38888c'
      name: 'Score Holtland'
      street: 'Leeraner Straße'
      brand: SCORE
    - id: 'c0c4e510-c7b0-46b4-564b-808a6439cc0d'
      name: 'VELA24'
      #street: 'Leeraner Straße'
      brand: VELA
    - id: '839ec92a-1b5c-4989-82bc-5bebac644742'
      name: 'Multi Emden'
      #street: 'Leeraner Straße'
      brand: TANKLOGO




sensor:
  - platform: min_max
    type: min
    name: "Diesel: lowest monitored price"
    entity_ids:
      - sensor.score_holtland_diesel
      - sensor.vela24_diesel
      - sensor.multi_emden_diesel
   

group:
  all_gas_stations:
    name: All Gas Stations
    view: yes
    entities:
      - sensor.score_holtland_diesel
      - sensor.vela24_diesel
      - sensor.multi_emden_diesel



input_number:
  slider1:
    name: Notification Price Diesel
    min: 1.10
    max: 1.50
    step: 0.01
    unit_of_measurement: €
    icon: mdi:currency-eur



automation:
  alias: Diesel Price Monitor
  trigger:
    platform: state
    entity_id: sensor.score_holtland_diesel, sensor.vela24_diesel, sensor.multi_emden_diesel, input_number.slider1

  
  condition:
    condition: template
    value_template: "{{ states('sensor.diesel_lowest_monitored_price') |float < (states('input_number.slider1') |float) }}"

  action:
    service: notify.ios_socrates_iphone
    data_template:
      message: |-
        {%- for entity_id in states.group.all_gas_stations.attributes.entity_id -%}
          {%- set domain, device = entity_id.split('.') -%}
          {%- if (states[domain][device].state |float < states.input_number.slider1.state |float) -%}
            {{states[domain][device].attributes.friendly_name}} - {{ states[domain][device].state + " €\n"}}
          {%- endif -%}
        {%- endfor -%}

Thanks to everyone who helped me to get a better understanding of Jinja templates in Home Assistant!

it’s great that you got it working! :slightly_smiling_face:

Tho I was hoping that there was a fix to the “multiple return values” problem. maybe i’ll have to hit up the templating gurus in another thread…

also, I’m not sure if it’s an issue for you or not in this case but it’s not usually good to put your various api_keys/passwords into your posts.

yes, there’s a difference:
https://yaml-multiline.info

Wow! Thanks for that. It’s taken me over 18 months of using yaml with HA to learn about that.

1 Like

also, I’m not sure if it’s an issue for you or not in this case but it’s not usually good to put your various api_keys/passwords into your posts.

Oops! Yes, that is an issue for me. Thanks for pointing it out. I’ve changed it now, but Google probably has already cached the key anyway :upside_down_face: