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.

Parents
  • HI Susheel, 

    I haven't got chance to test your code yet. But from the code and from the log it looks normal to me.

    Please try doing a "nrfjprog --eraseall" to make sure that the chip is completely wiped out. 

    Next is to isolate the problem to see if it's the issue on the client or on the server. 

    You can think of using a phone to provision the server and the client and make sure they can communicate. 


    Then you turn off /erase one of them, client or server and let the embedded provisioner to configure the one you just turn off/erase. 
    This way we can isolate if the embedded having an issue on the server or the client. 


    Also please check on the client when you press the button if it's actually react and send anything. 

  • Hello Hung, Thank you for your response. 

    Please try doing a "nrfjprog --eraseall" to make sure that the chip is completely wiped out. 

    I perform the "nrfjprog --eraseall" using the nRF connect programmer whenever I try to erase the boards. I see that the entire flash layout is blank after the erase.

    You can think of using a phone to provision the server and the client and make sure they can communicate

    I am able to successfully communicate and control the light from the light_switch node when provisioned using the mobile app.

    Then you turn off /erase one of them, client or server and let the embedded provisioner to configure the one you just turn off/erase. 
    This way we can isolate if the embedded having an issue on the server or the client.

    I am not able to test this as the embedded provisioner is using another set of keys to provision and configure the unprovisioned node. But, I was able to see the mesh model messages being transmitted using the nRF connect app.

  • Hi Susheel, 

    Please try the following provisioner. 

    I had to increase the MAIN_STACK and the WORKQUEUE_STACK to make it work. 

    Other than that I added your code (simplified) and it seems to work for me regardless if I erase and reprovision the nodes back to the network. 

    NCS v2.0.0

    mesh_provisioner.zip

  • Hello,

    your solution works however, I just had to increase the TTL value in my original code to get it to work. I am assuming it needed an extra hop to reach the destination. Is my thinking right? 

    Thank you for your support

  • Hi Susheel, 

    Sorry for the late response. I was on vacation. 
    Which TTL value did you increased from and to ? 
    If the 2 nodes are not in the range of each other then they will need to use a relay node to communicate, if TTL is not enough for the hops then they will not be able to communicate. 

Reply Children
Related