Several recipients
Combine phones in one notification group.
An unavailable door contact can silently undermine an otherwise good automation. A low battery can produce the same result a few days later. This guide creates one quiet, daily health check for sensors you choose yourself. It sends a message only when the list contains a real problem.
Home Assistant distinguishes unknown, where the state is not yet known, from
unavailable, where the entity is unavailable. These definitions come from
the official sensor documentation.
Both states deserve investigation, but neither one proves by itself that the
hardware has failed.
Avoid scanning every entity in Home Assistant automatically. A system-wide search catches test entities, disabled devices, and cloud services that do not need a daily alert. Start with a short list:
Find the exact entity IDs under Settings → Tools → States.
Battery sensors with device_class: battery normally use percentages. Some
devices expose a binary low-battery sensor instead; this example deliberately
handles numeric battery percentages only. Home Assistant’s
battery tutorial
explains the difference.
You can also open States directly. Older versions call that page Developer tools.
Confirm that a test message reaches your phone. The example requires an
available notify entity, as described in the notification documentation.
If you only have an older notify.mobile_app_... action, use that phone’s
specific action instead of the final notify.send_message action in the example.
The mobile notifications guide covers
setup and testing of the newer recipients.
The example runs at 09:00. It includes an optional startup trigger, disabled by default. If you enable it, the action waits five minutes so integrations have time to start. Home Assistant documents both the normal time trigger and the special Home Assistant startup trigger.
Create an empty automation
Go to Settings → Automations & scenes → Create automation → Create new automation. Open the three-dot menu and select Edit in YAML.
Paste the complete example below
Replace the entity IDs in both lists. notify.my_phone is illustrative;
select your own notify entity or notification group.
Save it with a clear name
Run the manual test below first. Enable the startup trigger only if you also want a check five minutes after a restart.
alias: "Sensor health: daily check"description: "Alerts for selected unavailable sensors and low batteries"mode: singletriggers: - trigger: time at: "09:00:00" id: daily - trigger: homeassistant event: start id: startup enabled: falsevariables: watched_entities: - binary_sensor.front_door_contact - binary_sensor.utility_room_leak - sensor.freezer_temperature battery_entities: - sensor.front_door_battery - sensor.utility_room_leak_battery battery_limit: 20actions: - if: - condition: trigger id: startup then: - delay: "00:05:00" - variables: health_report: >- {% set ns = namespace(lines=[]) %} {% for entity_id in watched_entities + battery_entities %} {% set value = states(entity_id) %} {% set name = state_attr(entity_id, 'friendly_name') or entity_id %} {% if value in ['unknown', 'unavailable'] %} {% set ns.lines = ns.lines + [name ~ ': ' ~ value] %} {% endif %} {% endfor %} {% for entity_id in battery_entities %} {% set value = states(entity_id) %} {% set name = state_attr(entity_id, 'friendly_name') or entity_id %} {% if is_number(value) and value | float < battery_limit %} {% set ns.lines = ns.lines + [name ~ ': ' ~ value ~ '%'] %} {% endif %} {% endfor %} {{ ns.lines | join('\n') }} - condition: template value_template: "{{ health_report | trim != '' }}" - action: notify.send_message target: entity_id: notify.my_phone data: title: "Sensors need attention" message: "{{ health_report | trim }}"If you maintain automations.yaml manually, the destination is its list of
automations: add - before alias and indent the rest of the block by two
spaces. Do not paste that file-style variant into the editor.
float(0)Every entity state is read as text. unknown | float(0) therefore becomes 0
and can cause a false empty-battery alert. The example first requires
is_number(value) and only then compares the number with the threshold. This
follows Home Assistant’s documentation for
types and conversion
and keeps unavailability separate from a low battery. A battery sensor with
unknown or unavailable therefore appears with that state in the message,
never as 0%.
A battery at exactly 20% does not trigger this example; the threshold means “below 20.” Adjust the number for the battery type and your experience. One daily check usually creates less noise than a message for every small change.
Battery-powered Zigbee, Z-Wave, and Matter sensors may sleep between reports to conserve energy. An old temperature value is therefore not automatically an outage. Check the device’s normal reporting pattern and its integration’s own diagnostics before declaring it dead.
last_changed is not a universal “last seen” measurement either. Home
Assistant’s state object
updates that field when the state itself changes, but not when only attributes
change. A door contact that remains closed can therefore have a very old
last_changed even if it has communicated. last_reported also depends on
whether the integration writes unchanged reports. Do not apply an arbitrary
6-, 12-, or 24-hour threshold to every kind of sensor.
watched_entities entry with a nonexistent test
ID. Run it again and confirm that the message reports unknown.battery_limit above a known numeric battery value. Run
it again and verify the wording and recipient.These steps exercise the template and notification on your own installation. The example on this page has only been checked statically; it has not been run against your Home Assistant instance.
Several recipients
Combine phones in one notification group.
Find the cause
Use Activity and Traces before changing integrations.
SmartBolig // AI Core
Get help with troubleshooting, architecture and concrete configuration. I use broad AI knowledge and find SmartBolig guides when they improve the answer.
Start with a useful question