Wrap BleakScanner context manager in try-except to detect adapter initialization errors. If 'No Bluetooth adapters found' or similar, log warning and set shutdown event to trigger graceful exit with code 0. Prevents systemd restart loop on hardware without BT adapter (e.g. OPi).
Net Alerter — Device Presence Tripwire Daemon
Persistent systemd daemon that passively monitors device presence on the network via DHCP sniffing and Netlink kernel events. Sends Matrix alerts on device arrival/departure.
Files
| File | Purpose |
|---|---|
net_alerter.py |
Main daemon (stdlib-only, 15K) |
net_alerter.service |
Systemd unit file |
deploy-daemon.sh |
Universal deployment script |
DAEMON_DEPLOYMENT.md |
General deployment guide |
ORANGE_PI_DEPLOYMENT.md |
Orange Pi Zero 3 specific guide |
deploy.sh |
Legacy cron-based deployer (deprecated) |
Quick Start (Orange Pi Zero 3 @ 10.0.0.0)
cd ~/tools/bigbrother/net_alerter
./deploy-daemon.sh root@10.0.0.0
Then configure Matrix credentials:
ssh root@10.0.0.0 "cat > /opt/net_alerter/.env <<EOF
MATRIX_HOMESERVER=https://m.example.org
MATRIX_ACCESS_TOKEN=<your_token>
MATRIX_ROOM_ID=!REDACTED:example.org
EOF
chmod 600 /opt/net_alerter/.env
systemctl restart net_alerter"
Verify:
ssh root@10.0.0.0 "journalctl -u net_alerter -n 30"
How It Works
Three Concurrent Threads
-
DHCP Sniffer — AF_PACKET raw socket captures DHCP traffic
- Extracts MAC, IP, hostname from DHCP packets
- Triggers arrival on Discover/Request, departure on Release
-
Netlink RTM_NEWNEIGH Watcher — Kernel ARP neighbor creation events
- Fires when device reaches REACHABLE state
- Handles static-IP devices
-
Netlink RTM_DELNEIGH Watcher — Kernel ARP neighbor deletion events
- Fires when device times out from ARP cache (5-10 minutes)
- Triggers departure alert
Zero Active Probing
- No nmap, nping, arp-scan, ping
- Only passive listening on raw sockets
- No traffic generated by this daemon
Dependencies
- Runtime: Python 3.6+, root access
- Libraries: stdlib only (socket, struct, threading, time, logging, os)
- Data: OUI database at
/usr/share/hwdata/oui.txtor/usr/share/misc/oui.txt(usually present on Debian)
Configuration
.env file at /opt/net_alerter/.env:
MATRIX_HOMESERVER=https://m.example.org
MATRIX_ACCESS_TOKEN=syt_...
MATRIX_ROOM_ID=!REDACTED:example.org
Optional Environment Variables
NET_ALERTER_ENV— Path to config file (default:/opt/net_alerter/.env)
Deployment Methods
Method 1: Automated Script (Recommended)
./deploy-daemon.sh root@10.0.0.0
Method 2: Manual
See DAEMON_DEPLOYMENT.md → Manual Deployment section
Method 3: Orange Pi Specific
See ORANGE_PI_DEPLOYMENT.md for step-by-step guide with troubleshooting
Monitoring
Service Status
ssh root@10.0.0.0 "systemctl status net_alerter"
Real-Time Logs
ssh root@10.0.0.0 "journalctl -u net_alerter -f"
Check Device Count
ssh root@10.0.0.0 "journalctl -u net_alerter | grep 'Tracking.*devices'"
Example Alerts
Arrival
[NET] ARRIVED: iphone.local (10.0.0.0) [Apple Inc.] MAC:a4:5e:60:ab:cd:ef
Departure
[NET] DEPARTED: iphone.local (10.0.0.0) [Apple Inc.] MAC:a4:5e:60:ab:cd:ef — present 2h 34m
Performance
| Metric | Value |
|---|---|
| CPU | <1% (idle, thread sleeping on sockets) |
| Memory | ~15-20 MB |
| Network Traffic | 0 (passive only) |
| Detection Latency | <100ms for Netlink events, 5-10min for ARP timeouts |
| Startup Time | ~2 seconds |
Troubleshooting
See DAEMON_DEPLOYMENT.md → Troubleshooting section for:
- Service won't start
- No alerts being sent
- Not detecting devices
- High CPU usage
Migration from Cron
The legacy cron-based implementation (deploy.sh) ran every 5 minutes with active probing (nmap). The new daemon:
- Runs continuously
- Zero active probing
- Real-time detection via kernel Netlink notifications
- Lower CPU and network overhead
To migrate, stop the old cron and deploy the daemon.
Development
Code Structure
load_env()— Parse.envconfigurationseed_from_arp_cache()— Bootstrap known devices on startuplookup_oui()— MAC vendor lookupon_arrival()/on_departure()— Event handlers, trigger Matrix alertsdhcp_sniffer()— DHCP packet capture threadparse_dhcp()— Extract MAC/IP/hostname from DHCP payloadsnetlink_watcher()— Netlink event listener threadparse_netlink()/parse_ndmsg()— Kernel neighbor event parsingsend_alert()— POST to Matrix API
Testing
python3 -m py_compile net_alerter.py # Syntax check
python3 -c "import net_alerter" # Import check
Note: Full functional tests require root, raw sockets, and live DHCP traffic.
References
- Netlink: https://man7.org/linux/man-pages/man7/netlink.7.html
- RTnetlink: https://man7.org/linux/man-pages/man7/rtnetlink.7.html
- AF_PACKET: https://man7.org/linux/man-pages/man7/packet.7.html
- DHCP (RFC 2131): https://tools.ietf.org/html/rfc2131
License
Part of BigBrother project.