Xiao Ble Sense - Ota Dfu from Arduino IDE code

Hi all.
Finally I got ota dfu working with the android app Bluefruit Connect and the binaries created in Arduino IDE.
It wasn´t easy, because I didn´t find the solution ready to use in one place, I had to pick up a lot of half-solutions around the forums, just to finally merge everything in something that now is perfectly working, at least for my needings.

My goal was a completely sealed system, battery operated, without any button or external access, just a signalling led and a magnetic charging port.

The system stays most of the time in ultra low power mode, just to be activated by some accelerometer activity.
When active it advertises some ble services, among them the bledfu and bleuart services.
Now the app Bluefruit Connect can connect to the board to exchange some data through the bleuart service and , if necessary, to upload a new custom firmware.
Here comes the difficulties, because the process didn´t work out of the box and needed some adjustment to function.
The Updates feature of the Bluefruit Connect app have a Use Custom Firmwares button, which require the selection of a .hex file and a init file, which I thought were those generated by the arduino ide (export compiled bineries), but not exactly.
The “myapp.ino.hex” file is ok, and can be used as is.
The init file (the “myapp.ino.dat” file contained in the “myapp.ino.zip”) for some reason is not usable and makes the process fail, then another must be created using the following command line.
<adafruit-nrfutil.exe dfu genpkg --dev-type 0x0052 --application myapp.ino.hex dfu_package.zip>
The correct “myapp.ino.dat” must be extracted from dfu_package.zip and can be used in the update process, with the original .hex file.

Here another strange thing happens inside the Bluefruit Connect app, when the update process is started.
The board correctly goes in dfu mode ,but the app cannot complete the updating process because the board resets and its ble name changes to ADA_DFU, so the app is no more able to connect to the board again and complete the process (I thought it should do it automatically, because the mac address is the same, but not…)
Anyway, it is possible to make it work in two ways.
1 - cancel the update process when it displays the connection error, move back in the menu , connect to the now available ADA_DFU board and repeat the custom firmware update process, now it will work.
2 - I preferred not to wait for the app error, I forced the board to enter in dfu mode by sending a command through the bleuart protocol, then calling the enterOTADfu() api function inside my code.
Then , when the ADA_DFU board appears in the list, I connect to it and do the update.

Some system specification is important to make everything function:

  • the board must be the right one among the Seeed Nrf52840 Boards (NOT mbed-enabled boards)
  • the original bootloader was changed with an updated one, available in the adafruit repository ( thanks to Aovestdipaperino for the good job done on it)
  • the bledfu service must be advertised with all your other ble services (someone says must be the first service in the list).
    If the bledfu service is not initialized, the update process will work as well, but for some reason the board cannot restart after the update, and you must press the rst button, which in my case is not an option.

I hope this tutorial can help anyone who like me have been struggling for months attempting to make the ota dfu to work.

Hi there,

And Congrats on getting that Salad mixed and working…It’s a big deal the DFU - OTA area everyone can use it if it worked easier.
One reason I like the MCUBoot Bootloader over Adafruity.

Some stuff to consider…and AI observations.

Key Observations on the User’s Approach

  1. He used Adafruit’s adafruit-nrfutil tool, which is fine — it generates the correct zip DFU packages expected by the bootloader.
  2. He had issues with BLE disconnection and name change to ADA_DFU, which is a known quirk with the Adafruit bootloader. The app doesn’t reconnect automatically unless explicitly designed to do so.
  3. He relied on Bluefruit Connect, which isn’t maintained as actively as Nordic’s tools and doesn’t handle edge cases well (like reconnecting to ADA_DFU).

What He Did Right

  • Replaced the outdated bootloader with an Adafruit UF2-compatible one (from AovestdiPaperino’s GitHub likely — he’s known in the community).
  • Used BLE UART to trigger OTA DFU without buttons — ideal for sealed, headless systems.
  • Created a real-world workaround for OTA reconnection glitches.

What Could Be Improved

1. Use nRF Connect for Mobile Instead

  • It automatically handles reconnection to DFU mode device names.
  • Supports DFU ZIP packages directly (the .dat, .hex, .bin bundled in a .zip).
  • Better error reporting and logging.
  • Actively maintained by Nordic.

2. Use a Proper Bootloader with Buttonless DFU Support

  • Either Adafruit’s latest bootloader with buttonless DFU enabled
  • Or MCUboot + Zephyr/NCS (more complex, but truly robust)
  • This solves the “needs manual reset” problem entirely when correctly configured.

3. Simplify With Arduino IDE Tools

  • If the device is always sealed and headless, you can pre-bundle the DFU trigger via:
#include <bluefruit.h>
Bluefruit.begin();
Bluefruit.setTxPower(4);
Bluefruit.setName("SensorNode");
bledfu.begin(); // Needed if using Adafruit bootloader

If doing sealed SensorNodes like my project:

  • :white_check_mark: Stick with Adafruit’s bootloader for UF2 + OTA (just flash it once using SWD).
  • :white_check_mark: Use nrfutil dfu genpkg to generate OTA ZIP from Arduino .hex.
  • :white_check_mark: Trigger DFU in code (enterOTADfu() or NVIC_SystemReset() after setting flags).
  • :white_check_mark: Use nRF Connect for Mobile for smoother updates — especially with multiple SensorNodes.

IMO, Bluefruit Connect can work, but it’s clunky.
nRF Connect for Mobile is more robust, supports reconnections, and should be the go-to for DFU via BLE.

I’m currently working on a Multi-Node connected SensorNode setup
The DFU is the holy grail for this sort of thing.

HTH
GL :slight_smile: PJ :v:



6 SensorNode’s each with TEMP, HUMID, BATTERY, Motion or Digital BLE characteristics. all readable and two Notifies each. All 6 connected to a Xiao ESP32S3 :crossed_fingers:

1 Like