Use for loops to get a notification for each device with low battery and the battery type

Hi I haven’t used for loops before, so this is a first for me, I have parts of this working, but a bit stumped stumped as to how to finish this off.
What I’m looking to achieve is to receive a notification for each device that has low battery the and what type of battery/ies it takes.

Any help appreciated :+1:

  alias: device_low_batt
  trigger:

    - platform: time
      at:
        - '10:00:00'
        - '17:00:00'
      id: time_trigger

    - platform: template
      value_template: >-
        {% set low_batt_device = states.sensor
          | selectattr('attributes.device_class', 'eq', 'battery')
          | selectattr("state", "is_number")
          | selectattr("state", "<=", "20")
          | rejectattr("entity_id", "search", ".*_zwave")
          | rejectattr("entity_id", "search", ".*iphone*") | list %}
        {{ low_batt_device | count > 0 }}
      id: low_batt_trigger

  mode: parallel
  action:
    - variables:

        type_aa_x2: >-
          {{ expand("sensor.wiser_roomstat_hallway_battery_level",
             "sensor.wiser_itrv_bathroom_battery_level",
             "sensor.wiser_itrv_bedroom_battery_level",
             "sensor.wiser_itrv_living_room_battery_level")
             | map(attribute="entity_id") | list }}

        type_aa_x4: >-
          {{ expand("sensor.cat_flap_battery_level")
             | map(attribute="entity_id") | list }}

        type_cr123a: >-
          {{ expand("sensor.hallway_smoke_detector_battery_level",
             "sensor.living_room_smoke_detector_battery_level",
             "sensor.front_door_lock_battery_level")
             | map(attribute="entity_id") | list }}

        type_cr1632: >-
          {{ expand("sensor.mailbox_door_battery_level",
             "sensor.wardrobe_door_battery_level")
             | map(attribute="entity_id") | list }}

        type_cr2: >-
          {{ expand("sensor.front_door_recessed_battery_level")
             | map(attribute="entity_id") | list }}

        type_cr2032: >-
          {{ expand("sensor.sideboard_battery_level",
             "sensor.mailbox_vibration_battery_level",
             "sensor.bath_shower_leak_battery_level",
             "sensor.sink_taps_leak_battery_level",
             "sensor.toilet_leak_battery_level",
             "sensor.bathroom_fan_shortcut_button_battery_level",
             "sensor.table_lamp_remote_battery_level",
             "sensor.desk_lamp_remote_battery_level")
             | map(attribute="entity_id") | list }}

        type_cr650: >-
          {{ expand("sensor.bath_mixer_battery_level")
             | map(attribute="entity_id") | list }}

        # Append friendly name with "sensor"
        append_with_sensor: >-
          {{ expand("sensor.sideboard_battery_level", 
             "sensor.bath_mixer_battery_level",
             "sensor.mailbox_vibration_battery_level",
             "sensor.mailbox_door_battery_level",
             "sensor.front_door_recessed_battery_level",
             "sensor.bath_shower_leak_battery_level",
             "sensor.sink_taps_leak_battery_level",
             "sensor.toilet_leak_battery_level",
             "sensor.wardrobe_door_battery_level")
             | map(attribute="entity_id") | list }}

        # Append friendly name with "thermostatic valve"
        append_with_thermostatic_valve: >-
          {{ expand("sensor.wiser_itrv_hallway_battery_level",
             "sensor.wiser_itrv_bathroom_battery_level",
             "sensor.wiser_itrv_bedroom_battery_level",
             "sensor.wiser_itrv_kitchen_battery_level",
             "sensor.wiser_itrv_living_room_battery_level")
             | map(attribute="entity_id") | list }}        

        # Append friendly name with "thermostat"
        append_with_thermostat: >-
          {{ expand("sensor.wiser_roomstat_hallway_battery_level")
             | map(attribute="entity_id") | list }}


    - service: notify.mobile_app_iphone
      data_template:
        title: Replace Battery
        message:
          {% for low_batt_device in states.sensor
             | selectattr('attributes.device_class', 'eq', 'battery')
             | selectattr("state", "is_number")
             | selectattr("state", "<=", "20")
             | rejectattr("entity_id", "search", ".*_zwave")
             | rejectattr("entity_id", "search", ".*iphone*") %}
            {% if 0 <= low_batt_device.state | int(-1) %}
              {% if low_batt_device in append_with_sensor %}
                The {{ low_batt_device.attributes.friendly_name.split(" battery level")[0] }} sensor battery is at {{ low_batt_device.state }}%, the battery type is {% if low_batt_device in type_aa_x2 %}AA x2{% elif low_batt_device in type_aa_x4 %}AA x4{% elif low_batt_device in type_cr123a %}CR123A{% elif low_batt_device in type_cr1632 %}CR1632{% elif low_batt_device in type_cr2 %}CR2{% elif low_batt_device in type_cr2032 %}CR2032{% elif low_batt_device in type_cr650 %}CR650{% endif %}.
              {% elif low_batt_device in append_with_thermostatic_valve %}
                The {{ low_batt_device.attributes.friendly_name.split("Wiser iTRV ")[1].split(" Battery")[0] }} thermostatic valve battery is at {{ low_batt_device.state }}%, the battery type is {% if low_batt_device in type_aa_x2 %}AA x2{% elif low_batt_device in type_aa_x4 %}AA x4{% elif low_batt_device in type_cr123a %}CR123A{% elif low_batt_device in type_cr1632 %}CR1632{% elif low_batt_device in type_cr2 %}CR2{% elif low_batt_device in type_cr2032 %}CR2032{% elif low_batt_device in type_cr650 %}CR650{% endif %}.
              {% elif low_batt_device in append_with_thermostat %}
                The {{ low_batt_device.attributes.friendly_name.split("Wiser RoomStat ")[1].split(" Battery")[0] }} thermostat battery is at {{ low_batt_device.state }}%, the battery type is {% if low_batt_device in type_aa_x2 %}AA x2{% elif low_batt_device in type_aa_x4 %}AA x4{% elif low_batt_device in type_cr123a %}CR123A{% elif low_batt_device in type_cr1632 %}CR1632{% elif low_batt_device in type_cr2 %}CR2{% elif low_batt_device in type_cr2032 %}CR2032{% elif low_batt_device in type_cr650 %}CR650{% endif %}.
              {% else %}
                The {{ low_batt_device.attributes.friendly_name.name.split(" battery level")[0] }} battery is at {{ low_batt_device.state }}%, the battery type is {% if low_batt_device in type_aa_x2 %}AA x2{% elif low_batt_device in type_aa_x4 %}AA x4{% elif low_batt_device in type_cr123a %}CR123A{% elif low_batt_device in type_cr1632 %}CR1632{% elif low_batt_device in type_cr2 %}CR2{% elif low_batt_device in type_cr2032 %}CR2032{% elif low_batt_device in type_cr650 %}CR650{% endif %}.
              {% endif %}
            {% endif %}
          {% endfor %}

