BLE protocol
The ESP32 is the source of truth. Every change, whether it comes from the encoder or from BLE, is notified so the OLED and the PWA stay in sync.
- Advertised name:
BULLOADER - All integers are little-endian.
- All UUIDs share one random base; only the 3rd and 4th hex digits change:
8adb76XX-5374-47c7-9127-d9895246807a.
Any change here must land together with both constant files:
firmware/src/ble_uuids.h and web/src/ble/protocol.ts.
| Name | UUID |
|---|---|
| service | 8adb7600-5374-47c7-9127-d9895246807a |
Characteristics
Section intitulée « Characteristics »| Name | UUID | Type | Properties |
|---|---|---|---|
target |
8adb7601-5374-47c7-9127-d9895246807a |
uint16 | read, write, notify |
command |
8adb7602-5374-47c7-9127-d9895246807a |
uint8 | write |
count |
8adb7603-5374-47c7-9127-d9895246807a |
uint16 | read, notify |
state |
8adb7604-5374-47c7-9127-d9895246807a |
uint8 | read, notify |
battery |
8adb7605-5374-47c7-9127-d9895246807a |
uint16 (mV) | read, notify |
presets |
8adb7606-5374-47c7-9127-d9895246807a |
uint16[4] | read, write |
config |
8adb7607-5374-47c7-9127-d9895246807a |
packed struct (v1) | read, write |
Number of BBs to load, 1–9999. A write while a run is in progress is ignored; the firmware then notifies the real value back so the client corrects itself. Out-of-range values are clamped.
| Value | Meaning |
|---|---|
| 0 | Stop (anything running: a load or a test spin) |
| 1 | Go (start loading target BBs) |
| 2 | Test spin at full speed, until stop (calibration, M3) |
| 3 | Test spin at slow speed, until stop (calibration, M3) |
Unknown values are ignored.
BBs counted in the current (or last) run. Reset to 0 when a run starts. Notifications are throttled to ~20 Hz, but the final value of a run is always notified.
| Value | State |
|---|---|
| 0 | idle |
| 1 | running |
| 2 | slowdown |
| 3 | done |
| 4 | jam |
| 5 | low_batt |
| 6 | testing |
testing is a test spin started by commands 2 or 3.
LiPo voltage in millivolts. Notified every ~5 s.
Four uint16, 8 bytes. Defaults 30 / 50 / 120 / 300. Persisted in NVS on write. A write with the wrong length is ignored.
Packed struct, 11 bytes. The first byte is a format version: the firmware ignores writes whose version or length doesn’t match, and the PWA refuses to decode an unknown version instead of showing garbage.
| Offset | Type | Field | Default | Notes |
|---|---|---|---|---|
| 0 | uint8 | version |
1 | |
| 1 | uint16 | servo_neutral_us |
1500 | Pulse width where the servo stops |
| 3 | int16 | speed_full_offset_us |
300 | Added to neutral at full speed |
| 5 | int16 | speed_slow_offset_us |
100 | Added to neutral in slowdown |
| 7 | uint8 | reverse |
0 | 1 = invert rotation direction |
| 8 | uint8 | slowdown_n |
4 | Switch to slow when ≤ N BBs remain |
| 9 | uint16 | jam_timeout_ms |
1500 | No BB for this long → jam |
Persisted in NVS on write.