ZeroTrace AirLeak
Firmware Overview
What runs on the AirLeak unit, and how to interact with it
The AirLeak firmware is what makes the unit do what it does. It runs on the ESP32-S3, drives the BLE radio, decodes every captured advertisement, classifies devices, fires alerts, and streams the result to the mobile app over Bluetooth.
This section is the advanced reference for the firmware: how you talk to it, what settings persist, the alert engine, the safe-mode behavior, and how state survives reboots.
If you're just getting started, start with Installation and First Capture. Come back here when you want to tune behavior or understand what the unit is reporting.
What the firmware does
2.4 GHz BLE radio
│
▼
┌─────────────────────┐
│ Observer scan │
│ (NimBLE, passive │
│ + active SCAN_REQ)│
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Parser │
│ BLE advertisement │
│ decoders │
└─────────────────────┘
│
▼
┌─────────────────────┐
│ Aggregator │
│ Classifier │
│ Leakage scoring │
└─────────────────────┘
│
├──────────────► Alert engine ──► threat-indicator LED
│
▼
┌─────────────────────┐
│ Delta ring → CBOR │──► Mobile app (BLE notify)
│ capture stream │
└─────────────────────┘
┌─────────────────────┐
│ Persistent config │ ← device name, LED,
│ (LittleFS + NVS) │ threat-indicator tuning
└─────────────────────┘
The work splits across the two cores: the NimBLE host and scan callbacks on core 0, the parser / aggregator / stream tasks on core 1. That split is why a single-core ESP32 variant cannot run AirLeak's pipeline without dropping advertisements under load, see Why ESP32-S3?.
How you interact with the firmware
The only control surface is the mobile app over a BLE link. There is no web UI, no access point, and no serial console. (A compile-time AL_DEBUG_SERIAL flag exists for print-only USB diagnostics during development, but it's off in shipping firmware and is one-directional.)
Control rides a Nordic UART Service (NUS) JSON-RPC channel; the capture stream rides a separate dedicated BLE characteristic. The app calls these methods:
| RPC | Purpose |
|---|---|
identity.read | Device name, firmware type / version, HWID, licensed flag |
license.request / set / status | HWID-bound license activation |
config.get / config.set | Read / write persistent settings |
mode.read / mode.set | Read / change capture mode |
state.read | Live health: uptime, heap, mode, active devices, scan-duty estimate, drop counts |
capture.snapshot / since / subscribe / unsubscribe | Capture-stream sync |
led.set | LED color preview |
diag.read / clear | On-flash crash / heap / boot diagnostic log |
node.* | TraceNet swarm node management |
For day-to-day use you never touch these directly, the app's tabs (Live, Hunt, Drive, Insights, Modes, Settings, About) cover everything.
What persists, what resets
| State | Persisted? | When it resets |
|---|---|---|
| Capture mode | yes (NVS) | Mode change |
| Config settings (device name, LED, threat-indicator tuning, emit thresholds, swarm) | yes (LittleFS /config.json) | config.set, or factory reset |
| License | yes | Re-licensing / factory reset |
| Live device aggregator | no | Reboot or switch to Setup |
| Alert ring buffer | no | Reboot |
| Diagnostic log | yes (on-flash) | diag.clear |
Full details are on the Persistence page.
Where to read deeper
- Settings Reference, every persistent setting and its default
- Heartbeat / state fields, what
state.readreports - Throttle & emit policy, how the stream is coalesced
- Alert Rules, every alert the engine can fire
- Safe Mode, when it triggers and what it does
- Persistence, what survives reboot, what doesn't
Earlier (WiFi-era) AirLeak builds had a USB serial CLI. The shipping BLE-only firmware removed it, the mobile app over BLE is the single control surface.