# Example 05 — BLE JSON channel
Minimal ESP-IDF app that enables the optional **`iotmer_ble`** component and exposes a BLE GATT JSON channel.
This example is intentionally small: it demonstrates a **JSON-over-BLE** transport and a few commissioning commands
implemented in `main`.
## Build
```bash
cd components/iotmer/examples/05_ble_json
idf.py set-target esp32c3 # or esp32, esp32s3, esp32c6, …
idf.py menuconfig
idf.py build flash monitor
```
## Configure
- **Component config → IOTMER BLE (JSON channel)**: enable `CONFIG_IOTMER_BLE=y`, set name prefix and security.
- This example sets `CONFIG_IOTMER_BLE_GAP_NAME_PREFIX="MER-"` in `sdkconfig.defaults` (advertised name is `MER-` + short hex suffix).
- **Component config → Bluetooth**: enable controller + NimBLE host for your target.
## GATT contract
- Service UUID: `1d14d6ee-1001-4000-8024-b5a3c0ffee01`
- RX characteristic (write): `1d14d6ee-1002-4000-8024-b5a3c0ffee01`
- TX characteristic (notify/read): `1d14d6ee-1003-4000-8024-b5a3c0ffee01`
Central apps should subscribe to TX notifications before sending requests.
## JSON requests and responses
Requests are UTF‑8 JSON written to RX. Responses are UTF‑8 JSON received via TX notifications.
All requests include:
- `type` (string)
- `rid` (string): request id generated by the central; echoed back in responses
### `ping`
Request:
- `{"type":"ping","rid":"1"}`
Response:
- `{"type":"pong","rid":"1"}`
### `wifi.set`
Request:
- `{"type":"wifi.set","rid":"2","ssid":"MyWiFi","pass":"MyPassword"}`
Response:
- `{"type":"wifi.set.ok","rid":"2"}`
#### Optional: `claim_code` (bind-claim)
If `claim_code` is provided, the device will attempt to bind the device to a user identity after Wi‑Fi comes up.
Request:
- `{"type":"wifi.set","rid":"2","ssid":"MyWiFi","pass":"MyPassword","claim_code":"pc_..."}`
Additional responses (order may vary slightly):
- `{"type":"claim.bind.start","rid":"2"}`
- `{"type":"wifi.connect.ok","rid":"2"}`
- `{"type":"creds.ok","rid":"2"}`
- Success: `{"type":"claim.bind.ok","rid":"2"}`
- Failure: `{"type":"error","rid":"2","code":"claim.bind","message":"ESP_ERR_..."}`
If the backend returns HTTP **410 Gone**, it means the **claim code expired** (generate a new one and retry quickly).
### `wifi.clear`
Request:
- `{"type":"wifi.clear","rid":"3"}`
Response:
- `{"type":"wifi.clear.ok","rid":"3"}`
## macOS note (pairing cache)
If you see **CoreBluetooth error 14** ("Peer removed pairing information") while connecting from a PC client,
forget/remove the device under **System Settings → Bluetooth**, then retry.
## Protocol documentation
See the published docs for the full contract carried over `iotmer_ble`:
[BLE JSON provisioning](https://docs.iotmer.com/docs/sdk/esp-idf/ble-json-provisioning).
## PC test client (optional)
See `pc_ble_client/` (Python + Bleak).
To create a project from this example, run:
idf.py create-project-from-example "iotmertech/iotmer=0.1.14:05_ble_json"