Dev Patel

v0.1.0 · simulation-verified · Oct 2026 → Present

Wi-Fi Sight

My Wi-Fi knows
when someone's breathing.

Camera-free presence, motion and breathing-rate sensing from the Wi-Fi channel between three cheap ESP32-S3 boards — a deliberately small scope, a simulator with a written-down physical model, and a plain list of what isn't validated.

The dashboard replaying a bundled synthetic living-room recording: occupied, still, breathing at 21.5 a minute, with the simulator's ground truth in yellow beside every estimate.

Highlights

93.7%1presence accuracy, synthetic
0.61 /minbreathing error, synthetic
82tests

The problem.

A person in a room changes how Wi-Fi travels through it, and the channel state information an ESP32 exposes is enough to see that. It is a camera-free way to know whether a room is occupied, which matters wherever a camera would be unwelcome.

The field has a credibility problem. A very popular 'see people through walls with Wi-Fi' project was publicly questioned over whether its code does what its README claims. I wanted the opposite: three claims I could back up — is someone there, are they moving, how fast are they breathing — and a benchmark anyone can rerun.

What I built.

A transmitter broadcasts tiny ESP-NOW frames at 50 a second on a fixed channel. Each receiver captures their CSI and applies Espressif's gain compensation so automatic gain control doesn't look like movement. On the laptop, each packet's random phase offset is removed, outliers are rejected, and everything is resampled to 20 Hz.

Twenty-five seconds of empty room teaches each link its own static profile and noise, and every later score is in units of that link's false-alarm threshold. Presence is the static profile moving away from the empty room; motion is energy above 1.5 Hz with fans subtracted; breathing is a 0.1–0.6 Hz band, PCA and a spectral peak with a calibrated confidence. Receivers are fused with k-of-n evidence, and the empty room is re-learned when people leave.

With no boards in hand, the algorithms are checked against a simulator whose physical model is written down, including walls, drift, fans and several kinds of interference. Seeds used for tuning are excluded from every reported number.

What I considered.

Rejected

Lead with 'works through walls'

Rejected after review. It holds only when the transmitter-receiver link itself crosses the wall. With every board on this side, a person in the next room is found about a third of the time (simulated recall 0.35).

Rejected

Fuse receivers with a noisy-OR

Replaced by k-of-n evidence. Fused presence barely moved on the core suite (93.8% to 93.7%), but the hard cases improved: through-wall 78.3% to 79.0%, fan 65.2% to 70.0%, other room 41.5% to 47.0%.

Chosen

A small scope, a documented simulator, held-out seeds and a 'Can't' column

Every number says where it came from, and the README lists what the system cannot do beside what it can. The cost is that until real boards are flashed, every accuracy figure is synthetic.

Results.

  • On 29.6 minutes of held-out synthetic scenarios: presence 93.7% fused against 87.4% and 87.8% for each receiver alone, motion 96.5%, breathing error 0.61 breaths a minute with 94.2% of estimates within 2, and no breathing reported in an empty room.
  • Stress suites reported as plainly: through a wall when the link crosses it 79.0%; a fan switched on after calibration 70.0% at precision 0.58; a person next door with every board on this side 47.0%, recall 0.35.
  • Breathing reliable from 8 to 30 a minute, about 20 s after someone settles; someone entering is detected in a median 1.0 s.
  • Both firmware projects compile in CI against ESP-IDF 5.1.4; the host pipeline runs 30–34x faster than real time on one laptop core; 82 tests.

Architecture

How it fits together.

ESP32-S3 TXESP-NOW · 50 pkt/sRX ×2CSI + AGCcompensationPer packetphase cleanup · Hampelresample 20 HzPresencestatic profileMotion> 1.5 HzBreathing0.1–0.6 Hz · PCAFusionk-of-n evidencedashboard · API
  1. 01

    ESP32-S3 TXESP-NOW · 50 pkt/s

  2. 02

    RX ×2CSI + AGC · compensation

  3. 03

    Per packetphase cleanup · Hampel · resample 20 Hz

  4. 04

    Presencestatic profile

    Motion> 1.5 Hz

    Breathing0.1–0.6 Hz · PCA

  5. 05

    Fusionk-of-n evidence · dashboard · API

Two receivers, one empty-room baseline each, three detectors, one fusion step. Every score is relative to the link's own false-alarm level.

In hindsight

This is a simulator result, and the README says so in every table. The firmware has compiled but never run on a board, a pet walking around reads as a person, and the fan suite is still below its best single link. The fusion change taught me to read my own numbers more suspiciously: the fused figure beat every single link partly because the per-link numbers fell, not because fusion got better. Next is the only step that matters — flash the boards, record labelled sessions in a real room, and publish those numbers next to these.

Tech specs.

Type
Project
Where
Personal
When
Oct 2026 → Present
Duration
1 mo
Status
v0.1.0 · simulation-verified
Stack
CESP-IDFESP32-S3PythonNumPySciPyGitHub Actions
Caveats
Every accuracy figure is on simulated data with held-out seeds. The firmware compiles in CI but has not yet been flashed onto real ESP32-S3 boards.