Add presence daemon user documentation and architecture guide
This commit is contained in:
@@ -0,0 +1,202 @@
|
|||||||
|
# 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
|
||||||
Reference in New Issue
Block a user