Notification on Low Battery Levels

Hello,

I just realized that my motion detector in the kitchen was dead - I happen to be on my maintenance tab of HA that has a group of battery levels and kitchen has been at 0% for 12 days. I’ve been meaning to write a notification automation and finally got around to it.

The notification runs every 24 hours and notifies me if my battery reporting devices are low. I have a group setup that contains all the battery sensors and my automation iterates over that group.

The group

battery_levels:
  name: Battery Levels
  entities:
    - sensor.foyer_coat_closet_door_battery
    - sensor.laundry_room_door_battery
    - sensor.kitchen_motion_battery
    - sensor.foyer_motion_battery
    - sensor.living_room_motion_battery

The automation

- id: notify_if_batteries_are_low
  alias: Notification- Alert That Batteries Are Low
  initial_state: 'on'
  trigger:
    - platform: time
      at: '19:00:00'
  condition:
    condition: or
    conditions:
      - condition: template
        value_template: >
          {% set min_battery_level = 10 -%}
          {% set ns = namespace(found=false) -%}
          {% for entity_id in states.group.battery_levels.attributes.entity_id -%}
            {% set parts = entity_id.split('.') -%}
            {% if (states(entity_id) | replace("%","") | int) < min_battery_level -%}
              {% set ns.found = true -%}
            {% endif -%}
          {% endfor -%}
          {{ ns.found }}
  action:
    - service: notify.with_discord
      data_template:
        target: !secret discord_room_general
        message: >
          {%- set min_battery_level = 10 -%}
          {%- for entity_id in states.group.battery_levels.attributes.entity_id -%}
            {%- set parts = entity_id.split('.') -%}
            {%- if (states(entity_id) | replace("%","") | int) < min_battery_level -%}
              {{ states[parts[0]][parts[1]].name }} battery level is {{ states(entity_id) }}.{{ '\n' }}
            {%- endif -%}
          {%- endfor -%}
9 Likes

This is what I use; and the benefit is no group required… you can change the states.zwave to states if you have some sensors you also want to include.

This is a script I run every 6 hours.

zwave_battery_check:
  alias: Zwave Battery Check

  sequence:
    - condition: template
      value_template: >-
        {%- set battery_alert_threshold = 40|int -%}
        {{ states.zwave | selectattr('attributes.battery_level', 'defined') | selectattr('attributes.battery_level','<', battery_alert_threshold ) | list | count >= 1 }}

    - wait_template: "{{ is_state('script.notify_all_engines' , 'off') }}"

    - service: script.notify_all_engines
      data_template:
        title: "ZWAVE Low Battery"
        who: "john"
        message: >-
          {%- set battery_alert_threshold = 40|int -%}
          {%- set low_batteries = states.zwave | selectattr('attributes.battery_level', 'defined') | selectattr('attributes.battery_level','<', battery_alert_threshold ) | map(attribute='name') | list | join(', ') -%}
          Low batteries in the following devices: {{ low_batteries }}
10 Likes

Thanks for sharing; much cleaner approach!

I overlooked selectattr when reading the documentation, didn’t know we could use that as filter. An example like this should be added into the HA documentation because it shows the power of combining multiple filters in Jinja2.

Thanks for sharing your code.

I have one sensor which has a battery and is wired powered. While wire powered the batter_level value is a constant 4. How do I dismiss of that sensor?

This does not work

 | selectattr('attributes.battery_level','<>', '4.0')
 | reject('attributes.battery_level', '==', '4.0')
 | reject('attributes.battery_level', '=', '4.0')
 | rejectattr('battery_level','4')

Is it zwave or some other type?

It’s a Zwave device.

This works for skipping a sensor with a state level ( = 4) from the list off devices:

{% set battery_alert_threshold = 25|int %}
{% set low_batteries = states.zwave
| selectattr(‘attributes.battery_level’, ‘defined’)
|rejectattr(‘attributes.battery_level’, ‘==’, 4)
| selectattr(‘attributes.battery_level’,‘<’, battery_alert_threshold )
| map(attribute=‘name’)
| list | join(', ') %}

Unfortunately it is not working anymore. Has anyone adapted the code?

