203 lines
5.5 KiB
Markdown
203 lines
5.5 KiB
Markdown
# Presence Daemon — Person Presence Intelligence
|
||
|
||
Passive multi-signal WiFi/ARP/DHCP/BLE person presence tracking daemon for BigBrother drop implant.
|
||
|
||
## Quick Start
|
||
|
||
```bash
|
||
cd /home/n0mad1k/tools/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
|