Is there an integration that reports which WAN is actually carrying traffic?

I have a dual WAN setup at home (fixed wireless as primary, 5G as backup) and I
could not find a way to answer a simple question: which of the two is carrying
my traffic right now?

What I tried, and why none of it worked:

  • The gateway integration (UniFi in my case) only exposes the primary WAN. When
    the primary is down, the reported external IP is 0.0.0.0 even while the house
    is happily online through the secondary. Yesterday it reported 0.0.0.0 for
    fourteen hours straight.
  • Ookla Speedtest does report the ISP name, which is exactly the label I want,
    but it runs once a day. One sample per day cannot tell you what is happening
    now, and cannot produce a meaningful split over time either.
  • DNS IP gives me the public address, which is the right signal, but not who it
    belongs to.

What I ended up building, before I go and reinvent a wheel:

  1. myip.opendns.com asked of the OpenDNS resolvers, once a minute, returns the
    public address.
  2. The Team Cymru DNS service (.origin.asn.cymru.com) returns the
    autonomous system number announcing that address.
  3. A small user-defined table maps the ASN to a label, so the sensor reads
    “Eolo”, “Iliad”, “Disconnected” or “Unknown”.

Two DNS queries, no API key, no quota, nothing a provider can put behind a
paywall.

I tried plain reverse DNS first, since it would have been simpler: on my lines
the PTR record resolved for only 2 of 5 addresses, while the ASN lookup resolved
5 of 5.

So, the actual question: does this already exist? I would much rather use
something maintained than publish yet another custom component. Pointers to
anything close, even partial, would be very welcome.

I have dual-ISP w/ auto-failover: Gb fiber primary, Starlink secondary. (Until fiber, Starlink was primary, & DSL :poop: was secondary.)

I have been using Ookla Speedtest, running multiple times/day (4 hr, I think). But I would like quicker notification of failover (e.g., when the varmints chewed thru my fiber line).

So if you find an already-existing way to detect failover, or are thinking about packaging your approach into an external component, I’d be very interested.

1 Like

Set up the DNSIP integration with defaults so it reports your currently connected ip.

Then implement an automation like this:

- id: 1a4dc408-76f5-41cf-8b68-c3ec3bcf3c59
  alias: 'IP Change'
  triggers:
  - trigger: state
    entity_id: sensor.myip
  actions:
  - action: telegram_bot.send_message
    data:
      chat_id: !secret telegram_alert_chat_group_id
      title: '⚠️ <b>Public IP changed</b>'
      message: "From {{ trigger.from_state.state }} to {{ trigger.to_state.state }}"

Of course this assumes that both your main and failover IPs are static or in different subnets that you can distinguish.

1 Like

I’m on Draytek ecosystem for my network, but I guess similar approach could work also for UniFi - why not to use SNMP? In my case it reports not only if specific WAN is up or down, but also metrices of each of them. I have triple WAN implemented - 1Gb FTTH, LTE failover and virtual WAN that connects via VPN.

1 Like

+1 on this suggestion.

In HAs, it’s easy to measure what each WAN is doing via SNMP. As example, I have real-time upload and download.data counters for my two WANs, each implemented as an SNMP sensor.

For a failover setup, you can tell which WAN is in use based on which counters are moving.

1 Like

That is a good idea. I’ll do a walk of my UCG Ultra later and see if I can find a relevant OID.

1 Like

I examine cloudflare and google latency on the UCG and check to see if > 0

- binary_sensor:

    - name: WAN1 Status Virgin

      unique_id: wan1_status_virgin

      icon: "{{ 'mdi:web' if this.state == 'off' else 'mdi:web-off' }}"

      state: >

        {{ states('sensor.ucg_ultra_nottingham_rd_cloudflare_wan_latency') | float(0) > 0

            or states('sensor.ucg_ultra_nottingham_rd_google_wan_latency') | float(0) > 0 }}



    - name: WAN2 Status Starlink

      unique_id: wan2_status_starlink

      icon: mdi:web

      state: >

        {{ states('sensor.ucg_ultra_nottingham_rd_cloudflare_wan2_latency') | float(0) > 0

            or states('sensor.ucg_ultra_nottingham_rd_google_wan2_latency') | float(0) > 0 }}



