What do you need before you start?
- Battery-powered devices already in Home Assistant: Zigbee, Z-Wave, Thread or Bluetooth door sensors, motion sensors, leak sensors, smart locks, thermostats' radiator valves and similar. If you are still choosing sensors, our smart window sensor guide and temperature and humidity sensor roundup cover popular battery-powered options.
- Phone notifications set up: the Companion app is the easy route. If you have not done this yet, follow the Home Assistant notifications guide first.
- Access to the automation YAML editor: every example below is pasted straight into Settings → Automations & Scenes → Create automation → Edit in YAML.
How does Home Assistant know a battery is low?
Home Assistant uses two different signals depending on the device, and a complete alert has to cover both. Most integrations expose a numeric sensor with the battery device class, which reports the battery level as a percentage (Home Assistant sensor docs).
A smaller group of devices, including some smoke alarms and older wireless sensors, expose a binary sensor with the battery device class instead. For that class, on means the battery is low and off means normal (Home Assistant binary sensor docs). There is no percentage to compare, so you test the state itself.
| Entity type | Device class | What the state means | How to test it |
|---|---|---|---|
| Sensor | battery | Battery level in % | Numeric comparison, e.g. below 20 |
| Binary sensor | battery | on = low, off = normal | State equals on |
| Either type | n/a | unavailable or unknown | Separate "gone silent" check |
Step 1: Find out which battery entities you actually have
Before writing anything, see what Home Assistant already knows. Open Developer tools → Template and paste this to list every battery percentage sensor with its current value:
{% for s in states.sensor if s.attributes.device_class == 'battery' %}
{{ s.name }}: {{ s.state }}
{% endfor %}
Run the same loop over states.binary_sensor for the low/normal type. Two things usually show up here: a few devices you forgot were battery powered, and a few that report no battery at all. Mains-powered Zigbee plugs and bulbs have no cells to count, so they will not appear, which is exactly what you want.
Step 2: Build the daily low battery digest
A daily digest beats one notification per device. Seven sensors dipping below the threshold over a weekend becomes one message on Monday morning, not seven buzzes. This automation runs at 09:00, builds a list, and only notifies you when the list is not empty:
alias: Battery check - daily low battery digest
mode: single
triggers:
- trigger: time
at: "09:00:00"
variables:
threshold: 20
low_levels: >-
{% set ns = namespace(items=[]) %}
{% for s in states.sensor
if s.attributes.device_class == 'battery'
and s.state | is_number
and s.state | float < threshold %}
{% set ns.items = ns.items + [s.name ~ ' (' ~ s.state | float | round(0) ~ '%)'] %}
{% endfor %}
{{ ns.items | join(', ') }}
low_flags: >-
{{ states.binary_sensor
| selectattr('attributes.device_class', 'eq', 'battery')
| selectattr('state', 'eq', 'on')
| map(attribute='name') | join(', ') }}
conditions:
- condition: template
value_template: "{{ low_levels != '' or low_flags != '' }}"
actions:
- action: notify.mobile_app_your_phone
data:
title: "Batteries need changing"
message: >-
{{ low_levels }}{{ ', ' if low_levels != '' and low_flags != '' else '' }}{{ low_flags }}
Change threshold to taste and swap notify.mobile_app_your_phone for your own notify action. The notify docs note that older setups may still provide a phone-specific action of this form, so check what your phone's action is called under Developer tools → Actions (notify integration docs).
Step 3: Choose a sensible threshold
Twenty per cent is a sound starting point for most Zigbee and Z-Wave sensors, because it leaves days or weeks to buy replacements. Some batteries misbehave at the bottom end: coin cells can drop quickly after a long, flat stretch, so the gap between "20%" and "dead" is shorter than a phone's would be.
If one device is critical, give it its own tighter rule rather than raising the global threshold. A front-door lock or a smoke alarm deserves 30%, while a spare-room temperature sensor can wait until 10%. Exclude noisy devices from the digest by adding an extra and s.entity_id not in [...] test to the loop.
Step 4: Add an immediate alert for critical devices
A morning digest is too slow for a door lock. For devices where a flat battery is a real problem, add a dedicated automation using the numeric state trigger. This trigger fires when a value crosses a threshold and does not keep firing while it stays below it (numeric state trigger docs):
alias: Battery - front door lock low
triggers:
- trigger: numeric_state
entity_id: sensor.front_door_lock_battery
below: 25
for: "00:10:00"
actions:
- action: notify.mobile_app_your_phone
data:
title: "Front door lock battery low"
message: "Battery is at {{ states('sensor.front_door_lock_battery') }}%. Replace it soon."
The for option makes the value stay below the threshold for ten minutes before the trigger fires, which filters out the odd glitchy reading some sensors report when they wake up. The same pattern suits the water leak and smoke sensors in our leak sensor and smoke alarm guides, where a dead battery means a missed alert.
Step 5: Catch sensors that have stopped reporting
A sensor with a completely flat battery does not report 0%. It goes unavailable, and a numeric threshold can never fire on that. This second automation lists every battery entity that has gone silent:
alias: Battery check - silent sensors
triggers:
- trigger: time
at: "09:05:00"
variables:
silent: >-
{{ states.sensor
| selectattr('attributes.device_class', 'eq', 'battery')
| selectattr('state', 'in', ['unavailable', 'unknown'])
| map(attribute='name') | join(', ') }}
conditions:
- condition: template
value_template: "{{ silent != '' }}"
actions:
- action: notify.mobile_app_your_phone
data:
title: "Battery sensors not reporting"
message: "{{ silent }}"
Treat this list as "check these first". A sensor may have a dead battery, may have dropped off the mesh, or may belong to an integration that is itself offline. Either way you want to hear about it, particularly for the security devices discussed in our guide to checking on an elderly parent, where silent sensors defeat the whole point of the automation.
Step 6: Test it before you trust it
Never assume an alert works. Temporarily set threshold to 100 so that every battery sensor qualifies, then run the digest from Settings → Automations & Scenes by choosing Run actions on its three-dot menu. You should receive a long list. Set the threshold back to 20 and run it again, which should produce either a short list or nothing at all.
Test the silent-sensor check by temporarily disabling a battery-powered device in its integration, or by pulling the battery out of one spare sensor for a few minutes. If a notification arrives naming that device, the chain works end to end.
Why is my low battery alert not firing?
The digest sends nothing even though a battery looks low: check the entity's device class in Developer tools → States. Only entities whose device class is battery are counted, and some integrations expose battery as a plain attribute or a differently classified sensor. Add a template that reads the attribute for those devices.
The same device keeps appearing every morning: that is the digest doing its job. If it is a device you cannot reach yet, add its entity ID to an exclusion list until you have replaced the cells, then remove the exclusion.
Percentages jump around: some devices report coarse steps such as 100, 50 and 10, or fluctuate under load. The for option on the immediate alert helps, and leaving the digest at 20% rather than something tighter avoids flapping.
Notifications fail while you are away: your phone needs a route to Home Assistant. Confirm you can receive other notifications remotely before blaming the automation. If your broadband or power drops, see the power cut alert guide.
What should you do next?
Once the digest is running, make the replacement job easy: keep a small drawer of the common cell sizes your devices use, and note each device's battery type in its name or notes. Pair this with humidity-driven alerts such as the mould risk alert, which rely on exactly the sort of small battery sensors this automation keeps alive.







