v6.0 · MODULAR ESP32-S3 sensor platform · FreeRTOS uploader · OTA

ESP32 sensors,
made simple.
One platform. Many devices.

Gridspin IoT ships two production devices on one disciplined stack: a 7-day biosignal wearable with 8-ch EMG, multi-wavelength PPG, 9-DOF IMU and GSR — and a 32-sensor smart-shelf that knows which serum bottle just left the pad. Same FreeRTOS uploader, same packed binary, same cloud.

ESP32-S3 + FreeRTOS 131 B / record packed Per-device token HTTPS
ADS1299 · 8-CH EMG · 500 SPS MAX30101 · PPG BNO055 · TMP117 · MLX ESP32-S3 · FreeRTOS 7-day HR / SpO2 72 · 98%
32
FSR sensors per shelf, 8 × 4 grid
8 ch
EMG @ 500 SPS · ADS1299
7 days
wearable battery, SPARSE duty
131 B
per record, packed binary V2.1
15 min
FreeRTOS uploader cadence, HTTPS

The platform thesis

Most IoT projects ship one device.
We ship a recipe.

Every Gridspin IoT device — wearable, shelf, whatever comes next — uses the same firmware spine: a FreeRTOS uploader pinned to Core 0, a packed binary log on SD, OTA over Wi-Fi, NVS-persistent config, per-device token auth into a single cloud ingest. Pick the sensor stack. Reuse the platform.

Product · Biosignal wearable

Research-grade biosignals, from a watch that lasts a week.

A multimodal wearable on ESP32-S3 — 8-channel EMG, multi-wavelength PPG, 9-DOF IMU, dual temperature, and GSR. Packed at 131 bytes per record on SD, log-rotated every 15 minutes, uploaded over HTTPS with a per-device token. OTA-flashable, field-recoverable.

  • 8-channel EMG, clinical-grade — ADS1299 @ 500 SPS, 24× gain, BIAS + lead-off, timestamped at the ISR.
  • Multimodal physiology — PPG (RED/IR/Green), 9-DOF IMU with quaternion fusion, contact + IR temp, GSR — packed at 131 B / record.
  • A week on one charge — SPARSE 30 s / 3 min duty cycle, Wi-Fi on demand, deep-sleep between captures; 7 days on 2000 mAh.
  • Cloud-ready — auto-push every 15 min, per-device token auth, GCS for raw bins, Postgres for features.
  • OTA + remote provisioningSET_WIFI, SET_PATIENT_ID, SET_SERVER_URL persist to NVS.
human-performance pain research remote PT sleep / ANS
Sensor stack
131 B / record
EMG · ADS1299
8-ch · 24× gain · BIAS + lead-off
500 SPS
PPG · MAX30101
RED · IR · Green
50 Hz
IMU · BNO055
9-DOF · quaternion fusion
50 Hz
Temp · TMP117 + MLX90632
contact + IR
1 Hz
GSR · ADC1_CH7
skin conductance
15 Hz
Active
~131 mA
Standby
~52 mA
Battery
2000 mAh
Binary format · PPNOCI_BIN_V2.1
# struct-packed, little-endian, 131 bytes / record
FORMAT = "<QIII16fbffI8iBB"
#         │  │  │   │   │ │ │ │  │
#         │  │  │   │   │ │ │ │  └── 2× lead-off (bytes)
#         │  │  │   │   │ │ │ └───── 8× EMG ch (int32)
#         │  │  │   │   │ │ └─────── GSR (uint32)
#         │  │  │   │   │ └───────── temp_contact / temp_ir
#         │  │  │   │   └─────────── (lead-off byte flag)
#         │  │  │   └─────────────── IMU + euler + quat (16 float)
#         │  │  └─────────────────── PPG  RED · IR · GREEN
#         │  └────────────────────── sample index
#         └───────────────────────── timestamp_us (uint64)

Product · Smart-shelf inventory pad

