You know what it’s like – so many Raspberry Pis at home… what started with a genuinely simple question: “how many Raspberry Pis on the home LAN are actually powered on right now?” grew into something much more. It should’ve been a one-liner….
It was not a one-liner. It’s never a one-liner.
Here’s roughly how it grew:
1️⃣ pi_discover.py — runs arp-scan (or falls back to nmap and a plain ping sweep, reading MACs back out of the kernel’s own ARP cache), then checks every MAC against the known Raspberry Pi Foundation / Trading Ltd OUI blocks. Point it at a subnet, get back exactly what’s actually a Pi. 👍 “Job’s a good ‘un“… Oh, wait….
2️⃣ A persistent catalog — just a CSV, keyed by MAC, tracking first-seen and last-seen. A Pi that’s powered off doesn’t disappear from the list anymore, it just shows up as “offline · 3d ago”.
3️⃣ webapp.py — because apparently typing a command in a terminal is just too much effort. A small Flask dashboard on top of the same CSV: a Rescan button, CSV/JSON export, a toggle between “Pi-only” and “show me the whole LAN.” Remind me again, how do you spell F-E-A-T-U-R-E C-R-E-E-P ???
4️⃣ A full reskin — lime-green top bar and all, reverse-engineered from a decade-old Hugo/Bootstrap theme I half-remembered lusting after on someone else’s site, tracked down via a Wayback Machine snapshot’s <head> tag because I couldn’t find the theme name “written down” anywhere…
5️⃣ Hand-editable hardware fields — type, RAM, disk, free text. OUI matching tells you that something’s a Pi, but not which Pi, and I got tired of guessing from memory 😬
6️⃣ The first proper gotcha: a CM4 on a Waveshare dual-Ethernet base that refused to show up at all. Turns out the second RJ45 port isn’t CM4 silicon — it’s a bolted-on Realtek PCIe chip with its own OUI, nothing to do with Raspberry Pi. A perfectly real Pi, invisible to a MAC-based scanner, because the interface it happened to be plugged into wasn’t Pi hardware. 🙄
7️⃣ A detour into whether any of this could run from my phone instead. Short answer: no. Android denies raw sockets and blocks reading the kernel’s ARP cache to every unrooted third-party app — Termux, native NDK code, doesn’t matter which — so you get a list of live IPs and zero MAC addresses. Apparently even the polished commercial scanner apps are mostly faking device identification via mDNS/UPnP chatter these days, not actual ARP, for the same reason.
8️⃣ And finally (? really?), merge_catalogs.sh — because a fedora laptop and a Pi 5 scanning the same LAN from two different points see slightly different sets of devices, and by the time I’d hand-typed hardware info into one copy, a careless re-scan on the other could easily have blown it all away. Maybe.
Current tally: one shell script, one small web app, one merge tool, and a .gitignore that somehow took longer to get right than several of the actual features. No sign of this (ever) being finished.


One thought on “Pi Scanner: the shell script that turned into a web app”