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

multiple clients to server message on Mesh

 in the code below. implemented on a mesh form multiple Clients (Publication addresses)  to the  server (subscriped) to all the clients.

The code reads beacon data, removes the Minor ID, combine it with the Client UUID . This needs to be sent to the server.

I would like to know 

1.  how to use the function :  access_model_reliable_publish(); to transmit the array Result[24]  from the code below 

2. Max clients that can send data to 1 server on a mesh.


/* Models */
#include "generic_onoff_client.h"

/* Logging and RTT */
#include "log.h"
#include "rtt_input.h"

/* Example specific includes */
#include "app_config.h"
#include "nrf_mesh_config_examples.h"
#include "light_switch_example_common.h"
#include "example_common.h"
#include "ble_softdevice_support.h"
#include "nrf_delay.h"
#include "string.h"
#define APP_STATE_OFF                (0)
#define APP_STATE_ON                 (1)

#define APP_UNACK_MSG_REPEAT_COUNT   (2)

static generic_onoff_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT];
static bool                   m_device_provisioned;
char scanner_UUID[17]; // scanner 2 bytes + 1



//for below also investigate ? nrf_mesh_rx_cb_t This callback can be used to receive raw advertisement packets
static void rx_cb(const nrf_mesh_adv_packet_rx_data_t * p_rx_data) // used for listening for incoming packets  with function nrf_mesh_rx_cb_set(rx_cb);
{
    LEDS_OFF(BSP_LED_0_MASK);  /* @c LED_RGB_RED_MASK on pca10031 */
    char msg[64];
    char beacon_Minor_ID[5]; // the length of the eMbeacon unique ID
    char Result[24]; // 5+16+1 for nul term
    char beacon_uuid[37]; // the length of EM microelectronics packet**** check this it may be shorter
 

// copy the UUID of the beacon
    memcpy(beacon_uuid,p_rx_data->p_payload, p_rx_data->length); // copy the UUID of the beacon
 // check if it is a EMbeacon Beacon make in bit 2:9
       if ((beacon_uuid[2]==0x45)|(beacon_uuid[3]==0x4D)|(beacon_uuid[4]==0x42)|(beacon_uuid[5]==0x65)
          |(beacon_uuid[6]==0x61)|(beacon_uuid[7]==0x63)|(beacon_uuid[8]==0x6f)|(beacon_uuid[9]==0x6e)) // EMBeacon name check
// if it is a beacon send PCA10059 (scanner) UUID and Beacon UUID to the client on the mesh
    {     
      memcpy (beacon_Minor_ID,beacon_uuid + 10,5); // move the 5 unique beacon ID bytes for use in mesh to identify the beacon
      memcpy(Result, (void*) &scanner_UUID[0], 16);       // combine Beacon Minor UUID and Scanner complete UUID 
      memcpy(&Result[16], (void*) &beacon_Minor_ID[0], 8); // Advertisement address 
 
 // Transmit Result on the mesh  to the gateway server.


access_model_reliable_publish();

Thanks in advance

Parents
  • Hello,

    You must have a model that can transfer your packet. "Model" = Bluetooth mesh "service". 

    The light switch example uses an on_off_model. This can only transfer a single byte, and it actually only holds a bool, so you need to modify this model to contain a string. See how the publish function is used in the light switch example, and see if you can modify/create a model that holds this array instead of just an on_off state.

    Depending on the number of nodes in your mesh network, using access_model_reliable_publish may not be a good idea. This requires the node that subscribes to the messages to send an ACK, doubling the amount of messages travelling around in your network. If you don't have too many nodes subscribing, this will probably be ok, but if it was a lighting system, and all the lightbulbs in a warehouse were to ACK all messages, the mesh will be flooded with messages.  That being said, there is no maximum number of nodes that can publish on a channel which the server subscribes to. Only the maximum number of nodes in a network will be the theoretical limit for this, which  is around 32 000 nodes.

    Best regards,

    Edvin

  • Thanks Edvin

    Will the simple_message_client work

    for me here? Mesh V3.00

    If so where do I declare m_central_handel -  im getting a compile error.

    //simple send message example
    void address_set(uint16_t addr)                 //function for setting address
    {
      uint32_t err_code;
      err_code = dsm_address_publish_add(addr, &m_central_handle); //NRF_ERROR_NO_MEM
      ERROR_CHECK(err_code);
      ERROR_CHECK(access_model_publish_address_set(m_clients[0].model_handle, m_central_handle));
    }
    
    
    void send_message(void)                         //function for sending a simple message
    {
        uint32_t status=0;
        uint8_t buffer[5] = "hello";
        uint8_t length;
        uint16_t address;
        access_message_tx_t msg; // declare variable access.h
        length = sizeof(buffer); //SEGGER_RTT_Read(0, buffer, sizeof(buffer));
        
        if(length)
        {
          //no-need:SEGGER_RTT_WriteString(0, "entering message field\n");
          msg.opcode.opcode = simple_message_OPCODE_SEND;
          msg.opcode.company_id = 0x0059; // Nordic's company ID
    
          msg.p_buffer = (const uint8_t *) &buffer[0];
          msg.length = length;
          address = 0xCAFE;
          address_set(address);
          printf(0,"Sending to group address 0x%04x\n", address);
        status= access_model_publish(m_clients[3].model_handle, &msg);
      
          if(status == NRF_ERROR_INVALID_STATE ||
          status == NRF_ERROR_BUSY||
          status == NRF_ERROR_NO_MEM)
          {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
            hal_led_blink_ms(LEDS_MASK, 50, 4);
          }
          else
          {
             ERROR_CHECK(status);
          }
        }
    }
    

  • Hello,

    I think it will be easier to start with one of the Mesh SDK examples, rather than starting from scratch. The handles you will get from the provisioner. You need to provision your devices in order to communicate between them. To provision you can either use the light_switch->provisioner example, or you can use the nRF Mesh app for mobile. For a simple description on how to use this app, please check the youtube link on this site.

  • Hi Edvin, I am running the sample light switch. I am capable of using the  mobile app and can provision a mesh network. I would like to know if the above simple_message implemented in the light switch  example will work. However I dont want to send to all nodes just 1

     My problem with the above code is Im stuck with a compile error 

    m_central_handel is for some reason not declared

    If you can assist me to get this working it would be great.

    /* Copyright (c) 2010 - 2018, Nordic Semiconductor ASA
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdint.h>
    #include <string.h>
    
    /* HAL */
    #include "boards.h"
    #include "simple_hal.h"
    #include "app_timer.h"
    
    /* Core */
    #include "nrf_mesh_config_core.h"
    #include "nrf_mesh_configure.h"
    #include "nrf_mesh.h"
    #include "mesh_stack.h"
    #include "device_state_manager.h"
    #include "access_config.h"
    
    /* Provisioning and configuration */
    #include "mesh_provisionee.h"
    #include "mesh_app_utils.h"
    
    /* Models */
    #include "generic_onoff_client.h"
    
    /* Logging and RTT */
    #include "log.h"
    #include "rtt_input.h"
    
    /* Example specific includes */
    #include "app_config.h"
    #include "nrf_mesh_config_examples.h"
    #include "light_switch_example_common.h"
    #include "example_common.h"
    #include "ble_softdevice_support.h"
    #include "nrf_delay.h"
    #include "string.h"
    #include "simple_message_common.h"
    #define APP_STATE_OFF                (0)
    #define APP_STATE_ON                 (1)
    
    #define APP_UNACK_MSG_REPEAT_COUNT   (2)
    
    static generic_onoff_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT];
    static bool                   m_device_provisioned;
    char scanner_UUID[17]; // scanner 2 bytes + 1
    
    //#define DSM_NONVIRTUAL_ADDR_MAX (4)
    
    //for below also investigate ? nrf_mesh_rx_cb_t This callback can be used to receive raw advertisement packets
    static void rx_cb(const nrf_mesh_adv_packet_rx_data_t * p_rx_data) // used for listening for incoming packets  with function nrf_mesh_rx_cb_set(rx_cb);
    {
        LEDS_OFF(BSP_LED_0_MASK);  /* @c LED_RGB_RED_MASK on pca10031 */
        char msg[64];
        char beacon_Minor_ID[5]; // the length of the eMbeacon unique ID
        char Result[24]; // 5+16+1 for nul term
        char beacon_uuid[37]; // the length of EM microelectronics packet**** check this it may be shorter
     
    
    
        memcpy(beacon_uuid,p_rx_data->p_payload, p_rx_data->length); // copy the UUID of the beacon
     // check if it is a EMbeacon Beacon make in bit 2:9
           if ((beacon_uuid[2]==0x45)|(beacon_uuid[3]==0x4D)|(beacon_uuid[4]==0x42)|(beacon_uuid[5]==0x65)
              |(beacon_uuid[6]==0x61)|(beacon_uuid[7]==0x63)|(beacon_uuid[8]==0x6f)|(beacon_uuid[9]==0x6e)) // EMBeacon name check
    // if it is a beacon send PCA10059 (scanner) UUID and Beacon UUID to the server  on the mesh
        {     
          memcpy (beacon_Minor_ID,beacon_uuid + 10,5); // move the 5 unique beacon ID bytes for use in mesh to identify the beacon
          memcpy(Result, (void*) &scanner_UUID[0], 16); // combine Beacon Minor UUID and Scanner complete UUID 
          memcpy(&Result[16], (void*) &beacon_Minor_ID[0], 8); 
     
     // Transmit Result on the mesh  to the gateway server.
         send_message(void) // send hello on the mesh to see tes if it works
          
    
    //Print all incoming into debug terminal
    /*
    sprintf(msg, "[%02x:%02x:%02x:%02x:%02x:%02x]",
                     
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[0],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[1],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[2],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[3],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[4],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[5]);*/
    __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, msg, p_rx_data->p_payload, p_rx_data->length);
    
                LEDS_ON(BSP_LED_0_MASK);  // @c LED_RGB_RED_MASK on pca10031 
        }
    }
    
    
    //simple send message example
    void address_set(uint16_t addr)                 //function for setting address
    {
      uint32_t err_code;
      err_code = dsm_address_publish_add(addr, &m_central_handle); //NRF_ERROR_NO_MEM
      ERROR_CHECK(err_code);
      ERROR_CHECK(access_model_publish_address_set(m_clients[0].model_handle, m_central_handle));
    }
    
    
    void send_message(void)                         //function for sending a simple message
    {
        uint32_t status=0;
        uint8_t buffer[5] = "hello";
        uint8_t length;
        uint16_t address;
        access_message_tx_t msg; // declare variable access.h
        length = sizeof(buffer); //SEGGER_RTT_Read(0, buffer, sizeof(buffer));
        
        if(length)
        {
          //no-need:SEGGER_RTT_WriteString(0, "entering message field\n");
          msg.opcode.opcode = simple_message_OPCODE_SEND;
          msg.opcode.company_id = 0x0059; // Nordic's company ID
    
          msg.p_buffer = (const uint8_t *) &buffer[0];
          msg.length = length;
          address = 0xCAFE;
          address_set(address);
          printf(0,"Sending to group address 0x%04x\n", address);
        status= access_model_publish(m_clients[3].model_handle, &msg);
      
          if(status == NRF_ERROR_INVALID_STATE ||
          status == NRF_ERROR_BUSY||
          status == NRF_ERROR_NO_MEM)
          {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
            hal_led_blink_ms(LEDS_MASK, 50, 4);
          }
          else
          {
             ERROR_CHECK(status);
          }
        }
    }
    
    
    /* Forward declaration */
    static void app_gen_onoff_client_publish_interval_cb(access_model_handle_t handle, void * p_self);
    static void app_generic_onoff_client_status_cb(const generic_onoff_client_t * p_self,
                                                   const access_message_rx_meta_t * p_meta,
                                                   const generic_onoff_status_params_t * p_in);
    static void app_gen_onoff_client_transaction_status_cb(access_model_handle_t model_handle,
                                                           void * p_args,
                                                           access_reliable_status_t status);
    
    const generic_onoff_client_callbacks_t client_cbs =
    {
        .onoff_status_cb = app_generic_onoff_client_status_cb,
        .ack_transaction_status_cb = app_gen_onoff_client_transaction_status_cb,
        .periodic_publish_cb = app_gen_onoff_client_publish_interval_cb
    };
    
    static void device_identification_start_cb(uint8_t attention_duration_s)
    {
        hal_led_mask_set(LEDS_MASK, false);
        hal_led_blink_ms(BSP_LED_2_MASK  | BSP_LED_3_MASK, 
                         LED_BLINK_ATTENTION_INTERVAL_MS, 
                         LED_BLINK_ATTENTION_COUNT(attention_duration_s));
    }
    
    static void provisioning_aborted_cb(void)
    {
        hal_led_blink_stop();
    }
    
    static void provisioning_complete_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Successfully provisioned\n");
    
    #if MESH_FEATURE_GATT_ENABLED
        /* Restores the application parameters after switching from the Provisioning
         * service to the Proxy  */
        gap_params_init();
        conn_params_init();
    #endif
    
        dsm_local_unicast_address_t node_address;
        dsm_local_unicast_addresses_get(&node_address);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node Address: 0x%04x \n", node_address.address_start);
    
        hal_led_blink_stop();
        hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF);
        hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_PROV);
    }
    
    /* This callback is called periodically if model is configured for periodic publishing */
    static void app_gen_onoff_client_publish_interval_cb(access_model_handle_t handle, void * p_self)
    {
         __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Publish desired message here.\n");
    }
    
    /* Acknowledged transaction status callback, if acknowledged transfer fails, application can
    * determine suitable course of action (e.g. re-initiate previous transaction) by using this
    * callback.
    */
    static void app_gen_onoff_client_transaction_status_cb(access_model_handle_t model_handle,
                                                           void * p_args,
                                                           access_reliable_status_t status)
    {
        switch(status)
        {
            case ACCESS_RELIABLE_TRANSFER_SUCCESS:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer success.\n");
                break;
    
            case ACCESS_RELIABLE_TRANSFER_TIMEOUT:
                hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY);
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer timeout.\n");
                break;
    
            case ACCESS_RELIABLE_TRANSFER_CANCELLED:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer cancelled.\n");
                break;
    
            default:
                ERROR_CHECK(NRF_ERROR_INTERNAL);
                break;
        }
    }
    
    /* Generic OnOff client model interface: Process the received status message in this callback */
    static void app_generic_onoff_client_status_cb(const generic_onoff_client_t * p_self,
                                                   const access_message_rx_meta_t * p_meta,
                                                   const generic_onoff_status_params_t * p_in)
    {
        if (p_in->remaining_time_ms > 0)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "OnOff server: 0x%04x, Present OnOff: %d, Target OnOff: %d, Remaining Time: %d ms\n",
                  p_meta->src.value, p_in->present_on_off, p_in->target_on_off, p_in->remaining_time_ms);
        }
        else
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "OnOff server: 0x%04x, Present OnOff: %d\n",
                  p_meta->src.value, p_in->present_on_off);
        }
    }
    
    static void node_reset(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Node reset  -----\n");
        hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_RESET);
        /* This function may return if there are ongoing flash operations. */
        mesh_stack_device_reset();
    }
    
    static void config_server_evt_cb(const config_server_evt_t * p_evt)
    {
        if (p_evt->type == CONFIG_SERVER_EVT_NODE_RESET)
        {
            node_reset();
        }
    }
    
    static void button_event_handler(uint32_t button_number)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
    
        uint32_t status = NRF_SUCCESS;
        generic_onoff_set_params_t set_params;
        model_transition_t transition_params;
        static uint8_t tid = 0;
    
        /* Button 1: On, Button 2: Off, Client[0]
         * Button 2: On, Button 3: Off, Client[1]
         */
    
        switch(button_number)
        {
            case 0:
            case 2:
                set_params.on_off = APP_STATE_ON;
                break;
    
            case 1:
            case 3:
                set_params.on_off = APP_STATE_OFF;
                break;
        }
    
        set_params.tid = tid++;
        transition_params.delay_ms = APP_CONFIG_ONOFF_DELAY_MS;
        transition_params.transition_time_ms = APP_CONFIG_ONOFF_TRANSITION_TIME_MS;
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Sending msg: ONOFF SET %d\n", set_params.on_off);
    
        switch (button_number)
        {
            case 0:
            case 1:
                /* Demonstrate acknowledged transaction, using 1st client model instance */
                /* In this examples, users will not be blocked if the model is busy */
                (void)access_model_reliable_cancel(m_clients[0].model_handle);
                status = generic_onoff_client_set(&m_clients[0], &set_params, &transition_params);
                hal_led_pin_set(BSP_LED_0, set_params.on_off);
                break;
    
            case 2:
            case 3:
                /* Demonstrate un-acknowledged transaction, using 2nd client model instance */
                status = generic_onoff_client_set_unack(&m_clients[1], &set_params,
                                                        &transition_params, APP_UNACK_MSG_REPEAT_COUNT);
                hal_led_pin_set(BSP_LED_1, set_params.on_off);
                break;
        }
    
        switch (status)
        {
            case NRF_SUCCESS:
                break;
    
            case NRF_ERROR_NO_MEM:
            case NRF_ERROR_BUSY:
            case NRF_ERROR_INVALID_STATE:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Client %u cannot send\n", button_number);
                hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY);
                break;
    
            case NRF_ERROR_INVALID_PARAM:
                /* Publication not enabled for this client. One (or more) of the following is wrong:
                 * - An application key is missing, or there is no application key bound to the model
                 * - The client does not have its publication state set
                 *
                 * It is the provisioner that adds an application key, binds it to the model and sets
                 * the model's publication state.
                 */
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Publication not configured for client %u\n", button_number);
                break;
    
            default:
                ERROR_CHECK(status);
                break;
        }
    }
    
    static void rtt_input_handler(int key)
    {
        if (key >= '0' && key <= '3')
        {
            uint32_t button_number = key - '0';
            button_event_handler(button_number);
        }
    }
    
    static void models_init_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
    
        for (uint32_t i = 0; i < CLIENT_MODEL_INSTANCE_COUNT; ++i)
        {
            m_clients[i].settings.p_callbacks = &client_cbs;
            m_clients[i].settings.timeout = 0;
            m_clients[i].settings.force_segmented = APP_CONFIG_FORCE_SEGMENTATION;
            m_clients[i].settings.transmic_size = APP_CONFIG_MIC_SIZE;
    
            ERROR_CHECK(generic_onoff_client_init(&m_clients[i], i + 1));
        }
    }
    
    static void mesh_init(void)
    {
        uint8_t dev_uuid[NRF_MESH_UUID_SIZE];
        uint8_t node_uuid_prefix[NODE_UUID_PREFIX_LEN] = CLIENT_NODE_UUID_PREFIX;
    
        ERROR_CHECK(mesh_app_uuid_gen(dev_uuid, node_uuid_prefix, NODE_UUID_PREFIX_LEN));
        mesh_stack_init_params_t init_params =
        {
            .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
            .core.lfclksrc           = DEV_BOARD_LF_CLK_CFG,
            .core.p_uuid             = dev_uuid,
            .models.models_init_cb   = models_init_cb,
            .models.config_server_cb = config_server_evt_cb
        };
        ERROR_CHECK(mesh_stack_init(&init_params, &m_device_provisioned));
    /* Start listening for incoming packets */
        nrf_mesh_rx_cb_set(rx_cb);
    }
    
    static void initialize(void)
    {
        __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS | LOG_SRC_BEARER, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- PCA10059 CLIENT -----\n");
    
        ERROR_CHECK(app_timer_init());
        hal_leds_init();
    
    #if BUTTON_BOARD
        ERROR_CHECK(hal_buttons_init(button_event_handler));
    #endif
    
        ble_stack_init();
    
    #if MESH_FEATURE_GATT_ENABLED
        gap_params_init();
        conn_params_init();
    #endif
    
        mesh_init();
    }
    
    static void start(void)
    {
        rtt_input_enable(rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);
    
        if (!m_device_provisioned)
        {
            static const uint8_t static_auth_data[NRF_MESH_KEY_SIZE] = STATIC_AUTH_DATA;
            mesh_provisionee_start_params_t prov_start_params =
            {
                .p_static_data    = static_auth_data,
                .prov_complete_cb = provisioning_complete_cb,
                .prov_device_identification_start_cb = device_identification_start_cb,
                .prov_device_identification_stop_cb = NULL,
                .prov_abort_cb = provisioning_aborted_cb,
                .p_device_uri = NULL
            };
            ERROR_CHECK(mesh_provisionee_prov_start(&prov_start_params));
        }
    
    //get this device UUID PCA10059
        const uint8_t *p_uuid = nrf_mesh_configure_device_uuid_get();
        UNUSED_VARIABLE(p_uuid);
        //strncpy (scanner_UUID,p_uuid,17); // copy the uuid
       memcpy(scanner_UUID, p_uuid,17);
        __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Device UUID ", p_uuid, NRF_MESH_UUID_SIZE);
    
        ERROR_CHECK(mesh_stack_start());
    
        hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF);
     //   hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_START);
    }
    
    int main(void)
    { 
    
        /* Configure board. */
      bsp_board_init(BSP_INIT_LEDS);
      initialize();   
      start();
    
        for (;;)
        {
       (void)sd_app_evt_wait();
         
              }
    }
    
    
    

