Monitoring/alarming system for battery powered devices

This community gave me such a lot of information and knowledge… time to strike back. :wink:

Hereby I want to share my solution for monitoring battery powered devices and alarming if necessary.
I read a lot about this in several posts but I did not find the full solution I had in mind. So I tried to put all the pieces together for my own purposes. Maybe it’s helpful for others too.

Problem
How do I know, when a battery runs dry?

Simple solution
Create an automation and trigger it using the battery sensor of the device.
Create another automation for the next device.
Create another automation for the next device.
…and so on
I started with this but I don’t like it anymore. Too much automations to set up, too much work. And every time you add or remove a device you have to do the same work again and again and again…

Objective
Create a fully automated system for monitoring and alarming low battery levels.

Requirements

  • fully automated, once the setup is done it runs without any further interaction for any device, even when added in future
  • possibility for customization (but should run without customization too)

Constraints
There must be a sensor… well, where else should we know from. Usually every battery powered smarthome device should have a sensor for the battery level. If not… maybe look for another device. :wink:

Solution
Fortunately Home Assistant has device classes and all the sensors of my devices which are busy reporting the battery level have the device class “battery”. Sounds reasonable, we can work with this.

Here it is:

automation:
  - id: "battery_level_check"
    alias: "Energy: Check battery level for all devices"
    mode: restart
    trigger:
      - platform: time
        at: "16:00"
    action:
      - service: script.battery_level_check_multi

script:
  battery_level_check_multi:
    alias: "Energy: Check battery level for all devices"
    mode: queued
    sequence:
      - repeat:
          # get alle entities with device class "battery"
          for_each: "{{ states.sensor | selectattr('attributes.device_class', 'eq', 'battery') | map(attribute='entity_id') | list }}"
          sequence:
            - service: script.battery_level_check_single
              data:
                entity: "{{ repeat.item }}"

  battery_level_check_single:
    alias: "Energy: Check battery level for one device"
    mode: queued
    sequence:
      # check if 'entity' is set and a real entity
      - condition: template
        value_template: "{{ entity is defined and states(entity) != 'unknown' }}"
      # check if battery level is below 'battery_min'
      - condition: template
        value_template: "{{ states(entity) | int(0) <= state_attr(entity, 'battery_min') | int(30) }}"
      # send message
      - service: script.message_warning_battery
        data_template:
          device: "{{ device_attr(entity, 'name_by_user') }}"
          description: "{{ area_name(entity) }}"
          battery: "{{ states(entity) | int(0) }}"
          type: "{{ state_attr(entity, 'battery_needed') if state_attr(entity, 'battery_needed') != none else '<unknown>' }}"

The real magic happens in the template behind “for each:”.
It’s of course possible to compact all the code into one big automation but for clarity reasons I decided to split it into the triggering automation and the two scripts.

The messaging script “script.message_warning_battery” turns everything into a Pushover message but this is not the scope of this post. Feel free to adapt it to your needs.

Customization
The threshold when to alarm a battery level and a useful information about the type of battery needed can be customized using the file ‘customize.yaml’.
An entry there could look like this:

sensor.devicexyz_battery_level:
  battery_needed: "2 x AAA"
  battery_min: 40

You need the entity of the battery level sensor. The battery type is a simple text, put in whatever you may find reasonable, the “battery_min” value is in percent and is compared against the state of the battery level entity.
If those customized values are not defined, the script defaults to “unknown” and 30%.

What’s left
I had to learn that some of my devices silently break down because of an empty battery. But the last sensor value was far above the threshold. Obviously the battery sensor values are not always as accurate as I wish.
The herewith proposed solution will never find those devices since the battery level looks good forever in this case.

In the next days I will introduce another solution to find those devices too.

1 Like

This looks interesting.

It’s two different items, correct? One automation and one script?

I monitor my battery levels but I also monitor unavailable entities too - “belt & suspenders” approach because I don’t trust device battery reporting.

1 Like

One automation and actually two scripts as you can see in the YAML code.