Unable to configure mesh models (generic on/off model for both server and client) correctly using the Mesh provisioner example

Hello,

I have been trying to provision and configure two nodes running Light and the Light_switch examples using a separate node running the mesh provisioner example from the SDK. I am using the nRF Connect SDK 1.9.1 version.

It worked the very first time and I was able to turn the Light node on/off using the switch. I wanted to test the case where a node transitions to an unprovisioned state after a reset. To do this, I followed these steps

  1. Turned off the provisioner node.
  2. Erased and reflashed the Light and Light_Switch nodes.
  3. Provisioned and configured the models using the nRF mesh mobile app.
  4. Tested to see if the switch was turning on/off the light (worked)
  5. Reset both nodes using the nRF mesh application.
  6. Turned on the mesh provisioner node.
  7. Provisioner picked up both the unprovisioned beacons and had no issue provisioning and configuring all the models.

But, the switch does not turn the light node on/off anymore. I have tried completely erasing and reflashed all nodes including the provisioner, but it does not work even work once now. There is no problem in configuring the individual models. Here are the changes that I have made to the provisioner code(added comments to the sections added).

static void configure_node(struct bt_mesh_cdb_node *node)
{
	NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_RX_SDU_MAX);
	struct bt_mesh_comp_p0_elem elem;
	struct bt_mesh_cdb_app_key *key;
	struct bt_mesh_comp_p0 comp;
	uint8_t status;
	int err, elem_addr;
	size_t subs_count = 1; // ----------------------------added code------------------//
	uint16_t sub;
	struct bt_mesh_cfg_mod_pub clnt_pub = { 0 };
	struct bt_mesh_cfg_mod_pub srv_pub = { 0 };//-------------till here-------------------//

	printk("Configuring node 0x%04x...\n", node->addr);

	key = bt_mesh_cdb_app_key_get(app_idx);
	if (key == NULL) {
		printk("No app-key 0x%04x\n", app_idx);
		return;
	}

	/* Add Application Key */
	err = bt_mesh_cfg_app_key_add(net_idx, node->addr, net_idx, app_idx,
				      key->keys[0].app_key, &status);
	if (err || status) {
		printk("Failed to add app-key (err %d status %d)\n", err, status);
		return;
	}

	/* Get the node's composition data and bind all models to the appkey */
	err = bt_mesh_cfg_comp_data_get(net_idx, node->addr, 0, &status, &buf);
	if (err || status) {
		printk("Failed to get Composition data (err %d, status: %d)\n",
		       err, status);
		return;
	}

	err = bt_mesh_comp_p0_get(&comp, &buf);
	if (err) {
		printk("Unable to parse composition data (err: %d)\n", err);
		return;
	}

	elem_addr = node->addr;
	while (bt_mesh_comp_p0_elem_pull(&comp, &elem)) {
		printk("Element @ 0x%04x: %u + %u models\n", elem_addr,
		       elem.nsig, elem.nvnd);
		for (int i = 0; i < elem.nsig; i++) {
			uint16_t id = bt_mesh_comp_p0_elem_mod(&elem, i);

			if (id == BT_MESH_MODEL_ID_CFG_CLI ||
			    id == BT_MESH_MODEL_ID_CFG_SRV) {
				continue;
			}
			printk("Binding AppKey to model 0x%03x:%04x\n",
			       elem_addr, id);

			err = bt_mesh_cfg_mod_app_bind(net_idx, node->addr,
						       elem_addr, app_idx, id,
						       &status);
			if (err || status) {
				printk("Failed (err: %d, status: %d)\n", err,
				       status);
			}

			if (id == BT_MESH_MODEL_ID_GEN_ONOFF_SRV) // ----------------------------added code------------------//
			{
				printk("Configuring Srv model on remote node\n");
				srv_pub.addr = 0xc001;
				srv_pub.app_idx = app_idx;
				srv_pub.cred_flag = false;
				srv_pub.ttl = 1;
				srv_pub.period = 0U;
				srv_pub.transmit = 0U;

				err = bt_mesh_cfg_mod_pub_set(net_idx, node->addr, elem_addr,
						BT_MESH_MODEL_ID_GEN_ONOFF_SRV, &srv_pub,
						&status);

				if (err || status) {
					printk("Failed to add pub address (err: %d, status: %d)\n", err,
				       	status);
				}

				err = bt_mesh_cfg_mod_sub_add(net_idx, node->addr, elem_addr, 0xc000,
						  BT_MESH_MODEL_ID_GEN_ONOFF_SRV, &status);

				if (err || status) {
					printk("Failed to add sub address (err: %d, status: %d)\n", err,
				       	status);
				}


			}
			else if(id == BT_MESH_MODEL_ID_GEN_ONOFF_CLI)
			{
				printk("Configuring Client model on remote node\n");
				clnt_pub.addr = 0xc000;
				clnt_pub.app_idx = app_idx;
				clnt_pub.cred_flag = false;
				clnt_pub.ttl = 1;
				clnt_pub.period = 0U;//BT_MESH_PUB_PERIOD_10SEC(0);
				clnt_pub.transmit = 0U;//BT_MESH_TRANSMIT(0, 0);

				err = bt_mesh_cfg_mod_sub_add(net_idx, node->addr, elem_addr, 0xc001,
						  BT_MESH_MODEL_ID_GEN_ONOFF_CLI, &status);

				if (err || status) { 
					printk("Failed to add sub address (err: %d, status: %d)\n", err,
				       	status);
				}

				err = bt_mesh_cfg_mod_pub_set(net_idx, node->addr, elem_addr,
						BT_MESH_MODEL_ID_GEN_ONOFF_CLI, &clnt_pub,
						&status);

				if (err || status) {
					printk("Failed to add pub address (err: %d, status: %d)\n", err,
				       	status);
				}


			}//-------------till here-------------------//
		}

		for (int i = 0; i < elem.nvnd; i++) {
			struct bt_mesh_mod_id_vnd id =
				bt_mesh_comp_p0_elem_mod_vnd(&elem, i);

			printk("Binding AppKey to model 0x%03x:%04x:%04x\n",
			       elem_addr, id.company, id.id);

			err = bt_mesh_cfg_mod_app_bind_vnd(net_idx, node->addr,
							   elem_addr, app_idx,
							   id.id, id.company,
							   &status);
			if (err || status) {
				printk("Failed (err: %d, status: %d)\n", err,
				       status);
			}
		}

		elem_addr++;
	}

	atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED);

	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
		bt_mesh_cdb_node_store(node);
	}

	printk("Configuration complete\n");
}

Please advice. Why did it work for the very first time? Does mesh provisioner use any fixed/static data to provision and configure? However, before I do a test I completely erase the device using the "erase board" option in nRF connect app in visual code which wipes the entire flash. So, it should not really mater even if the provisioner uses static data. Please correct me if I am wrong. Thank you.

Related