Reply
  • Hi Edvin, I am running the sample light switch. I am capable of using the  mobile app and can provision a mesh network. I would like to know if the above simple_message implemented in the light switch  example will work. However I dont want to send to all nodes just 1

     My problem with the above code is Im stuck with a compile error 

    m_central_handel is for some reason not declared

    If you can assist me to get this working it would be great.

    /* Copyright (c) 2010 - 2018, Nordic Semiconductor ASA
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdint.h>
    #include <string.h>
    
    /* HAL */
    #include "boards.h"
    #include "simple_hal.h"
    #include "app_timer.h"
    
    /* Core */
    #include "nrf_mesh_config_core.h"
    #include "nrf_mesh_configure.h"
    #include "nrf_mesh.h"
    #include "mesh_stack.h"
    #include "device_state_manager.h"
    #include "access_config.h"
    
    /* Provisioning and configuration */
    #include "mesh_provisionee.h"
    #include "mesh_app_utils.h"
    
    /* Models */
    #include "generic_onoff_client.h"
    
    /* Logging and RTT */
    #include "log.h"
    #include "rtt_input.h"
    
    /* Example specific includes */
    #include "app_config.h"
    #include "nrf_mesh_config_examples.h"
    #include "light_switch_example_common.h"
    #include "example_common.h"
    #include "ble_softdevice_support.h"
    #include "nrf_delay.h"
    #include "string.h"
    #include "simple_message_common.h"
    #define APP_STATE_OFF                (0)
    #define APP_STATE_ON                 (1)
    
    #define APP_UNACK_MSG_REPEAT_COUNT   (2)
    
    static generic_onoff_client_t m_clients[CLIENT_MODEL_INSTANCE_COUNT];
    static bool                   m_device_provisioned;
    char scanner_UUID[17]; // scanner 2 bytes + 1
    
    //#define DSM_NONVIRTUAL_ADDR_MAX (4)
    
    //for below also investigate ? nrf_mesh_rx_cb_t This callback can be used to receive raw advertisement packets
    static void rx_cb(const nrf_mesh_adv_packet_rx_data_t * p_rx_data) // used for listening for incoming packets  with function nrf_mesh_rx_cb_set(rx_cb);
    {
        LEDS_OFF(BSP_LED_0_MASK);  /* @c LED_RGB_RED_MASK on pca10031 */
        char msg[64];
        char beacon_Minor_ID[5]; // the length of the eMbeacon unique ID
        char Result[24]; // 5+16+1 for nul term
        char beacon_uuid[37]; // the length of EM microelectronics packet**** check this it may be shorter
     
    
    
        memcpy(beacon_uuid,p_rx_data->p_payload, p_rx_data->length); // copy the UUID of the beacon
     // check if it is a EMbeacon Beacon make in bit 2:9
           if ((beacon_uuid[2]==0x45)|(beacon_uuid[3]==0x4D)|(beacon_uuid[4]==0x42)|(beacon_uuid[5]==0x65)
              |(beacon_uuid[6]==0x61)|(beacon_uuid[7]==0x63)|(beacon_uuid[8]==0x6f)|(beacon_uuid[9]==0x6e)) // EMBeacon name check
    // if it is a beacon send PCA10059 (scanner) UUID and Beacon UUID to the server  on the mesh
        {     
          memcpy (beacon_Minor_ID,beacon_uuid + 10,5); // move the 5 unique beacon ID bytes for use in mesh to identify the beacon
          memcpy(Result, (void*) &scanner_UUID[0], 16); // combine Beacon Minor UUID and Scanner complete UUID 
          memcpy(&Result[16], (void*) &beacon_Minor_ID[0], 8); 
     
     // Transmit Result on the mesh  to the gateway server.
         send_message(void) // send hello on the mesh to see tes if it works
          
    
    //Print all incoming into debug terminal
    /*
    sprintf(msg, "[%02x:%02x:%02x:%02x:%02x:%02x]",
                     
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[0],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[1],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[2],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[3],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[4],
                       p_rx_data->p_metadata->params.scanner.adv_addr.addr[5]);*/
    __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, msg, p_rx_data->p_payload, p_rx_data->length);
    
                LEDS_ON(BSP_LED_0_MASK);  // @c LED_RGB_RED_MASK on pca10031 
        }
    }
    
    
    //simple send message example
    void address_set(uint16_t addr)                 //function for setting address
    {
      uint32_t err_code;
      err_code = dsm_address_publish_add(addr, &m_central_handle); //NRF_ERROR_NO_MEM
      ERROR_CHECK(err_code);
      ERROR_CHECK(access_model_publish_address_set(m_clients[0].model_handle, m_central_handle));
    }
    
    
    void send_message(void)                         //function for sending a simple message
    {
        uint32_t status=0;
        uint8_t buffer[5] = "hello";
        uint8_t length;
        uint16_t address;
        access_message_tx_t msg; // declare variable access.h
        length = sizeof(buffer); //SEGGER_RTT_Read(0, buffer, sizeof(buffer));
        
        if(length)
        {
          //no-need:SEGGER_RTT_WriteString(0, "entering message field\n");
          msg.opcode.opcode = simple_message_OPCODE_SEND;
          msg.opcode.company_id = 0x0059; // Nordic's company ID
    
          msg.p_buffer = (const uint8_t *) &buffer[0];
          msg.length = length;
          address = 0xCAFE;
          address_set(address);
          printf(0,"Sending to group address 0x%04x\n", address);
        status= access_model_publish(m_clients[3].model_handle, &msg);
      
          if(status == NRF_ERROR_INVALID_STATE ||
          status == NRF_ERROR_BUSY||
          status == NRF_ERROR_NO_MEM)
          {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Cannot send. Device is busy.\n");
            hal_led_blink_ms(LEDS_MASK, 50, 4);
          }
          else
          {
             ERROR_CHECK(status);
          }
        }
    }
    
    
    /* Forward declaration */
    static void app_gen_onoff_client_publish_interval_cb(access_model_handle_t handle, void * p_self);
    static void app_generic_onoff_client_status_cb(const generic_onoff_client_t * p_self,
                                                   const access_message_rx_meta_t * p_meta,
                                                   const generic_onoff_status_params_t * p_in);
    static void app_gen_onoff_client_transaction_status_cb(access_model_handle_t model_handle,
                                                           void * p_args,
                                                           access_reliable_status_t status);
    
    const generic_onoff_client_callbacks_t client_cbs =
    {
        .onoff_status_cb = app_generic_onoff_client_status_cb,
        .ack_transaction_status_cb = app_gen_onoff_client_transaction_status_cb,
        .periodic_publish_cb = app_gen_onoff_client_publish_interval_cb
    };
    
    static void device_identification_start_cb(uint8_t attention_duration_s)
    {
        hal_led_mask_set(LEDS_MASK, false);
        hal_led_blink_ms(BSP_LED_2_MASK  | BSP_LED_3_MASK, 
                         LED_BLINK_ATTENTION_INTERVAL_MS, 
                         LED_BLINK_ATTENTION_COUNT(attention_duration_s));
    }
    
    static void provisioning_aborted_cb(void)
    {
        hal_led_blink_stop();
    }
    
    static void provisioning_complete_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Successfully provisioned\n");
    
    #if MESH_FEATURE_GATT_ENABLED
        /* Restores the application parameters after switching from the Provisioning
         * service to the Proxy  */
        gap_params_init();
        conn_params_init();
    #endif
    
        dsm_local_unicast_address_t node_address;
        dsm_local_unicast_addresses_get(&node_address);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node Address: 0x%04x \n", node_address.address_start);
    
        hal_led_blink_stop();
        hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF);
        hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_PROV);
    }
    
    /* This callback is called periodically if model is configured for periodic publishing */
    static void app_gen_onoff_client_publish_interval_cb(access_model_handle_t handle, void * p_self)
    {
         __LOG(LOG_SRC_APP, LOG_LEVEL_WARN, "Publish desired message here.\n");
    }
    
    /* Acknowledged transaction status callback, if acknowledged transfer fails, application can
    * determine suitable course of action (e.g. re-initiate previous transaction) by using this
    * callback.
    */
    static void app_gen_onoff_client_transaction_status_cb(access_model_handle_t model_handle,
                                                           void * p_args,
                                                           access_reliable_status_t status)
    {
        switch(status)
        {
            case ACCESS_RELIABLE_TRANSFER_SUCCESS:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer success.\n");
                break;
    
            case ACCESS_RELIABLE_TRANSFER_TIMEOUT:
                hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY);
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer timeout.\n");
                break;
    
            case ACCESS_RELIABLE_TRANSFER_CANCELLED:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Acknowledged transfer cancelled.\n");
                break;
    
            default:
                ERROR_CHECK(NRF_ERROR_INTERNAL);
                break;
        }
    }
    
    /* Generic OnOff client model interface: Process the received status message in this callback */
    static void app_generic_onoff_client_status_cb(const generic_onoff_client_t * p_self,
                                                   const access_message_rx_meta_t * p_meta,
                                                   const generic_onoff_status_params_t * p_in)
    {
        if (p_in->remaining_time_ms > 0)
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "OnOff server: 0x%04x, Present OnOff: %d, Target OnOff: %d, Remaining Time: %d ms\n",
                  p_meta->src.value, p_in->present_on_off, p_in->target_on_off, p_in->remaining_time_ms);
        }
        else
        {
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "OnOff server: 0x%04x, Present OnOff: %d\n",
                  p_meta->src.value, p_in->present_on_off);
        }
    }
    
    static void node_reset(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Node reset  -----\n");
        hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_RESET);
        /* This function may return if there are ongoing flash operations. */
        mesh_stack_device_reset();
    }
    
    static void config_server_evt_cb(const config_server_evt_t * p_evt)
    {
        if (p_evt->type == CONFIG_SERVER_EVT_NODE_RESET)
        {
            node_reset();
        }
    }
    
    static void button_event_handler(uint32_t button_number)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Button %u pressed\n", button_number);
    
        uint32_t status = NRF_SUCCESS;
        generic_onoff_set_params_t set_params;
        model_transition_t transition_params;
        static uint8_t tid = 0;
    
        /* Button 1: On, Button 2: Off, Client[0]
         * Button 2: On, Button 3: Off, Client[1]
         */
    
        switch(button_number)
        {
            case 0:
            case 2:
                set_params.on_off = APP_STATE_ON;
                break;
    
            case 1:
            case 3:
                set_params.on_off = APP_STATE_OFF;
                break;
        }
    
        set_params.tid = tid++;
        transition_params.delay_ms = APP_CONFIG_ONOFF_DELAY_MS;
        transition_params.transition_time_ms = APP_CONFIG_ONOFF_TRANSITION_TIME_MS;
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Sending msg: ONOFF SET %d\n", set_params.on_off);
    
        switch (button_number)
        {
            case 0:
            case 1:
                /* Demonstrate acknowledged transaction, using 1st client model instance */
                /* In this examples, users will not be blocked if the model is busy */
                (void)access_model_reliable_cancel(m_clients[0].model_handle);
                status = generic_onoff_client_set(&m_clients[0], &set_params, &transition_params);
                hal_led_pin_set(BSP_LED_0, set_params.on_off);
                break;
    
            case 2:
            case 3:
                /* Demonstrate un-acknowledged transaction, using 2nd client model instance */
                status = generic_onoff_client_set_unack(&m_clients[1], &set_params,
                                                        &transition_params, APP_UNACK_MSG_REPEAT_COUNT);
                hal_led_pin_set(BSP_LED_1, set_params.on_off);
                break;
        }
    
        switch (status)
        {
            case NRF_SUCCESS:
                break;
    
            case NRF_ERROR_NO_MEM:
            case NRF_ERROR_BUSY:
            case NRF_ERROR_INVALID_STATE:
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Client %u cannot send\n", button_number);
                hal_led_blink_ms(LEDS_MASK, LED_BLINK_SHORT_INTERVAL_MS, LED_BLINK_CNT_NO_REPLY);
                break;
    
            case NRF_ERROR_INVALID_PARAM:
                /* Publication not enabled for this client. One (or more) of the following is wrong:
                 * - An application key is missing, or there is no application key bound to the model
                 * - The client does not have its publication state set
                 *
                 * It is the provisioner that adds an application key, binds it to the model and sets
                 * the model's publication state.
                 */
                __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Publication not configured for client %u\n", button_number);
                break;
    
            default:
                ERROR_CHECK(status);
                break;
        }
    }
    
    static void rtt_input_handler(int key)
    {
        if (key >= '0' && key <= '3')
        {
            uint32_t button_number = key - '0';
            button_event_handler(button_number);
        }
    }
    
    static void models_init_cb(void)
    {
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");
    
        for (uint32_t i = 0; i < CLIENT_MODEL_INSTANCE_COUNT; ++i)
        {
            m_clients[i].settings.p_callbacks = &client_cbs;
            m_clients[i].settings.timeout = 0;
            m_clients[i].settings.force_segmented = APP_CONFIG_FORCE_SEGMENTATION;
            m_clients[i].settings.transmic_size = APP_CONFIG_MIC_SIZE;
    
            ERROR_CHECK(generic_onoff_client_init(&m_clients[i], i + 1));
        }
    }
    
    static void mesh_init(void)
    {
        uint8_t dev_uuid[NRF_MESH_UUID_SIZE];
        uint8_t node_uuid_prefix[NODE_UUID_PREFIX_LEN] = CLIENT_NODE_UUID_PREFIX;
    
        ERROR_CHECK(mesh_app_uuid_gen(dev_uuid, node_uuid_prefix, NODE_UUID_PREFIX_LEN));
        mesh_stack_init_params_t init_params =
        {
            .core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
            .core.lfclksrc           = DEV_BOARD_LF_CLK_CFG,
            .core.p_uuid             = dev_uuid,
            .models.models_init_cb   = models_init_cb,
            .models.config_server_cb = config_server_evt_cb
        };
        ERROR_CHECK(mesh_stack_init(&init_params, &m_device_provisioned));
    /* Start listening for incoming packets */
        nrf_mesh_rx_cb_set(rx_cb);
    }
    
    static void initialize(void)
    {
        __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS | LOG_SRC_BEARER, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- PCA10059 CLIENT -----\n");
    
        ERROR_CHECK(app_timer_init());
        hal_leds_init();
    
    #if BUTTON_BOARD
        ERROR_CHECK(hal_buttons_init(button_event_handler));
    #endif
    
        ble_stack_init();
    
    #if MESH_FEATURE_GATT_ENABLED
        gap_params_init();
        conn_params_init();
    #endif
    
        mesh_init();
    }
    
    static void start(void)
    {
        rtt_input_enable(rtt_input_handler, RTT_INPUT_POLL_PERIOD_MS);
    
        if (!m_device_provisioned)
        {
            static const uint8_t static_auth_data[NRF_MESH_KEY_SIZE] = STATIC_AUTH_DATA;
            mesh_provisionee_start_params_t prov_start_params =
            {
                .p_static_data    = static_auth_data,
                .prov_complete_cb = provisioning_complete_cb,
                .prov_device_identification_start_cb = device_identification_start_cb,
                .prov_device_identification_stop_cb = NULL,
                .prov_abort_cb = provisioning_aborted_cb,
                .p_device_uri = NULL
            };
            ERROR_CHECK(mesh_provisionee_prov_start(&prov_start_params));
        }
    
    //get this device UUID PCA10059
        const uint8_t *p_uuid = nrf_mesh_configure_device_uuid_get();
        UNUSED_VARIABLE(p_uuid);
        //strncpy (scanner_UUID,p_uuid,17); // copy the uuid
       memcpy(scanner_UUID, p_uuid,17);
        __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Device UUID ", p_uuid, NRF_MESH_UUID_SIZE);
    
        ERROR_CHECK(mesh_stack_start());
    
        hal_led_mask_set(LEDS_MASK, LED_MASK_STATE_OFF);
     //   hal_led_blink_ms(LEDS_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_START);
    }
    
    int main(void)
    { 
    
        /* Configure board. */
      bsp_board_init(BSP_INIT_LEDS);
      initialize();   
      start();
    
        for (;;)
        {
       (void)sd_app_evt_wait();
         
              }
    }
    
    
    

