Not able to receive status messages published by onoff Server using message context instead of default publish parameters set by provisioner

Hello,

I am trying to send status messages to a Client model with a specific unicast address on one node. This node's parent element has both generic onoff server and client models implemented. All onoff server and client models across all nodes are configured to publish and subscribe to specific group addresses (0xc000 and 0xc001 respectively). When I try to publish a status message to this client model using the message context (with the destination address as the elements unicast address) instead of using the default publish parameters, it does get received by the access layer but, not by the client model (breakpoint at status handler does not hit).

When I publish a get/set message to the server model in the same element, using the same context instead of the default publish parameters, it gets received by the model (breakpoint at get/set handlers get hit). Am I missing something here? Please suggest.

I am working with NCS 1.9.1 on nRF52480 DK's

Parents
  • Hi,

    This seems a bit odd. 

    What example are you basing your project on? Can you give more details on what you have done so far? What modifications have you done? 

    Are you getting any error codes? It is received by the access layer so I assume it is being sent successfully from the server.

    message context (with the destination address as the elements unicast address) instead of using the default publish parameters

    Can you elaborate on this?

  • I have attached my modified main.c of Provisioner, Model_handler c files for both switch and light examples. This is just to test if the message can be address to the provisioner node only. The unicast address for the provisioner element is 0x0001

    below is the provisioner node main.c

    /*
     * Copyright (c) 2019 Tobias Svehagen
     *
     * SPDX-License-Identifier: Apache-2.0
     */
    
    #include <sys/printk.h>
    
    #include <settings/settings.h>
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/mesh.h>
    #include <bluetooth/mesh/gen_onoff_srv.h>
    #include <bluetooth/mesh/gen_onoff_cli.h>
    
    static const uint16_t net_idx;
    static const uint16_t app_idx;
    static uint16_t self_addr = 1, node_addr;
    static const uint8_t dev_uuid[16] = { 0xdd, 0xdd };
    static uint8_t node_uuid[16];
    
    K_SEM_DEFINE(sem_unprov_beacon, 0, 1);
    K_SEM_DEFINE(sem_node_added, 0, 1);
    
    static struct bt_mesh_cfg_cli cfg_cli = {
    };
    
    static void status_handler(struct bt_mesh_onoff_cli *cli,
    			   struct bt_mesh_msg_ctx *ctx,
    			   const struct bt_mesh_onoff_status *status);
    
    static void stat_set(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    const struct bt_mesh_onoff_set *set,
    		    struct bt_mesh_onoff_status *rsp);
    
    static void stat_get(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    struct bt_mesh_onoff_status *rsp);
    
    static const struct bt_mesh_onoff_srv_handlers onoff_handlers = {
    	.set = stat_set,
    	.get = stat_get,
    };
    
    struct bt_mesh_onoff_cli client = BT_MESH_ONOFF_CLI_INIT(&status_handler);
    struct bt_mesh_onoff_srv srv = BT_MESH_ONOFF_SRV_INIT(&onoff_handlers);
    
    static void status_handler(struct bt_mesh_onoff_cli *cli,
    			   struct bt_mesh_msg_ctx *ctx,
    			   const struct bt_mesh_onoff_status *status)
    {
    	printk("status ack received.. with onoff status %d from node address %d\n", status->present_on_off, ctx->addr);
    }
    
    static void stat_set(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    const struct bt_mesh_onoff_set *set,
    		    struct bt_mesh_onoff_status *rsp)
    {
    	printk("SET: request received.. with onoff status %d from node address %d\n", set->on_off, ctx->addr);
    }
    
    static void stat_get(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    struct bt_mesh_onoff_status *rsp)
    {
    	printk("GET: request received.. from node address %d\n", ctx->addr);
    }
    
    static void health_current_status(struct bt_mesh_health_cli *cli, uint16_t addr,
    				  uint8_t test_id, uint16_t cid, uint8_t *faults,
    				  size_t fault_count)
    {
    	size_t i;
    
    	printk("Health Current Status from 0x%04x\n", addr);
    
    	if (!fault_count) {
    		printk("Health Test ID 0x%02x Company ID 0x%04x: no faults\n",
    		       test_id, cid);
    		return;
    	}
    
    	printk("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu:\n",
    	       test_id, cid, fault_count);
    
    	for (i = 0; i < fault_count; i++) {
    		printk("\t0x%02x\n", faults[i]);
    	}
    }
    
    static struct bt_mesh_health_cli health_cli = {
    	.current_status = health_current_status,
    };
    
    static struct bt_mesh_model root_models[] = {
    	BT_MESH_MODEL_CFG_SRV,
    	BT_MESH_MODEL_CFG_CLI(&cfg_cli),
    	BT_MESH_MODEL_ONOFF_CLI(&client),
    	BT_MESH_MODEL_ONOFF_SRV(&srv),
    	BT_MESH_MODEL_HEALTH_CLI(&health_cli),
    };
    
    static struct bt_mesh_elem elements[] = {
    	BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
    };
    
    static const struct bt_mesh_comp comp = {
    	.cid = BT_COMP_ID_LF,
    	.elem = elements,
    	.elem_count = ARRAY_SIZE(elements),
    };
    
    static void setup_cdb(void)
    {
    	struct bt_mesh_cdb_app_key *key;
    
    	key = bt_mesh_cdb_app_key_alloc(net_idx, app_idx);
    	if (key == NULL) {
    		printk("Failed to allocate app-key 0x%04x\n", app_idx);
    		return;
    	}
    
    	bt_rand(key->keys[0].app_key, 16);
    
    	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
    		bt_mesh_cdb_app_key_store(key);
    	}
    }
    
    static void configure_self(struct bt_mesh_cdb_node *self)
    {
    	struct bt_mesh_cdb_app_key *key;
    	uint8_t status = 0;
    	int err;
    	struct bt_mesh_cfg_mod_pub clnt_pub = { 0 };
    	struct bt_mesh_cfg_mod_pub srv_pub = { 0 };
    
    	printk("Configuring self...\n");
    
    	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(self->net_idx, self->addr, self->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;
    	}
    
    	err = bt_mesh_cfg_mod_app_bind(self->net_idx, self->addr, self->addr,
    				       app_idx, BT_MESH_MODEL_ID_HEALTH_CLI,
    				       &status);
    	if (err || status) {
    		printk("Failed to bind app-key (err %d, status %d)\n", err,
    		       status);
    		return;
    	}
    
    	err = bt_mesh_cfg_mod_app_bind(self->net_idx, self->addr, self->addr,
    				       app_idx, BT_MESH_MODEL_ID_GEN_ONOFF_SRV,
    				       &status);
    	if (err || status) {
    		printk("Failed to bind app-key (err %d, status %d)\n", err,
    		       status);
    		return;
    	}
    	// else{
    	// 	printk("Configuring Srv model on local node\n");
    
    	// 	srv_pub.addr = 0xc001;
    	// 	srv_pub.app_idx = app_idx;
    	// 	srv_pub.cred_flag = false;
    	// 	srv_pub.uuid=NULL;
    	// 	srv_pub.ttl = 5;
    	// 	srv_pub.period = 0U;//BT_MESH_PUB_PERIOD_10SEC(0);
    	// 	srv_pub.transmit = 0U;// BT_MESH_TRANSMIT(1, 100);
    
    	// 	err = bt_mesh_cfg_mod_pub_set(net_idx, self->addr, self->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);
    	// 			return;
    	// 	}
    
    	// 	err = bt_mesh_cfg_mod_sub_add(net_idx, self->addr, self->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);
    	// 			return;
    	// 	}
    	// }
    
    	err = bt_mesh_cfg_mod_app_bind(self->net_idx, self->addr, self->addr,
    				       app_idx, BT_MESH_MODEL_ID_GEN_ONOFF_CLI,
    				       &status);
    	if (err || status) {
    		printk("Failed to bind app-key (err %d, status %d)\n", err,
    		       status);
    		return;
    	}
    	// else{
    	// 	printk("Configuring Client model on local node\n");
    	// 	clnt_pub.addr = 0xc000;
    		
    	// 	clnt_pub.app_idx = app_idx;
    	// 	clnt_pub.cred_flag = false;
    	// 	clnt_pub.uuid=NULL;
    	// 	clnt_pub.ttl = 5;
    	// 	clnt_pub.period = 0U;//BT_MESH_PUB_PERIOD_10SEC(0);
    	// 	clnt_pub.transmit = 0U;// BT_MESH_TRANSMIT(1, 100);
    
    	// 	err = bt_mesh_cfg_mod_pub_set(net_idx, self->addr, self->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);
    	// 			return;
    	// 	}
    
    	// 	err = bt_mesh_cfg_mod_sub_add(net_idx, self->addr, self->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);
    	// 			return;
    	// 	}
    	// }
    
    	atomic_set_bit(self->flags, BT_MESH_CDB_NODE_CONFIGURED);
    
    	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
    		bt_mesh_cdb_node_store(self);
    	}
    
    	printk("Configuration complete\n");
    }
    
    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-------------------//
    	static int flag = 0;
    
    	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);
    
    		// ---------------------test code ----------------------------//
    			if ((id == BT_MESH_MODEL_ID_GEN_ONOFF_SRV) || (id == BT_MESH_MODEL_ID_GEN_ONOFF_CLI))
    			{
    				flag++;
    				printk("value to flag -> %d\n", flag);
    			}
    		// ---------------------test code ----------------------------//
    
    			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);
    			}
    
    		// ----------------------------added code--------------------//
    			if(flag == 4)
    			{
    				flag = 0;
    
    				if (id == BT_MESH_MODEL_ID_GEN_ONOFF_SRV) 
    				{
    					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.uuid=NULL;
    					srv_pub.ttl = 5;
    					srv_pub.period = 0U;//BT_MESH_PUB_PERIOD_10SEC(0);
    					srv_pub.transmit = 0U;// BT_MESH_TRANSMIT(1, 100);
    
    					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_SENSOR_SRV)
    				{
    					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.uuid=NULL;
    					srv_pub.ttl = 5;
    					srv_pub.period = 0U;//BT_MESH_PUB_PERIOD_10SEC(0);
    					srv_pub.transmit = 0U;// BT_MESH_TRANSMIT(1, 100);
    
    					err = bt_mesh_cfg_mod_pub_set(net_idx, node->addr, elem_addr,
    							BT_MESH_MODEL_ID_SENSOR_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_SENSOR_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_SENSOR_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.uuid=NULL;
    					clnt_pub.ttl = 5;
    					clnt_pub.period = 0U;//BT_MESH_PUB_PERIOD_10SEC(0);
    					clnt_pub.transmit = 0U;// BT_MESH_TRANSMIT(1, 100);
    
    					err = bt_mesh_cfg_mod_pub_set(net_idx, node->addr, elem_addr,
    							BT_MESH_MODEL_ID_SENSOR_CLI, &clnt_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, 0xc001,
    							BT_MESH_MODEL_ID_SENSOR_CLI, &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.uuid=NULL;
    					clnt_pub.ttl = 5;
    					clnt_pub.period = 0U;//BT_MESH_PUB_PERIOD_10SEC(0);
    					clnt_pub.transmit = 0U;// BT_MESH_TRANSMIT(1, 100);
    
    					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);
    					}
    
    					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);
    					}
    
    				
    				}//-------------till here-------------------//
    				else
    				{}//-------------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");
    }
    
    static void unprovisioned_beacon(uint8_t uuid[16],
    				 bt_mesh_prov_oob_info_t oob_info,
    				 uint32_t *uri_hash)
    {
    	memcpy(node_uuid, uuid, 16);
    	k_sem_give(&sem_unprov_beacon);
    }
    
    static void node_added(uint16_t net_idx, uint8_t uuid[16], uint16_t addr, uint8_t num_elem)
    {
    	node_addr = addr;
    	k_sem_give(&sem_node_added);
    }
    
    static const struct bt_mesh_prov prov = {
    	.uuid = dev_uuid,
    	.unprovisioned_beacon = unprovisioned_beacon,
    	.node_added = node_added,
    };
    
    static int bt_ready(void)
    {
    	uint8_t net_key[16], dev_key[16];
    	int err;
    
    	err = bt_mesh_init(&prov, &comp);
    	if (err) {
    		printk("Initializing mesh failed (err %d)\n", err);
    		return err;
    	}
    
    	printk("Mesh initialized\n");
    
    	if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
    		printk("Loading stored settings\n");
    		settings_load();
    	}
    
    	bt_rand(net_key, 16);
    
    	err = bt_mesh_cdb_create(net_key);
    	if (err == -EALREADY) {
    		printk("Using stored CDB\n");
    	} else if (err) {
    		printk("Failed to create CDB (err %d)\n", err);
    		return err;
    	} else {
    		printk("Created CDB\n");
    		setup_cdb();
    	}
    
    	bt_rand(dev_key, 16);
    
    	err = bt_mesh_provision(net_key, BT_MESH_NET_PRIMARY, 0, 0, self_addr,
    				dev_key);
    	if (err == -EALREADY) {
    		printk("Using stored settings\n");
    	} else if (err) {
    		printk("Provisioning failed (err %d)\n", err);
    		return err;
    	} else {
    		printk("Provisioning completed\n");
    	}
    
    	return 0;
    }
    
    static uint8_t check_unconfigured(struct bt_mesh_cdb_node *node, void *data)
    {
    	if (!atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) {
    		if (node->addr == self_addr) {
    			configure_self(node);
    		} else {
    			configure_node(node);
    		}
    	}
    
    	return BT_MESH_CDB_ITER_CONTINUE;
    }
    
    void main(void)
    {
    	char uuid_hex_str[32 + 1];
    	int err;
    
    	printk("Initializing...\n");
    
    	/* Initialize the Bluetooth Subsystem */
    	err = bt_enable(NULL);
    	if (err) {
    		printk("Bluetooth init failed (err %d)\n", err);
    		return;
    	}
    
    	printk("Bluetooth initialized\n");
    	bt_ready();
    
    	while (1) {
    		k_sem_reset(&sem_unprov_beacon);
    		k_sem_reset(&sem_node_added);
    		bt_mesh_cdb_node_foreach(check_unconfigured, NULL);
    
    		printk("Waiting for unprovisioned beacon...\n");
    		err = k_sem_take(&sem_unprov_beacon, K_SECONDS(10));
    		if (err == -EAGAIN) {
    			continue;
    		}
    
    		bin2hex(node_uuid, 16, uuid_hex_str, sizeof(uuid_hex_str));
    
    		printk("Provisioning %s\n", uuid_hex_str);
    		err = bt_mesh_provision_adv(node_uuid, net_idx, 0, 0);
    		if (err < 0) {
    			printk("Provisioning failed (err %d)\n", err);
    			continue;
    		}
    
    		printk("Waiting for node to be added...\n");
    		err = k_sem_take(&sem_node_added, K_SECONDS(10));
    		if (err == -EAGAIN) {
    			printk("Timeout waiting for node to be added\n");
    			continue;
    		}
    
    		printk("Added node 0x%04x\n", node_addr);
    	}
    }
    

    below is the model_handler.c for light node

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/mesh/models.h>
    #include <dk_buttons_and_leds.h>
    #include "model_handler.h"
    
    static void led_set(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    const struct bt_mesh_onoff_set *set,
    		    struct bt_mesh_onoff_status *rsp);
    
    static void led_get(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    struct bt_mesh_onoff_status *rsp);
    
    static const struct bt_mesh_onoff_srv_handlers onoff_handlers = {
    	.set = led_set,
    	.get = led_get,
    };
    
    struct led_ctx {
    	struct bt_mesh_onoff_srv srv;
    	struct k_work_delayable work;
    	uint32_t remaining;
    	bool value;
    };
    
    static struct led_ctx led_ctx[] = {
    #if DT_NODE_EXISTS(DT_ALIAS(led0))
    	{ .srv = BT_MESH_ONOFF_SRV_INIT(&onoff_handlers) },
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led1))
    	{ .srv = BT_MESH_ONOFF_SRV_INIT(&onoff_handlers) },
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led2))
    	{ .srv = BT_MESH_ONOFF_SRV_INIT(&onoff_handlers) },
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led3))
    	{ .srv = BT_MESH_ONOFF_SRV_INIT(&onoff_handlers) },
    #endif
    };
    
    static void led_transition_start(struct led_ctx *led)
    {
    	int led_idx = led - &led_ctx[0];
    
    	/* As long as the transition is in progress, the onoff
    	 * state is "on":
    	 */
    	dk_set_led(led_idx, true);
    	k_work_reschedule(&led->work, K_MSEC(led->remaining));
    	led->remaining = 0;
    }
    
    static void led_status(struct led_ctx *led, struct bt_mesh_onoff_status *status)
    {
    	int err = 0;
    	/* Do not include delay in the remaining time. */
    	status->remaining_time = led->remaining ? led->remaining :
    		k_ticks_to_ms_ceil32(k_work_delayable_remaining_get(&led->work));
    	status->target_on_off = led->value;
    	/* As long as the transition is in progress, the onoff state is "on": */
    	status->present_on_off = led->value || status->remaining_time;
    
    	//----------------------Added test code--------------------------------//
    	struct bt_mesh_onoff_status stat;
    	struct bt_mesh_msg_ctx ctx;
    	ctx.addr= 0x001;
    	ctx.app_idx= 0;
    	ctx.send_rel=false;
    	ctx.send_ttl= BT_MESH_TTL_DEFAULT;
    	stat.present_on_off = false;// use false to send remote reset request message
    	err = bt_mesh_onoff_srv_pub(&led->srv, &ctx, &stat);
    	if(err)
    	{
    		printk("Error publishing status to provisioner on..%d\n", err);
    	}
    	//---------------------Till here---------------------------------------//
    }
    
    static void led_set(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    const struct bt_mesh_onoff_set *set,
    		    struct bt_mesh_onoff_status *rsp)
    {
    	struct led_ctx *led = CONTAINER_OF(srv, struct led_ctx, srv);
    	int led_idx = led - &led_ctx[0];
    
    	if (set->on_off == led->value) {
    		goto respond;
    	}
    
    	led->value = set->on_off;
    	if (!bt_mesh_model_transition_time(set->transition)) {
    		led->remaining = 0;
    		dk_set_led(led_idx, set->on_off);
    		goto respond;
    	}
    
    	led->remaining = set->transition->time;
    
    	if (set->transition->delay) {
    		k_work_reschedule(&led->work, K_MSEC(set->transition->delay));
    	} else {
    		led_transition_start(led);
    	}
    
    respond:
    	if (rsp) {
    		led_status(led, rsp);
    	}
    }
    
    static void led_get(struct bt_mesh_onoff_srv *srv, struct bt_mesh_msg_ctx *ctx,
    		    struct bt_mesh_onoff_status *rsp)
    {
    	struct led_ctx *led = CONTAINER_OF(srv, struct led_ctx, srv);
    
    	led_status(led, rsp);
    }
    
    static void led_work(struct k_work *work)
    {
    	struct led_ctx *led = CONTAINER_OF(work, struct led_ctx, work.work);
    	int led_idx = led - &led_ctx[0];
    
    	if (led->remaining) {
    		led_transition_start(led);
    	} else {
    		dk_set_led(led_idx, led->value);
    
    		/* Publish the new value at the end of the transition */
    		struct bt_mesh_onoff_status status;
    
    		led_status(led, &status);
    		bt_mesh_onoff_srv_pub(&led->srv, NULL, &status);
    	}
    }
    
    /* Set up a repeating delayed work to blink the DK's LEDs when attention is
     * requested.
     */
    static struct k_work_delayable attention_blink_work;
    static bool attention;
    
    static void attention_blink(struct k_work *work)
    {
    	static int idx;
    	const uint8_t pattern[] = {
    #if DT_NODE_EXISTS(DT_ALIAS(led0))
    		BIT(0),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led1))
    		BIT(1),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led2))
    		BIT(2),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led3))
    		BIT(3),
    #endif
    	};
    
    	if (attention) {
    		dk_set_leds(pattern[idx++ % ARRAY_SIZE(pattern)]);
    		k_work_reschedule(&attention_blink_work, K_MSEC(30));
    	} else {
    		dk_set_leds(DK_NO_LEDS_MSK);
    	}
    }
    
    static void attention_on(struct bt_mesh_model *mod)
    {
    	attention = true;
    	k_work_reschedule(&attention_blink_work, K_NO_WAIT);
    }
    
    static void attention_off(struct bt_mesh_model *mod)
    {
    	/* Will stop rescheduling blink timer */
    	attention = false;
    }
    
    static const struct bt_mesh_health_srv_cb health_srv_cb = {
    	.attn_on = attention_on,
    	.attn_off = attention_off,
    };
    
    static struct bt_mesh_health_srv health_srv = {
    	.cb = &health_srv_cb,
    };
    
    BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
    
    static struct bt_mesh_elem elements[] = {
    #if DT_NODE_EXISTS(DT_ALIAS(led0))
    	BT_MESH_ELEM(
    		1, BT_MESH_MODEL_LIST(
    			BT_MESH_MODEL_CFG_SRV,
    			BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
    			BT_MESH_MODEL_ONOFF_SRV(&led_ctx[0].srv)),
    		BT_MESH_MODEL_NONE),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led1))
    	BT_MESH_ELEM(
    		2, BT_MESH_MODEL_LIST(BT_MESH_MODEL_ONOFF_SRV(&led_ctx[1].srv)),
    		BT_MESH_MODEL_NONE),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led2))
    	BT_MESH_ELEM(
    		3, BT_MESH_MODEL_LIST(BT_MESH_MODEL_ONOFF_SRV(&led_ctx[2].srv)),
    		BT_MESH_MODEL_NONE),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(led3))
    	BT_MESH_ELEM(
    		4, BT_MESH_MODEL_LIST(BT_MESH_MODEL_ONOFF_SRV(&led_ctx[3].srv)),
    		BT_MESH_MODEL_NONE),
    #endif
    };
    
    static const struct bt_mesh_comp comp = {
    	.cid = CONFIG_BT_COMPANY_ID,
    	.elem = elements,
    	.elem_count = ARRAY_SIZE(elements),
    };
    
    const struct bt_mesh_comp *model_handler_init(void)
    {
    	k_work_init_delayable(&attention_blink_work, attention_blink);
    
    	for (int i = 0; i < ARRAY_SIZE(led_ctx); ++i) {
    		k_work_init_delayable(&led_ctx[i].work, led_work);
    	}
    
    	return &comp;
    }
    

    below is the model_handler.c for switch node

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    /**
     * @file
     * @brief Model handler for the light switch.
     *
     * Instantiates a Generic OnOff Client model for each button on the devkit, as
     * well as the standard Config and Health Server models. Handles all application
     * behavior related to the models.
     */
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/mesh/models.h>
    #include <dk_buttons_and_leds.h>
    #include "model_handler.h"
    
    /* Light switch behavior */
    
    /** Context for a single light switch. */
    struct button {
    	/** Current light status of the corresponding server. */
    	bool status;
    	/** Generic OnOff client instance for this switch. */
    	struct bt_mesh_onoff_cli client;
    };
    
    static void status_handler(struct bt_mesh_onoff_cli *cli,
    			   struct bt_mesh_msg_ctx *ctx,
    			   const struct bt_mesh_onoff_status *status);
    
    static struct button buttons[] = {
    #if DT_NODE_EXISTS(DT_ALIAS(sw0))
    	{ .client = BT_MESH_ONOFF_CLI_INIT(&status_handler) },
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw1))
    	{ .client = BT_MESH_ONOFF_CLI_INIT(&status_handler) },
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw2))
    	{ .client = BT_MESH_ONOFF_CLI_INIT(&status_handler) },
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw3))
    	{ .client = BT_MESH_ONOFF_CLI_INIT(&status_handler) },
    #endif
    };
    
    static void status_handler(struct bt_mesh_onoff_cli *cli,
    			   struct bt_mesh_msg_ctx *ctx,
    			   const struct bt_mesh_onoff_status *status)
    {
    	struct button *button =
    		CONTAINER_OF(cli, struct button, client);
    	int index = button - &buttons[0];
    
    	button->status = status->present_on_off;
    	dk_set_led(index, status->present_on_off);
    
    	printk("Button %d: Received response: %s\n", index + 1,
    	       status->present_on_off ? "on" : "off");
    }
    
    static void button_handler_cb(uint32_t pressed, uint32_t changed)
    {
    	int err;
    	if (!bt_mesh_is_provisioned()) {
    		return;
    	}
    
    	for (int i = 0; i < ARRAY_SIZE(buttons); ++i) {
    
    		struct bt_mesh_onoff_set set = {
    			.on_off = !buttons[i].status,
    		};
    
    		if(!(pressed & changed & BIT(i)))
    		{
    			continue;
    		}
    
    	//------------------Added test code-----------------------------//
    		struct bt_mesh_msg_ctx m;
    		m.addr= 0x0001;
    		m.app_idx= 0;
    		m.send_rel=false;
    		m.send_ttl= BT_MESH_TTL_DEFAULT;
    		err = bt_mesh_onoff_cli_set_unack(&buttons[i].client, NULL, &set);
    		if (!err) {
    			/* There'll be no response status for the
    				* unacked message. Set the state immediately.
    				*/
    			buttons[i].status = set.on_off;
    			dk_set_led(i, set.on_off);
    		}
    	//------------------Added test code-----------------------------//
    		/* As we can't know how many nodes are in a group, it doesn't
    		 * make sense to send acknowledged messages to group addresses -
    		 * we won't be able to make use of the responses anyway.
    		 */
    
    		if (bt_mesh_model_pub_is_unicast(buttons[i].client.model)) {
    		err = bt_mesh_onoff_cli_set(&buttons[i].client, NULL,
    						&set, NULL);
    		} else {
    			err = bt_mesh_onoff_cli_set_unack(&buttons[i].client,
    							NULL, &set);
    			if (!err) {
    				/* There'll be no response status for the
    				* unacked message. Set the state immediately.
    				*/
    				buttons[i].status = set.on_off;
    				dk_set_led(i, set.on_off);
    			}
    		}
    
    		if (err) {
    			printk("OnOff %d set failed: %d\n", i + 1, err);
    		}	
    	}
    }
    
    /* Set up a repeating delayed work to blink the DK's LEDs when attention is
     * requested.
     */
    static struct k_work_delayable attention_blink_work;
    static bool attention;
    
    static void attention_blink(struct k_work *work)
    {
    	static int idx;
    	const uint8_t pattern[] = {
    #if DT_NODE_EXISTS(DT_ALIAS(sw0))
    		BIT(0),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw1))
    		BIT(1),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw2))
    		BIT(2),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw3))
    		BIT(3),
    #endif
    	};
    
    	if (attention) {
    		dk_set_leds(pattern[idx++ % ARRAY_SIZE(pattern)]);
    		k_work_reschedule(&attention_blink_work, K_MSEC(30));
    	} else {
    		dk_set_leds(DK_NO_LEDS_MSK);
    	}
    }
    
    static void attention_on(struct bt_mesh_model *mod)
    {
    	attention = true;
    	k_work_reschedule(&attention_blink_work, K_NO_WAIT);
    }
    
    static void attention_off(struct bt_mesh_model *mod)
    {
    	/* Will stop rescheduling blink timer */
    	attention = false;
    }
    
    static const struct bt_mesh_health_srv_cb health_srv_cb = {
    	.attn_on = attention_on,
    	.attn_off = attention_off,
    };
    
    static struct bt_mesh_health_srv health_srv = {
    	.cb = &health_srv_cb,
    };
    
    BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
    
    static struct bt_mesh_elem elements[] = {
    #if DT_NODE_EXISTS(DT_ALIAS(sw0))
    	BT_MESH_ELEM(1,
    		     BT_MESH_MODEL_LIST(
    			     BT_MESH_MODEL_CFG_SRV,
    			     BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
    			     BT_MESH_MODEL_ONOFF_CLI(&buttons[0].client)),
    		     BT_MESH_MODEL_NONE),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw1))
    	BT_MESH_ELEM(2,
    		     BT_MESH_MODEL_LIST(
    			     BT_MESH_MODEL_ONOFF_CLI(&buttons[1].client)),
    		     BT_MESH_MODEL_NONE),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw2))
    	BT_MESH_ELEM(3,
    		     BT_MESH_MODEL_LIST(
    			     BT_MESH_MODEL_ONOFF_CLI(&buttons[2].client)),
    		     BT_MESH_MODEL_NONE),
    #endif
    #if DT_NODE_EXISTS(DT_ALIAS(sw3))
    	BT_MESH_ELEM(4,
    		     BT_MESH_MODEL_LIST(
    			     BT_MESH_MODEL_ONOFF_CLI(&buttons[3].client)),
    		     BT_MESH_MODEL_NONE),
    #endif
    };
    
    static const struct bt_mesh_comp comp = {
    	.cid = CONFIG_BT_COMPANY_ID,
    	.elem = elements,
    	.elem_count = ARRAY_SIZE(elements),
    };
    
    const struct bt_mesh_comp *model_handler_init(void)
    {
    	static struct button_handler button_handler = {
    		.cb = button_handler_cb,
    	};
    
    	dk_button_handler_add(&button_handler);
    	k_work_init_delayable(&attention_blink_work, attention_blink);
    
    	return &comp;
    }
    

    Can status messages be sent randomly? or do they get accepted only after a get/set message gets sent first? Please advice

  • Hi, 

    • Could you attach a minimal sample that recreates the issue including configuration files?
      • Don't upload anything that contains sensitive information without converting this to a private case. Let me know if we need to do so.
    • Also what devices are you using as a light and switch nodes?

    Kind regards,
    Andreas

  • I have attached the files requested. This is just a test setup and no sensitive information is shared.

    Test setup:

    • 2 nRF52480 DK's (one light and the other light switch, 1 nRF52 DK acting as the provisioner.
    • I have added onoff server and client models to the provisioner node composition.
    • For this code to work, you would have to provision the client first as it is hardcoded to send a context message to 0x0006 which would then be the first element address of the light server(0x0001 -> provisioner; 0x0002 to 0x0005 -> client; 0x0006 to 0x0009 -> server).

    3750.sample.zip

    Regards,

    Susheel

  • Hi,

    Susheel said:
    I have attached the files requested. This is just a test setup and no sensitive information is shared.

    Thank you for supplying this information!

    Susheel said:

    I made the changes but, it did not solve the issue. Here is a log output from my provisioner node.

    After this reply, the mesh team did some more testing of your previously supplied with the first fix we suggested (initializing ctx with {} or set with a struct):

    1. I had to increase CONFIG_MAIN_STACK_SIZE to 2500 (approximate value). Default value was not enough and the device was rebooting when tried to add app key.
    2. I had to uncomment code in the configure_self function to subscribe the provisioner to the group address
    3. I had to comment out the code with if (flag == 4) otherwise the provisioner didn't configure publication on the light_switch.

    I was able to receive messages from the light_switch on the provisioner:

    Waiting for unprovisioned beacon...
    SET: request received.. with onoff status 1 from node address 3
    [00:07:07.092,956] <dbg> bt_mesh_access: bt_mesh_model_recv: app_idx 0x0000 src 0x0003 dst 0x0001
    [00:07:07.093,017] <dbg> bt_mesh_access: bt_mesh_model_recv: len 4: 82030105
    [00:07:07.093,017] <dbg> bt_mesh_access: bt_mesh_model_recv: OpCode 0x00008203
    [00:07:07.093,048] <wrn> bt_mesh_access: Elem: 0
    [00:07:07.093,078] <wrn> bt_mesh_access: Model: 1000
    [00:07:07.098,693] <dbg> bt_mesh_access: bt_mesh_model_publish: 
    [00:07:07.098,724] <dbg> bt_mesh_access: bt_mesh_model_publish: Publish Retransmit Count 1 Interval 50ms
    [00:07:07.099,029] <dbg> bt_mesh_access: mod_publish: 427099
    [00:07:07.213,195] <dbg> bt_mesh_access: publish_sent: err 0, time 427213
    [00:07:07.213,195] <dbg> bt_mesh_access: next_period: Publishing took 115ms

    I will relay your latest reply to them, but before we do the next step of solving this issue could you try step 1-3 suggested by the Mesh team together with initializing ctx as suggested, and see if that gives the same results that we were able to produce?

    Kind regards 
    Andreas

  • Hello Andreas,

    You must be referring to the code I had originally posted. I had attached a test code only targeting this issue to my previous comment "3750.sample.zip". With this code and configuration, I had no reset issues and the ctx was initialized as recommended(line 70 in model_handler_light.c)

    regarding the step 2 you had recommended, I do not want the onoff models in the provisioner to publish/subscribe to any group addresses. My idea is to send unicast messages to these models from the server/client nodes. As long as they are assigned the same app_key, I believe they should be able to receive unicast messages directed only to them.

    I am able to send contextual unicast messages from the light_switch to the provisioner. My issue is only with the ligh not being able to send status messages to the provisioner(i.e reaches the access layer but not the model).

    Thank you for your assistance so far. Awaiting your advise.

    Regards,

    Susheel

  • Hi,

    Susheel said:
    You must be referring to the code I had originally posted.

    Yes, thats correct, as my colleague had performed the test which led to the suggestion below.

    I've relayed this information to them and will follow up with a reply as soon as I hear back from them

    Kind regards,
    Andreas

Reply Children
Related