Smart blinds you control, schedule, and calibrate end-to-end — a Flutter app talks to an Express server over Socket.IO, which relays to ESP32-C6 hubs, with BLE-only provisioning for the first handshake.
- Role
- Solo · firmware + backend + app
- Stack
- ESP-IDF · Express/Socket.IO · Flutter
- When
- Ongoing · pre-release
- Status
- Functional prototype
Overview
A Flutter app talks to an Express server over Socket.IO/HTTPS, which relays commands to ESP32-C6 hubs — also over Socket.IO — with BLE used only for the initial Wi-Fi + auth handshake. Blind position is unified across all three codebases as an 11-step model (0–10, where 5 = fully open).
System architecture
- Server as relay — all app↔device traffic routes through the server after provisioning.
- Dual-path updates — Socket.IO for real-time, HTTP polling as a fallback.
- BLE-only provisioning — the phone delivers Wi-Fi creds + initial JWT straight to the ESP32, never via the server.
- One 11-position model shared across HTTP, Socket.IO, and BLE keeps the firmware tiny and the UI legible.
Highlights
One drivetrain, closed-loop both ways
A continuous-rotation servo turns a gear that tilts the blind; a meshed encoder gear feeds a rotary encoder that counts ticks for absolute position. A second encoder is a manual wand — turn the blind by hand and the servo follows it.
Calibration as a Socket.IO handshake
A multi-stage exchange (calib_start → stage1 → stage2 → calib_done): the device records the "up" then "down" tick extremes as the user moves the blind, and the tick→position mapping is saved to NVS — the server is a pure relay.
BLE for provisioning only
Wi-Fi creds + JWT go over a custom NimBLE service; once provisioned, BLE goes dormant and all real-time traffic switches to Socket.IO. Trade-off: LE Secure Connections without bonding, assuming physical proximity at setup.
Power management on the ESP32-C6
Dynamic frequency scaling (80–160 MHz), light sleep when idle, GPIO-gated servo power, and a MAX17048 fuel gauge for state-of-charge telemetry and a low-battery warning under 20%.
Hardened backend
Layered rate limits (HTTP, auth, WS connects/messages, email), JWT + Argon2 auth, and boot-time cleanup of stale connections and expired tokens so restarts don't leave zombie devices.
Status
- So close to having a demo! Functional prototype — provisioning, real-time control, scheduling, multi-device groups, and the full user lifecycle all work.
- A
taskdrivenpowersavebranch (deeper power management) will replace main; then it may be released, with the app on TestFlight and the hardware open-sourced.