\- sensor:

    - name: Active WAN

      unique_id: active_wan

      icon: mdi:web

      state: >

        {% set virgin = states('sensor.ucg_ultra_nottingham_rd_cloudflare_wan_latency') | float(0) > 0

            or states('sensor.ucg_ultra_nottingham_rd_google_wan_latency') | float(0) > 0 %}

        {% set starlink = states('sensor.ucg_ultra_nottingham_rd_cloudflare_wan2_latency') | float(0) > 0

            or states('sensor.ucg_ultra_nottingham_rd_google_wan2_latency') | float(0) > 0 %}

        {% if virgin %}

          Virgin

        {% elif starlink %}

          Starlink

        {% else %}

          Offline

        {% endif %}



    - name: WAN1 Virgin Status

      unique_id: wan1_virgin_status

      icon: mdi:web

      state: >

        {% if is_state('binary_sensor.wan1_status_virgin', 'on') %}

          Online

        {% else %}

          Offline

        {% endif %}



    - name: WAN2 Starlink Status

      unique_id: wan2_starlink_status

      icon: mdi:web

      state: >

        {% if is_state('binary_sensor.wan2_status_starlink', 'on') %}

          {% if is_state('binary_sensor.wan1_status_virgin', 'on') %}

            Standby

          {% else %}

            Online

          {% endif %}

        {% else %}

          Offline

        {% endif %}
type or paste code here
1 Like

not sure where the \ in - sensor came from but should be - sensor

1 Like

Assuming a Unifi router.
Do any of the approaches above detect the failover quicker than 1 minute?

At the moment I have a sensor that just polls the router querying which interface is active.
However I don’t want to put to much load on either HA or the router, so the polling is set to a 60 seconds.

The only approaches I could find to handle push notifications were basically Syslog/SIEM - i.e. send all events to an external server then parse the log/CEF events.
That just seems like massive overkill for this problem.


Assuming your Unifi “controller” is at 192.168.1.1 you can query the full stats on any device ** just by calling its REST endpoint with the primary MAC of the device you are interested in.

https://192.168.1.1/proxy/network/api/s/default/stat/device/a1:b2:c3:d4:e5:f6