Children
  • What compiling error do you get?

    m_central_handle (nor m_central_handel) is declared in your main.c file. If you want to send a message to one node instead of all, you must send it on a channel that only one node is subscribing to. This is done during the provisioning. Please check the video link from my previous reply on how to set up publish and subscription channels.

  • sorry yes handle 'm_central_handle' undeclared (first use in this function)

    Where is this declared in my C and how?  If you can show me please.

  • This should not be used directly in main. But in config_server.c it is declared like:

    dsm_handle_t publish_address_handle = DSM_HANDLE_INVALID;

    This is just an empty handle that is populated in dsm_address_publish_add(publish_address, &publish_address_handle);

    If you have the address, you may do this manually, but as I mentioned, this should really (!) be done through the commissioning process. That is the reason why this function is not used in the main.c file in the examples.

    If you have not already, I suggest you read through the guide on how to run the light switch example here:

    https://www.nordicsemi.com/DocLib/Content/SDK_Doc/Mesh_SDK/v3-1-0/md_examples_light_switch_README

    Depending on whether you have 2 or 3 nRF devices, you can either use one device as the provisioner(evaluate using the static provisioner), or you can use the nRF Mesh app as the provisioner (evaluate using the nRFMesh mobile app).

    BR,

    Edvin

  • Thanks Edvin, I have removed it. I have 10 clients 1 server. I can provision them successfully with the client light switch example. Im trying to implement the following example https://devzone.nordicsemi.com/f/nordic-q-a/29836/send-and-receive-a-string-via-access-layer

    I have the following error   address_set(address)  error ;undefined reference to `address_set'

    Where do I need to set this?

    Does this simple message example work on mesh 3 or 3.1? is there no working example available, it will really help a lot.

    Thanks

  • Hello,

    I think that what Bjørn is explaining in the ticket that you linked to is important. It seems like the snippet is for Mesh SDK1.0.0, which is old, and there has been a lot (!) of improvements, so I suggest that you start with SDK for mesh >= 3.0.0, and use the information in this setup to convert the onoff model to a simple_message model.

    As long as you don't change anything with the address setup you don't have to worry about it, and let the provisioning handle the addresses. You should only need the generic_onoff_client_set() or generic_onoff_client_set_unack() (depending on whether you want the messages to be ACKed or not).

    The address is stored in the m_clients[].model_handle when you provision.

Related