Files

5.5 KiB
Raw Permalink Blame History

Presence Daemon — Person Presence Intelligence

Passive multi-signal WiFi/ARP/DHCP/BLE person presence tracking daemon for BigBrother drop implant.

Quick Start

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:

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:

{
  "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:

    sudo systemctl status sensor
    
  2. Check database initialization:

    sqlite3 /opt/sensor/sensor.db ".tables"
    
  3. Query persons:

    sqlite3 /opt/sensor/sensor.db "SELECT * FROM persons;"
    
  4. Query recent signals:

    sqlite3 /opt/sensor/sensor.db "SELECT * FROM signals ORDER BY ts DESC LIMIT 10;"
    
  5. Check status endpoint:

    curl http://127.0.0.1:9191/
    
  6. Check logs:

    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