In an earlier post we built Going Connect, a tray app that finds Going products over mDNS. Then the reality of our own office set in.
“That Pi over there isn’t even a Going product, it’s just a dev image someone flashed. What was its IP?”
A ZPi development unit, an Arduino uploader server, a Zero 2 flashed five minutes ago for a test — a plain Raspberry Pi advertises no mDNS TXT records. avahi leaks a hostname at best, and it certainly is not going to follow our vendor=Going convention. So the existing mDNS filter in Going Connect never saw any of them.
This time we filled that gap by adding an active scan to the same app: going out and finding the devices that do not announce themselves.
The real problem — an IP never tells you which Raspberry Pi
Finding a Raspberry Pi on the network hits the same wall every time you deploy several of them.
- DHCP means the IP changes on reboot (
.236becomes.249) - Looking at
192.168.0.xtells you nothing about whether it is a Zero 2 or a Pi 4 - Running
nmapgets you as far as “port 22 open”, but never “this is the old Pi3 in the storage room”
So somebody had to memorize it or stick a label on the case. That gave us the goal:
Give a device a nickname once, and find it by name even after its IP changes.
The active scan pipeline, six stages
The active scan pipeline runs the opposite way to mDNS. mDNS was comfortable because the device tells you who it is; here we have to sweep the network ourselves. We built a six-stage pipeline.
Determine the subnet (/24) ← only real NICs with a gateway (WSL and Hyper-V virtual switches excluded)
↓
Parallel ping sweep (254 hosts) ← the point is not the replies, it is populating the ARP table
↓
Filter MACs from the ARP table ← keep only Raspberry Pi Foundation OUIs
↓
Port probe (22/80/5000…) ← label which services are up
↓
Reverse hostname lookup (DNS)
↓
Detailed SSH query (once) ← exact model name and OS
Use the MAC to decide “is this a Pi?” first
The key to picking Raspberry Pis out of dozens of devices on a network is the first three bytes of the MAC address (the OUI). The Raspberry Pi Foundation uses a handful of OUI blocks, and that is our first filter.
private static readonly string[] PiOuis =
{ "B8:27:EB", "DC:A6:32", "E4:5F:01", "D8:3A:DD", "28:CD:C1", "2C:CF:67" };
The ping sweep is not really about the replies. Pinging each IP once makes the OS record that IP-to-MAC mapping in its ARP cache, and reading that cache is the actual goal. On Windows we read GetIpNetTable from iphlpapi.dll directly through P/Invoke, and fall back to parsing arp -a if that fails.
Use SSH to get the exact model name
An OUI only tells you “this is a Raspberry Pi” — not whether it is a Zero 2 or a Pi 4. So we go one step further: if port 22 is open, we connect over SSH with a registered account and read exactly three lines.
cat /proc/device-tree/model → "Raspberry Pi Zero 2 W Rev 1.0"
hostname → "raspberrypi"
. /etc/os-release; echo $PRETTY_NAME → "Debian GNU/Linux 13 (trixie)"
This happens exactly once, on first discovery. The model name never changes, so we cache it against the MAC and later scans never touch SSH again. Account passwords must not sit in plain text, so they are encrypted with DPAPI (ProtectedData, CurrentUser scope).
The real core — a device store keyed by MAC
Storage keyed by MAC is the heart of this feature, not the clever scanning. When a device is saved to %AppData%\GoingConnect\pi-devices.json, the key is the MAC, not the IP.
{
"D8:3A:DD:XX:XX:XX": {
"nickname": "Test Zero2 (for the control board)",
"lastIp": "192.168.0.x",
"model": "Raspberry Pi Zero 2 W Rev 1.0",
"os": "Debian GNU/Linux 13 (trixie)",
"hostname": "raspberrypi"
}
}
That single decision buys two things:
- Even when the IP changes, a matching MAC means the same device, so the nickname follows it
- Even when a scan misses it, it is not removed from the list but greyed out as offline, so “the Pi in the storage room that is currently powered down” still shows up
The mDNS side drops a device after 90 seconds of silence; the Pi side does the exact opposite and keeps it even when offline. What we want to know is not “what is alive right now” but “where is that Pi I look after — or is it switched off?”
The trap we hit — ARP is sometimes late
The ARP table scan missed one of our two Pis on the first run; the Pi 4 never showed up. The cause is that pinging 254 hosts at once makes individual ARP registrations drop out intermittently. The ping reply comes back, but at the moment you read the ARP table the entry is not in there yet.
The fix was simple: ping the last known IP of every device we already know one extra time, with a generous timeout. The device we most want to find reliably is, after all, “that Pi we saw before”.
// Ping known device IPs once more so they definitely answer
foreach (var ipStr in knownIps)
if (IPAddress.TryParse(ipStr, out var ip))
tasks.Add(PingOnce(ip));
After the fix we re-verified: both the Zero 2 and the Pi 4 were found, a nicknamed device kept its name across a restart, and a fake device that does not exist stayed in the list greyed out as offline.
How it bolts onto the existing tray app — parallel and non-invasive
The Windows WPF tray app already fit, so we added this there rather than writing a separate program because Going Connect’s structure already fit. The Device model already had Brand grouping and a Label for user labels, and the UI already preferred Label for display. So mapping a Pi like this was enough to get a whole new group with almost no UI work.
| Device field | Pi mapping |
|---|---|
Brand | "Raspberry Pi" (automatically becomes a new group) |
Serial (identity key) | MAC address |
Product | model name read over SSH |
Label | the nickname from storage |
The existing mDNS discovery and Find Me were not touched by a single line. The two discovery services each own their device list and push into the same view, so Going products and plain Pis coexist in one window.
Recap: finding Raspberry Pis on the network
When finding a Raspberry Pi on the network, mDNS is elegant when the device cooperates, and useless when it does not. For those, the answer was an active approach: wake the ARP table with pings, narrow it down by MAC, confirm it over SSH.
And what actually solved the problem was not any of that scanning technology, but the one-line design decision to key devices by MAC. IP addresses change; MAC addresses do not. Now, once a Pi has a nickname, you can find it by name whether a reboot changed its IP or it happens to be switched off.
IP addresses change and MAC addresses do not — tying the nickname to the MAC was the single design decision that solved the problem.
Contact
- Email: [email protected]
- Instagram: https://www.instagram.com/going.sen/
- Website: https://intosen.com/kr/consult/
Comments
Enter a nickname to leave a comment, or sign in with Google or GitHub.