Watchdog¶
A monitor that stops measuring by itself, and stays stopped until someone power-cycles it, loses exactly the hours you wanted to see. Two such failures have happened on Smoking Pi hosts, more than once each, and before this command nothing recovered from either without a person:
- The Wi-Fi radio hangs.
wlan0stays up, often still associated to the access point, and receives nothing. Every target goes to 100% loss, the LAN router included, and SSH over Wi-Fi is dead. The hangs lasted 21 hours, 3 h 20 min and 17 hours, and a power cycle ended most of them. The signature, and what is known and suspected about the cause, are in Wi-Fi uplink stats. - SmokePing does not start. After a power cycle the SmokePing container
was running, but the SmokePing service inside it stayed
down (not started yet): its startup sequence stalled. Nothing was measured for 16 minutes, until a manualsmoking-pi restart smokeping. A reboot of another Pi on the same release came up normally: it is a race at boot, not a bug that repeats.
smoking-pi watchdog checks for both every minute and puts them right.
Turning it on¶
sudo smoking-pi watchdog enable
This installs two systemd units, smoking-pi-watchdog.timer and
smoking-pi-watchdog.service, in /etc/systemd/system. The timer starts
two minutes after boot and then runs smoking-pi watchdog check every
minute, as root. sudo smoking-pi watchdog disable removes both units.
Uninstalling the package removes them too.
To have the watchdog reload the driver but never reboot the host, use:
sudo smoking-pi watchdog enable --no-reboot
The watchdog is off until you turn it on: it can reboot the host, and that is your decision to make.
What it does¶
The Wi-Fi radio¶
Each check pings the router (the default route's gateway) through the Wi-Fi
interface, and, if it stays quiet, two public addresses (1.1.1.1,
8.8.8.8) through the same interface. One answer from any of them is
enough. If none answers, the check looks at whether the router still
answers on the link: the pings made the kernel ask for the router's address
(ARP). A working radio hears the reply; a deaf one does not, so its
neighbor entry for the router never becomes REACHABLE (ip neigh). The
watchdog only acts when nothing answers, at either level:
- An ISP outage leaves the router answering ping, so the watchdog does nothing.
- A router that ignores ping still answers on the link, and the Internet answers through it when it is up. Either one keeps the watchdog quiet.
| Nothing answers through Wi-Fi for | Action |
|---|---|
| 10 minutes | Reload the Wi-Fi driver: remove its kernel module and the modules that hold it (on a Raspberry Pi, brcmfmac and brcmfmac_cyw or brcmfmac_wcc), then load them again. NetworkManager reconnects by itself. |
| 5 more minutes | Reboot the host, unless the watchdog already rebooted it in the last 6 hours or was enabled with --no-reboot. |
Anything answering again ends the episode, and that is logged with how long it lasted.
The reload is recorded before it starts. If the driver hangs in the kernel, the unit's 5-minute start timeout ends the check, and the next check moves on to the reboot. If the driver does not come back, or comes back under another interface name, that still counts as nothing answering, and the reboot follows: that is the case a reboot is for.
The episode's minutes are counted in time since boot, not by the wall clock. A Raspberry Pi has no real-time clock, and NTP can move its clock by hours just after a boot.
After a reboot the clock starts again: the driver reload comes 10 minutes later, and a second reboot only once 6 hours have passed since the first. A router that is off for a whole day therefore costs four reboots, not a loop. A reboot loses nothing, because with the uplink gone there is nothing to measure.
The check only watches Wi-Fi. A host whose default route is a cable, or a tunnel, is left alone. It also acts only on an interface it has seen work: until one check has had an answer through it, a silent Wi-Fi starts nothing, so a host whose Wi-Fi never worked here is not rebooted over it. That same memory covers a host with no default route at all: a hung radio can lose its association, and the DHCP lease with it. A wired host with its cable out, or one where Wi-Fi was never set up, is left alone.
Each log line also records two clues for the analysis afterwards, neither of which triggers anything:
- whether the radio was still associated to the access point;
- how many packets it received while the router was unreachable.
Associated, with zero packets received, is the deaf-radio signature from Wi-Fi uplink stats. Not associated looks more like the access point being gone.
SmokePing¶
Each check finds this stack's SmokePing container by its Compose labels and
asks s6, the process supervisor inside it, whether the SmokePing service is
up, and for how long (s6-svstat -o up,wantedup,updownfor
/run/service/svc-smokeping). The container gets 5
minutes from its start; a normal start takes under two. If the service is
still not up on two checks in a row, the watchdog runs smoking-pi restart
smokeping. A service whose supervisor never started counts as down too.
If another smoking-pi command is changing the stack at that moment (an
upgrade, or the stack starting at boot), the watchdog skips that minute
rather than restart a container that command may be replacing.
At most three restarts in any six hours; after that it only logs, so a
SmokePing that fails for a real reason (a broken Targets file, say) is
left for you to read in smoking-pi logs smokeping. A container that is
stopped, or a stack that is down, is not checked: that was a decision, not
a failure. An image whose state the watchdog cannot read is noted once and
left alone.
A SmokePing that dies as it starts is the opposite case. s6 starts it again every second or two, so it reads as up half the time, and a container restart would start the same broken configuration again. When the service changed state less than 30 seconds ago on two checks at least 50 seconds apart, the watchdog logs, once per loop:
smokeping: svc-smokeping keeps restarting 46 min after the container started: SmokePing exits at start, usually a configuration error, which a restart does not fix; not restarting (sudo smoking-pi logs smokeping)
and restarts nothing. smoking-pi logs smokeping shows the line SmokePing
refused (ERROR: /config/General, line 17: table syntax error, for
example).
What it did¶
smoking-pi watchdog
Watchdog: yes
Wi-Fi: reload the driver after 10 min with nothing answering, reboot 5 min later (at most every 6 h)
SmokePing: restart it when not running 5 min after its container started (at most 3 times in 6 h)
Last events (UTC):
2026-10-13T03:12:00Z wifi: nothing answers on wlan0, neither router 192.168.1.1 nor the Internet (associated to aa:bb:cc:dd:ee:ff); watching
2026-10-13T03:22:00Z wifi: nothing answers on wlan0 for 10 min (associated to aa:bb:cc:dd:ee:ff, 0 packets received meanwhile); reloading the brcmfmac driver
2026-10-13T03:23:00Z wifi: wlan0 reaches the network again after 11 min
The events are kept in /var/lib/smoking-pi/watchdog/events.log (the last
200 lines), so they survive the reboot the watchdog may cause. Every line is
also in the unit's journal:
journalctl -u smoking-pi-watchdog
On Pro with InfluxDB, each event is also written to the stack's database
(measurement watchdog_event), and the alerter sends it as a notification:
a driver reload, a reboot or a SmokePing restart as information (the
outage that caused it was the alert; this is what was done about it), an
action the watchdog could not take (or a SmokePing that keeps dying at
start) as a warning. Basic, Standard and Pro on ClickHouse have no InfluxDB
container, and record nothing there. The write uses the token the database
container was created with; if sync-influx-token.sh had to repair a
token mismatch, a failed write is noted in the unit's journal ("could not
record the event in InfluxDB") and the alerter's own influx_unreadable
says the rest. The start of an episode ("watching") and enable/disable are not
sent. These go through the alerter's outbox like any alert, so a reboot
made while the network was down is told once the Pi is back. Mute them with
the watchdog rule (mute_alerts(rule="watchdog")).
A reboot ends the journal of the boot that hung. To read that boot's kernel messages afterwards (what the driver said before it went quiet), keep the journal across reboots: see Keep the journal across reboots.
Trying it without waiting for a hang¶
--dry-run makes a check say what it would do now, and do nothing: no
action, and nothing recorded, so it never changes what the timer does next:
sudo smoking-pi watchdog check --dry-run
To watch the whole sequence, cut the host off at the firewall from a session that does not go through the router (a console, or SSH from another machine on the same LAN). The rules are not saved, so the reboot clears them:
sudo nft add table inet wdtest
sudo nft add chain inet wdtest out '{ type filter hook output priority 0; }'
sudo nft add rule inet wdtest out oifname wlan0 ip daddr != 192.168.1.0/24 drop
sudo nft add rule inet wdtest out ip daddr 192.168.1.1 drop
sudo nft add table arp wdtest
sudo nft add chain arp wdtest out '{ type filter hook output priority 0; }'
sudo nft add rule arp wdtest out arp daddr ip 192.168.1.1 drop
Replace 192.168.1.0/24 with your LAN and 192.168.1.1 with your router
(ip -4 route show default). The first rule cuts everything beyond the LAN,
the second cuts the router itself, and the third stops the host asking for
the router on the link (ARP). Other hosts on the LAN still reach
the Pi, because that traffic does not go through the router. The driver
reload does not clear the rules. The reboot that follows does, and that is
the recovery to look for. Blocking less is not enough: the Internet, or the
router's link-level answer, keeps the watchdog quiet, as it should. The
packet count in the log keeps climbing during the rehearsal, because the
radio still receives. In a real hang it stays at zero.