Separate an NBN outage from a local network fault
An external ping failing does not prove the NBN is down: Home Assistant may have lost Wi-Fi, the modem may be rebooting or one remote host may be unavailable. Use several independent checks and persistence so the alert says what the evidence supports.
The fault this project detects
This project distinguishes likely upstream internet loss from local gateway loss and degraded-but-not-down service. It uses a local gateway target, two unrelated external targets and Ping diagnostic sensors for latency and packet loss.
The design suits an Australian home or small business on NBN with Home Assistant connected by Ethernet where practical. Configure each Ping integration in the interface, keep the router target local, and choose external targets you are permitted to monitor.
The evidence model
A useful alarm does not promote one noisy reading straight to an emergency. It combines measurements that fail in different ways:
- Value: round-trip time and packet-loss diagnostics show service quality.
- Direction: rising latency or loss is visible before a complete outage.
- Agreement: two external failures make a remote-host fault less likely.
- Context and time: local gateway reachability and persistence separate upstream loss from Home Assistant losing the LAN.
The result is a classification, not an accusation. It can say that upstream reachability appears lost while the local gateway remains available; it cannot prove which NBN component or provider system failed.
Freshness is separate evidence
An entity can keep a plausible old value without becoming unavailable. Inspect last_changed on a source that should genuinely change, and pull up its own History graph over a normal stretch of days to find the longest healthy interval between meaningful state changes — that gap is the figure to record. If the measured process can legitimately stay flat, add a changing source heartbeat or timestamp; do not treat an unchanged temperature, level or power value as proof that the transport is alive.
Rate maths: never copy a gradient
The Trend integration expresses min_gradient in units per second. The arithmetic example from the project brief is 4 °C/hour ÷ 3600 = 0.00111 °C/s. That is an example conversion, not a threshold for this equipment. Calculate the rate from your own timestamped readings: take two readings from that entity's History, then work out your measured change (in the sensor's own unit) ÷ the elapsed seconds between those readings = your site-specific gradient. A Derivative helper can instead display a friendlier per-hour unit when configured that way.
Collect this data before choosing a threshold
Collect baseline round-trip time, jitter and packet loss at quiet and busy periods. Include scheduled modem reboots, backup jobs and known congestion periods.
| Measurement | Why it matters | Required value |
|---|---|---|
binary_sensor.nbn_gateway | Local path health | Watch it over a normal week and note how consistently available it stays and what a normal response trace looks like |
binary_sensor.external_target_a | First upstream check | Watch it through a real outage or scheduled maintenance window if you get the chance, and note how it behaves |
binary_sensor.external_target_b | Independent upstream check | Do the same for this target, watching how it behaves during an outage or maintenance window |
sensor.external_target_a_round_trip_time_average | Latency baseline | Check its History over a normal week for the everyday ms range, then compare that with a period you know was degraded |
sensor.external_target_a_packet_loss | Loss baseline | Do the same comparison for packet loss: a normal-week baseline versus a known-bad period |
The experiment that makes this article defensible
- Record a normal day, including periods when the connection is busy.
- Disconnect a non-critical test device from the LAN to understand a local client failure without touching the NBN service.
- During a planned modem restart, capture gateway, external targets, loss and latency on one timeline.
- If a genuine provider outage occurs, preserve the exact sequence and recovery instead of manufacturing repeated WAN interruptions.
Before you rely on this automation, capture your own evidence from that walkthrough: timestamped readings for each step, the Home Assistant version you're running, the exact entity IDs involved, and one or two History or dashboard screenshots. Do not stage an unsafe electrical, refrigeration, pressure, battery or water fault merely to make a graph.
Create the helpers
Use Settings → Devices & services → Helpers. Create the named Number or Toggle helpers before loading the templates. Where this guide uses a Derivative, Statistics, History Stats, Integral, Schedule or Utility Meter helper, the current Home Assistant interface can create it; the source links below describe the current options.
| Helper or derived entity | Purpose | Setting |
|---|---|---|
Ping: nbn_gateway | UI-created Ping integration for the local router or modem | The local IP address of your own router or modem, found on its admin page or in your network settings |
Ping: external_target_a | UI-created Ping integration for one permitted external target | A permitted external host name or IP you're comfortable pinging regularly (check the target's acceptable-use terms first) |
Ping: external_target_b | Second independent external target | A second target on a different operator or network path from target A, so the two won't fail together for the same reason |
input_number.internet_fault_hold_minutes | Persistence before classifying an outage | How many minutes of sustained loss you want before calling it an outage, long enough to ignore a brief blip |
input_number.internet_warning_packet_loss_percent | Degraded-service loss threshold | The packet-loss percentage you'd call degraded rather than normal jitter, set from your own baseline readings above |
input_number.internet_warning_latency_ms | Degraded-service latency threshold | The latency in ms you'd call degraded for your connection, taken from the normal-versus-degraded comparison above |
input_boolean.internet_reliability_monitoring_enabled | Master notification gate | Leave this off until you've tested the automation end to end, then switch it on |
input_number.internet_reliability_critical_repeat_minutes | Critical repeat spacing | How many minutes between repeat critical alerts — enough to avoid spamming yourself, short enough not to miss a genuine emergency |
Current Home Assistant YAML
Merge top-level keys with your existing configuration instead of duplicating them. Replace the example entity IDs consistently. If you keep automations in automations.yaml, paste only the automation list items there, without a top-level automation: wrapper.
Classify local, upstream and degraded states
Enable the Ping diagnostic entities you need after adding the integrations. Entity IDs vary with the names you choose, so replace every example consistently.
template:
- binary_sensor:
- name: "Internet reliability warning"
unique_id: internet_reliability_warning
default_entity_id: binary_sensor.internet_reliability_warning
device_class: problem
delay_on:
minutes: >
{{ states('input_number.internet_fault_hold_minutes') | int(0) }}
availability: >
{{ has_value('sensor.external_target_a_packet_loss')
and has_value('sensor.external_target_a_round_trip_time_average') }}
state: >
{% set loss = states('sensor.external_target_a_packet_loss') | float %}
{% set latency = states('sensor.external_target_a_round_trip_time_average') | float %}
{{ is_state('binary_sensor.nbn_gateway', 'on')
and (loss >= (states('input_number.internet_warning_packet_loss_percent') | float)
or latency >= (states('input_number.internet_warning_latency_ms') | float)) }}
attributes:
reason: >-
Gateway is {{ states('binary_sensor.nbn_gateway') }};
target A is {{ states('binary_sensor.external_target_a') }} with
{{ states('sensor.external_target_a_packet_loss') }}% loss and
{{ states('sensor.external_target_a_round_trip_time_average') }} ms average RTT;
target B is {{ states('binary_sensor.external_target_b') }}.
- name: "Internet reliability critical"
unique_id: internet_reliability_critical
default_entity_id: binary_sensor.internet_reliability_critical
device_class: problem
delay_on:
minutes: >
{{ states('input_number.internet_fault_hold_minutes') | int(0) }}
state: >
{{ is_state('binary_sensor.nbn_gateway', 'on')
and is_state('binary_sensor.external_target_a', 'off')
and is_state('binary_sensor.external_target_b', 'off') }}
attributes:
reason: >-
The local gateway responds, but both external targets do not.
This supports an upstream reachability fault; it does not identify the cause.
- name: "Home network path fault"
unique_id: home_network_path_fault
default_entity_id: binary_sensor.home_network_path_fault
device_class: problem
delay_on:
minutes: >
{{ states('input_number.internet_fault_hold_minutes') | int(0) }}
state: >
{{ is_state('binary_sensor.nbn_gateway', 'off') }}Warning and Critical notification actions
Replace the mobile notification action and media-player entity with your own. Put critical-monitoring-alert.mp3 in /media, test it manually, and leave the monitoring Toggle off until calibration is complete.
automation:
- id: internet_reliability_warning_push
alias: "Internet link - Warning push"
mode: single
triggers:
- trigger: state
entity_id: binary_sensor.internet_reliability_warning
to: "on"
conditions:
- condition: state
entity_id: input_boolean.internet_reliability_monitoring_enabled
state: "on"
actions:
- action: notify.mobile_app_your_phone
data:
title: "Internet link warning"
message: >-
{{ state_attr('binary_sensor.internet_reliability_warning', 'reason')
or 'The warning condition is active. Check Home Assistant for evidence.' }}
- id: internet_reliability_critical_repeat
alias: "Internet link - Critical repeat"
mode: restart
triggers:
- trigger: state
entity_id: binary_sensor.internet_reliability_critical
to: "on"
conditions:
- condition: state
entity_id: input_boolean.internet_reliability_monitoring_enabled
state: "on"
actions:
- action: notify.mobile_app_your_phone
data:
title: "Internet link critical"
message: "The critical condition is active. Check the equipment and evidence now."
- action: media_player.play_media
target:
entity_id: media_player.alert_speaker
data:
media_content_id: "media-source://media_source/local/critical-monitoring-alert.mp3"
media_content_type: "audio/mpeg"
- repeat:
while:
- condition: state
entity_id: binary_sensor.internet_reliability_critical
state: "on"
- condition: template
value_template: >-
{{ states('input_number.internet_reliability_critical_repeat_minutes') | int(0) > 0 }}
sequence:
- delay:
minutes: >-
{{ states('input_number.internet_reliability_critical_repeat_minutes') | int(0) }}
- condition: state
entity_id: binary_sensor.internet_reliability_critical
state: "on"
- action: notify.mobile_app_your_phone
data:
title: "Internet link still critical"
message: "The critical condition remains active."
- action: media_player.play_media
target:
entity_id: media_player.alert_speaker
data:
media_content_id: "media-source://media_source/local/critical-monitoring-alert.mp3"
media_content_type: "audio/mpeg"
Why the logic works
A reachable gateway proves Home Assistant still has a local path. Agreement between two external failures makes a single remote host less likely, while latency and loss expose degradation before the connection disappears completely.
The design is intentionally diagnostic rather than controlling. It reports an impossible or abnormal relationship; it does not bypass equipment protection or decide that a single suspected cause is proven.
Severity tiers without alert fatigue
| Tier | Meaning | Action |
|---|---|---|
| Advisory | Latency or loss is unusual but not persistent enough to interrupt you. | Dashboard only |
| Warning | Measured loss or latency remains outside the calibrated service envelope while the gateway is reachable. | One push notification |
| Critical | The gateway remains reachable while both independent external targets fail for the hold time. | Push, repeat and audible alert |
A weak clue remains visible without interrupting you. A Warning requires persistence or corroboration. Critical is reserved for direct danger or several independent signals. That separation is what stops a useful monitoring system becoming notification wallpaper.
Troubleshooting
- One target is always off
- Choose a host that permits and reliably answers ICMP, or replace that signal with another reviewed health check.
- Wi-Fi Home Assistant reports false outages
- Use Ethernet where practical and monitor Home Assistant's local gateway path separately.
- Diagnostic sensors are missing
- Open the Ping device and enable the disabled diagnostic entities you actually need.
- Busy uploads increase latency
- Treat load-dependent latency as a separate baseline or add a traffic-context entity.
- The provider status page disagrees
- Your monitor measures reachability from your premises, not the provider's whole network or official fault classification.
Safety and limits
Do not automate repeated modem power-cycling from this diagnosis. It can hide evidence, interrupt emergency communications and damage support troubleshooting. Keep a mobile fallback for genuinely important notifications.
If a webhook is added later, treat its webhook_id like a password, keep local_only: true unless a reviewed design requires otherwise, and never use an unauthenticated webhook for locks, garage doors, power isolation or anything destructive.
Official sources
These are the primary documentation pages used for the design. Check them against the Home Assistant or ESPHome version you are actually running.
Related Smart Home Fix guides
- Fix unreliable entities before trusting alarms
- Separate smart-home devices without breaking discovery
- Reduce false alarms without hiding real faults
FAQ
Does this prove that the NBN is down?
No. It shows that the local gateway responds while multiple external targets do not. That supports an upstream reachability fault but does not identify the failed provider component.
Why use two external targets?
One host can block pings, undergo maintenance or have its own routing problem. Agreement reduces that ambiguity.
Where do the latency and packet-loss sensors come from?
The current Ping integration exposes diagnostic sensors on its device. Some are disabled by default and must be enabled deliberately.
Should Home Assistant reboot the modem automatically?
Not from this evidence alone. Automatic power-cycling can erase useful diagnostics, prolong outages and interrupt services that were still working.
Can alerts work during an internet outage?
Local dashboard and audible actions can. Cloud push delivery may not, so important sites need a separately designed communication path such as a reviewed mobile backup.