# Presence Daemon — Person Presence Intelligence Passive multi-signal WiFi/ARP/DHCP/BLE person presence tracking daemon for BigBrother drop implant. ## Quick Start ```bash cd /path/to/bigbrother/presence sudo bash install.sh ``` This creates `/opt/sensor/sensor.py`, initializes the database, and starts the systemd service. ## Configuration Environment variables: - `PRESENCE_MONITOR_IFACE` — WiFi monitor mode interface (default: wlan1) - `PRESENCE_DATA_IFACE` — Connected network interface for ARP/DHCP (default: wlan0) - `PRESENCE_DB_PATH` — SQLite database location (default: /opt/presence/presence.db) - `PRESENCE_MATRIX_WEBHOOK` — Matrix webhook URL for alerts (default: empty, no alerts) Example systemd override: ```bash sudo systemctl edit sensor # Add to [Service] section: # Environment=PRESENCE_MONITOR_IFACE=wlan2 # Environment=PRESENCE_MATRIX_WEBHOOK=https://matrix.example.com/hook/... ``` ## Architecture ### Sensor Threads (4 concurrent) 1. **Probe Sniffer** — WiFi probe request capture on monitor interface - Passive 802.11 frame parsing (type 0, subtype 4) - Extracts source MAC → +0.60 certainty bump - Runs on PRESENCE_MONITOR_IFACE 2. **ARP Listener** — netlink RTM_NEWNEIGH/RTM_DELNEIGH events - Kernel neighbor discovery events - Filters infrastructure IPs - Extracts MAC → +0.50 certainty bump 3. **DHCP Sniffer** — AF_PACKET raw socket on data interface - Captures DHCP DISCOVER/REQUEST packets - Extracts client MAC (chaddr field) - Extracts hostname (option 12) - MAC → +0.80 certainty bump 4. **BLE Scanner** — Passive BLE device discovery - Uses `bleak` library if available - Gracefully disables if ImportError - Device address → +0.40 certainty bump ### Core Logic **Signal Fusion** (per person): - Collect all device certainties - Apply exponential decay: `certainty × e^(-0.08 × age_minutes)` - Aggregate: `max + 0.08 × second_max` - Check state machine **Presence Anchor** (critical): - Once PRESENT (certainty ≥ 0.40), hold PRESENT for 45 minutes from last signal - Prevents false ABSENT from temporary signal loss (iOS suppression, WiFi roam, power save) - After 45 minutes without signal ≥ 0.40 → ABSENT **State Machine**: ``` UNKNOWN → PRESENT → ABSENT → PRESENT ↓ agg_cert ↓ └─────────≥ 0.40 45 min no signal ``` **Alerting**: - UNKNOWN → PRESENT: "ARRIVED" alert - PRESENT → ABSENT: "DEPARTED" alert - Via Matrix webhook if configured ### Database Schema **persons** — Named people - id (PK) - name — Person name - notes — Optional metadata **devices** — MAC-to-person mapping - mac (PK) - person_id (FK) - label — Device name (iPhone, Laptop, etc.) - added_at — Timestamp **signals** — Raw signal observations - id (PK) - mac — Device MAC - signal_type — "probe", "arp", "dhcp", or "ble" - certainty — Aggregated certainty after this signal - ts — Observation timestamp **occupancy_log** — State transitions - id (PK) - person_id (FK) - old_status — Previous state - new_status — New state - ts — Transition timestamp ## HTTP Status Endpoint GET http://127.0.0.1:9191/ Returns JSON: ```json { "persons": [ { "id": 1, "name": "Alice", "status": "PRESENT", "last_change": 1712761234.5 } ] } ``` ## Limitations (Phase 1) - **No auto-enrollment**: Device-to-person mapping must be set up manually in database - **No mDNS parsing**: Hostnames are not extracted or used for identity - **BLE optional**: Requires `bleak` library; gracefully disabled if missing - **Monitor mode required**: Probe sniffer needs separate WiFi adapter in monitor mode - **Root access needed**: Raw sockets require CAP_NET_ADMIN or root - **Single location**: No multi-room support ## Files - `presence_daemon.py` — Main daemon (1000+ lines) - `presence_schema.sql` — SQLite schema - `install.sh` — Deployment script - `AUDIT_impl.md` — Implementation notes and audit checklist - `README.md` — This file ## Logging Logs to `/var/log/sensor.log` and stdout. Log level: INFO (debug messages only on errors). Example log output: ``` 2026-04-10 14:54:32,123 [INFO] Database initialized at /opt/sensor/sensor.db 2026-04-10 14:54:32,124 [INFO] Loaded 2 persons from database 2026-04-10 14:54:32,125 [INFO] Probe sniffer started on wlan1 2026-04-10 14:54:32,126 [INFO] ARP listener started 2026-04-10 14:54:32,127 [INFO] DHCP sniffer started on wlan0 2026-04-10 14:54:32,128 [INFO] BLE scanner started 2026-04-10 14:54:32,129 [INFO] Status server started on http://127.0.0.1:9191 2026-04-10 14:54:32,130 [INFO] Sensor daemon started ``` ## Testing 1. Verify systemd service is running: ```bash sudo systemctl status sensor ``` 2. Check database initialization: ```bash sqlite3 /opt/sensor/sensor.db ".tables" ``` 3. Query persons: ```bash sqlite3 /opt/sensor/sensor.db "SELECT * FROM persons;" ``` 4. Query recent signals: ```bash sqlite3 /opt/sensor/sensor.db "SELECT * FROM signals ORDER BY ts DESC LIMIT 10;" ``` 5. Check status endpoint: ```bash curl http://127.0.0.1:9191/ ``` 6. Check logs: ```bash tail -f /var/log/sensor.log ``` ## Phase 2 Roadmap - Auto-enrollment from mDNS hostnames - BLE MAC signature recognition (Apple Watch, AirPods) - Device quorum (multi-device presence confirmation) - Tentative device linking via co-occurrence windows ## Phase 3 Roadmap - Pattern of life analytics - Arrival/departure time learning - Occupancy forecasting - Multi-location aggregation