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