It works for me still under 102.3 and 103.0 - what errors are you getting?

@gabrielmiranda it works for me still too, what version of HA are you using?

Can you help with the script?Where must i put it and how i can trigger it.I am new at HA.Thanks.

What does your script.notify_all_engines look like? And how are you notifying “john”?

notify_all_engines:
  sequence:
    - service: persistent_notification.create
      data_template:
        title: >-
          {{ title }}
        message: >-
          {{ message }}
        notification_id: >-
          {{ title }}

    - service: logbook.log
      data_template:
        name: "NOTIFY ALL:"
        message: >-
          {{ message }}

    - service_template: >-
        {%- if who is not string -%}{%- set who = 'john' -%}{%- endif -%}
        {%- if who == 'john' -%}
          notify.mobile_app_johns_iphone
        {%- elif who == 'kim' -%}
          notify.mobile_app_kimberleys_iphone
        {%- elif who == 'family' -%}
          notify.family
        {%- elif who == 'parents' -%}
          notify.parents
        {%- elif who == 'kids' -%}
          notify.kids
        {%- elif who == 'xx' -%}
          notify.mobile_app_notify_xx
        {%- else -%}
          notify.mobile_app_notify_yy
        {%- endif -%}
      data_template:
        title: "Home Assistant Notify ALL"
        message: >-
          {{ message }}
1 Like

Based on the submission of @jwelter, I tried something for myself.
This automation reports all battery levels in a single notification.
I use this automation for Telegram notifications, so that’s why all entities in a single notification is fine for me.

I configured this automation in the Home Assistant frontend.

Trigger
Trigger type: Time
At: 19:00

Condition
Condition type: Template
Value template:

{%- set battery_alert_threshold = 10 | int -%}
{{ states | selectattr('attributes.battery_level', 'defined') | selectattr('attributes.battery_level','<=', battery_alert_threshold ) | list | count >= 1 }}

Action
Action type: Call service
Service: notify.telegram_mychatbot
Service data:

message: >-
  {%- set ns = namespace(message = 'The battery level of the following device(s) is low:\n') -%}
  {%- set battery_alert_threshold = 10 | int -%}
  {%- set low_batteries = states |
  selectattr('attributes.battery_level', 'defined') |
  selectattr('attributes.battery_level','<=', battery_alert_threshold ) -%} 
  {%- for battery in low_batteries -%}
  {%- set ns.message = ns.message + '- ' + battery.name + ' (' + (battery.attributes.battery_level | round(0) | string) + '%)\n' -%}
  {%- endfor -%}
  {{ ns.message }}
title: '*Home Assistant - Battery level report*'

You can set the value of battery_alert_threshold in the condition and in the action to the percentage of your liking.

The notification will look something like this:

Home Assistant - Battery level report
The battery level of the following device(s) is low:
– Bedroom Cube (4%)
– Bedroom Temperature Sensor (9%)

I hope that this helps someone who wants to achieve the same :grin:

4 Likes

How to find ikea batteries such as sensor.0x588e81fffe11693e_battery?

@jwelter Great use of states, selectattr(), list and map(), love it! Thanks for sharing!

Another Possibility - lovelace-auto-entities by Thomas Loven with configuration like this:

  - type: custom:auto-entities
    show_empty: false
    card:
      type: entities
      title: Battery Sensors
      show_header_toggle: false
      state_color: true
    filter:
      include:
        - entity_id: "*battery*"
          sort:
            method: state
            numeric: true
            ignore_case: true
      exclude:
        - entity_id: "*time*"
        - entity_id: "*temperature*"
        - entity_id: "*mbp*"
        - entity_id: "*ipad_battery_state*"
        - entity_id: "*shenzhen*"
        - name: "Ups*"

Hi @MrNick4B - that looks awesome (and working in part for me!) - newbie here and learning from the community posts and lots and lots of trail and error, perhaps you can point me in the right way.

Cut and pasted your automation in and got it running fine, using SMTP email notification and they’re coming through. I have three battery devices, one through the mobile integration and the other two through deconz integration.

