docs: update README to reflect ECDH+AES-GCM, BLE OTA, multi-client, and broker features
This commit is contained in:
parent
ccf8467c00
commit
6e98f61d4a
1 changed files with 243 additions and 162 deletions
405
README.md
405
README.md
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
BLE-gestuurde relais-switch voor de M5Stack Atom S3 Lite (ESP32-S3) met een bijbehorende Android-app. De relais kunnen worden bediend via capacitieve touch-sensoren (HS-S43A) óf via Bluetooth Low Energy vanaf een Android-telefoon.
|
||||
|
||||
De BLE-verbinding is beveiligd met **HMAC-SHA256 authenticatie** (application-level handtekening met replay-protectie). BLE-link encryptie/bonding is bewust niet toegepast — HMAC biedt authenticatie en replay-bescherming op applicatieniveau, voldoende voor een relais-aan/uit commando.
|
||||
De BLE-verbinding is beveiligd met **ECDH (secp256r1) sleuteluitwisseling** en **AES-256-GCM encryptie** (authenticiteit + confidentiality). Een **PSK** (pre-shared key, via USB provisioning) wordt gebruikt voor ECDH pubkey HMAC-verificatie, niet direct voor command authenticatie. Sequence counters bieden replay-protectie. Eerdere versies gebruikten HMAC-SHA256 zonder encryptie — ECDH+AES-GCM is vanaf firmware server v16 / client v3.
|
||||
|
||||
## Hardware
|
||||
|
||||
|
|
@ -14,16 +14,16 @@ De BLE-verbinding is beveiligd met **HMAC-SHA256 authenticatie** (application-le
|
|||
| Relais 2 | Op **G2** |
|
||||
| Touch sensor 1 | HS-S43A Digital Capacitive Switch Module op **G8** (actief LOW) |
|
||||
| Touch sensor 2 | HS-S43A Digital Capacitive Switch Module op **G6** (actief LOW) |
|
||||
| Knop | Op **G41** (active low) |
|
||||
| Status LED | Op **G35** (WS2812 RGB, rood = geen verbinding, geel = verbinding <60s, uit = stabiel) |
|
||||
| Knop | Op **G41** (active low, interne Atom S3 Lite knop) |
|
||||
| Status LED | Op **G35** (WS2812 RGB extern, rood = geen verbinding, geel = verbinding < 60 s, uit = stabiel) |
|
||||
|
||||
### Pinout
|
||||
|
||||
```
|
||||
G1 = RELAY1
|
||||
G2 = RELAY2
|
||||
G6 = TOUCH2 (INPUT)
|
||||
G8 = TOUCH1 (INPUT)
|
||||
G6 = TOUCH2 (INPUT_PULLUP, actief LOW)
|
||||
G8 = TOUCH1 (INPUT_PULLUP, actief LOW)
|
||||
G41 = BUTTON (INPUT, active low)
|
||||
G35 = LED (WS2812 RGB, OUTPUT)
|
||||
```
|
||||
|
|
@ -47,108 +47,148 @@ De LED fungeert als debug-indicator en schakelt uit na 60 seconden stabiele verb
|
|||
|
||||
| State | LED | Prioriteit |
|
||||
|-------|-----|-----------|
|
||||
| OTA in progress | Groen knipperend (100ms) | 1 (hoogst) |
|
||||
| OTA in progress | Groen knipperend (100 ms) | 1 (hoogst) |
|
||||
| OTA completed, wacht op confirm | Geel vast | 1 |
|
||||
| Geen verbinding | Rood | 2 |
|
||||
| Verbinding actief (< 60s) | Geel | 3 |
|
||||
| Verbinding stabiel (>= 60s) | Uit | 4 (laagst) |
|
||||
| Relais-flash overlay | Groen 150ms | overlay |
|
||||
| Verbinding actief (< 60 s) | Geel | 3 |
|
||||
| Verbinding stabiel (>= 60 s) | Uit | 4 (laagst) |
|
||||
| Relais-flash overlay | Groen 150 ms | overlay |
|
||||
|
||||
De relais-flash toont kort groen bij een verandering in relais-status, waarna de LED terugkeert naar de verbindingskleur.
|
||||
|
||||
## Beveiliging
|
||||
|
||||
De relay is beveiligd tegen ongeautoriseerde toegang via HMAC-SHA256 authenticatie op applicatieniveau.
|
||||
De relay is beveiligd tegen ongeautoriseerde toegang via ECDH (Elliptic Curve Diffie-Hellman over secp256r1) met AES-256-GCM encryptie op applicatieniveau.
|
||||
|
||||
### HMAC-SHA256 Authenticatie (application-level)
|
||||
### ECDH + AES-256-GCM
|
||||
|
||||
- Zowel de module firmware als de Android app delen een **32-byte shared secret** (HMAC key), die via USB provisioning op beide apparaten terechtkomt
|
||||
- Elk commando wordt ondertekend met `HMAC-SHA256(key, command || sequence)`
|
||||
- De module verifieert de handtekening voordat het relais schakelt
|
||||
- Een **sequence counter** voorkomt replay-aanvallen: elk packet moet een strikt oplopend volgnummer hebben
|
||||
- Zowel de firmware als de Android app delen een **32-byte PSK** (pre-shared key), die via USB provisioning op beide apparaten terechtkomt
|
||||
- Bij BLE-connectie wordt een **ECDH sleuteluitwisseling** uitgevoerd:
|
||||
1. Client en server genereren elk een secp256r1 sleutelpaar
|
||||
2. Ze sturen hun public key (65 bytes) + HMAC-SHA256(PSK, public key) (32 bytes) naar elkaar (**ECDH packet: 97 bytes**)
|
||||
3. De ontvanger verifieert de HMAC met de PSK — ongeautoriseerde apparaten worden hier al geweerd
|
||||
4. Uit de eigen private key + peer public key wordt een shared secret berekend
|
||||
5. `SHA-256(shared secret)` levert de **AES-256 sleutel** op
|
||||
- Elk relay-commando wordt daarna versleuteld met **AES-256-GCM** (authenticity + confidentiality)
|
||||
- Een **sequence counter** (uint32, big-endian) voorkomt replay-aanvallen: elk packet moet een strikt oplopend volgnummer hebben
|
||||
- GCM biedt zowel encryptie als integriteitsverificatie (AEAD)
|
||||
|
||||
#### Packet formaat (37 bytes)
|
||||
#### AES-GCM packet formaat (29 bytes)
|
||||
|
||||
```
|
||||
Offset Grootte Veld Beschrijving
|
||||
0 1 byte command 0x00=relay1 OFF, 0x01=ON, 0x02=relay2 ON, 0x03=OFF
|
||||
1 4 bytes sequence Big-endian uint32, strikt oplopend (start bij 1)
|
||||
5 32 bytes hmac HMAC-SHA256(key, command || sequence)
|
||||
Offset Grootte Veld Beschrijving
|
||||
0 4 bytes sequence Big-endian uint32, strikt oplopend (start bij 1)
|
||||
4 8 bytes nonce Random nonce voor AES-GCM
|
||||
12 1 byte ciphertext 1 byte plaintext (command), versleuteld
|
||||
13 16 bytes tag GCM authenticatie-tag
|
||||
```
|
||||
|
||||
De sequence counter reset naar 0 bij elke (re)connectie op de module. De app start bij 1 om te zorgen dat het eerste packet altijd geaccepteerd wordt (`1 > 0`). Replay van een eerder packet wordt geweerd omdat `seq <= lastSeq`. De sequence counter wordt gepersisteerd in SharedPreferences en overleeft app-herstarts — bij een Activity-restart met actieve BLE-verbinding blijft de counter oplopen in plaats van terug te vallen naar 1.
|
||||
#### ECDH packet formaat (97 bytes)
|
||||
|
||||
#### Key management
|
||||
```
|
||||
Offset Grootte Veld Beschrijving
|
||||
0 65 bytes public key Uncompressed secp256r1 public key
|
||||
65 32 bytes hmac HMAC-SHA256(PSK, public key)
|
||||
```
|
||||
|
||||
- De HMAC key wordt **niet meegecompileerd** — de module start zonder key en wordt geprovisioneerd via USB
|
||||
- De key wordt opgeslagen in **NVS** (Non-Volatile Storage) op de module via de Arduino `Preferences` library (namespace `hmac`, key `key`, partitie op 0x9000-0xDFFF)
|
||||
- De app slaat de key op in **SharedPreferences** (overleeft app-herstarts)
|
||||
- **USB provisioning:** Open Instellingen → Firmware bijwerken. De app checkt eerst de firmware versie (`VERSION?`) en flasht indien nodig. Na het flashen (of als versie al actueel is) volgt automatisch de key exchange:
|
||||
- Als de module al een key heeft → module antwoordt `HMAC_KEY:<hex>` → app slaat op lokaal op
|
||||
- Als de module nog geen key heeft → module antwoordt `NO_KEY` → app genereert willekeurige 32-byte key via `SecureRandom` → stuurt `SET_KEY:<hex>\n` en `SET_ID:<hex>\n` → module slaat op in NVS → app slaat op lokaal op
|
||||
#### Commando codes
|
||||
|
||||
#### USB Serial Protocol
|
||||
```
|
||||
0x00 = relay1 OFF
|
||||
0x01 = relay1 ON
|
||||
0x02 = relay2 ON
|
||||
0x03 = relay2 OFF
|
||||
```
|
||||
|
||||
De sequence counter reset naar 0 bij elke (re)connectie op de module. De app start bij 1 om te zorgen dat het eerste packet altijd geaccepteerd wordt (`1 > 0`). De sequence counter wordt gepersisteerd in SharedPreferences en overleeft app-herstarts.
|
||||
|
||||
### Key management
|
||||
|
||||
- De PSK wordt **niet meegecompileerd** — de module start zonder key en wordt geprovisioneerd via USB
|
||||
- De PSK en device UUID worden opgeslagen in **NVS** (namespace `syl`, keys `psk` en `uuid`, partitie op 0x9000-0xDFFF)
|
||||
- De app slaat PSK, device UUID, server UUID en client UUID op in **SharedPreferences**
|
||||
- **USB provisioning:** Open Instellingen → Module bijwerken. De app checkt eerst de firmware versie (`VERSION?`) en flasht indien nodig. Na het flashen (of als versie al actueel is) volgt automatisch de key exchange:
|
||||
- Als de module al keys heeft → module antwoordt `DEVICE_ID:<hex>` en `PSK:<hex>` → app slaat lokaal op
|
||||
- Als de module nog geen keys heeft → module antwoordt `NO_KEY` → app genereert willekeurige 32-byte PSK via `SecureRandom` → stuurt `SET_KEY:<hex>\n`, `SET_ID:<hex>\n`, en voor client devices `SET_SERVER:<hex>\n` → module slaat op in NVS → app slaat lokaal op
|
||||
|
||||
### USB Serial Protocol
|
||||
|
||||
```
|
||||
App → module: VERSION?\n
|
||||
module → App: BUILD_NR:1\n (firmware versie check)
|
||||
module → App: BUILD_NR:<version>\n (firmware versie check)
|
||||
|
||||
App → module: ID?\n
|
||||
module → App: SylDa_Server\n of SylDa_Client\n (device type)
|
||||
|
||||
App → module: KEY?\n
|
||||
module → App: DEVICE_ID:B874...D7F\n (module UUID)
|
||||
module → App: HMAC_KEY:F2F1...642\n (HMAC key)
|
||||
module → App: NO_KEY\n (als module nog geen key heeft)
|
||||
module → App: DEVICE_ID:<hex>\n (module UUID, 16 bytes = 32 hex)
|
||||
module → App: PSK:<hex>\n (PSK, 32 bytes = 64 hex)
|
||||
module → App: NO_KEY\n (als module nog geen key heeft)
|
||||
|
||||
App → module: SET_KEY:F2F1...642\n (nieuwe key schrijven)
|
||||
module → App: OK\n (bevestiging)
|
||||
App → module: SET_KEY:<hex>\n (nieuwe PSK schrijven, 64 hex)
|
||||
module → App: OK\n
|
||||
|
||||
App → module: SET_ID:B874...D7F\n (UUID schrijven)
|
||||
module → App: OK\n (bevestiging)
|
||||
App → module: SET_ID:<hex>\n (UUID schrijven, 32 hex)
|
||||
module → App: OK\n
|
||||
|
||||
App → module: SET_SERVER:<hex>\n (server UUID voor client, 32 hex)
|
||||
module → App: OK\n
|
||||
```
|
||||
|
||||
#### Provisioning flow
|
||||
### Multi-client ondersteuning
|
||||
|
||||
De server ondersteunt tot **2 gelijktijdige BLE-clients** (MAX_CLIENTS 2). Elke client krijgt een onafhankelijke ECDH-handshake, AES-sleutel en sequence counter. Relais-commando's van alle clients worden gecombineerd: een relais gaat aan als minimaal één client het aan-commando stuurt (OR-logica).
|
||||
|
||||
De server kan OTA-updates distribueren naar verbonden clients via het **broker protocol**:
|
||||
|
||||
```
|
||||
Android app ESP32 (USB CDC)
|
||||
─────────── ───────────────
|
||||
User taps "Firmware bijwerken"
|
||||
Check version: VERSION?\n ───────►
|
||||
◄─────────── BUILD_NR:<version>\n
|
||||
(flash if needed, module reboots)
|
||||
Key exchange: KEY?\n ──────────►
|
||||
◄─────────── HMAC_KEY:<hex>\n
|
||||
DEVICE_ID:<hex>\n
|
||||
(of NO_KEY\n als leeg)
|
||||
(if NO_KEY) SET_KEY + SET_ID ─► Save to NVS
|
||||
BROKER_CMD_UPDATE_AVAILABLE (0x10) — server vertelt client dat er een update klaarstaat
|
||||
BROKER_CMD_CLIENT_READY (0x20) — client meldt zich klaar voor OTA
|
||||
```
|
||||
|
||||
Broker packets zijn versleuteld met AES-256-GCM (48 bytes: 4 seq + 8 nonce + 20 plain + 16 tag), onafhankelijk van relay-commando encryptie.
|
||||
|
||||
### Beveiligingsanalyse
|
||||
|
||||
| Aanval | Hoe geweerd |
|
||||
|---|---|
|
||||
| **Replay** | Sequence counter — zelfde packet werkt niet 2x (`seq <= lastSeq` wordt geweerd) |
|
||||
| **Ongeautoriseerd device** | HMAC vereist geheime sleutel (32-byte random via USB provisioning) |
|
||||
| **Replay** | Sequence counter — zelfde packet werkt niet 2× (`seq <= lastSeq` geweerd) |
|
||||
| **Ongeautoriseerd device** | ECDH pubkey HMAC vereist PSK — verkeerde PSK = afgewezen public key |
|
||||
| **BLE spoofing (client)** | **Bekend lek (issue #10):** ESP32 client scant op naam "SylDa_Server" i.p.v. UUID — geen server-verificatie. De Android app scant wél op service UUID én verifieert device UUID na connect. |
|
||||
| **Commando vervalsing** | HMAC dekt command byte + sequence — wijzigen maakt handtekening ongeldig |
|
||||
| **Brute-force key** | 32-byte key = 2^256 mogelijkheden — onhaalbaar |
|
||||
| **Sniffen** | Pakketten zijn onversleuteld; geen confidentiality. Alleen commando's (aan/uit) zijn zichtbaar, niet de key. |
|
||||
| **Reverse engineering van key** | Sleutel staat niet in de APK — wordt pas bij USB provisioning gegenereerd en in SharedPreferences opgeslagen. Extractie vereist fysieke toegang tot de telefoon. |
|
||||
| **Key extractie via USB** | Fysieke USB-toegang tot de module geeft `KEY?\n` de huidige key terug. Bescherming: fysieke toegang tot het board beperken. |
|
||||
| **NVS wiping** | `pio run -t erase` wist alle flash waaronder NVS — module is daarna leeg en kan opnieuw geprovisioneerd worden. |
|
||||
| **Commando vervalsing** | AES-GCM versleutelt en authenticeert command byte + nonce — wijzigen maakt tag ongeldig |
|
||||
| **Afluisteren** | AES-256-GCM biedt confidentiality — commando's zijn onleesbaar zonder AES-sleutel |
|
||||
| **Brute-force PSK** | 32-byte PSK = 2^256 mogelijkheden — onhaalbaar |
|
||||
| **Reverse engineering van PSK** | PSK staat niet in de APK — wordt pas bij USB provisioning gegenereerd en in SharedPreferences opgeslagen. |
|
||||
| **PSK extractie via USB** | `KEY?\n` geeft de huidige PSK terug. Fysieke USB-toegang is nodig — bescherm het board. |
|
||||
| **NVS wiping** | `pio run -t erase` wist alle flash waaronder NVS — module start daarna zonder keys. |
|
||||
|
||||
### Waarom geen BLE-link encryptie?
|
||||
### Firmware (OTA via BLE)
|
||||
|
||||
BLE-link encryptie (bonding/Just Works) vereist complexe pairing flows die op Android sliding bugs veroorzaken (write queues, `GATT_INSUFFICIENT_AUTHENTICATION` handling, state leaks). HMAC biedt authenticatie en replay-bescherming op applicatieniveau — voldoende voor een relais. Het enige wat link-encryptie extra biedt is confidentiality (afluisteren), wat voor een aan/uit commando irrelevant is. De HMAC key wordt fysiek via USB uitgewisseld, nooit via BLE.
|
||||
De firmware kan **over-the-air** worden geüpdatet via BLE (zonder USB):
|
||||
|
||||
1. De app scant en verbindt zoals normaal
|
||||
2. Instellingen → Module bijwerken (Server mode + BLE transport)
|
||||
3. De app leest de `VERSION` characteristic — als de versie actueel is, wordt overgeslagen
|
||||
4. Firmware wordt in **500-byte chunks** verzonden via de `OTA` characteristic (WRITE_NR + NOTIFY)
|
||||
5. Elke chunk krijgt een ACK/NAK response
|
||||
6. Na alle chunks wordt de SHA-256 hash van de ontvangen firmware geverifieerd
|
||||
7. Bij match: `0xFF` confirmatie → `esp_ota_set_boot_partition` → module reboot met nieuwe firmware
|
||||
8. 10-seconden timeout op 0xFF confirm — geen confirm = update wordt weggegooid
|
||||
|
||||
Tijdens OTA zijn relais geforceerd UIT en knippert de LED groen. Na afloop (wachtend op confirm) is de LED geel.
|
||||
|
||||
> **Client OTA:** Clients kunnen ook OTA ontvangen. De server stuurt `BROKER_CMD_UPDATE_AVAILABLE`, de client antwoordt `BROKER_CMD_CLIENT_READY`, en start vervolgens een eigen BLE OTA-server (`SylDa_Client_OTA_XX`). De app verbindt met de client direct voor de OTA transfer.
|
||||
|
||||
## Firmware
|
||||
|
||||
De firmware is geschreven in C++ met behulp van PlatformIO en de Arduino-framework. BLE wordt verzorgd door de ESP32 NimBLE library, HMAC door mbedtls (ingebouwd in ESP-IDF). Er zijn twee PlatformIO environments:
|
||||
De firmware is geschreven in C++ met PlatformIO en de Arduino-framework. BLE: ESP32 NimBLE library, crypto: mbedtls (ingebouwd in ESP-IDF).
|
||||
|
||||
| Environment | Bronbestand | Rol |
|
||||
|---|---|---|
|
||||
| `s3lite-server` | `src/main.cpp` | Ontvangt BLE-verbindingen, bedient relais |
|
||||
| `s3lite-client` | `src/client.cpp` | Verbindt als BLE-central met server, stuurt relais-commando's |
|
||||
| `s3lite-server` | `src/main.cpp` | Ontvangt BLE-verbindingen, bedient relais, broker voor OTA-distributie |
|
||||
| `s3lite-client` | `src/client.cpp` | Verbindt als BLE-central met server, stuurt relais-commando's, ontvangt OTA |
|
||||
|
||||
Firmwareversies worden beheerd via `version.txt` (single source of truth). PlatformIO genereert `src/version.h` automatisch via een pre-build script.
|
||||
Firmwareversies: `version.txt` (single source of truth) → `src/version.h` (gegenereerd door `tools/pio_version_pre.py`) + `SylDaVersions.kt` (Android). Versiebeheer via `tools/check_versions.sh`.
|
||||
|
||||
### Logica
|
||||
|
||||
|
|
@ -156,133 +196,150 @@ Elk relais gaat aan als **één van beide** bronnen actief is:
|
|||
|
||||
| Relais | Bron | Voorwaarde | Resultaat |
|
||||
|---|---|---|---|
|
||||
| Relais 1 | Touch sensor 1 | G8 = HIGH (aanraken) | Relais 1 aan |
|
||||
| Relais 1 | BLE command | App stuurt HMAC-ondertekend `0x01` | Relais 1 aan |
|
||||
| Relais 2 | Touch sensor 2 | G6 = HIGH (aanraken) | Relais 2 aan |
|
||||
| Relais 2 | BLE command | App stuurt HMAC-ondertekend `0x02` | Relais 2 aan |
|
||||
| Relais 1 | Touch sensor 1 | G8 = LOW (aanraken, actief LOW) | Relais 1 aan |
|
||||
| Relais 1 | BLE/AES command | App stuurt AES-GCM `0x01` | Relais 1 aan |
|
||||
| Relais 1 | BLE/AES command (client) | Client stuurt AES-GCM `0x01` | Relais 1 aan |
|
||||
| Relais 1 | Interne knop (G41) | Knop ingedrukt (LOW) | Relais 1 aan |
|
||||
| Relais 2 | Touch sensor 2 | G6 = LOW (aanraken, actief LOW) | Relais 2 aan |
|
||||
| Relais 2 | BLE/AES command | App stuurt AES-GCM `0x02` | Relais 2 aan |
|
||||
| Relais 2 | BLE/AES command (client) | Client stuurt AES-GCM `0x02` | Relais 2 aan |
|
||||
| Beide | Geen van beide | Geen touch + geen BLE command | Relais uit |
|
||||
|
||||
De touch sensoren en BLE werken onafhankelijk. Als de sensor losgelaten wordt en de BLE-knop niet ingedrukt is, gaat het relais uit.
|
||||
De touch sensoren, BLE, en interne knop werken onafhankelijk (OR-logica). De interne knop (G41) activeert alleen relais 1. Bij meerdere BLE-clients worden hun commando's samengevoegd.
|
||||
|
||||
### BLE GATT
|
||||
|
||||
| Eigenschap | UUID |
|
||||
|---|---|
|
||||
| Service | `4fafc201-1fb5-459e-8fcc-c5c9c331914b` |
|
||||
| Relay Characteristic | `beb5483e-36e1-4688-b7f5-ea07361f26d8` |
|
||||
| UUID Characteristic | `beb5483e-36e1-4688-b7f5-ea07361f26d9` |
|
||||
|
||||
De relay characteristic ondersteunt `WRITE_NR` (Write Without Response). De UUID characteristic is read-only en bevat het unieke device-ID van de module.
|
||||
| Eigenschap | UUID | Properties | Beschrijving |
|
||||
|---|---|---|---|
|
||||
| Service | `4fafc201-1fb5-459e-8fcc-c5c9c331914b` | — | SylDa service |
|
||||
| Relay | `beb5483e-36e1-4688-b7f5-ea07361f26d8` | WRITE_NR | AES-GCM relay commands (29 bytes) |
|
||||
| UUID | `beb5483e-36e1-4688-b7f5-ea07361f26d9` | READ | Device UUID (16 bytes) |
|
||||
| VERSION | `beb5483e-36e1-4688-b7f5-ea07361f26db` | READ | Firmware versie string |
|
||||
| OTA | `beb5483e-36e1-4688-b7f5-ea07361f26da` | WRITE_NR, NOTIFY | BLE OTA firmware update |
|
||||
| ECDH | `beb5483e-36e1-4688-b7f5-ea07361f26dc` | WRITE_NR, NOTIFY | ECDH sleuteluitwisseling |
|
||||
| CLIENT_REGISTRY | `beb5483e-36e1-4688-b7f5-ea07361f26dd` | READ, WRITE_NR, NOTIFY | Client registratie (UUID + versie) |
|
||||
| CLIENT_CONTROL | `beb5483e-36e1-4688-b7f5-ea07361f26de` | WRITE_NR, NOTIFY | Broker protocol (OTA notificaties) |
|
||||
|
||||
### Key provisioning
|
||||
|
||||
De firmware wordt zonder HMAC key gecompileerd. Bij de eerste opstart print de module:
|
||||
De firmware wordt zonder PSK gecompileerd. Bij de eerste opstart print de module:
|
||||
|
||||
```
|
||||
No HMAC key provisioned — connect USB and run SET_KEY
|
||||
No PSK — connect USB and run SET_KEY
|
||||
```
|
||||
|
||||
Sluit de module via USB aan op de telefoon met de app geïnstalleerd. De app genereert automatisch een willekeurige key en stuurt deze naar de module. Na provisioning print de module bij opstarten:
|
||||
Sluit de module via USB aan op de telefoon met de app geïnstalleerd. De app genereert automatisch een willekeurige PSK en stuurt deze naar de module. Na provisioning print de module bij opstarten:
|
||||
|
||||
```
|
||||
HMAC key loaded from NVS
|
||||
PSK loaded from NVS
|
||||
```
|
||||
|
||||
**Key wissen (factory reset):** Om de module terug te zetten naar ongeprovisioneerd:
|
||||
|
||||
```bash
|
||||
pio run -t erase
|
||||
```
|
||||
|
||||
Dit wist alle flash inclusief NVS. Na opnieuw flashen start de module weer zonder key.
|
||||
**Key wissen (factory reset):** `pio run -t erase` wist alle flash inclusief NVS.
|
||||
|
||||
### Serial monitor
|
||||
|
||||
Baudrate: **115200** (USB CDC). De firmware stuurt heartbeat-statussen elke 5 seconden, logt statuswijzigingen, en print de HMAC key (of de afwezigheid ervan) bij opstarten.
|
||||
Baudrate: **115200** (USB CDC). De firmware stuurt heartbeats elke 60 seconden, logt statuswijzigingen, en print de PSK-status bij opstarten.
|
||||
|
||||
**Met geprovisioneerde key:**
|
||||
**Met geprovisioneerde PSK (server):**
|
||||
```
|
||||
=== SylDa BLE Relay ===
|
||||
HMAC key loaded from NVS
|
||||
LED red (no connection), starting BLE...
|
||||
BLE: advertising started as 'SylDa_Server' (start=1, isAdv=1)
|
||||
=== AtomS3 Lite BLE Relay v20 ===
|
||||
PSK loaded from NVS
|
||||
BLE: advertising started
|
||||
Setup done.
|
||||
[heartbeat] R1=0 R2=0 t1=1 t2=1 btn=1 ble1=0 ble2=0
|
||||
BLE: device connected
|
||||
BLE: relay1 ON (seq=1)
|
||||
BLE: relay1 OFF (seq=2)
|
||||
Relays: R1=ON R2=OFF (t1=YES t2=no btn=no ble1=OFF ble2=OFF)
|
||||
[heartbeat] R1=ON R2=OFF t1=YES t2=no btn=no ble1=OFF ble2=OFF clients=1
|
||||
```
|
||||
|
||||
**Zonder key (nieuwe/gewiste module):**
|
||||
**Zonder PSK (nieuwe/gewiste module):**
|
||||
```
|
||||
=== SylDa BLE Relay ===
|
||||
No HMAC key provisioned — connect USB and run SET_KEY
|
||||
LED red (no connection), starting BLE...
|
||||
BLE: advertising started as 'SylDa_Server' (start=1, isAdv=1)
|
||||
No HMAC key — use USB SET_KEY to provision
|
||||
=== AtomS3 Lite BLE Relay v20 ===
|
||||
No PSK — connect USB and run SET_KEY
|
||||
BLE: advertising started
|
||||
No PSK — use USB SET_KEY to provision
|
||||
Setup done.
|
||||
```
|
||||
|
||||
In deze staat accepteert de module wel BLE-verbindingen, maar elk HMAC-packet faalt verificatie omdat er geen key is om mee te vergelijken.
|
||||
**Client firmware log (geprovisioneerd):**
|
||||
```
|
||||
=== AtomS3 Lite SylDa Client v6 ===
|
||||
PSK loaded from NVS
|
||||
UUID loaded from NVS
|
||||
BLE: scanning...
|
||||
BLE: connected to xx:xx:xx:xx:xx:xx
|
||||
[hb] t1=no t2=no btn=no r1=OFF r2=OFF conn=yes ecdh=yes
|
||||
```
|
||||
|
||||
### Uploaden
|
||||
|
||||
> **Download-mode:** Houd de reset-knop ~2 seconden ingedrukt tot de groene LED aangaat, laat dan los. Het board is nu in download-mode.
|
||||
> **Download-mode:** Houd de reset-knop ~2 seconden ingedrukt tot de groene LED aangaat, laat dan los.
|
||||
|
||||
```bash
|
||||
# Flash server firmware (behoudt NVS/key)
|
||||
# Flash server firmware (behoudt NVS/PSK)
|
||||
pio run -e s3lite-server --target upload
|
||||
|
||||
# Flash client firmware (behoudt NVS/key)
|
||||
# Flash client firmware (behoudt NVS/PSK)
|
||||
pio run -e s3lite-client --target upload
|
||||
|
||||
# Volledig wissen (incl. NVS/key) + opnieuw flashen
|
||||
# Volledig wissen (incl. NVS/PSK) + opnieuw flashen
|
||||
pio run -t erase && pio run -e s3lite-server --target upload
|
||||
```
|
||||
|
||||
Na het uploaden treedt er een harde reset op. Als het board in download-mode blijft, USB eruit/erin of kort op reset tikken om in run-mode te komen.
|
||||
De upload port wordt automatisch gedetecteerd door `tools/pio_upload_port.py` (post-build script). Deze script zoekt de ESP32 via `ID?` over de seriële poort en past `upload_port` aan in `platformio.ini`.
|
||||
|
||||
**Direct flashen (handmatig):**
|
||||
```bash
|
||||
~/.platformio/packages/tool-esptoolpy/esptool.py --no-stub --chip esp32s3 --port /dev/ttyACM1 --baud 115200 --before default_reset --after hard_reset write_flash --flash_mode keep --flash_size keep 0x0 .pio/build/s3lite-server/bootloader.bin 0x8000 .pio/build/s3lite-server/partitions.bin 0xE000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/s3lite-server/firmware.bin
|
||||
```
|
||||
|
||||
### Firmware flashen via de app
|
||||
|
||||
De firmware kan rechtstreeks via de Android-app worden geflashed, geen computer nodig:
|
||||
De firmware kan rechtstreeks via de Android-app worden geflashed (USB) of geüpdatet (BLE OTA):
|
||||
|
||||
1. Sluit de module via USB-OTG aan op de telefoon
|
||||
2. Open de app → Instellingen → Firmware bijwerken
|
||||
3. De app checkt de firmware versie. Als de versie actueel is, wordt het flashen overgeslagen
|
||||
4. Is de firmware verouderd, dan flasht de app bootloader, partitions, en firmware
|
||||
5. Na het flashen herstart de module en volgt automatisch de key exchange
|
||||
1. Sluit de module via USB-OTG aan op de telefoon (USB) of zorg dat deze verbonden is via BLE (OTA)
|
||||
2. Open de app → Instellingen
|
||||
3. Kies **Device Mode** (Server/Client) en **Transport Mode** (BLE/USB)
|
||||
4. Tik op **Module bijwerken**
|
||||
5. **USB transport:** App checkt versie, flasht bootloader/partitions/firmware indien verouderd, wisselt daarna PSK uit
|
||||
6. **BLE transport (alleen server mode):** App checkt VERSION characteristic, voert OTA update uit zonder USB
|
||||
|
||||
De firmware binaries worden via `tools/copy_firmware.sh` naar de app assets gekopieerd (`assets/firmware/server/` en `assets/firmware/client/`).
|
||||
Firmware binaries: `tools/copy_firmware.sh` kopieert `.bin` bestanden naar `assets/firmware/server/` en `assets/firmware/client/`.
|
||||
|
||||
## Android App
|
||||
|
||||
### Features
|
||||
|
||||
- **Auto-connect:** De app scant automatisch bij opstarten naar de BLE service UUID `4fafc201-1fb5-459e-8fcc-c5c9c331914b` ("SylDa_Server")
|
||||
- **Auto-reconnect:** Bij wegvallen van de verbinding wordt na 2 seconden opnieuw gescant
|
||||
- **Scan retry:** Bij scan timeout wordt relais 1 een "Opnieuw zoeken" knop — tik om opnieuw te scannen
|
||||
- **Hold-to-activate:** Houd de knop ingedrukt voor relais aan, loslaten voor relais uit
|
||||
- **Twee onafhankelijke relais:** Twee knoppen, elk met eigen HMAC commando code
|
||||
- **Write Without Response:** Gebruikt `WRITE_TYPE_NO_RESPONSE` voor minimale latency
|
||||
- **MTU negotiatie:** Vraagt MTU 512 aan na service discovery (voor 37-byte HMAC packets)
|
||||
- **HMAC authenticatie:** Elk commando wordt ondertekend met HMAC-SHA256 + sequence counter
|
||||
- **Key exchange geïntegreerd:** De "Firmware bijwerken" knop checkt versie, flasht indien nodig, en wisselt automatisch sleutels uit
|
||||
- **Thema-selector:** Instellingen → Weergave kiest Systeem, Licht of Donker
|
||||
- **Permissies:** Vraagt BLUETOOTH_SCAN en BLUETOOTH_CONNECT aan. Bij weigeren wordt de knop uitgeschakeld en verwezen naar Instellingen
|
||||
- **Auto-connect:** Scant bij opstarten naar BLE service UUID `4fafc201-1fb5-459e-8fcc-c5c9c331914b` ("SylDa_Server")
|
||||
- **Manufacturer data matching:** Scant op manufacturer ID 0xFFFF die de eerste 4 bytes van de device UUID bevat — directe UUID-match bij scan
|
||||
- **Device UUID verificatie:** Leest `UUID_CHAR_UUID` en vergelijkt met opgeslagen UUID — alleen correcte apparaten worden geaccepteerd
|
||||
- **Firmware versie check:** Bij connect wordt VERSION characteristic gelezen — toont "Update beschikbaar" als app-versie nieuwer is
|
||||
- **Auto-reconnect:** Bij wegvallen verbinding na 2 seconden opnieuw scannen
|
||||
- **Scan retry:** Bij timeout 3× automatisch herhalen, daarna "Opnieuw zoeken" knop
|
||||
- **Hold-to-activate:** Knop ingedrukt = relais aan, loslaten = relais uit
|
||||
- **Twee onafhankelijke relais:** Twee knoppen, elk met eigen AES-GCM commando
|
||||
- **Write Without Response:** `WRITE_TYPE_NO_RESPONSE` voor minimale latency
|
||||
- **MTU negotiatie:** Vraagt MTU 512 aan na service discovery
|
||||
- **ECDH + AES-256-GCM:** ECDH sleuteluitwisseling bij connectie, daarna AES-GCM encryptie voor elk commando
|
||||
- **BLE OTA update:** Firmware updaten via BLE zonder USB (server mode + BLE transport)
|
||||
- **Key exchange geïntegreerd:** Module bijwerken = versie check → flashen (indien nodig) → PSK-uitwisseling — volledig automatisch
|
||||
- **Thema-selector:** Instellingen → Weergave met Systeem, Licht of Donker
|
||||
- **Permissies:** Vraagt BLUETOOTH_SCAN en BLUETOOTH_CONNECT. Bij weigeren wordt verwezen naar Instellingen
|
||||
- **Broker protocol:** Ontvangt `CLIENT_CONTROL` notificaties van de server (OTA beschikbaar, client ready)
|
||||
|
||||
### Instellingenscherm
|
||||
|
||||
1. Open de app → tik op **instellingen** (tandwiel-icoon rechtsboven)
|
||||
2. **Firmware bijwerken:** Sluit de module aan via USB. De app checkt de firmware versie, flasht indien nodig, en wisselt daarna automatisch sleutels uit. Eén knop voor de hele flow.
|
||||
3. **Weergave:** Kies Systeem (volgt telefoon), Licht of Donker
|
||||
4. **Relais labels:** Stel eigen namen in voor de twee relais knoppen
|
||||
2. **Device Mode:** Kies Server of Client (bepaalt welke firmware wordt geflashed / provisioning flow)
|
||||
3. **Transport Mode:** Kies BLE of USB (bepaalt hoe firmware wordt geüpdatet: OTA via BLE of USB flash)
|
||||
4. **Module bijwerken:** Versie check → flash/OTA → PSK-uitwisseling — één knop voor de hele flow
|
||||
5. **Weergave:** Kies Systeem (volgt telefoon), Licht of Donker
|
||||
6. **Relais labels:** Stel eigen namen in voor de twee relais knoppen
|
||||
|
||||
De key wordt opgeslagen in SharedPreferences en overleeft app-herstarts. Bij geen key toont de hoofdapp "Geen sleutel — open Instellingen" en wordt er niet gescant.
|
||||
De PSK en UUIDs worden opgeslagen in SharedPreferences en overleven app-herstarts. Bij geen PSK toont de hoofdapp "Geen sleutel — open Instellingen".
|
||||
|
||||
### Hoofdscherm UI
|
||||
|
||||
- **instellingen** tekst + tandwiel-icoon rechtsboven → opent instellingenscherm
|
||||
- **Twee knoppen** centrum → hold-to-activate voor relais 1 en 2
|
||||
- **Twee knoppen** in het midden → hold-to-activate voor relais 1 en 2 (labels aanpasbaar)
|
||||
- **Status tekst** linksonder (14sp) → toont verbindingsstatus
|
||||
|
||||
### Bouwen
|
||||
|
|
@ -305,7 +362,7 @@ cd android
|
|||
JAVA_HOME=/home/linuxbrew/.linuxbrew/opt/openjdk@21/libexec ./gradlew installDebug
|
||||
```
|
||||
|
||||
De APK staat na build in `android/app/build/outputs/apk/debug/app-debug.apk`.
|
||||
APK: `android/app/build/outputs/apk/debug/app-debug.apk`.
|
||||
|
||||
### Installeren
|
||||
|
||||
|
|
@ -323,33 +380,39 @@ adb -s <ip>:5555 install -r android/app/build/outputs/apk/debug/app-debug.apk
|
|||
|
||||
2. **Firmware flashen & sleutel uitwisselen (één flow):**
|
||||
- Sluit de module via USB-OTG aan op de telefoon
|
||||
- Open de app → Instellingen → Firmware bijwerken
|
||||
- De app checkt versie, flasht indien nodig, en wisselt sleutels uit — volledig automatisch
|
||||
- Open de app → Instellingen → kies Device Mode (Server/Client) → kies Transport (USB) → Module bijwerken
|
||||
- De app checkt versie, flasht indien nodig, en wisselt PSK uit — volledig automatisch
|
||||
|
||||
3. **Gebruiken:** De app scant automatisch, verbindt, en toont "Verbonden". Houd een knop ingedrukt om het relais te schakelen.
|
||||
|
||||
### Nieuwe module, bestaande telefoon
|
||||
|
||||
- Sluit de nieuwe module via USB aan → Firmware bijwerken → app flasht firmware en genereert nieuwe key
|
||||
- Sluit nieuwe module via USB aan → Instellingen → Module bijwerken → app flasht en provisioneert
|
||||
|
||||
### Bestaande module, nieuwe telefoon
|
||||
|
||||
- Sluit de module via USB-OTG aan op de nieuwe telefoon
|
||||
- Firmware bijwerken → app herkent bestaande firmware, slaat key over, leest bestaande key uit
|
||||
- Sluit module via USB-OTG aan op nieuwe telefoon → Instellingen → Module bijwerken → app leest bestaande PSK uit (antwoordt `PSK:<hex>`)
|
||||
|
||||
## Projectstructuur
|
||||
|
||||
```
|
||||
Project_SylDa/
|
||||
├── platformio.ini # PlatformIO configuratie (ESP32-S3, server + client environments)
|
||||
├── platformio.ini # PlatformIO configuratie (ESP32-S3, server + client)
|
||||
├── version.txt # Single source of truth voor firmwareversies
|
||||
├── icon.png / icon.svg # Project icon
|
||||
├── src/
|
||||
│ ├── main.cpp # Server firmware (BLE + HMAC + NVS + USB serial + touch + relais)
|
||||
│ ├── client.cpp # Client firmware (BLE central + touch + relais commando's)
|
||||
│ ├── main.cpp # Server firmware (BLE + ECDH/AES + NVS + USB + touch + relais + OTA + broker)
|
||||
│ ├── client.cpp # Client firmware (BLE central + ECDH/AES + touch + relais + OTA server mode)
|
||||
│ ├── ecdh_helper.h # ECDH crypto helper (secp256r1, AES-sleutel afleiding, pubkey HMAC)
|
||||
│ └── version.h # Auto-gegenereerd uit version.txt — niet handmatig bewerken
|
||||
├── tools/
|
||||
│ ├── copy_firmware.sh # Kopieert firmware binaries naar app assets
|
||||
│ └── pio_version_pre.py # PlatformIO pre-build script (genereert version.h)
|
||||
│ ├── copy_firmware.sh # Kopieert firmware binaries naar Android app assets
|
||||
│ ├── pio_version_pre.py # PlatformIO pre-build script (genereert version.h)
|
||||
│ ├── pio_upload_port.py # PlatformIO post-build script (auto-detecteert upload port)
|
||||
│ ├── check_versions.sh # Valideert version.txt vs version.h vs SylDaVersions.kt
|
||||
│ └── test_ota_notify.py # Test BLE OTA notificatie flow
|
||||
├── scripts/
|
||||
│ └── release.sh # Release automatisering: firmware + APK/AAB + Forgejo release
|
||||
├── android/
|
||||
│ ├── build.gradle # Root Gradle config
|
||||
│ ├── settings.gradle # Gradle settings
|
||||
|
|
@ -392,6 +455,8 @@ Project_SylDa/
|
|||
│ │ ├── values/strings.xml
|
||||
│ │ └── xml/
|
||||
│ │ └── device_filter.xml
|
||||
├── docs/ # Documentatie (handleiding, ontwerpplannen)
|
||||
├── release/ # Release artifacts
|
||||
├── .gitignore
|
||||
├── LICENSE
|
||||
└── README.md
|
||||
|
|
@ -401,37 +466,53 @@ Project_SylDa/
|
|||
|
||||
### WRITE_TYPE_NO_RESPONSE (geen BLE write ACK)
|
||||
|
||||
De app gebruikt `WRITE_TYPE_NO_RESPONSE` (Write Without Response) in plaats van `WRITE_TYPE_DEFAULT` (Write With Response). Eerdere versies gebruikten ACK's, maar de BLE write acknowledgement duurde lang genoeg dat de gebruiker de knop kon loslaten vóór de ACK arriveerde. Als `ACTION_UP` plaatsvond tijdens een pending write, werd het loslaten genegeerd en bleven het relais en de app hangen in de ON-status. `WRITE_TYPE_NO_RESPONSE` verwijdert die latency en maakt directe ON→OFF sequenties mogelijk. De UI reflecteert de intentie van de gebruiker ("ingedrukt" / "losgelaten") in plaats van bevestigde relais-state — een aanvaardbare afweging voor een hold-to-activate interactie.
|
||||
De app gebruikt `WRITE_TYPE_NO_RESPONSE` in plaats van `WRITE_TYPE_DEFAULT`. Eerdere versies gebruikten ACK's, maar de BLE write acknowledgement duurde lang genoeg dat de gebruiker de knop kon loslaten vóór de ACK arriveerde. Als `ACTION_UP` plaatsvond tijdens een pending write, werd het loslaten genegeerd en bleven relais en app hangen in ON-status. `WRITE_TYPE_NO_RESPONSE` verwijdert die latency en maakt directe ON→OFF sequenties mogelijk.
|
||||
|
||||
### compileSdk/targetSdk 34 (niet 35 / Android 15)
|
||||
|
||||
De doelgroep bestaat uit lichamelijk gehandicapte gebruikers die zeer terughoudend zijn met het updaten van hun telefoon. Door te blijven op API 34 (Android 14) wordt de compatibiliteit met zoveel mogelijk apparaten gemaximaliseerd. Heroverweeg wanneer de gebruikersbasis voldoende is gemigreerd.
|
||||
De doelgroep (lichamelijk gehandicapte gebruikers) is terughoudend met telefoonupdates. API 34 (Android 14) maximaliseert compatibiliteit. Heroverweeg bij voldoende migratie.
|
||||
|
||||
### Thema-selector en DayNight
|
||||
|
||||
De app gebruikt `Theme.AppCompat.DayNight` in plaats van het eerder geforceerde `Theme.AppCompat.Light`. De instellingen bieden 3 opties: Systeem (volgt telefoon), Licht en Donker. Gekozen is voor de standaard Android-best-practice: geen eigen font-slider of contrast-kleurenkiezer, omdat Android's systeem-lettergrootte-instelling (`sp`-eenheden schalen automatisch) en hoog-contrast modus (Android 13+) al voldoen voor de doelgroep van visueel beperkte gebruikers. Een eigen implementatie zou het wiel opnieuw uitvinden en onnodige complexiteit toevoegen.
|
||||
`Theme.AppCompat.DayNight` met 3 opties: Systeem, Licht, Donker. Android's `sp`-eenheden en hoog-contrast modus (Android 13+) volstaan voor visueel beperkte gebruikers — eigen implementatie zou onnodige complexiteit toevoegen.
|
||||
|
||||
### ECDH + AES-256-GCM i.p.v. HMAC-only
|
||||
|
||||
HMAC-SHA256 (vroegere versies) bood authenticatie maar geen confidentiality. ECDH+AES-GCM voegt encryptie toe zonder de complexiteit van BLE-link bonding (die Android sliding bugs veroorzaakt: write queues, `GATT_INSUFFICIENT_AUTHENTICATION`). De PSK wordt alleen gebruikt voor ECDH pubkey HMAC-verificatie — daarna is alle communicatie versleuteld met afgeleide AES-256-GCM sleutels. GCM is AEAD: één operatie voor zowel encryptie als authenticatie.
|
||||
|
||||
## Technische notities
|
||||
|
||||
- De Atom S3 Lite heeft GPIO G1, G2, G5-G8, G38, G39 beschikbaar op de headers. G41 is de interne knop (active low). G46 is de interne LED.
|
||||
- G1 en G2 zitten op de HY2.0-4P Grove poort. G5-G8, G38, G39 zitten op de onderste expansie-header.
|
||||
- De firmware gebruikt geen M5Unified library — alleen Arduino core + ESP32 NimBLE + mbedtls.
|
||||
- De Atom S3 Lite heeft GPIO G1, G2, G5-G8, G38, G39 beschikbaar op de headers. G41 is de interne knop (active low). G35 wordt gebruikt voor een externe WS2812 LED (niet de interne G46 SK6812).
|
||||
- G1 en G2 zitten op de HY2.0-4P Grove poort. G5-G8, G38, G39 op de onderste expansie-header.
|
||||
- De firmware gebruikt geen M5Unified library — alleen Arduino core + ESP32 NimBLE + mbedtls + FastLED.
|
||||
- `ARDUINO_USB_CDC_ON_BOOT=1` is ingeschakeld voor virtuele serial via USB.
|
||||
- De HMAC key wordt opgeslagen in NVS (namespace `hmac`, key `key`, partitie 0x9000-0xDFFF). Via `pio run -t erase` kan NVS gewist worden.
|
||||
- Firmwareversies worden beheerd via `version.txt` — `src/version.h` wordt automatisch gegenereerd, nooit handmatig bewerken.
|
||||
- De app gebruikt `WRITE_TYPE_NO_RESPONSE` (Write Without Response) voor minimale latency.
|
||||
- De sequence counter start bij 1 (niet 0) om te voorkomen dat het eerste packet na connectie als replay wordt geweerd.
|
||||
- De app gebruikt raw Android USB API (`UsbDeviceConnection.bulkTransfer`) in plaats van een externe serial library.
|
||||
- `minSdk` is 26 (Android 8.0).
|
||||
- ProgressDialog is vervangen door eigen `AlertDialog` layouts (`dialog_waiting.xml`, `dialog_progress.xml`).
|
||||
- De HMAC key in de app is opgeslagen via `SharedPreferences`.
|
||||
- De app gebruikt `Theme.AppCompat.DayNight` met Systeem/Licht/Donker thema-selector.
|
||||
- `compileSdk`/`targetSdk` blijft op 34 (Android 14) voor maximale compatibiliteit met de doelgroep.
|
||||
- NVS: namespace `syl`, PSK in key `psk`, UUID in key `uuid`, server UUID in key `server`, BLE-adres in key `addr`. Partitie op 0x9000-0xDFFF.
|
||||
- `pio run -t erase` wist alle NVS. `tools/pio_upload_port.py` auto-detecteert de upload port via `ID?` query.
|
||||
- Firmwareversies: `version.txt` → `src/version.h` (gegenereerd) + `SylDaVersions.kt` (Android). `tools/check_versions.sh` valideert consistentie.
|
||||
- De app gebruikt raw Android USB API (`UsbDeviceConnection.bulkTransfer`) — geen externe serial library.
|
||||
- `minSdk` is 26 (Android 8.0). `compileSdk`/`targetSdk` blijft op 34.
|
||||
- Sequence counters starten bij 1 (niet 0), wrappen bij 1.000.000.
|
||||
- BLE MTU: server stelt 248 in (ESP32 NimBLE limiet), app vraagt 512. OTA/ECDH chunks passen zich aan aan `negotiatedMtu - 3`.
|
||||
- Server krijgt maximaal 2 gelijktijdige BLE-clients. Client slaat server BLE-adres op in NVS voor snelle reconnect (valt terug op scan als adres niet werkt).
|
||||
- Server advertising bevat manufacturer data (0xFFFF) met eerste 4 bytes van device UUID voor snelle identificatie.
|
||||
- OTA: 500-byte chunks (aangepast aan MTU), 3 retries per chunk, SHA-256 hash verificatie, 10s 0xFF confirm timeout.
|
||||
- Client in OTA server modus advertiseert als `SylDa_Client_OTA_XX` (XX = laatste 2 hex van device UUID).
|
||||
|
||||
## Release
|
||||
|
||||
```bash
|
||||
# Volledige release (firmware + APK + AAB + Forgejo)
|
||||
bash scripts/release.sh
|
||||
```
|
||||
|
||||
Deze script:
|
||||
1. Compileert server + client firmware (`pio run`)
|
||||
2. Kopieert firmware naar Android assets (`copy_firmware.sh`)
|
||||
3. Bouwt release APK + AAB (`gradlew assembleRelease assembleAndroidTest bundleRelease`)
|
||||
4. Publiceert de release op Forgejo (met APK/AAB als attachments)
|
||||
|
||||
## Licentie
|
||||
|
||||
Dit project is gelicentieerd onder de **GNU General Public License v3.0 of later** (GPL-3.0-or-later).
|
||||
**GNU General Public License v3.0 or later** (GPL-3.0-or-later).
|
||||
|
||||
Deze licentie is vereist omdat de app gebruik maakt van [`esp32-flash-lib`](https://github.com/dkaukov/esp32-flash) (GPL-3.0), een library voor het flashen van ESP32 firmware. De GPL-3.0 copyleft-clausule bepaalt dat een werk dat aan een GPL-3.0 werk linkt zelf ook onder GPL-3.0 (of een compatibele licentie) moet worden gedistribueerd.
|
||||
|
||||
Zie het `LICENSE` bestand voor de volledige licentietekst.
|
||||
Vereist omdat de app [`esp32-flash-lib`](https://github.com/dkaukov/esp32-flash) (GPL-3.0) gebruikt voor ESP32 firmware flashing. Zie het `LICENSE` bestand.
|
||||
|
|
|
|||
Loading…
Reference in a new issue