Two winters ago I started noticing that the power in our flat on the Asian side dropped most Saturday mornings, usually between 09:10 and 09:40, and almost never on Sundays. The fridge clock and the router were the only evidence. I wanted a record I could actually trust, not my memory of “it happened again.”
I already had a Raspberry Pi 3 in a drawer and a cheap USB UPS hat that reports battery voltage over I2C. The Pi draws about 3W; the hat holds it up for roughly 90 seconds after mains drops, which is plenty to write a shutdown record. The main trick was not measuring the outage—it was measuring the gap between last heartbeat and next boot, because the Pi can’t log while it’s dead.
A one-minute cron job writes a heartbeat with the current boot ID:
# /etc/cron.d/heartbeat
* * * * * root /usr/local/bin/hb.sh
# hb.sh
#!/bin/sh
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
BOOT=$(cat /proc/sys/kernel/random/boot_id)
echo "$NOW $BOOT" >> /var/log/power/hb.log
On boot, a systemd unit reads the last line of hb.log, compares the boot ID, and appends a row with the gap in seconds:
#!/bin/sh
LAST=$(tail -n1 /var/log/power/hb.log)
LAST_TS=$(echo "$LAST" | awk '{print $1}')
LAST_BOOT=$(echo "$LAST" | awk '{print $2}')
NOW_BOOT=$(cat /proc/sys/kernel/random/boot_id)
if [ "$LAST_BOOT" != "$NOW_BOOT" ]; then
GAP=$(( $(date -u -d "$(date -u +%Y-%m-%dT%H:%M:%SZ)" +%s) - $(date -u -d "$LAST_TS" +%s) ))
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) reboot gap=${GAP}s" >> /var/log/power/outages.log
fi
The UPS hat also logs voltage every 10 seconds, so a short dip that doesn’t kill the Pi still shows up as a sag. That gave me two signals: hard reboots and brownouts.
Why this shape instead of a smart plug with cloud logging? The plug is easier, but it dies with the router, and the router is on the same circuit. The Pi plus UPS is self-contained: it records the outage from the inside, which is the only place that stays alive long enough to say anything. The cost is precision. I know a reboot happened, not the exact second mains dropped—the gap is between last heartbeat and boot, so the error bar is about 60 seconds. For a pattern over two years that’s fine.
Where it fails: if the outage lasts longer than the UPS, the Pi loses the last few heartbeats (I lost about 20 minutes once during a long cut and had to infer it from the router’s own log). If the SD card corrupts on power loss—it has twice—the heartbeat file is gone and I have a hole. And clock drift matters: without NTP after boot, the gap calculation is garbage. I now force ntpdate before the boot unit runs, or skip the row if the clock is clearly wrong.
What I ended up with is a CSV of about 140 reboot rows over two years, most clustered on Saturday mornings, plus a smaller set of brownouts on hot afternoons in July. The pattern is real and boring, which is what I wanted.
For anyone who has done something similar: how do you handle the clock-drift problem on a device that boots with no network? I’ve been fudging it with a rough last-known-time file, and I suspect there’s a cleaner way.
0 条评论
还没有评论,写下第一条。