YAML config nested {% if %} statements - help? battery_alert.yaml [given up]

Yes, thanks for posting outdated code that doesn’t include anything discussed in this thread of PR that I’ve linked many times.

Actually, nevermind. I give up.

What is in my PR already worked for me personally, and I was just trying to add an on/off switch for other people who wanted to see unknown devices for troubleshooting.

I didn’t think it would be this difficult.

My apologies. I’ll bow out of this conversation…

Its ok, its been a long day. Have a good weekend.

I did start looking at the code in your PR. I will extract the automation part and create an automation from it and see where I get to… Sorry for missing the point originally, it’s been a long week and I’m a little under the weather…

Hey, if you want to test, you should only need to create a <config_dir>/packages/battery_alert.yaml file and dump the contents from the PR file here into that.

That should already work as a basis with alerts etc.
The file itself has updated instructions to access it in Lovelace etc.

After that, you can use the code updates from this thread to supplant the scripts on lines 494 and 528 (of the same file) to see what I’m talking about.

Good luck.

Rather than disturbing my installed & working package, I was just going to create your automation manually and trigger it manually:

- alias: battery_persistent_notification
  initial_state: 'on'
  trigger:
    - platform: time_pattern
      minutes: '/15'
      seconds: 00
    - platform: state
      entity_id:
        - input_number.battery_alert_threshold_min
        - input_number.battery_alert_threshold_max
  action:
    - condition: template
      value_template: &low_battery_check >
        {% macro battery_level() %}
        {% for entity_id in states.group.battery_status.attributes.entity_id if (
            not (
                  is_state_attr(entity_id, 'battery_alert_disabled', true)
                  or is_state_attr(entity_id, 'restored', true)
                )
          and states(entity_id) is not none
          and (
            (
              (
                states(entity_id) is number
                or states(entity_id) | length == states(entity_id)| int | string | length
                or states(entity_id) | length == states(entity_id)| float | string | length
              )
              and states(entity_id) | int < states.input_number.battery_alert_threshold_max.state | int
              and states(entity_id) | int > states.input_number.battery_alert_threshold_min.state | int
            )
            or states(entity_id) | lower == 'low'
            or states(entity_id) | lower == 'unknown'
            or states(entity_id) | lower == 'unavailable'
          )
        ) -%}
          {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
        {% endfor -%}
        {% endmacro %}
        {{ battery_level() | trim != "" }}
    - service: input_boolean.turn_on
      data:
        entity_id: input_boolean.low_batteries
    - service: persistent_notification.create
      data_template:
        title: "Low Battery Levels"
        notification_id: low_battery_alert
        message: &message >
          {% macro battery_level() %}
          {% for entity_id in states.group.battery_status.attributes.entity_id if (
            not (
                  is_state_attr(entity_id, 'battery_alert_disabled', true)
                  or is_state_attr(entity_id, 'restored', true)
                )
            and states(entity_id) is not none
            and (
              (
                (
                  states(entity_id) is number
                  or states(entity_id) | length == states(entity_id)| int | string | length
                  or states(entity_id) | length == states(entity_id)| float | string | length
                )
                and states(entity_id) | int < states.input_number.battery_alert_threshold_max.state | int
                and states(entity_id) | int > states.input_number.battery_alert_threshold_min.state | int
              )
              or states(entity_id) | lower == 'low'
              or states(entity_id) | lower == 'unknown'
              or states(entity_id) | lower == 'unavailable'
            )
          ) -%}
            {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
          {% endfor -%}
          {% endmacro %}
          {{ battery_level() }}

I replaced the batteries in my water timer with the old batteries (26%) that I recently replaced.
The original battery_alert.yaml persistent notification automation triggered an alert right away.
Your automation above when I executed it put this into my log:

2020-11-07 11:27:09 INFO (MainThread) [homeassistant.components.automation.new_automation] New Automation: Test condition template: False

Remind me again what it is you are trying to fix?

Here you go!!! I painstakingly converted @petro 's template code and debugged the required jinja syntax. When I execute the Test Automation with the revised code, I get an alert!

{%- set ns = namespace(results=[]) %}
{% macro battery_level() %}
{%- for entity_id in expand('group.battery_status') %}
  {%- if entity_id.state in ['unknown', 'unavailable'] and input_boolean.show_unavailable_batteries and not (entity_id.attributes.battery_alert_disabled or entity_id.attributes.restored) %}
    {%- set ns.results = ns.results + [  entity_id.name ~ ' ' ~ entity_id.state ] %}
  {%- else %}
    {%- if entity_id.state.lower() in ['low', 'medium', 'high'] %}
      {%- if entity_id.state.lower() == 'input_number.battery_alert_threshold_min' %}
        {%- set ns.results = ns.results + [ entity_id.name ~ ' ' ~ entity_id.state ] %}
      {%- endif %}
    {%- elif (states.input_number.battery_alert_threshold_min.state|float) <  (entity_id.state|float) < (states.input_number.battery_alert_threshold_max.state|float) %}
      {%- set ns.results = ns.results + [ entity_id.name ~ ' ' ~ entity_id.state ] %}
    {%- endif %}
  {%- endif %}
{%- endfor %}
{{ ns.results | join(', ') }}{% endmacro %}
        {{ battery_level() | trim != "" }}

Test Automation:

alias: Test Automation
trigger:
  - platform: time_pattern
    minutes: /15
    seconds: '0'
  - platform: state
    entity_id:
      - input_number.battery_alert_threshold_min
      - input_number.battery_alert_threshold_max
action:
  - condition: template
    value_template: >
      {%- set ns = namespace(results=[]) %} {% macro battery_level() %} {%- for
      entity_id in expand('group.battery_status') %}
        {%- if entity_id.state in ['unknown', 'unavailable'] and input_boolean.show_unavailable_batteries and not (entity_id.attributes.battery_alert_disabled or entity_id.attributes.restored) %}
          {%- set ns.results = ns.results + [  entity_id.name ~ ' ' ~ entity_id.state ] %}
        {%- else %}
          {%- if entity_id.state.lower() in ['low', 'medium', 'high'] %}
            {%- if entity_id.state.lower() == 'input_number.battery_alert_threshold_min' %}
              {%- set ns.results = ns.results + [ entity_id.name ~ ' ' ~ entity_id.state ] %}
            {%- endif %}
          {%- elif (states.input_number.battery_alert_threshold_min.state|float) <  (entity_id.state|float) < (states.input_number.battery_alert_threshold_max.state|float) %}
            {%- set ns.results = ns.results + [ entity_id.name ~ ' ' ~ entity_id.state ] %}
          {%- endif %}
        {%- endif %}
      {%- endfor %} {{ ns.results | join(', ') }}{% endmacro %} {{
      battery_level() | trim != "" }}
  - service: input_boolean.turn_on
    data:
      entity_id: input_boolean.low_batteries
  - service: persistent_notification.create
    data_template:
      title: Low Battery Levels
      notification_id: low_battery_alert
      message: >
        {% macro battery_level() %} {% for entity_id in
        states.group.battery_status.attributes.entity_id if (
          not (
                is_state_attr(entity_id, 'battery_alert_disabled', true)
                or is_state_attr(entity_id, 'restored', true)
              )
          and states(entity_id) is not none
          and (
            (
              (
                states(entity_id) is number
                or states(entity_id) | length == states(entity_id)| int | string | length
                or states(entity_id) | length == states(entity_id)| float | string | length
              )
              and states(entity_id) | int < states.input_number.battery_alert_threshold_max.state | int
              and states(entity_id) | int > states.input_number.battery_alert_threshold_min.state | int
            )
            or states(entity_id) | lower == 'low'
            or states(entity_id) | lower == 'unknown'
            or states(entity_id) | lower == 'unavailable'
          )
        ) -%}
          {{ state_attr(entity_id, "friendly_name") }} ({{ states(entity_id) }})
        {% endfor -%} {% endmacro %} {{ battery_level() }}
initial_state: 'on'
mode: single


Alert

I’m not sure if 'input_number.battery_alert_threshold_min' should be states.input_number.battery_alert_threshold_min.state or not. I’m not sure how that section of the code is supposed to function. If entity_id.state is ‘low’, ‘medium’ or ‘high’, it will never compare against input_number.battery_alert_threshold_min since that state is a string from “0” to “100”. input_number will not let you enter "Low’, "Medium’ or 'High.
The troublesome part was the next elif. That was the part that was returning False for me until I figured out the correct syntax.

You don’t need the macro, it does nothing. And the last line does nothing either. Also, you have a lot of errors that make the added unavailable flag do nothing. The template as written changes the outputs. I wish I would have been told that this was needed for a condition to move forward. For a condition to send the message…

condition

{%- set show_unavailable = ( states.input_boolean.show_unavailable_batteries.state == 'on' ) %}
{%- set high = states('input_number.battery_alert_threshold_max') | float %}
{%- set low = states('input_number.battery_alert_threshold_min') | float %}
{%- set ns = namespace(cnt=0) %}
{%- for s in expand('group.battery_status') %}
  {%- if s.state in ['unknown', 'unavailable'] and show_unavailable and not (s.attributes.battery_alert_disabled or s.attributes.restored) %}
    {%- set ns.cnt = ns.cnt + 1 %}
  {%- else %}
    {%- if s.state.lower() in ['low', 'medium', 'high'] %}
      {%- if s.state.lower() == 'low' %}
        {%- set ns.cnt = ns.cnt + 1 %}
      {%- endif %}
    {%- elif low <  s.state | float < high %}
      {%- set ns.cnt = ns.cnt + 1 %}
    {%- endif %}
  {%- endif %}
{%- endfor %}
{{ ns.cnt > 0 }}

And for a message, it appears you guys don’t want comma separated values…

message

{%- macro fmat(obj) %}{{ obj.name }} ({{obj.state}}){% endmacro -%}
{%- set show_unavailable = ( states.input_boolean.show_unavailable_batteries.state == 'on' ) %}
{%- set high = states('input_number.battery_alert_threshold_max') | float %}
{%- set low = states('input_number.battery_alert_threshold_min') | float %}
{%- set ns = namespace(results=[]) %}
{%- for s in expand('group.battery_status') %}
  {%- if s.state in ['unknown', 'unavailable'] and show_unavailable and not (s.attributes.battery_alert_disabled or s.attributes.restored) %}
    {%- set ns.results = ns.results + [ fmat(s) ] %}
  {%- else %}
    {%- if s.state.lower() in ['low', 'medium', 'high'] %}
      {%- if s.state.lower() == 'low' %}
        {%- set ns.results = ns.results + [ fmat(s) ] %}
      {%- endif %}
    {%- elif low <  s.state | float < high %}
      {%- set ns.results = ns.results + [ fmat(s) ] %}
    {%- endif %}
  {%- endif %}
{%- endfor %}
{{ ns.results | join('\n') }}

I agree the macro portion is not necessary. I’m not sure what he wants. The original add-on is working fine for me. Something about show_unavailable_batteries? I simply converted your suggested code to work in an automation…

Are you the author of the original code?

Yes but you broke the functionality he was aiming after.

This isn’t valid, you have to wrap that in states(‘’) and check it against ‘on’ or use is_state()

It’s not erroring out for you because

this always resolves to false on your system.

Then later in the automation, you don’t include the unavailable states.

I am not, that’s why I don’t know what the expected output for the message is. OP is claiming it doesn’t work, yet when you and I tried it, it worked.

Typo in the above:
{%- if entity_id.state.lower() in ['low', 'medium', 'high'] %}
should be
{%- if s.state.lower() in ['low', 'medium', 'high'] %}

This is working for me but I do not have any unavailable’s for testing…

alias: Battery Persistent Notification - Test New Condition Template
trigger:
  - platform: time_pattern
    minutes: /15
    seconds: '0'
  - platform: state
    entity_id:
      - input_number.battery_alert_threshold_min
      - input_number.battery_alert_threshold_max
action:
  - condition: template
    value_template: >-
      {%- set show_unavailable = (
      states.input_boolean.show_unavailable_batteries.state == 'on' ) %}

      {%- set high = states('input_number.battery_alert_threshold_max') | float
      %}

      {%- set low = states('input_number.battery_alert_threshold_min') | float
      %}

      {%- set ns = namespace(cnt=0) %}

      {%- for s in expand('group.battery_status') %}
        {%- if s.state in ['unknown', 'unavailable'] and show_unavailable and not (s.attributes.battery_alert_disabled or s.attributes.restored) %}
          {%- set ns.cnt = ns.cnt + 1 %}
        {%- else %}
          {%- if s.state.lower() in ['low', 'medium', 'high'] %}
            {%- if s.state.lower() == 'low' %}
              {%- set ns.cnt = ns.cnt + 1 %}
            {%- endif %}
          {%- elif low <  s.state | float < high %}
            {%- set ns.cnt = ns.cnt + 1 %}
          {%- endif %}
        {%- endif %}
      {%- endfor %}

      {{ ns.cnt > 0 }}
  - service: input_boolean.turn_on
    data:
      entity_id: input_boolean.low_batteries
  - service: persistent_notification.create
    data_template:
      title: Low Battery Levels
      notification_id: low_battery_alert
      message: >
        {%- macro fmat(obj) %}{{ obj.name }} ({{obj.state}}){% endmacro -%} {%-
        set show_unavailable = (
        states.input_boolean.show_unavailable_batteries.state == 'on' ) %} {%-
        set high = states('input_number.battery_alert_threshold_max') | float %}
        {%- set low = states('input_number.battery_alert_threshold_min') | float
        %} {%- set ns = namespace(results=[]) %} {%- for s in
        expand('group.battery_status') %}
          {%- if s.state in ['unknown', 'unavailable'] and show_unavailable and not (s.attributes.battery_alert_disabled or s.attributes.restored) %}
            {%- set ns.results = ns.results + [ fmat(s) ] %}
          {%- else %}
            {%- if s.state.lower() in ['low', 'medium', 'high'] %}
              {%- if s.state.lower() == 'low' %}
                {%- set ns.results = ns.results + [ fmat(s) ] %}
              {%- endif %}
            {%- elif low <  s.state | float < high %}
              {%- set ns.results = ns.results + [ fmat(s) ] %}
            {%- endif %}
          {%- endif %}
        {%- endfor %} {{ ns.results | join('\n') }}
initial_state: 'on'
mode: single

@plonka2000 Can you test??