# Hello BLE OTA Example Demonstrates the CUBE32 BLE OTA driver with an LVGL 9.x dark theme UI. Shows real-time BLE status, connection state, received commands, and responses. ## Features - **BLE OTA Driver** - NimBLE-based BLE GATT server - **LVGL Display** - Dark theme UI showing: - Driver state (Idle, Advertising, Connected, OTA in progress) - BLE connection status with color indicator - Connected device address - Last received command - Last sent response - RX/TX message counters - OTA progress bar (during firmware update) - **Command Handling**: - Get Status (0x01) - Get Configuration (0x02) - Text Message echo (0x04) - System Restart (0x10) - System Power Off (0x11) ## Hardware Requirements - CUBE32 board with: - ESP32-S3 (or other ESP32 with BLE support) - ST7789 display - Touch panel (optional, for restart button) ## BLE Service Structure ### Device Information Service (0x180A) | Characteristic | UUID | Properties | Description | |---------------|--------|------------|-------------| | Model Number | 0x2A24 | Read | "CUBE32" | | Serial Number | 0x2A25 | Read | Device SN | | FW Revision | 0x2A26 | Read | Firmware version | | HW Revision | 0x2A27 | Read | Hardware version | | SW Revision | 0x2A28 | Read | Software version | | Manufacturer | 0x2A29 | Read | "CUBE32" | ### OTA Service (0x8018) | Characteristic | UUID | Properties | Description | |-----------------|--------|---------------------|-------------| | RECV_FW_CHAR | 0x8020 | Write, Indicate | Receive firmware data | | PROGRESS_CHAR | 0x8021 | Read, Indicate | OTA progress (0-100) | | COMMAND_CHAR | 0x8022 | Write, Indicate | OTA commands | | CUSTOMER_CHAR | 0x8023 | Write, Notify, Indicate | Custom commands/responses | ## Configuration ### 1. Enable Required Components In `idf.py menuconfig`: **CUBE32 Board Configuration → BLE OTA Configuration:** - ✅ Enable BLE OTA - Set BLE Device Name (default: "CUBE32") - ☑️ Start BLE OTA on Double Boot (optional) - Set Double Boot Time Gap (default: 5000ms) **CUBE32 Board Configuration → Display Configuration:** - ✅ Enable Display - ✅ Enable LVGL **Component config → LVGL → Font usage:** - ✅ Enable Montserrat 14 **Component config → Bluetooth:** - ✅ Bluetooth (auto-enabled) - Host → NimBLE - BLE only (auto-selected) ### 2. Select Application **CUBE32 Application Selection:** - Select "Hello BLE OTA Example" ## Build and Flash ```bash idf.py set-target esp32s3 idf.py menuconfig # Configure as above idf.py build idf.py -p PORT flash monitor ``` ## Usage 1. Flash the firmware to CUBE32 2. The device will start advertising as "CUBE32" (or configured name) 3. Use a BLE client to connect: - Python client: `tools/ble_ota_client/` - Mobile app: nRF Connect, LightBlue, or custom app 4. Send commands via the CUSTOMER_CHAR (0x8023) characteristic ## Assets partition (BSP-07 test target) The example carries a small `assets/` folder that is packed and flashed to the `assets` data partition together with the app, so the BLE data-partition OTA (BSP 0.0.17, BLE protocol 1.2) can be tested with real data: | Part | What it does | |------|--------------| | `assets/` | Sample files: `README.txt`, `config/theme.json`, `images/gradient_320x240.rgb565` (150 KB) | | `tools/pack_assets.py` | Packs the folder into one image (header, file table, data, SHA-256 trailer) | | `main/CMakeLists.txt` | Builds `build/hello_ble_ota_assets.bin` and flashes it to `assets` with `idf.py flash` | | `main/assets_check.cpp` | Verifies the image at boot and after every BLE update; logs `ASSETS boot: OK ...` | The Normal UI shows `Assets: OK, 3 files, 151 KB` (cyan), `UPDATING...` (orange) during a BLE update, or `INVALID (hash)` / `INVALID (header)` (red) when the partition does not hold a valid image. The app registers `BleOta::setDataOtaHandler()`: BEGIN marks the assets as updating, END re-verifies them. BLE OTA does not depend on the partition, so an invalid image never blocks a BLE reflash. The label ends with how the partition was flashed (`BLE` or `USB`, from `BleOta::dataPartitionMethod()`); the boot log says `BLE-verified (matches last BLE install)` / `not installed via BLE (USB/serial)`. The device cannot see the transport; flashing the app over USB (`idf.py flash`) also marks the assets as USB. Requires a partition table with an `assets` partition (for example `partitions/cube32/16m.csv`). Change the files in `assets/` and rebuild to get a new image. Check an image with `python3 tools/pack_assets.py --verify build/hello_ble_ota_assets.bin`. Use this image for `--bsp07-tests`; see `tools/ble_ota_client/README.md`. ## BLE Command Protocol Commands are sent to CUSTOMER_CHAR (0x8023) with the following format: ``` [CMD_ID] [DATA...] ``` ### Commands | Command ID | Name | Data | Description | |------------|-----------------|------|-------------| | 0x01 | GET_STATUS | None | Request device status | | 0x02 | GET_CONFIG | None | Request device configuration | | 0x04 | TEXT_MESSAGE | ASCII text | Send text message (echoed back) | | 0x10 | RESTART | None | Restart the device | | 0x11 | POWER_OFF | None | Power off the device | ### Response Format Responses are sent via notification on CUSTOMER_CHAR: ``` [CMD_ID] [STATUS] [DATA...] ``` | Status | Description | |--------|-------------| | 0x00 | OK | | 0x01 | Error | | 0x02 | Invalid command | | 0x03 | Busy | ## Python Client A Python test client is provided in `tools/ble_ota_client/`: ```bash # Install dependencies pip install bleak # Run the client cd tools/ble_ota_client python ble_client.py ``` See `tools/ble_ota_client/README.md` for details. ## UI Display The LVGL UI shows: ``` ┌──────────────────────────┐ │ 🔵 BLE OTA │ │ ● State: ADVERTISING │ │ Connection: Advertising │ │ Addr: --:--:--:--:--:-- │ ├──────────────────────────┤ │ RX: CMD:0x01 LEN:0 │ │ TX: CMD:0x01 STS:0x00 │ │ RX: 5 TX: 5 │ │ │ │ [ 🔄 Restart ] │ └──────────────────────────┘ ``` Color indicators: - ⚫ Gray: Idle - 🔵 Blue: Advertising - 🟢 Green: Connected - 🟠 Orange: OTA in progress - 🔴 Red: Error ## Double Boot Feature When enabled, you can trigger BLE OTA mode by: 1. Press reset button 2. Wait less than 5 seconds (configurable) 3. Press reset button again 4. BLE OTA starts automatically This is useful when the main application doesn't start BLE OTA by default. ## Troubleshooting ### BLE not advertising - Check that BLE OTA is enabled in menuconfig - Check that NimBLE is selected as BLE host - Check serial monitor for initialization errors ### Connection drops immediately - Increase MTU size in configuration - Check for interference from other BLE devices - Try disabling BLE 5.0 features if using older clients ### OTA fails - Ensure firmware image has correct flash size (4MB default) - Check that firmware is built for the same target chip - Monitor progress via PROGRESS_CHAR characteristic ## Related Files - Driver: `components/cube32/include/drivers/ble/ble_ota.h` - Implementation: `components/cube32/src/drivers/ble/ble_ota.cpp` - Python client: `tools/ble_ota_client/`
To create a project from this example, run:
idf.py create-project-from-example "cube32esp/cube32_bsp=0.0.17:hello_ble_ota"