# WiFi Tracker ## Purpose Track LAN/Wi‑Fi presence visible from `ballbox-first` and expose a simple dashboard at `/wifi-tracker/`. This is presence estimation from the Pi. It is not exact AP association telemetry. ## Pieces - collector: `/home/sebas/pi-config/bin/wifi-presence-log` - raw events: `/home/sebas/runtime/agent-logs/wifi-presence/activity.jsonl` - rotated raw events: `/home/sebas/runtime/agent-logs/wifi-presence/activity-*.jsonl.gz` - legacy uncompressed rotates: `/home/sebas/runtime/agent-logs/wifi-presence/activity-*.jsonl` - state: `/home/sebas/runtime/agent-logs/wifi-presence/state.json` - aliases: `/home/sebas/runtime/agent-logs/wifi-presence/aliases.json` - fingerprints/evidence: `/home/sebas/runtime/agent-logs/wifi-presence/fingerprints.json` - alert prefs: `/home/sebas/runtime/agent-logs/wifi-presence/alert-prefs.json` - inventory ever-seen: `/home/sebas/runtime/agent-logs/wifi-presence/inventory.json` - persistent daily rollup: `/home/sebas/runtime/agent-logs/wifi-presence/daily-summary.json` - summary: `/var/www/wifi-tracker/summary.json` - UI: `/var/www/wifi-tracker/index.html` - API: `/home/sebas/pi-config/bin/wifi-tracker-api.py` ## Services - `wifi-presence-log.timer` - `wifi-presence-log.service` - `wifi-tracker-api.service` ## URLs - `/wifi-tracker/` - `/wifi-tracker/api/summary` - `/wifi-tracker/api/aliases` - `/wifi-tracker/api/alert-prefs` - `/wifi-tracker/api/health` ## Useful commands ```bash systemctl --user status wifi-presence-log.timer systemctl --user status wifi-tracker-api.service systemctl --user start wifi-presence-log.service journalctl --user -u wifi-tracker-api.service -n 50 --no-pager curl -s http://127.0.0.1/wifi-tracker/api/health | jq curl -s http://127.0.0.1/wifi-tracker/api/summary | jq '.totals' tail -n 20 /home/sebas/runtime/agent-logs/wifi-presence/activity.jsonl ``` ## Data model Raw event types: - `cycle_start` - `router_probe` - `device_snapshot` - `device_online` - `device_offline` - `cycle_end` Dashboard activity summary is still derived from approximate sessions. A new session starts when snapshot gaps exceed the configured offline gap. Buckets still exist in summary data, but the main UI now emphasizes a device presence timeline instead of percentage-style bars. The main graph shows horizontal blue segments for periods considered present. Those segments are derived from raw `device_snapshot` observations, with online turning on immediately and offline only turning off after 3 consecutive missing scan slots (~6 minutes at the current 2-minute scan interval). The collector now also maintains an `inventory.json` ever-seen device list so historical devices remain visible in the UI even if they are not present in the current state snapshot. The collector now also runs lightweight proactive fingerprinting for visible devices. If a device has no manual alias, the service may write a descriptive alias directly into `aliases.json` with a ` [from AI]` suffix. Manual aliases always win and are not overwritten. Per-MAC evidence is stored in `fingerprints.json`, including guessed alias, confidence, sources, ports, and small evidence snippets. ## Retention The raw JSONL log rotates automatically when it grows past the configured size threshold. Rotated logs are gzip-compressed. Default now is keep forever (`ROTATE_KEEP=0`). Set a positive value only if you want capped retention. The collector also writes `daily-summary.json`, a durable per-device per-day rollup with hours, sessions, first seen, and last seen. That file is rebuilt from retained raw logs and survives even when old fine-grained snapshots age out. Recent UI/API activity still reads from the live tail for speed; long-range history should use `daily-summary.json`. Alert toggles are stored in `alert-prefs.json`. The UI can enable or disable alerts per device without removing the device from the inventory.