docs: BLE OTA firmware update design spec

This commit is contained in:
eddy 2026-07-30 06:30:56 +02:00
commit 5524f173ac

View 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 |