BLE Biosensor Pipeline
ESP32-S3 heart-rate monitor with gap-detection and backfill sync to Android and a Pi backend.
the problem
Continuous heart-rate capture over Bluetooth Low Energy is lossy — phones sleep, connections drop, people walk out of range. A monitor that silently loses data during those gaps isn't a monitor. I wanted a complete record in spite of the dropouts.
architecture
- MAX30102optical sensor
- ESP32-S3C++ firmware + buffer
- BLE
- AndroidKotlin client
- Raspberry PiNode.js backend
A MAX30102 optical sensor feeds an ESP32-S3 running C++ firmware, which streams readings over BLE to a Kotlin Android client and on to a Node.js backend on a Raspberry Pi. The pipeline detects gaps in the record and backfills them on reconnect, so a dropped link becomes a delay rather than a hole.
engineering decisions
Gap detection and backfill instead of best-effort streaming
Rather than assume the link is up, each tier tracks what it has and what it's missing, then reconciles on reconnect. Completeness is designed in, not hoped for.
Buffering at the edge
The ESP32-S3 holds readings so a disconnected phone doesn't mean lost samples — the device keeps recording and hands the backlog over when the link returns.
A tiered edge → phone → server path
Each hop has a clear job: the microcontroller captures and buffers, the phone relays and caches, the Pi is the durable store. Failures at any hop degrade gracefully.
reliability & security
Gap detection and backfill are the reliability story: the record converges to complete once connectivity returns, so a lost connection costs latency, not data.
constraints
A constrained microcontroller, an intermittent BLE link, and a phone that will sleep whenever the OS decides. The design assumes the connection is unreliable by default.