Personally, I find it quite useful to give the battery sensors their own attribute “battery_type”. This way you can see in the frontend which battery is needed and you can use the attribute in templates:

# /config/customize.yaml

sensor.bewegungsmelder_flur_battery_level:
  battery_type: CR2032
sensor.lux_battery_level:
  battery_type: CR2450
sensor.tradfri_blind:
  battery_type: IKEA Braunit

Your automation then could look like this:


# Condition

{{ states.sensor
  |selectattr('attributes.device_class', 'eq', 'battery')
  |rejectattr('entity_id', 'search', 'zwave|iphone')
  |map(attribute='state')
  |map('int', 0)
  |select('<', 40)
  |list
  |count != 0
}}


# Message

{% for state in states.sensor  
|selectattr('attributes.device_class', 'eq', 'battery')
|rejectattr('entity_id', 'search', 'zwave|iphone')
-%}

{% if state.state |int(0) <= 40 and state.state not in ['unavailable', 'unknown', 'none'] -%}
  The {{ state.attributes.friendly_name |replace(' Battery Level', ' sensor battery') |replace('Battery', 'sensor battery') }} 
is at {{ state.state }}%, the battery type is {{ state.attributes.battery_type }}.
{% endif %}
{%- endfor -%}

2 Likes

Thanks, that’s a good tip to add the attribute battery_type :+1:

Could you please post the entire battery level automation?

Thank you!