rd03e.c: RD03E_FRAME_LEN was 5 but the frame's own documented layout
(header + gesture + distance_lo + distance_hi + footer[2]) is 6 bytes.
The footer check read buf[i+3], colliding with the distance high byte at
that same index — so every frame that validated at all was forced to have
distance_cm = lo | 0x5500 (~218m) regardless of what the sensor reported.
Distance readings were garbage 100% of the time, not intermittently.
mems_mic.c: i2s_del_channel() was missing on 2 of 3 init failure paths,
leaking the channel handle.
bmp280.c: the I2C bus/device handles leaked on 4 of 5 init failure paths;
added a fail label that releases both.
app_main.c: sensors now init before Wi-Fi bring-up, matching the rationale
sensor_driver.h already documents (a hanging sensor bus must not be able to
block network bring-up).
rtlsdr_experimental.c: rtlsdr_exp_stop() waited 500ms before
usb_host_uninstall(), but the daemon task blocks up to 1000ms inside
usb_host_lib_handle_events() before re-checking its running flag — the
delay must exceed that or teardown races a live daemon task.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Mic: confirmed via its pinout (L/R, WS, SCK, SD, VCC, GND) that the third
target module is a standard I2S digital MEMS mic (INMP441-family). Added
mems_mic.c/h using ESP-IDF's current driver/i2s_std.h API — reports RMS
audio level in dBFS as sensor_type "evp" rather than attempting on-device
voice-band FFT (the browser EVP mode's approach); the backend's existing
statistical anomaly detector handles spike detection from the raw level,
same as it already does for temperature/pressure/presence.
Also fixes a real gap Workstream B's report flagged: User.essence (a live
model column used throughout merged code — /auth/me, inventory purchases,
summon trickle) had no migration line in main.py's lifespan, which would
have broken on the actual production Postgres database.
Researched the exact modules the user is building with and fixed three
concrete issues the earlier speculative firmware got wrong:
1. WiFi: confirmed the target board (Waveshare ESP32-P4-Module-DEV-KIT,
chip ESP32-P4NRW32) bridges WiFi through an onboard ESP32-C6
co-processor over a fixed 7-pin SDIO link (CLK18/CMD19/D0-14/D1-15/
D2-16/D3-17/RESET54, cross-confirmed against Espressif's own
esp-hosted-mcu docs). wifi_manager.c's esp_wifi_init()/esp_wifi_start()
calls don't need to change — esp_wifi_remote/esp_hosted provide a
drop-in-compatible API — but the component manifest (new
main/idf_component.yml) and sdkconfig.defaults were missing entirely.
2. Real pin conflict: the presence sensor's original UART pins (17/18)
directly collided with the SDIO CLK/D3 pins above — wiring it there
would have broken WiFi, the sensor, or both. Moved to GPIO4/5.
3. Swapped placeholder parts for the user's actual hardware:
- BME280 -> BMP280 (GY-BMP280 module): temp+pressure only, no humidity.
Rewrote the driver rather than just renaming it — the old code would
have read nonexistent humidity registers and reported garbage
forever. 3.3V-only wiring note added (the BME280 assumption of
5V-tolerant logic doesn't hold for this specific breakout).
- LD2410 -> RD-03E (Ai-Thinker, not Hi-Link — a different manufacturer
with a different, incompatible UART protocol). Rewrote the frame
parser against the RD-03E's actual (if less-documented) 5-byte
simple-report format. Reports numeric distance instead of a boolean,
which better fits both the hardware's actual output and the backend's
statistical anomaly detector.
README, CMakeLists.txt, and all cross-references updated to match.
New firmware/esp32p4-sensor-node/ ESP-IDF (C, FreeRTOS) project skeleton
per docs/superpowers/specs/2026-07-23-esp32-sensor-node-design.md's
Workstream I:
- Wi-Fi station-mode connect with exponential-backoff reconnect
(wifi_manager.c), credentials from a gitignored main/device_config.h
the seeker fills in (template: device_config.h.example).
- Telemetry HTTP client (telemetry_client.c) POSTing the spec's exact
contract shape to /api/device/telemetry with a Bearer token, via
esp_http_client + cJSON.
- BME280 I2C driver (bme280.c) with Bosch's public double-precision
compensation formulas, using ESP-IDF's newer driver/i2c_master.h API.
- LD2410 mmWave presence driver (ld2410.c) over UART, chosen over a
plain PIR for its distance/motion data richness — its frame-offset
parsing is flagged as the least-certain code in the firmware.
- sensor_driver_t registry (sensor_driver.h, sensor_registry.c) so new
sensors are a new driver file + one array line, no main-loop changes.
- README.md: build steps, manual-config walkthrough, wiring/pinouts,
and an explicit "what's verified vs. not" section plus a real
hardware caveat (ESP32-P4 has no integrated Wi-Fi radio).
UNVERIFIED AGAINST REAL HARDWARE per the spec's honesty-policy note —
no ESP-IDF toolchain or physical boards available in this environment.
Syntax-checked with gcc against hand-written ESP-IDF API stubs (not
committed) as a best-effort substitute for a real idf.py build.
Workstream J (RTL-SDR experimental module) is explicitly out of scope
here; firmware/esp32p4-sensor-node/components/ is left in place for it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>