This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Mesh node self provisioning

Hi all,

I want to self provision my node. I am using nrf52832 dev board, mesh SDK v 3.1.0, light switch client example. You may wonder why self provisioning, when there is nrf mesh provisioning mobile app, but it is the necessary intermediate step in the project where I combine the provisioner and client role in one node. The parts of code for self provisioning:

static uint8_t m_netkey; 
static uint8_t m_appkey;
static uint8_t m_self_devkey;

static dsm_handle_t m_netkey_handle;
static dsm_handle_t m_appkey_handle;
static dsm_handle_t m_self_devkey_handle;

static dsm_handle_t group_handle;
static generic_onoff_client_t m_client;

void self_provision()
{
    dsm_local_unicast_address_t local_address = {START_ADDRESS, ACCESS_ELEMENT_COUNT};
    ERROR_CHECK(dsm_local_unicast_addresses_set(&local_address));
    
    //hardcoded keys
    m_netkey = NETKEY;     
    m_appkey = APPKEY;
    m_devkey = DEVKEY;
    
    ERROR_CHECK(dsm_subnet_add(0, netkey, &m_netkey_handle));
    ERROR_CHECK(dsm_appkey_add(0, m_netkey_handle ,m_appkey, &m_appkey_handle));
    ERROR_CHECK(dsm_devkey_add(START_ADDRESS, m_netkey_handle, m_self_devkey, &m_self_devkey_handle));
    
    ERROR_CHECK(dsm_address_publish_add(FIRST_GROUP_ADDRESS, &group_handle));
}

void app_default_models_bind_setup(void)
{
    ERROR_CHECK(config_server_bind(m_self_devkey_handle));
    
    ERROR_CHECK(access_model_application_bind(m_client.model_handle, m_appkey_handle));
    ERROR_CHECK(access_model_publish_application_set(m_client.model_handle, m_appkey_handle));
    
    ERROR_CHECK(access_model_publish_address_set((m_client.model_handle, group_handle));
}

void models_init_cb(void)
{
    ERROR_CHECK(config_client_init(app_config_client_event_cb));
    ERROR_CHECK(generic_onoff_client_init(&m_client, FIRST_ELEMENT_INDEX));
}

To test if I correctly self provision the CLIENT node, I used the nrf mesh app to provision the SERVER node (lifgt switch server example), took the appkey and the netkey assigned by the mesh app, hardcoded them into the code for light switch client, configured the subscription address on the server node (using nrf mesh app) and watched, if the server reacts on the button presses on my client board. But I just watched the transfer timeout (transfer timeout - You can can object I use acknowledged messages in group messaging. I am aware of the fact, it is just temporary solution). 

My question is: Is there something missing in the code snippets above relating to be capable to self provision the node? I assume it has to do something with config client or config server model. Every help appreciated :) 

Patrik

  • Hi Patrik, 

    This code worked for me. There is no model configured but I can see I can receive the message to address 0xC001 on access layer. This is a very minimum code, you would need to add device key, bind the appkey to model etc. 


    uint32_t my_mesh_stack_provisioning_data_store()
    {
        dsm_handle_t netkey_handle, devkey_handle;
        dsm_local_unicast_address_t local_address;
        uint8_t netkey[16]={0x79,0xF5,0xF1,0x6A,0x43,0x22,0x17,0xDF,0x1D,0xC1,0x59,0x10,0x13,0x0A,0x31,0x6F};
        uint8_t appkey[16]={0x5B,0xD8,0xDE,0xB4,0x49,0xAB,0x15,0x1B,0x72,0x7F,0xD4,0x56,0xF5,0x49,0x81,0x9B};
        local_address.address_start = 0x99;
        local_address.count = ACCESS_ELEMENT_COUNT;
        uint32_t status;
        dsm_handle_t app_handle;
        /* Store received provisioning data in the DSM */
        status = dsm_local_unicast_addresses_set(&local_address);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
        status = dsm_subnet_add(0, netkey, &netkey_handle);
        if (status != NRF_SUCCESS)
        {
            return status;
        }
        NRF_MESH_ERROR_CHECK(net_state_iv_index_set(0,0));
    
        dsm_handle_t network_handle = dsm_net_key_index_to_subnet_handle(0);
        status = dsm_appkey_add(0, network_handle, appkey, &app_handle);
        dsm_handle_t subscription_address_handle;
        status = dsm_address_subscription_add(0xC001, &subscription_address_handle);
        return status;
    }

    Note that to print out the "RX:" log in access.c you need to enable logging at level DBG1. 

    (Posted this just to find out that you figured it out 20 minutes earlier :) . Good news Patrik. ) 

  • Hi Hung, I am trying to do a similar thing as this post, but I need to ask, where does teh device key come from?

  • Hi Nishant, 

    The device key is generated using prov_utils_derive_keys(). My understanding is that  it's calculated on both side the provisioner and provisionee (should have the same result) using that function. So that key is not exchanged between them. 

  •       dsm_local_unicast_address_t local_address = {1, ACCESS_ELEMENT_COUNT};
          dsm_handle_t net_handle,dev_handle,app_handle,vendor_handle,handle;
    
          ERROR_CHECK(dsm_local_unicast_addresses_set(&local_address));
          ERROR_CHECK(dsm_subnet_add(0, KEY.privacy_key, &net_handle));
          ERROR_CHECK(dsm_devkey_add(local_address.address_start, net_handle, KEY.privacy_key, &dev_handle));
          KEY.privacy_key[15]=0xA0;
          ERROR_CHECK(dsm_appkey_add(0, net_handle ,KEY.privacy_key, &app_handle));
    
          ERROR_CHECK(config_server_bind(dev_handle));
          IsValid = vendor_handle_get(&vendor_handle);
          if(IsValid==0)  while(1); //stay locked
          ERROR_CHECK(access_model_application_bind(vendor_handle, app_handle));
    
          // Add the address to the DSM as a subscription address:
          i = dsm_address_subscription_add(GROUP_SUB_ADDR, &handle);
          // Add the subscription to the model:
          i = access_model_subscription_add(vendor_handle, handle);
    
          mesh_stack_device_reset();  //power cycle after self provisioning
        }

    Here is my version that works with vendor model

Related