Project_SylDa/docs/superpowers/specs/2026-07-30-ble-ota-design.md

5.4 KiB

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 VERSION_UUID = "beb5483e-36e1-4688-b7f5-ea07361f26db" — READ, exposeert firmwareversie als string
  • 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
  • Bij BLE connect: leest firmwareversie van ESP via VERSION_UUID characteristic, vergelijkt met versie in app. Toont toast bij beschikbare update.
  • Firmware bron: assets/firmware.bin (of bestandskiezer voor handmatige update)
  • SHA-256 hash berekening voor eindverificatie
  • Bundled firmwareversie (uit assets/) vergeleken met ESP-versie bij connect

Versie-check bij BLE connect

Bij elke BLE-verbinding leest de Android app de VERSION_UUID READ characteristic van de ESP. De ESP retourneert de stringwaarde van FIRMWARE_VERSION. De app vergelijkt met de versie van de gebundelde firmware.bin in assets. Als de ESP een lagere versie heeft toont de app een toast: "Firmware-update beschikbaar" — de gebruiker kan dan in SettingsActivity de OTA starten.

VERSION_UUID "beb5483e-36e1-4688-b7f5-ea07361f26db"
Properties READ
Waarde String, bijv. "1"

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: Bij BLE connect leest de app de firmwareversie van de ESP (VERSION_UUID characteristic). Bij mismatch met gebundelde firmware toont app een toast "Firmware-update beschikbaar" en activeert de OTA-knop.
  • 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 VERSION characteristic, 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