hello_ble_ota

Example of the component cube32esp/cube32_bsp v0.0.17
# 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"

or download archive (~65.63 KB)