Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Pi-Spy

Need to track down that Raspberry Pi you swore was on the network five minutes ago? Pi-Spy is still your over-caffeinated sidekick, but now it speaks fluent multi-interface, mDNS, and Tailscale. It enumerates every up IPv4 interface, sweeps each CIDR, folds in tailnet intel, and lines up the candidates in a numbered K.A.R.I. list so you can lock onto the right board and SSH in with a single keystroke.

Quick Start

# run the launcher (manages a venv, sets PYTHONPATH, execs `python -m Pi-Spy`)
./pi-spy

# include offline devices (cached or currently sleeping)
./pi-spy --include-offline

# jump straight to a known host (substring match) and ssh
./pi-spy --connect atrium --action ssh

# focus on tailnet entries and print multi-line details
./pi-spy --tailnet-only --action details

# merge cached-but-offline devices back into the list
./pi-spy --use-cache --include-offline --action details

(./bin/Pi-Spy still works if you prefer the original launcher.)

Discovery Pipeline

  • ip -o -4 addr show is parsed to enumerate every up, non-loopback IPv4 address and its CIDR.
  • Each interface CIDR is scanned with nmap -sn; in --fast mode large networks are trimmed to the first 64 hosts.
  • If available, avahi-browse -rt _ssh._tcp collects mDNS announcements for _ssh._tcp endpoints.
  • tailscale status --json (or tailscale status) injects tailnet peers when --tailscale is enabled.
  • Optional arp-scan --localnet runs (per interface) when --privileged is provided and the command exists.
  • Every discovered IP is probed with a short TCP connect to port 22 to confirm SSH reachability.
  • Records are deduplicated by MAC or IP, merged across sources, scored, and streamed into a K.A.R.I.-styled numbered list (online devices first by default):
[K.A.R.I.]: Pi-Spy with my little eye… 4 candidates across 2 interface(s). Filters: online only, tailnet-only.
 1. [ 90] atrium / 100.79.139.57 (tailnet, ssh)
 2. [ 80] freyja-nix / 100.103.68.25 (tailnet, ssh)
 3. [ 50] jellyfin / 100.106.56.126 (tailnet, offline)
 4. [ 10] 10.50.16.114 / 10.50.16.114 (lan, offline, cached)
Select device # (ENTER=cancel):

Choose a number and Pi-Spy immediately runs ssh user@best_ip, preferring tailnet endpoints when they’re reachable.

Command-line Options

Flag Description
--json Print the (filtered) device array as JSON and exit.
--fast Limit nmap -sn to the first 64 hosts on large CIDRs (mDNS / tailnet still run).
--tailscale / --no-tailscale Toggle tailnet discovery (auto-on when the CLI is present).
--cache / --no-cache Read/write ~/.config/pi-spy/devices.json to track last_seen history.
--privileged Allow arp-scan --localnet (requires root or CAP_NET_RAW).
--ssh-timeout SECS Tune the SSH probe timeout (default 1.0).
--action {ssh,print,details} Pick post-selection behavior (default ssh, or print when --json).
--connect TOKEN Skip the menu and match a device by id/hostname substring.
--user, --identity, --port Passed straight through to the ssh command (--user overrides the cached/prompted username).
--tailnet-only, --lan-only Filter the candidate list before rendering/output.
--include-offline Show offline devices (default view hides them).
--use-cache Merge cached-but-offline devices back into the list (marked as cached).

Interactive mode now defaults to an SSH connect (using tailnet IPs when confirmed reachable). If Pi-Spy hasn’t seen a username for the chosen device yet, it asks right after you pick it and remembers the answer for next time. Switch to --action print or --action details when you need structured data instead of a live shell, or set --connect <slug> to bypass the prompt entirely.

Cache + JSON Output

Cache entries live at ~/.config/pi-spy/devices.json by default (override with PI_SPY_CACHE). Each device record includes:

{
  "id": "AA:BB:CC:DD:EE:FF",
  "hostname": "mypi.local",
  "tailscale_name": "mypi.ts.net",
  "ip_local": ["10.0.0.50"],
  "ip_tailscale": ["100.100.100.5"],
  "mac": "AA:BB:CC:DD:EE:FF",
  "vendor": "Raspberry Pi Foundation",
  "score": 90,
  "sources": ["nmap", "mdns", "tailscale", "ssh"],
  "last_seen": "2024-05-01T12:00:00.000000+00:00"
}

--json mode prints an array of these objects; interactive mode uses the same data to populate the numbered list.

Pi-Spy remembers the SSH username you enter per device (stored in ~/.config/pi-spy/devices.json); supply --user USER to override it for a single run.

Troubleshooting Tidbits

  • No entries? Confirm the interface is UP, make sure nmap is installed, and try without --fast.
  • Need more accuracy on noisy networks? Re-run with sudo ./pi-spy --privileged so arp-scan can grab MAC addresses.
  • Want to skip UI scripting? Stick to --json and feed the array into your own tooling.
  • Client isolation / captive portals can hide hosts entirely; lean on the Tailscale feed if you have it.

Happy Pi hunting!

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages