Start with one updating availability list
For a Home Assistant unavailable device notification, start with a small list of entities—the individual readings and controls shown in Home Assistant. Check their current states on a repeating schedule, allow a short settling period, and replace the same notification instead of adding another copy each time.
The walkthrough below uses built-in features and creates a message in Home Assistant’s Notifications panel. It covers selected lights, switches and sensors without checking every diagnostic reading in the house. You need an existing Home Assistant installation, permission to edit automations, and the free built-in Uptime integration.
A state of unavailable tells you Home Assistant cannot currently supply that entity’s value. unknown means it has no known value. Either can justify investigation, but neither identifies a flat battery or a broken physical device by itself. The state documentation explains these values.
Researched from current Home Assistant and Zigbee2MQTT documentation on September 18, 2026. The configuration was parsed and its templates checked with simulated states; it was not run in a Home Assistant installation or tested on hardware. The cover is an AI-generated household illustration.
1. Choose the readings that matter
Open Settings → Tools → States. Older releases put this under Developer tools → States. Find a few devices you expect to stay connected, and copy one main entity ID for each—for example, a lamp’s control or a room’s temperature reading.
Use individual entities, not a room, device ID or group. One device can expose many readings; including all of them can turn one problem into a long list. This example deliberately requires you to maintain a short selection when devices are added or renamed.
On a small screen, swipe the table sideways to read every column.
| Candidate | Use it? | Reason |
|---|---|---|
| A study lamp that normally stays powered | Yes: its individual light entity. | A prolonged missing control is worth checking. |
| A room temperature sensor | Yes, after checking its normal reporting behavior. | Its integration must actually mark missing data unavailable for this rule to notice it. |
| A seasonal plug stored in a drawer | Leave it out. | It is disconnected deliberately. |
| A button’s last-press event or an optional diagnostic | Usually leave it out. | A value can remain unknown until an event occurs; that alone does not establish a fault. |
| A whole light group | Choose its members individually. | A group can conceal a problem affecting only one member. |
For battery replacement reminders, use the separate daily low-battery list. A good battery percentage and a working connection are different observations.
2. Add a startup grace period
Go to Settings → Devices & services → Add integration, search for Uptime, and add it. Open its sensor and copy the entity ID. The example uses sensor.uptime; replace that if yours differs.
Uptime stores when Home Assistant last started, as a date and time. It is not a running count of seconds. The recipe calculates elapsed time from that timestamp and waits 15 minutes before checking your list.
Fifteen minutes is a starting choice for this maintenance reminder, not a manufacturer’s guarantee. Increase it if your integrations normally need longer to settle. A missing or invalid Uptime reading produces a setup message instead of silently approving the check.
3. Create the availability check
Open Settings → Automations & scenes → Create automation → Create new automation. In the three-dot menu, choose Edit in YAML. Replace the new automation’s contents with this example. YAML is the text form of the automation; keep its indentation.
Replace the three entries under watched with your own entity IDs. You can use fewer or add more. Set uptime_entity to your Uptime sensor. Leave the two 15-minute values unchanged for the first check.
alias: Check selected device availability
description: One quiet Home Assistant message for sustained missing readings
triggers:
- trigger: time_pattern
minutes: "/5"
conditions: []
actions:
- variables:
watched:
- light.study_lamp
- sensor.hall_temperature
- binary_sensor.patio_door
uptime_entity: sensor.uptime
startup_minutes: 15
bad_state_minutes: 15
- variables:
started: "{{ as_timestamp(states(uptime_entity), none) }}"
- choose:
- conditions: "{{ started is none }}"
sequence:
- action: persistent_notification.create
data:
notification_id: selected_device_availability
title: Check availability monitor setup
message: "No startup timestamp. Check {{ uptime_entity }}."
- stop: Uptime timestamp is missing or invalid
- condition: template
value_template: >-
{{ as_timestamp(now()) - started >= startup_minutes * 60 }}
- variables:
report: |-
{% set ns = namespace(items=[]) %}
{% for e in watched | unique | sort %}
{% set found = expand(e) | list %}
{% if found | count == 0 %}
{% set ns.items = ns.items +
[e ~ ': no state; check entity ID or disabled entity'] %}
{% elif found | count != 1 or found[0].entity_id != e %}
{% set ns.items = ns.items +
[e ~ ': choose an individual entity, not a group'] %}
{% else %}
{% set s = found[0] %}
{% if s.state in ['unavailable', 'unknown']
and as_timestamp(now()) - as_timestamp(s.last_changed)
>= bad_state_minutes * 60 %}
{% set ns.items = ns.items +
[s.name ~ ' (' ~ e ~ '): ' ~ s.state] %}
{% endif %}
{% endif %}
{% endfor %}
{% if watched | count == 0 %}
No entities selected. Fill in the watched list.
{% else %}
{{ '- ' ~ (ns.items | join('\n- ')) if ns.items else '' }}
{% endif %}
- choose:
- conditions: "{{ report | trim | length > 0 }}"
sequence:
- action: persistent_notification.create
data:
notification_id: selected_device_availability
title: Check selected devices
message: |-
Checked {{ now().strftime('%Y-%m-%d %H:%M') }}.
{{ report | trim }}
default:
- action: persistent_notification.dismiss
data:
notification_id: selected_device_availability
mode: single
The time-pattern trigger runs on clock minutes 00, 05, 10, and so on. It checks the states Home Assistant already has; it does not poll every physical device for a fresh response.
The bad_state_minutes filter measures how long the entity has stayed in its current unknown or unavailable state. Changing between those two states starts that wait again. The code does not use an old last_changed timestamp to declare an otherwise valid reading dead.
A fixed notification_id makes Create notification replace the same message. When the next check finds no qualifying entries, Dismiss notification removes only this message. An empty selection or a missing entity is reported as a setup problem. If you dismiss an unresolved warning yourself, the next check recreates it.
The startup guard sits inside the action sequence, so it also applies when you select Run actions. During the grace period, the automation leaves any existing message unchanged. After a restart or reload, it checks current states again; it does not reconstruct an outage timeline from before the restart.
4. Check the timing against this example
This is an illustrative timeline, not a measured installation. Assume Home Assistant has been running since 9 am, the scheduled checks succeed, and both selected entities really change to unavailable at the times shown.
On a small screen, swipe the table sideways to read every column.
| Time and event | Expected result |
|---|---|
| 10:01 — the study lamp becomes unavailable. | No immediate notification. The rule waits for a sustained bad state. |
| 10:15 — scheduled check. | No lamp entry yet: only 14 minutes have elapsed. |
| 10:20 — scheduled check. | The lamp appears in the one notification. It has been unavailable for 19 minutes. |
| A second sensor became unavailable at 10:08. At 10:25, it still is. | The same message now lists both. The first fault does not prevent later faults being added. |
| 10:27 — the lamp reports a valid state again. | At 10:30, the lamp disappears from the list; the second sensor remains. |
| 10:31 — the second sensor recovers. | At 10:35, the message clears if there are no other qualifying or setup entries. |
Under this schedule, a stable bad state normally reaches the list 15 to under 20 minutes after Home Assistant reports it, subject to startup grace and successful runs. The integration may take much longer to notice the original physical failure. These are calculated timings for the example, not measured alert latency.
5. Verify it without disconnecting anything
- Confirm startup is old enough. Check the Uptime timestamp. Allow at least 15 minutes from that time before testing the list.
- Add one harmless missing ID. First confirm
sensor.tara_availability_test_missingdoes not exist in States. Add that text as an extra entry underwatched. Do not create it or change any real sensor’s state. - Save and select Run actions. The Notifications panel should show “Check selected devices” with the test ID and “no state; check entity ID or disabled entity.” Missing IDs are setup errors, so they do not wait through the bad-state delay.
- Let the next five-minute boundary pass. Open the automation’s Traces, its record of recent runs. Check for a time-pattern run and a new “Checked” time in the same notification. A manual run alone does not prove the schedule works.
- Remove the test ID, save, and run again. The test entry should disappear. The message clears only if all your real selections also pass; otherwise their entries remain.
This safely checks selection, message delivery, replacement, clearing and the scheduled trigger. It does not prove how quickly a physical device’s integration detects a failure, or exercise a real 15-minute outage. Use the automation testing documentation to inspect each step.
What an availability alert can miss
A valid-looking old value is outside this recipe’s scope. A temperature of 21°C might genuinely stay unchanged. Home Assistant’s state-object reference distinguishes state changes, attribute changes and reports. None is automatically a hardware heartbeat. Check the specific integration’s documented availability behavior before relying on a timestamp.
For example, Zigbee2MQTT’s availability feature is optional. Its documented defaults differ for powered and battery devices: active devices use a 10-minute check-in timeout followed by a ping, while passive battery devices have a 25-hour check-in timeout and cannot be pinged. Those are integration rules, separate from this guide’s added 15-minute filter. Review your installed settings and device behavior before changing them.
Repeatedly switching between unknown and unavailable can keep restarting this filter. A short outage that recovers between checks may never appear. Use the device’s own warnings and normal maintenance checks for alarms, locks and other important equipment. The automation only reports; it performs no device-control actions.
The check and its on-screen message run in Home Assistant. A selected entity may still rely on a vendor cloud. And if Home Assistant itself stops, this automation stops too: see what keeps working during a Home Assistant outage when planning essential controls.
When the result looks wrong
On a small screen, swipe the table sideways to read every column.
| What you see | What to check next |
|---|---|
| “No startup timestamp” | Check the Uptime integration and exact sensor ID. Its state must be a date/time, not an elapsed-seconds sensor. |
| A run stops at the startup condition | Compare the startup timestamp with the current time. The 15-minute grace period may still be active. |
| A missing entity or group warning | Correct the ID, check whether the entity is disabled, or replace the group with individual members. Do not treat this message as a confirmed dead device. |
| An unavailable entity is absent from the list | Confirm it is selected and has stayed in the same bad state for 15 minutes. Check the latest trace for errors or a skipped run. |
| A device stopped responding but still shows a number | Review its integration’s availability/check-in behavior. This rule cannot detect a stale valid value. |
| No scheduled trace | Check that the automation is enabled and Home Assistant is running. A manual run is a different test. |
If several devices became unavailable after a reboot, use the existing restart-unavailability troubleshooting guide to investigate their connection paths. A notification tells you where to look; it does not justify deleting devices or rebuilding their networks.
Other practical questions
Will this make my phone buzz?
No. This recipe updates the Home Assistant Notifications panel. Phone push needs a configured delivery action, such as the Companion App’s notify.mobile_app_… action. Avoid putting that action directly into this five-minute loop: an unresolved issue would generate repeated pushes. Decide on a daily summary or explicit repeat limit before adding phone delivery. The Companion notification documentation covers that separate channel.
Does a cleared message mean every device works?
No. It means the selected current readings did not meet this rule’s bad-state or setup checks at the displayed run. It does not test unselected entities, physical controls or stale values that still look valid.
Do I need a custom integration?
No custom integration is required for this configuration. Built-in Uptime, automation templates and persistent notifications are enough. Larger monitoring systems can add reporting-age rules, but those still need per-integration knowledge.
For a household handoff, agree who checks the list and which devices belong on it. Tara’s home automation kit with coordinated local routines connects that maintenance planning with the rest of the home.
