A local-first Wi-Fi CSI sensing instrument. Two ESP32-S3 boards bracket a seated subject; the RX board emits raw 802.11n Channel State Information per packet over USB; a Python collector + DSP pipeline turns those frames into motion / occupancy / signal-quality / (research-only) respiration windows; a Next.js console renders them in real time.
No camera. No microphone. No cloud. No identity Concerns.
ESP32-S3 TX ))) Wi-Fi 2.4 GHz multipath ((( ESP32-S3 RX
|
USB-CDC @ 115200 (CH343)
v
pyserial -> InMemoryEventBus -> DSP windows -> SQLite + JSONL
| |
+-------- FastAPI + WebSocket /ws/live -> Next.js UI
Two terminals, ~2 minutes from a fresh clone if you have hardware.
# Terminal 1 - one-time setup, then API
npm install # web + workspace deps
python -m venv .venv
. .\.venv\Scripts\Activate.ps1
python -m pip install -e ".[dev]" # backend + tests
.\scripts\setup_local.ps1 # auto-detects RX COM port,
# writes .env at repo root
python -m uvicorn apps.api.src.main:app --reload --host 127.0.0.1 --port 8000
# look for: [boot] settings source_mode=LIVE serial_port=COM10 ...# Terminal 2 - web UI
npm run web:dev
# open http://localhost:3000In the UI:
- Live Room → Readiness — first three rungs go green: API reachable, WebSocket connected, Serial port configured.
- Click Start session in the disconnected banner (or use Experiment Console → Create session).
- Within ~5 s, CSI frames flowing turns green and live charts populate.
- Hold the room empty → Calibrate (10 s) in the Baseline Calibration card. Without baseline, occupancy reads "uncalibrated".
The legacy console at /home is unchanged. Three new diagnostic surfaces are
one click away in its top bar:
| Route | What it shows |
|---|---|
/raw |
Per-frame inspector, live amplitude + phase spectrograms, link diagnostics, subcarrier health (Phase A + B surfaces). |
/3d |
3D wave view: operator-supplied room/TX/RX/subject geometry, real-time pulses driven by actual TX packet timing, subcarrier carpet, motion-modulated subject blob. Pop-out window via the HUD button. |
/devices-v2 |
Link state + the room geometry editor (2D drag floorplan + numeric fields). Save here before opening /3d. |
python scripts\validate_accuracy.py data\recordings\<session-id>.jsonlReplays a JSONL through the DSP and asserts sanity bounds (rate floor, quality floor, motion non-zero). Returns non-zero on failure so it can be added to CI later.
$env:AETHER_REPLAY_PATH = "data/recordings/<session-id>.jsonl"
python -m uvicorn apps.api.src.main:app --reload
# UI source badges all switch to REPLAY so it cannot be confused with live data| File | What it covers |
|---|---|
docs/SETUP.md |
Full setup, prerequisites, replay mode, where to look when broken |
docs/DEBUGGING.md |
Log tag reference for every layer; filter recipes for browser + API |
docs/TROUBLESHOOTING.md |
Symptom → fix recipes (Python version, pnpm, serial port, packet rate) |
docs/ARCHITECTURE.md |
Service boundaries, data flow, transport contracts |
docs/PROTOCOL.md |
Wire schemas (csi_frame.v1, derived_window.v1, experiment_event.v1) |
docs/DATA_MODEL.md |
Storage entities, retention, privacy fields |
docs/FIRMWARE.md |
TX/RX firmware roles, flash scripts |
docs/DEVICE_REALITY.md |
Honest hardware notes (geometry, baseline requirement) |
docs/VITAL_SIGNS_REALITY.md |
Why HR is research-only on this hardware |
docs/ETHICS_AND_PRIVACY.md |
Boundaries: no probe requests, no identity/emotion/medical |
docs/EXPERIMENT_PLAN.md |
current protocols (empty room, presence, motion, breathing, sweeps) |
docs/ROADMAP.md |
Vision through V3 |
docs/DECISION_LOG.md |
Major design decisions, dated |
PROBLEMS.md |
Known issues, root causes, things to fix later |
CLAUDE.md |
Operating notes for AI coding agents in this repo |
ESP32-S3 + ESP-IDF firmware → CH343 USB-serial → Python 3.12 + pyserial + asyncio pub/sub bus → NumPy/SciPy DSP (FFT + ACF + bandpass + baseline calibration) → Pydantic v2 protocol models → SQLite + JSONL storage → FastAPI + Uvicorn + native WebSocket → Next.js 16 + React 19 + TypeScript + Turbopack + uPlot + TanStack Table/Virtual.
Local-first throughout. No cloud, no auth, no telemetry, no hidden state.
apps/
api/ FastAPI service: routes, WebSocket, runtime, session store
web/ Next.js 16 app: features/, components/, lib/
services/
collector/ pyserial reader + replay reader + in-memory bus
dsp/ features, calibration, biorhythm, summaries
kb/ knowledge-base search (V1 scaffolding, not yet wired)
agent/ grounded-agent + MCP tools (V1 scaffolding, not yet wired)
packages/
protocol/python/ Pydantic models (single source of truth)
protocol/typescript/ TS mirror
protocol/schemas/ JSON Schemas (validated by tests/e2e/)
ui/ Shared design tokens
firmware/
esp32-s3-tx/ CSI-emitter board (transmit-only)
esp32-s3-rx/ CSI-capture board (CSI callback → JSON over USB)
scripts/
setup_local.ps1 Auto-detects boards, writes .env (Windows)
probe_serial.py Opens given COM ports for 4 s, reports CSI/heartbeat
hardware_check.ps1 One-port hardware confirmation
flash_tx.ps1 / .sh Build + flash via idf.py
flash_rx.ps1 / .sh
record_session.ps1 Convenience wrappers around the API
replay_session.ps1
no_nonreal_data_check.mjs CI guard against fake/mock/synthetic data
docs/ Markdown reference - see table above
data/
recordings/ Per-session raw + derived JSONL (gitignored)
exports/ Session report bundles (gitignored)
fixtures/ Tiny test inputs (kept in git)
npm test # protocol schema + no-fake-data scan
python -m pytest -q # 38 backend tests
npx tsc --noEmit -w @aether/web # frontend typecheckGitHub Actions (.github/workflows/ci.yml) runs all three on push.
Current (v0.2). Live CSI capture, storage, replay, real-time UI,
controlled experiments, structured logging, hardened baseline calibration
(acceptance gates + responsive-subcarrier feedback loop + per-frame phase
detrend), FFT/ACF respiration research-only readout. New: end-to-end
link instrumentation (/diagnostics/link), per-subcarrier introspection
(/diagnostics/subcarriers), raw-frame REST + WebSocket subscribe topic,
operator-supplied room geometry, Raw Sensor diagnostics page, and a 3D
wave-view route that animates real packet timing and subcarrier amplitude
in operator-supplied geometry — pop-out window supported. Single-room,
single-subject, single-link.
V1 / later. See docs/ROADMAP.md and PROBLEMS.md for what's scaffolded
but not wired (agent + KB) and what's known broken/unfinished.
Internal research project. Hardware-dependent; no public deploy. Read
docs/ETHICS_AND_PRIVACY.md before recording sessions.