docs: BLE OTA firmware update design spec
This commit is contained in:
parent
e069149fb4
commit
5524f173ac
1 changed files with 116 additions and 0 deletions
116
docs/superpowers/specs/2026-07-30-ble-ota-design.md
Normal file
116
docs/superpowers/specs/2026-07-30-ble-ota-design.md
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
# BLE OTA Firmware Updates — Design
|
||||||
|
|
||||||
|
## Doel
|
||||||
|
|
||||||
|
Firmware-updates via Bluetooth LE vanaf de Android app, zonder USB-kabel. Doelgroep: lichamelijk gehandicapten — zelfstandigheid zonder fysieke kabels.
|
||||||
|
|
||||||
|
## Huidige situatie
|
||||||
|
|
||||||
|
- Firmware: ~523KB (534.793 bytes, 16% van 3.2MB beschikbaar)
|
||||||
|
- BLE: NimBLE-Arduino, service "SylDa_Server" actief
|
||||||
|
- Partitietabel: al OTA-capable — `ota_0` (0x10000, 3264K), `ota_1` (0x340000, 3264K), `otadata` (0xe000, 8K)
|
||||||
|
- Android app: flasht nu via USB CDC (EspFlasher)
|
||||||
|
|
||||||
|
## Architectuur
|
||||||
|
|
||||||
|
### ESP32-S3 kant (`src/main.cpp`)
|
||||||
|
|
||||||
|
- Nieuwe BLE characteristic `OTA_UUID = "beb5483e-36e1-4688-b7f5-ea07361f26da"` — WRITE + NOTIFY
|
||||||
|
- Bestaande relay service blijft volledig intact, aparte characteristic in dezelfde service
|
||||||
|
- OTA-modus flag: tijdens OTA worden relay-commando's genegeerd, relais vallen UIT
|
||||||
|
- Gebruikt ESP-IDF `esp_ota_*` API:
|
||||||
|
- `esp_ota_get_next_update_partition()` — vindt target partitie
|
||||||
|
- `esp_ota_begin()` — initialiseert schrijfactie
|
||||||
|
- `esp_ota_write()` — schrijft chunk naar flash
|
||||||
|
- `esp_ota_end()` — valideert image, markeert als bootable
|
||||||
|
- `esp_ota_set_boot_partition()` — zet target als actieve bootpartitie
|
||||||
|
- `esp_restart()` — herstart naar nieuwe firmware
|
||||||
|
|
||||||
|
### Android kant
|
||||||
|
|
||||||
|
- Nieuwe `OtaManager.kt` — leest firmware, hasht, chunkt, verstuurt
|
||||||
|
- OTA-knop in `SettingsActivity.kt` met progress UI
|
||||||
|
- Firmware bron: `assets/firmware.bin` (of bestandskiezer voor handmatige update)
|
||||||
|
- SHA-256 hash berekening voor eindverificatie
|
||||||
|
|
||||||
|
## BLE OTA Protocol
|
||||||
|
|
||||||
|
```
|
||||||
|
OTA Characteristic UUID: beb5483e-36e1-4688-b7f5-ea07361f26da
|
||||||
|
Properties: WRITE, NOTIFY
|
||||||
|
MTU: 512 bytes (negotiated)
|
||||||
|
Chunk nuttige data: 488 bytes (512 - 24 header overhead)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Write commando's (App → ESP)
|
||||||
|
|
||||||
|
| Byte(s) | Commando |
|
||||||
|
|---|---|
|
||||||
|
| `0x10` + 4 bytes size (LE) | OTA_START — firmware grootte in bytes |
|
||||||
|
| 4 bytes seq (LE) + data[...] | OTA_DATA — chunk met sequentienummer |
|
||||||
|
| 32 bytes SHA-256 | OTA_END — hash van volledige firmware |
|
||||||
|
|
||||||
|
### Notificatie commando's (ESP → App)
|
||||||
|
|
||||||
|
| Byte(s) | Betekenis |
|
||||||
|
|---|---|
|
||||||
|
| `0x00` + 4 bytes seq (LE) | ACK — chunk ontvangen en geschreven |
|
||||||
|
| `0x01` + 4 bytes seq (LE) | NAK — chunk opnieuw versturen |
|
||||||
|
| `0x10` | OTA_COMPLETE — succes, reboot volgt |
|
||||||
|
| `0x11` + 1 byte error | OTA_ERROR |
|
||||||
|
|
||||||
|
### Flow
|
||||||
|
|
||||||
|
1. App stuurt `OTA_START` met firmware-grootte
|
||||||
|
2. ESP roept `esp_ota_begin()` aan, zet OTA-modus, relais UIT
|
||||||
|
3. App stuurt chunks sequentieel (seq 0, 1, 2, ...)
|
||||||
|
4. ESP schrijft elke chunk met `esp_ota_write()`, stuurt ACK terug
|
||||||
|
5. Bij timeout of corruptie: ESP stuurt NAK met seq-nummer, app herhaalt chunk
|
||||||
|
6. App stuurt `OTA_END` met SHA-256
|
||||||
|
7. ESP: `esp_ota_end()`, `esp_ota_set_boot_partition()`, stuurt `OTA_COMPLETE`
|
||||||
|
8. ESP: `esp_restart()`
|
||||||
|
|
||||||
|
## LED-signalering
|
||||||
|
|
||||||
|
| Patroon | Betekenis |
|
||||||
|
|---|---|
|
||||||
|
| Snel knipperen (100ms) | OTA bezig |
|
||||||
|
| Continu aan | OTA voltooid, reboot imminent |
|
||||||
|
| Langzaam knipperen (500ms) | OTA fout |
|
||||||
|
|
||||||
|
## Beveiliging
|
||||||
|
|
||||||
|
- Firmware wordt NIET per chunk met HMAC geauthenticeerd (snelheid)
|
||||||
|
- SHA-256 hash van volledige firmware meegezonden in OTA_END
|
||||||
|
- `esp_ota_end()` verifieert image header checksum automatisch
|
||||||
|
- Alleen een BLE-verbonden device kan OTA starten (BLE link-level encryptie via pairing)
|
||||||
|
- Bestaande HMAC-key voor relay-commando's blijft ongewijzigd
|
||||||
|
|
||||||
|
## Foutafhandeling
|
||||||
|
|
||||||
|
| Scenario | Afhandeling |
|
||||||
|
|---|---|
|
||||||
|
| Verbinding verbroken tijdens OTA | Huidige firmware blijft actief, `ota_1` ongeldig |
|
||||||
|
| Corrupte chunk | ESP stuurt NAK, app herhaalt chunk |
|
||||||
|
| SHA-256 mismatch in OTA_END | `esp_ota_end()` faalt, huidige firmware blijft |
|
||||||
|
| ESP crash tijdens OTA | Bootloader boot `ota_0`, `otadata` wijst er nog naar |
|
||||||
|
| Nieuwe firmware boot niet (8x bootloop) | ESP-IDF rollback: schakelt terug naar `ota_0` |
|
||||||
|
|
||||||
|
## Edge cases
|
||||||
|
|
||||||
|
- **OTA opnieuw starten:** `ota_1` wordt overschreven, geen clean-up nodig
|
||||||
|
- **Versie-check:** App kan firmwareversie opvragen voordat OTA start
|
||||||
|
- **Tijdens actieve relais:** relais vallen UIT bij start OTA (rust-toestand)
|
||||||
|
|
||||||
|
## Transfertijd schatting
|
||||||
|
|
||||||
|
523KB bij ~30 KB/s effectieve BLE throughput ≈ 17 seconden. Bij slechtere verbinding ~45-60 seconden. Acceptabel.
|
||||||
|
|
||||||
|
## Bestanden
|
||||||
|
|
||||||
|
| Bestand | Wijziging |
|
||||||
|
|---|---|
|
||||||
|
| `src/main.cpp` | OTA characteristic, `esp_ota_*` logica, OTA-modus flag, LED-signalering |
|
||||||
|
| `platformio.ini` | Geen wijziging (partitietabel al OTA-ready) |
|
||||||
|
| `android/.../OtaManager.kt` | Nieuw: firmware lezen, hashen, chunken, BLE verzenden |
|
||||||
|
| `android/.../SettingsActivity.kt` | OTA-knop + progress UI |
|
||||||
Loading…
Reference in a new issue