Performing FOTA updates in Bluetooth mesh

In nRF Connect SDK, there is currently no support for Device Firmware Update (DFU) over Bluetooth® mesh when performing firmware over-the-air (FOTA) updates for your Bluetooth mesh devices and applications. However, support for FOTA updates with point-to-point DFU over Bluetooth Low Energy using the MCUmgr subsystem and the Simple Management Protocol (SMP) is available.

Following the instructions described in FOTA over Bluetooth Low Energy, you can enable the support for and perform FOTA updates using a mobile app.

If the device’s composition data is going to change after the FOTA update on a Bluetooth mesh device is performed, unprovision the device before downloading the new image.

If you are using the nRF Connect Device Manager mobile app to perform FOTA updates, your Bluetooth mesh device might not be visible in the list of available devices. This happens if the device is not advertising the SMP service UUID and the filter that only shows devices advertising this service is enabled. The device can still be discovered through a service discovery, for example using the nRF Connect for Mobile app. See Discovering Bluetooth mesh devices in nRF Connect Device Manager for more details.

FOTA in Bluetooth mesh samples

The Bluetooth: Mesh light sample enables support for point-to-point DFU over Bluetooth Low Energy for nRF52 Series development kits. See the sample documentation for more details.

Point-to-point DFU over Bluetooth Low Energy is supported by default, out-of-the-box, for all samples and applications compatible with Thingy:53. See Updating firmware image for more information about updating firmware image on Thingy:53. For full list of samples and applications supported on Thingy:53, see Samples and applications compatible with Thingy:53.

Note

If you are using the nRF Connect Device Manager mobile app to perform FOTA updates on Thingy:53, your Bluetooth mesh device might not be visible in the list of available devices.

Discovering Bluetooth mesh devices in nRF Connect Device Manager

To make sure your device is visible in the nRF Connect Device Manager mobile app, do one of the following:

  • Disable the filter that only shows devices advertising the SMP service UUID in the nRF Connect Device Manager mobile app.

  • Make the device advertise the SMP service UUID, and thus be discoverable by the nRF Connect Device Manager mobile app with the filter enabled.

Disabling the filter

To disable the filter in the nRF Connect Device Manager mobile app, do the following steps:

  1. Tap the Filter button at the right top corner of your screen.

  2. Deselect Only devices advertising SMP UUID.

You should see the device appear in the list of devices.

Advertising SMP UUID

To make sure that your Bluetooth mesh device advertises the SMP service UUID, in addition to the instructions described in FOTA over Bluetooth Low Energy, do the following:

  1. Add the following code to your application:

    #include <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/conn.h>
    
    static void pending_adv_start(struct k_work *work);
    
    static struct bt_le_ext_adv *adv;
    /* This will result in the device advertising SMP service continuously. If this is undesirable,
     * set timeout to a finite value, and then create a mechanism in the application (e.g. by pressing
     * a button) to start SMP advertisements when needed by calling @ref bt_le_ext_adv_start.
     */
    static struct bt_le_ext_adv_start_param ext_adv_param = { .num_events = 0, .timeout = 0 };
    static struct k_work_delayable adv_work = Z_WORK_DELAYABLE_INITIALIZER(pending_adv_start);
    
    static struct bt_le_adv_param adv_params = {
    	.id = BT_ID_DEFAULT,
    	.sid = 0,
    	.secondary_max_skip = 0,
    	.options = BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME,
    	.interval_min = BT_GAP_ADV_SLOW_INT_MIN,
    	.interval_max = BT_GAP_ADV_SLOW_INT_MAX,
    	.peer = NULL
    };
    
    static const struct bt_data ad[] = {
    	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    	BT_DATA_BYTES(BT_DATA_UUID128_ALL, 0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86, 0xd3,
    		      0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d),
    };
    
    static void pending_adv_start(struct k_work *work)
    {
    	int err;
    
    	err = bt_le_ext_adv_start(adv, &ext_adv_param);
    	if (err) {
    		printk("Unable to restart SMP service advertising (err %d)\n", err);
    		return;
    	}
    
    	printk("SMP service advertising restarted\n");
    }
    
    static void connected(struct bt_conn *conn, uint8_t err)
    {
    	struct bt_conn_info cinfo;
    	int ec;
    
    	ec = bt_conn_get_info(conn, &cinfo);
    	if (ec) {
    		printk("Unable to get connection info (err %d)\n", ec);
    		return;
    	}
    
    	if (cinfo.id != adv_params.id) {
    		return;
    	}
    
    	printk("Connected to SMP service: err %d id %d\n", err, cinfo.id);
    }
    
    static void disconnected(struct bt_conn *conn, uint8_t reason)
    {
    	int err;
    	struct bt_conn_info cinfo;
    
    	err = bt_conn_get_info(conn, &cinfo);
    	if (err) {
    		printk("Unable to get connection info (err %d)\n", err);
    		return;
    	}
    
    	if (cinfo.id != adv_params.id) {
    		return;
    	}
    
    	printk("Disconnected from SMP service: reason %d id %d\n", reason, cinfo.id);
    
    	k_work_schedule(&adv_work, K_NO_WAIT);
    }
    
    static struct bt_conn_cb conn_callbacks = {
    	.connected = connected,
    	.disconnected = disconnected,
    };
    
    int smp_service_adv_init(void)
    {
    	int err;
    	size_t id_count = 0xFF;
    	int id;
    
    	/* Use different identity from Bluetooth mesh to avoid conflicts with Mesh Provisioning
    	 * Service and Mesh Proxy Service advertisements.
    	 */
    	bt_id_get(NULL, &id_count);
    
    	if (id_count < CONFIG_BT_ID_MAX) {
    		id = bt_id_create(NULL, NULL);
    		if (id < 0) {
    			printk("Unable to create a new identity for SMP (err %d)."
    			       " Using the default one.\n", id);
    			id = BT_ID_DEFAULT;
    		}
    
    		printk("Created a new identity for SMP: %d\n", id);
    	} else {
    		id = BT_ID_DEFAULT + 1;
    		printk("Recovered identity for SMP: %d\n", id);
    	}
    
    	adv_params.id = id;
    
    	err = bt_le_ext_adv_create(&adv_params, NULL, &adv);
    	if (err) {
    		printk("Creating SMP service adv instance failed (err %d)\n", err);
    		return err;
    	}
    
    	err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
    	if (err) {
    		printk("Setting SMP service adv data failed (err %d)\n", err);
    		return err;
    	}
    
    	err = bt_le_ext_adv_start(adv, &ext_adv_param);
    	if (err) {
    		printk("Starting advertising of SMP service failed (err %d)\n", err);
    	}
    
    	return err;
    }
    
  2. Register Bluetooth connection callbacks and call smp_service_adv_init after Bluetooth is initialized:

    	bt_conn_cb_register(&conn_callbacks);
    
    	/**
    	 * Since Bluetooth mesh utilizes the advertiser as the main channel of
    	 * communication, a secondary advertising set is necessary to broadcast
    	 * the SMP service.
    	 */
    	err = smp_service_adv_init();
    
  3. Increase the following configuration option values by one in the prj.conf file of your application:

This will make the device discoverable by the nRF Connect Device Manager mobile app with the Only devices advertising SMP UUID filter enabled. Observe that the device appears in the list of devices in the mobile app.