32 sensors. One pad.
Knows which bottle just walked off.

A silicone tray with 32 force-sensitive cells under your high-value SKUs. ESP32-S3 + 2× analog multiplexer in a back-central brain enclosure. Every pull, every replacement, every "did someone actually move this?" — timestamped, uploaded, and ready to alert.

Live shelf
Skincare bar · Pad 04
ONLINE 29 / 32 stocked 2 pulls · last hr
ESP32-S3 · MUX × 2 · 6.5″ × 2″
01
Cell 01 · Active
Premium A Serum
2 pulls today · last 3:42pm
fsr=412 · z=2.1
02
Cell 02 · Active
EGF Serum 15ml
stocked · idle
fsr=388 · z=0.4
03
Cell 03 · Just pulled
Pigment Peel
3:42:18pm · -42g delta
fsr=12 · alert sent
04
Cell 04 · Active
Ultra Peel
stocked · idle
05
Cell 05 · Active
Sensi Peel
stocked · idle
06
Cell 06 · Active
Line Pro
stocked · idle
07
Cell 07 · Active
Pro Peel
stocked · idle
08
Cell 08 · Active
Premium C&E Advanced
stocked · idle
09
Cell 09 · Active
Pigment Gel Pro
stocked · idle
10
Cell 10 · Active
B3 Serum
stocked · idle
11
Cell 11 · Active
Hyaluronic Serum
stocked · idle
12
Cell 12 · Empty
Hydrating Cream 50ml
out 41 min · restock?
fsr=4 · below_baseline
13
Cell 13 · Active
Intensive Retinol
stocked · idle
14
Cell 14 · Active
Brightening Essence
stocked · idle
15
Cell 15 · Active
Resurfacing Mask
stocked · idle
16
Cell 16 · Active
EGF Eye Cream
stocked · idle
17
Cell 17 · Active
B3 Eye
stocked · idle
18
Cell 18 · Active
Moonbeam Cleanser
stocked · idle
19
Cell 19 · Active
Sunnyside Vit C
stocked · idle
20
Cell 20 · Active
Skin Recovery
stocked · idle
21
Cell 21 · Picked up
Vit C Drops
in-hand · 3:42:09pm
fsr→408 → 22 · t=11s
22
Cell 22 · Active
EGF Serum 5ml
stocked · idle
23
Cell 23 · Active
Serum 71
stocked · idle
24
Cell 24 · Active
Halo AHA
stocked · idle
25
Cell 25 · Active
Brow Conditioner
stocked · idle
26
Cell 26 · Active
Lash Conditioner
stocked · idle
27
Cell 27 · Active
Night Mask
stocked · idle
28
Cell 28 · Active
Enzyme Mask
stocked · idle
29
Cell 29 · Active
Eye Cream Treatment
stocked · idle
30
Cell 30 · Active
Retinal Treatment
stocked · idle
31
Cell 31 · Active
ReBalance
stocked · idle
32
Cell 32 · Active
Clear Skin Peel
stocked · idle
Event log · pad-04 tail -f
15:42:18 PULL cell=03 sku="Pigment Peel" Δfsr=-376 → ingest 1.2KB
15:42:09 LIFT cell=21 sku="Vit C Drops" Δfsr=-386 hold=11s
15:01:55 EMPTY cell=12 sku="Hydrating Cream 50ml" duration=41m → restock_alert
14:18:02 REPL cell=14 sku="Brightening Essence" Δfsr=+402 z=2.7
14:00:00 SYNC uploaded 64KB · 487 records · ack=200

Per-slot pull detection

FSR baseline + delta. Every lift, every replacement, every "did this bottle actually get touched today?" — timestamped to the millisecond, logged to SD, pushed to the cloud.

High-value SKU tracking

Built for the $80-and-up shelf — medspa serums, Premium, Pro Lab, LashLab, Med Skin, Glow Co., Clear Co.. Drop in your brand mix; the grid adapts.

Loss prevention & restock alerts

