Skip to main content

wifireconnect

wifireconnect banner

A small Linux network watchdog that diagnoses connectivity failures and recovers Wi-Fi connections through iwd.

CI PyPI version Python versions License: MIT DeepWiki

Linux + iwd only. Observation comes from ifpeek (netlink / nl80211); recovery talks to iwd over D-Bus (jeepney). No root needed, no subprocesses, no passwords.

How it works

netlink events ───────► immediate health check
                            │
periodic heartbeat ─────────┘
                            │
                            ▼
                         diagnose
                            │
                            ▼
                       maybe recover

ifpeek.watch() reacts immediately to link / address / route changes, and a heartbeat covers the failures that produce no local event (a dead upstream, a zombie association). Each check classifies the connection from L2 upwards:

Fault Meaning Action
healthy Internet reachable nothing
no-interface The interface does not exist observe
associating Association in progress (operstate DORMANT) wait
not-associated No carrier reconnect
no-address Associated but no usable IP (DHCP problem) observe
no-route IP but no default route through the interface observe
zombie Local stack looks fine, gateway does not answer kick
upstream Gateway answers, internet does not nothing

The classification exists mostly to decide when NOT to act: resetting a healthy association because the ISP is down only adds flapping.

Recovery is hardened against flapping and against fighting iwd:

  • N consecutive checks blaming the association are required before acting (default 3); healthy or non-recoverable checks break the streak, so an upstream outage never accumulates credit towards a kick.
  • After acting, a cooldown suppresses further checks (default 60 s), which also swallows the netlink event storm the recovery itself produces.
  • If iwd is already connecting or roaming, the watchdog waits.
  • Recovery looks before it touches: it asks iwd for a fresh scan (through ifpeek, no root) and, if the target network is not in sight, does nothing. A zombie association is still an association; dropping it to reconnect to a network that is gone leaves you with nothing. With --min-signal, a target that is in sight but weaker than the threshold is left alone too.
  • Recoverable failures log what the radio sees: the associated BSS (BSSID, frequency, dBm) on every failed check, and the target's strongest BSS before recovering, so the log tells a channel change or a weak link from a stuck association.

Reconnection goes to the network you name with --ssid, else to the last network seen healthy, else to iwd's strongest known network in sight. iwd keeps the credentials (its known networks), so there is no --password and there never will be again.

Requirements

  • Linux with iwd managing the Wi-Fi.
  • Permission to talk to iwd on the system D-Bus: belong to the wheel or network group (see iwd's D-Bus policy), or run as root.

Installation

uv tool install wifireconnect   # recommended: isolated CLI on your PATH

To use it as a library, add it as a dependency instead:

uv add wifireconnect

Usage

Diagnose once (exit code: 0 healthy, 1 unhealthy, 2 no such interface):

$ wifireconnect check
wlan0: healthy: internet reachable (essid: MyNetwork)

Run the watchdog:

$ wifireconnect run

Useful options for run:

-i, --interface TEXT  Wi-Fi interface to watch (default: the first one found).
-s, --ssid TEXT       Known network to reconnect to (default: last seen healthy).
-H, --heartbeat FLOAT Seconds between checks when no event arrives. [default: 30]
-f, --failures INT    Consecutive failures required before recovering. [default: 3]
-c, --cooldown FLOAT  Seconds to hold off after a recovery attempt. [default: 60]
-t, --timeout FLOAT   Seconds to wait for each probe answer. [default: 3]
    --min-signal INT  Do not reconnect when the target is weaker than this many dBm
                      after a fresh scan, e.g. --min-signal=-85. [default: off]
    --dry-run         Diagnose and log, but never touch the association.
-v, --verbose         Debug output.

Start with --dry-run for a few days if you want to see what it would have done before letting it act.

As a service

A systemd unit template ships in contrib/wifireconnect.service:

cp contrib/wifireconnect.service /etc/systemd/system/
# edit ExecStart (path, interface), then:
systemctl enable --now wifireconnect

As a library

from wifireconnect import diagnose, Watchdog

diagnose("wlan0")
# Diagnosis(fault=<Fault.HEALTHY: 'healthy'>, interface='wlan0',
#           detail='internet reachable', essid='MyNetwork', gateway=None)

Watchdog(interface="wlan0", dry_run=True).run()  # blocks

Relation to ifpeek

ifpeek observes (netlink, nl80211, read-only D-Bus); wifireconnect decides and acts (probes, iwd). ifpeek peeks and never touches; everything that sends traffic or mutates state lives here.

Release files for wifireconnect 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for wifireconnect 1.1.0
File Size Uploaded
wifireconnect-1.1.0.tar.gz 23.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wifireconnect 1.1.0
File Interpreter ABI Platform
wifireconnect-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.6 kB

Release files / wifireconnect-1.1.0.tar.gz

Download URL wifireconnect-1.1.0.tar.gz
Size 23.3 kB
Tags Source
SHA-256 checksum
How to use checksums
371eb68efd94f8bb036c5a56241803fbed9b903b8918eeb714c8c7d8871b9d28
BLAKE2b-256 checksum
How to use checksums
dec8be3d87f7b7a619d35b49e3899b3c056462f751f011e49421c2d97e3e97e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release files / wifireconnect-1.1.0-py3-none-any.whl

Download URL wifireconnect-1.1.0-py3-none-any.whl
Size 16.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
80e41b839a8513df8908c89eae463ed17dc1ae8ac5cd59cd60277c921d4ba717
BLAKE2b-256 checksum
How to use checksums
3a70cc41287d8eaf1e497465364e36a95e843ff63781acf6504b5a2809d6431c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 6, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.1

2 release files

1.2.0

2 release files

This release

1.1.0 This release

2 release files

1.0.0

2 release files

0.2.0

2 release files

0.1.1

1 release file

0.1.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page