For the notification I can only get it to output the battery from the mobile as a line entry on the body of the text, I can trigger the automation from the other devices (by charging the mobile and tweaking the parameters thus ensuring the condition is checking the others), but for the life of me can’t see why they won’t spring up on the notification!!

Any words of wisdom happy to receive!!! (any appropriate config I’m equally happy to post!)

Thanks

Edit: so I can get them out on a message - trying to learn a bit more each time

{% for state in states.sensor -%}
  {{ state.name | lower }} is {{state.state_with_unit}}
{%- endfor %}

The batteries are coming out - back to unpicking the original message

So I’ve had to comprise for now, using the original automation posted the condition works fine but can’t get the ‘conditionality’ in the message to work and the devices to pop up. In the end gone with they’ll all be listed but had to use state.sensor and battery device_class to get them but this has the effect of not being able to do the test of the battery_level.

if anyone stumbles across this and has some ideas - all welcome!

- id: '1596277325558'
  alias: Auto - Low Battery Warning
  description: ''
  trigger:
  - at: '20:30'
    platform: time
  condition:
  - condition: template
    value_template: '{%- set battery_alert_threshold = 20 | int -%}
      {{ states | selectattr(''attributes.battery_level'', ''defined'') | selectattr(''attributes.battery_level'',''<='',
      battery_alert_threshold ) | list | count >= 1 }}'
  action:
  - data:
      message: '{%- set ns = namespace(message = ''Some devices have low battery:\n'')
        -%} {%- set battery_alert_threshold = 20 | int -%} {%- set low_batteries =
        states.sensor | selectattr(''attributes.device_class'', ''eq'', ''battery'')
        -%}  {%- for battery in low_batteries -%} {%- set ns.message = ns.message
        + ''- '' + battery.name + '' '' + battery.state + '' \n'' -%} {%- endfor -%}
        {{ ns.message }}'
      title: '** Home Assistant - Battery Level Report **'
    service: notify.email
  mode: single

So, again some more headaches and resolution. My challenge with this (and I was misled by the other posts because I didn’t understand it) was my devices didn’t have a battery level attribute but infact had an entity of battery level.

In the end I’ve looked for the word “battery” in the sensor name (given the only ones with battery in the name are battery level entities) and worked around that. I’m sure there’s a better way to do it (always open to suggestions) but for the moment this working out okay for me…

- id: '1596277325558'
  alias: System - Low Battery Warning
  description: ''
  trigger:
  - at: '19:00'
    platform: time
  condition:
  - condition: template
    value_template: "{%- set ns = namespace(message = false) -%}\n{%- set threshold\
      \ = 20 -%}\n{%- for item in states.sensor -%}\n{%- if \"battery\" in item.name\
      \ | lower and item.state | int < threshold and\n  item.state|int != 0 -%}\n\
      {%- set ns.message = (true) -%}\n{%- endif -%} \n{%- endfor -%} \n{{ ns.message\
      \ }}"
  action:
  - data:
      message: '{%- set ns = namespace(message = ''The battery level of the following
        device(s) is low:\n'') -%} {%- set threshold = 20 -%} {%- for item in states.sensor
        -%} {%- if "battery" in item.name | lower and item.state | int < threshold
        and item.state|int != 0 -%} {%- set ns.message = ns.message + '' - '' + item.name
        + '' ('' + item.state + ''%)\n'' -%} {%- endif -%} {%- endfor -%} {{ ns.message
        }}'
      title: '** Home Assistant - Battery Level Warning **'
    service: notify.email
  - data:
      message: '{%- set ns = namespace(message = ''The battery level of the following
        device(s) is low:\n'') -%} {%- set threshold = 20 -%} {%- for item in states.sensor
        -%} {%- if "battery" in item.name | lower and item.state | int < threshold
        and item.state|int != 0 -%} {%- set ns.message = ns.message + '' - '' + item.name
        + '' ('' + item.state + ''%)\n'' -%} {%- endif -%} {%- endfor -%} {{ ns.message
        }}'
    service: notify.mobile_app_mike_wood_iphonex
  mode: single

Note: I created these through the UI which is why the formal isn’t as clean as hand crafted!

1 Like