Shrinkage you can prove, restocks you don't forget. Cells that go empty trigger Slack/SMS; pulls outside hours flag for review.

Tray
24″ × 14.5″
silicone over rigid base
Wells
32 × 2.5″ Ø
oversized for skincare bottles
Sensor
1.0″ FSR
force-sensitive resistor / well
Brain
6.5″ × 2″ enclosure
ESP32-S3 + 2× analog MUX

One platform · two devices · same spine

What the wearable and the shelf share.

The discipline below is the recipe. Different sensors, same firmware spine, same cloud path. Add a third device tomorrow — the spine doesn't change.

ESP32-S3 + Arduino core

Dual-core MCU, SPI + I²C peripherals, SD card local logging. Same MCU, same toolchain across every device.

FreeRTOS uploader · pinned to Core 0

Background uploader task pinned so the capture loop on Core 1 never blocks for Wi-Fi. Multipart HTTPS, retry on the next window.

Packed binary log on SD

Struct-packed records, 15-min file rotation, 100 MB max → auto-rotate. 256-entry RAM buffer, flush every ~512 ms at 500 Hz.

Per-device token auth

DEVICE_INGEST_TOKEN in firmware secrets.h, validated server-side at every /api/data/ingest-esp POST. TLS 1.2/1.3 only.

OTA over Wi-Fi

ArduinoOTA hostname + password gated; onStart halts active capture before flashing so no record is half-written.

NVS-persistent config

Wi-Fi, device ID, server URL persist across reboots via Preferences. Serial commands push live updates — field-recoverable.

From silicon to dashboard

Sense → Pack → Sync → Surface
SENSOR
EMG · PPG · IMU · FSR
MCU
ESP32-S3 · FreeRTOS
LOG
SD · packed binary
UPLOAD
HTTPS · 15 min · token
SURFACE
GCS · Postgres · API

How it works

Sense. Sync. Surface.

Three steps from a sensor on a wrist or under a bottle to a number in your dashboard.

01

Sense

On-device sensors stream into a packed binary log on SD. Records are timestamped at the ISR — every byte tells you when it was captured.

02

Sync

A FreeRTOS uploader pushes every 15 minutes over HTTPS with a per-device token. Records sit on SD until the cloud acks — retries on the next window.

03

Surface

Cloud feature extraction lands in your dashboard and your APIs — per-session, per-beat, per-window for biosignals; per-cell, per-pull, per-shift for shelves.

API surface

Honest endpoints. Token-auth. Binary in, JSON out.

No MQTT. No WebSockets. Straight HTTPS multipart from the FreeRTOS uploader; clean REST for your apps.

Device-facing
token-auth
POST/api/data/ingest-esp
binary · per-device token
POST/api/data/ingest
multipart
POST/api/data/ingest/batch
multi-file
POST/api/data/<session_id>
append
POST/api/start_session
implicit register
POST/upload/phone_sensors
companion app
Management-facing
REST · JSON
GET /api/features/<session_id>
windowed
POST/api/features/batch
recompute
GET /api/dashboard/<patient_id>
summary
POST/api/collection/start
remote arm
GET /api/collection/status/<session_id>
live
GET /api/research/sessions[/<id>]
listing
# Ingest a packed binary record from the wearable or shelf
curl -X POST https://api.gridspin.xyz/api/data/ingest-esp \
  -H "X-Device-Token: $DEVICE_INGEST_TOKEN" \
  -H "X-Device-Id: pad-04" \
  -H "Content-Type: application/octet-stream" \
  --data-binary @/sd/log_20260620_154200.bin

# → 200 OK  {"records": 487, "session_id": "s-2026-06-20-..."}

Ready when you are

Pick a sensor stack.
Reuse the platform.

Wearable, smart shelf, or your own device built on the same spine — we'll spec it, scope it, ship it. Kits go out within two weeks.

hello@gridspin.xyz · iot.gridspin.xyz