ESPHome can already build firmware for nRF52840 boards, but updating them over Bluetooth required the MCUboot bootloader and the zephyr_mcumgr component. Many popular boards, such as the nice!nano, the Adafruit ItsyBitsy nRF52840 and the Feather nRF52840, come with the Adafruit bootloader instead, so they still had to be flashed over USB. A pull request merged on 25 October 2026 adds a new OTA platform, adafruit_ble, that sends updates to them over Bluetooth with esphome upload. It is in the development branch, so it should arrive with ESPHome 2026.11.

Configuration

The configuration example in the pull request sets bootloader: adafruit under nrf52, adds zephyr_ble_server with an on_numeric_comparison_request automation that accepts pairing and enables ota with platform: adafruit_ble. The pairing part is optional, but recommended: without it, any nearby device could start an update, and the build prints a warning. With pairing turned on, only a paired host can trigger one. The platform needs the Zephyr framework, zephyr_ble_server and one of the Adafruit bootloader variants. Any other bootloader fails validation with an explanation.

An upload is started with esphome upload --device BLE or with the board's Bluetooth address. ESPHome picks the method from the configuration: Adafruit DFU when adafruit_ble is set, MCUmgr otherwise.

How the update runs

The Adafruit bootloader uses Nordic's older DFU protocol and only offers its update service while it is in DFU mode. The update therefore has two steps. The application exposes a small write-only Bluetooth characteristic. Writing DFU to it restarts the board into the bootloader. ESPHome then looks for the bootloader at the board's address plus one and sends the firmware package. Only the board that was asked to restart gets flashed. On macOS, which hides Bluetooth addresses, ESPHome accepts the bootloader only if exactly one new DFU device appears after the restart. Another device in DFU mode nearby is listed in the error message and never flashed. A dropped link or a missed confirmation retries the transfer up to three times.

Because the bootloader does the update after the application has already restarted, on_progress, on_end, on_error and on_abort are rejected. Only on_begin and on_state_change fire. Rollback to the previous firmware depends on MCUboot, so with adafruit_ble alone it is off by default.

Recovery from safe mode

One change affects every configuration with zephyr_ble_server, including MCUmgr boards: the Bluetooth stack now also starts in safe mode, so a board stuck in a boot loop can still be updated wirelessly. User automations do not run in safe mode, so new pairings are rejected and only hosts that are already paired can connect.

The author tested the update on a nice!nano v1 and, from macOS, on an ItsyBitsy nRF52840 Express with a 215 kB transfer. The protocol code is ported from the nrf_dfu_py project. One catch: a board still running an MCUmgr-only build has to be updated once the old way before Bluetooth uploads through the Adafruit bootloader work. The documentation is still an open pull request.