For most people the controller and router are the same thing, hence the IP and the MAC will be for the router. There are a ton of different stats you can check to see which link is active, I just read the uplink comment:

      "uplink": {
        "comment": "WAN",
        "drops": 1,
        ...

That would be WAN2 when it fails over.

** - You can throw in the MAC for your wireless AP too and get all the stats on that.

1 Like

Thanks, all of you. Four different approaches came back, and none of them is
the one I ended up with, so let me close the loop.

@tim.plas you asked to be told if I packaged it. I did:

What it does differently: it never asks the router anything. Every 15 seconds
it asks myip.opendns.com of the OpenDNS resolvers what my public address is,
and when that address is one it has not seen before, it asks the Team Cymru DNS
service which autonomous system announces it. The AS number is then looked up
in a table you write yourself (35612 = Eolo;). The sensor reads your own
provider names, plus Disconnected and Unknown.

Why not the suggestions in this thread, which are all good:

  • @anon11644107 DNSIP plus an automation on the state change was my first
    version. It falls over when the addresses are dynamic, which mine are on both
    lines, so I needed the layer that turns an address into an owner.
  • @mirekmal @j112 SNMP counters are better than what I have if your router
    exposes them: real per-link traffic rather than an inference. I wanted
    something that works for a person who has never heard of an OID, on a router
    that may not speak SNMP at all.
  • @dtpugh your latency template is the cheapest thing here for a UCG, no
    argument. Mine is the vendor-neutral version of the same instinct.

Two DNS queries is the whole thing: no account, no API key, no quota, nothing
a provider can discontinue or put behind a paywall.

A real failover here today, straight from the logbook:

13:28:29  Disconnected
13:29:02  Iliad          (backup line, different AS)
13:54:32  Eolo           (primary back)

What I do not know yet, stated plainly:

  • it has run on exactly one instance, mine, against two lines;
  • load balancing: untested. If both lines carry traffic at once the public
    address will flap, and I do not know what the sensor does then;
  • CGNAT: untested. If your address is announced by somebody else, the AS number
    may not name who you pay;
  • it is a 15 second poll, not a push, so a switchover is seen within 15 seconds
    rather than instantly;
  • the two DNS lookups are the only part of the code with no automated tests, on
    purpose: everything else runs against fakes.

HACS custom repository, MIT. If you try it on a line that is not one of my two,
the report I actually need is narrow: which AS number came back, and whether
your table named it. That is the part I cannot test from here.

1 Like

(reposting, I deleted the previous one by accident)

@dtrott to answer your question directly: yes, well under a minute. It runs on
a 15 second cycle, and it can afford that because only one of its two questions
repeats.

The address lookup goes out every cycle, because that is the question that
detects the switchover. The second question, who announces that address, only
fires when the address is one it has not seen before, and the answer is kept
locally for 30 days. An address does not change owner, so asking again every
cycle would be four identical questions a minute for an answer that holds for
months.

So the load is one DNS query every 15 seconds to a public resolver, and zero
requests to the router. That is why I did not have to make the tradeoff you
made at 60 seconds: there is nothing here to protect the router from.

Your uplink.comment trick is more direct than mine if you are on UniFi, and I
would use it over my own thing on a pure UniFi setup. The only difference is
that mine does not care what the router is.

And I agree that syslog is overkill for this. The honest limit of my approach
is that it is still polling: worst case you hear about the failover 15 seconds
late, plus however long the DNS answer takes.

@drake69 - Outstanding! Very elegantly done!

One of my video streaming services gets funky every time I have an ISP failover, because it thinks I’m using the service elsewhere.

I had been meaning to write something someday, probably based off Ookla Speedtest (w/ 4-hr latency in my case). But Cerberus exactly meets my need. Thanks so much!

1 Like

Update: Well shucks, it looks like I’ll have to do a little bit of work. I thought I’d take the really easy route, & just have Cerberus WAN trigger a 1-line script to notify me every time a switchover occurred. But unfortunately, with how HA often handles stuff, the log shows I’m sometimes getting triggered by failover to my regular ISP from “Unavailable” or “Disconnected”.

So I guess I’ll have to do just slightly more, to filter out those false triggers. Still, I’m thrilled to be getting notifications of ISP failover with such a quick-responding and low-impact service. Thanks!

1 Like

Tim, that filtering was my job, not yours. As of 0.5.0 you do not have to
do it.

You had found a real defect. Inside the integration there was one signal,
“the reported provider moved”, and four different things produced it: a
real failover, the line dropping, the line coming back, and the lookup that
names the network failing to answer in time. Your one line script was doing
exactly what it was told. It was being told the wrong thing.

Now cerberus_wan_provider_changed fires on a change of provider and nothing
else. A line that drops and comes back on the same ISP no longer fires it;
a failover that happens while the line is down still does. There is also a
new cerberus_wan_connection_changed carrying every movement, and a second
field in the dialog for the line dropping or coming back.

One tip on the “Unavailable” half of what you saw: that comes from
triggering on the sensor state, which also fires while Home Assistant
restarts or reloads an integration. No integration can prevent that.
Trigger on the event instead and it goes away.

Thanks for writing it up rather than just working around it. A workaround
would have stayed in your config and I would never have known.

1 Like

Most excellent! Thanks much!