A drop-in ESP32 component that adds Over-The-Air (OTA) firmware update capability via Bluetooth Low Energy.
- High Performance: 40+ KB/s transfer speeds
- Data Integrity: CRC32 verification prevents corrupted firmware
- Error Reporting: Real-time notifications for failures
- Drop-in Integration: Single function call to enable OTA
- Non-intrusive: Works alongside existing BLE services
- Python Client: Included client for easy firmware uploads
Add to your project's idf_component.yml:
dependencies:
simple_ble_ota:
version: "^0.1.0"Or clone directly into your components/ directory.
#include "simple_ble_ota.h"
void app_main(void)
{
// Initialize NVS, NimBLE, etc. (your existing code)
// Add Simple BLE OTA service
ESP_ERROR_CHECK(simple_ble_ota_init());
// Continue with your application...
}Use the included Python client:
python3 simple-ble-ota-client.py firmware.bin- ESP-IDF: >= 5.4.0
- BLE Stack: NimBLE only
- Python Client:
pip install bleak
The component implements a custom protocol over BLE GATT:
- Service UUID:
487d0950-41b9-4c57-ad09-a46ac47e2150 - Control Point:
487d0950-41b9-4c57-ad09-a46ac47e2151(Write + Notify) - Data:
487d0950-41b9-4c57-ad09-a46ac47e2152(Write + Write-No-Response)
- START (0x01):
[0x01][size_bytes_0-3]- Begin OTA with firmware size - DATA: Chunked firmware data (244 bytes optimal)
- COMPLETE (0x02):
[0x02][crc32_bytes_0-3]- Finalize with CRC verification - ERROR (0xFF):
[0xFF][error_code]- Error notifications from ESP32
This component requires NimBLE to be initialized before calling simple_ble_ota_init():
// Example BLE initialization
nimble_port_init();
ble_hs_cfg.sync_cb = ble_app_on_sync;
ble_svc_gap_device_name_set("MyDevice");
ble_svc_gap_init();
ble_svc_gatt_init();
// Now add Simple BLE OTA
simple_ble_ota_init();
// Start NimBLE
nimble_port_freertos_init(nimble_host_task);The component adds its service without affecting existing GATT services. You can add other services before or after calling simple_ble_ota_init().
The component does not set the BLE device name. Use your existing method:
ble_svc_gap_device_name_set("MyDevice");pip install bleak# Basic usage
python3 simple-ble-ota-client.py firmware.bin
# Custom device name
python3 simple-ble-ota-client.py firmware.bin "MyDevice"
# Show help
python3 simple-ble-ota-client.py --help- Automatic device discovery by name
- Progress tracking with throughput display
- CRC32 integrity verification
- Comprehensive error handling
- Batched transfers for optimal performance
Initializes the Simple BLE OTA service and adds it to the GATT server.
Prerequisites:
- NimBLE stack initialized
- BLE host synced
- GATT server running
Returns:
ESP_OK: SuccessESP_ERR_INVALID_STATE: BLE not initializedESP_FAIL: Failed to add service
Check if an OTA update is currently in progress.
Returns:
true: OTA update activefalse: OTA idle
The ESP32 reports errors via BLE notifications:
0x01: CRC mismatch (data corruption)0x02: Partition full (insufficient space)0x03: OTA begin failed0x04: OTA write failed0x05: OTA end failed0xFF: Unknown error
- Transfer Speed: 40+ KB/s typical
- Chunk Size: 244 bytes (optimal for BLE MTU)
- Flow Control: Batched writes with periodic synchronization
- Memory Usage: Minimal - uses ESP-IDF OTA buffers
"NimBLE stack not initialized"
- Ensure
nimble_port_init()is called beforesimple_ble_ota_init()
Device not discoverable
- Set device name with
ble_svc_gap_device_name_set() - Start advertising after initialization
Connection fails
- Check device name matches Python client parameter
- Ensure BLE advertising is active
- Verify no firewall blocking Bluetooth
Transfer fails
- Check partition table has OTA partitions
- Ensure sufficient flash space
- Verify firmware size is correct
Enable component logging:
esp_log_level_set("SIMPLE_BLE_OTA", ESP_LOG_DEBUG);MIT License - see LICENSE file for details.
$ compote registry login --profile "staging" --registry-url "https://components-staging.espressif.com" --default-namespace kodira
$ compote component upload --profile "staging" --name simple_ble_ota$ compote registry login --registry-url "https://components.espressif.com" --default-namespace kodira
$ compote component upload --name simple_ble_ota