This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

ZigBee problems with coordinator to subscribe the multi sensor

Good day.

I am currently developing with two NRF52840 DK boards, and I also have two NRF Dongles. On a dongle a sniffer for ZigBee. I am working with SDK 3.2. This is my first project with ZigBee, so I don't have much know-how yet.

My goal is to implement the coordinator as like CLI agent. So that it subscribes to the multi-sensor and receives data. Is so to speak an A to B communication.

With "zb_zdo_match_desc_req()" I get the short address and the endpoint of the sensor. Then with "zb_zdo_ieee_addr_req()" I get the long address  (EUI64) of the sensor. After that the "zb_zdo_bind_req()" request starts (Between coordinator and sensor) and in the callback function ("p_resp->status") this is confirmed successfully with ZB_ZDP_STATUS_SUCCESS. However, I only connect to the ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT cluster.

My questions:
1) Is it necessary to connect both clusters (temperature/pressure) to subscribe to the multisensor? If so, is the bind request simply done again with the ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT?

2) Is subscribing the sensor in the first step as below, correct?

// Step 8:
// Subscribe on Sensor
static void subscribe_device(zb_uint8_t param)
{
    zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
    configure_reporting_req_t          req;
    tsn_ctx_t                        * p_tsn_cli;
    zb_uint8_t                       * p_cmd_ptr;
    zb_ret_t                           zb_err_code;
    //zb_bool_t                          subscribe;
    zb_ieee_addr_t                     sensor_ieee_adr;

    NRF_LOG_INFO("----------------------------------------");
    NRF_LOG_INFO("Step 8: subscribe_device");


    req.profile_id   = ZB_AF_HA_PROFILE_ID;
    req.cluster_id   = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;    //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT; //
    req.attr_id      = ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
    req.attr_type    = ZB_ZCL_ATTR_TYPE_S16;                //ZB_ZCL_ATTR_TYPE_16BIT;

    req.interval_min = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL;
    req.interval_max = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL;

    req.remote_node.addr_short = m_device_ctx.bulb_params.short_address;
    req.remote_addr_mode       = ZB_APS_ADDR_MODE_16_ENDP_PRESENT;      //= parse_address(addr_buf, &req.remote_node, ADDR_ANY);
    req.remote_ep              = m_device_ctx.bulb_params.endpoint; 
    
    p_buf = ZB_GET_OUT_BUF();

    NRF_LOG_INFO("Configure Reporting");

    p_tsn_cli = get_free_tsn_ctx();
    if (!p_tsn_cli)
    {
        NRF_LOG_ERROR("Too many configure reporting requests");
        ZB_FREE_BUF(p_buf);
        return;
    }
   
    // Configure new tsn context.
    p_tsn_cli->taken = true;
    //p_tsn_cli->p_cli = p_cli;
    p_tsn_cli->tsn   = ZCL_CTX().seq_number;

    ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_SRV_REQ(p_buf, 
                                                    p_cmd_ptr, 
                                                    ZB_ZCL_ENABLE_DEFAULT_RESPONSE);

    ZB_ZCL_GENERAL_ADD_SEND_REPORT_CONFIGURE_REPORTING_REQ(p_cmd_ptr,
                                                           req.attr_id, 
                                                           req.attr_type, 
                                                           req.interval_min, 
                                                           req.interval_max,
                                                           ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE);

    ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(p_buf, 
                                                p_cmd_ptr,
                                                req.remote_node, 
                                                req.remote_addr_mode, 
                                                req.remote_ep, 
                                                m_device_ctx.co_params.endpoint, //CONTROLL_ENDPOINT
                                                req.profile_id, 
                                                req.cluster_id, 
                                                NULL);
    NRF_LOG_INFO("Report sended Waiting for Values");
    //zb_err_code = ZB_SCHEDULE_ALARM(zb_subscribe_timeout, p_tsn_cli->tsn, ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT * ZB_TIME_ONE_SECOND);
    if (zb_err_code != RET_OK)
    {
        NRF_LOG_ERROR("Unable to schedule timeout timer");
        invalidate_ctx(p_tsn_cli);
    }
    NRF_LOG_INFO("End");
}

3) Does it even need "cmd_zb_subscribe_unsubscribe_cb" and what is that unsubscribe for?

My problems:
1)  The "ep_handler_report" is not called, but I see in Wireshark that a Report Attributes has been sent?

Is there still something to change at the sensor, because there I have left everything as is.

My ep_handler_report Handler:

 
static zb_uint8_t ep_handler_report(zb_uint8_t param)
{
    NRF_LOG_INFO("Ep Handler Report");
    zb_buf_t            *  p_zcl_cmd_buf = (zb_buf_t *)ZB_BUF_FROM_REF(param);
    zb_zcl_parsed_hdr_t *  p_cmd_info    = ZB_GET_BUF_PARAM(p_zcl_cmd_buf, zb_zcl_parsed_hdr_t);
    tsn_ctx_t           *  p_tsn_ctx;

    if (p_cmd_info->cmd_id == ZB_ZCL_CMD_REPORT_ATTRIB)
    {
        NRF_LOG_INFO("print_attr");
        print_attr(p_cmd_info, param);
        ZB_FREE_BUF_BY_REF(param);
        return ZB_TRUE;
    }
    else if (p_cmd_info->cmd_id == ZB_ZCL_CMD_CONFIG_REPORT_RESP)
    {
        // Find command context by ZCL sequence number.
        p_tsn_ctx = get_ctx_by_tsn(p_cmd_info->seq_number);
        if (p_tsn_ctx != NULL)
        {

            NRF_LOG_WARNING("Unsubscribe cb");
            cmd_zb_subscribe_unsubscribe_cb(p_tsn_ctx, param);
            return ZB_TRUE;
        }
    }
    NRF_LOG_INFO("False Handler report");
    ZB_FREE_BUF_BY_REF(param);
    return ZB_FALSE;
}
  
/* Register callback for handling ZCL commands. */
ZB_AF_SET_ENDPOINT_HANDLER(m_device_ctx.bulb_params.endpoint, ep_handler_report);

The other functions as well as the output of the data I took from the CLI as well as from other discussions.

With the function "print_attr()" the data is output (Same function as with CLI), what am I doing wrong here with subscribe?

2) After a while the network crashes, any idea what this is? The Connected LED on the sensor goes out.

I would also be glad if you could give me a quick rundown on the process for subscribing to devices. If you want the whole code, I can share it with pleasure.

Thanks in advance. Slight smile

With kind regards

Jonas T

  • Hi Marte,

    It works for me even after commenting out the lines, thank you very much. I will also still look around the problem, if I can get it to work Rolling eyes. Yes, the network crashes after about 4 min.
    Then I will hear from you again regarding last answer. Thumbsup

    Again quick question: For me the Attributes report works even if I don't call Subscribe function, is that normal? 

    Thanks a lot and best regards
    Jonas T

  • Hi Marte,

    Good news Tada. I managed to subscribe to both clusters and output them afterwards. 
    The solution was to write the buffers according to the CLI Agent. (I have attached it in case you are interested Thumbsup)

    Attached is the Main.c Code for the coordinator to read a multi-sensor (....\examples\zigbee\experimental\multi_sensor) example. (Works, but can be improved)

     //----------------------------------------------------------------------------------------
     // ___               _             _            
     //|_ _|  _ _    __  | |  _  _   __| |  ___   ___
     // | |  | ' \  / _| | | | || | / _` | / -_) (_-<
     //|___| |_||_| \__| |_|  \_,_| \__,_| \___| /__/
                                                   
    #include "zboss_api.h"
    #include "zb_mem_config_max.h"
    #include "zb_error_handler.h"
    #include "zigbee_helpers.h"
    
    #include "app_timer.h"
    #include "boards.h"
    #include "bsp.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "nrf.h"
    #include "nrf_drv_gpiote.h"
    
     //----------------------------------------------------------------------------------------
     // ___           __   _              
     //|   \   ___   / _| (_)  _ _    ___ 
     //| |) | / -_) |  _| | | | ' \  / -_)
     //|___/  \___| |_|   |_| |_||_| \___|
    
    #ifdef  BOARD_PCA10059   
    #include "Hardware_Configuration.h"
    #define LED_ERROR     1
    #define LED_CONNECTED 2
    #define LED_JOINING   3
    
    #define PIN_SCHALTER          NRF_GPIO_PIN_MAP(1, 15)
    #define PIN_TASTER_RED        2
    #define PIN_TASTER_WITHE      NRF_GPIO_PIN_MAP(1, 13)
    #define PIN_TASTER_WITHE_BIG  29
    #else
    
    #endif
    
    #define ERASE_PERSISTENT_CONFIG             ZB_TRUE   // See join process       /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. NOTE: If this option is set to ZB_TRUE then do full device erase for all network devices before running other samples. */
    #define MAX_CHILDREN                        10                                  /**< The maximum amount of connected devices. Setting this value to 0 disables association to this device.  */
    #define IEEE_CHANNEL_MASK                   (1l << ZIGBEE_CHANNEL)              /**< Scan only one, predefined channel to find the coordinator. */
    
    #define MATCH_DESC_REQ_START_DELAY          (2 * ZB_TIME_ONE_SECOND)            /**< Delay between the light switch startup and light bulb finding procedure. */
    #define IEEE_ADDRESSS_REQ_DELAY             (2 * ZB_TIME_ONE_SECOND)            /**< Delay between MATCH_DESC_REQ and IEEE_ADDRESSS_REQ */
    #define BIND_REQ_DELAY                      (2 * ZB_TIME_ONE_SECOND)            /**< Delay between IEEE_ADDRESSS_REQ and BIND_REQ */
    // #define MATCH_DESC_REQ_TIMEOUT              (5 * ZB_TIME_ONE_SECOND)            /**< Timeout for finding procedure. */
    #define TIME_ONE_SECOND                     ZB_TIME_ONE_SECOND
    #define MATCH_DESC_REQ_ROLE                 ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE    /**< Find only non-sleepy device. */
    
    // (I have another Button input module for Dongle, but now i make it on PCA10056)
    #ifdef  BOARD_PCA10059                                                          /**< If it is Dongle */
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_0                       /**< LED indicating that network is opened for new nodes. */
    #define LIGHT_SWITCH_BUTTON_ON            PIN_TASTER_WITHE                      /**< Button ID used to switch on the light bulb. */
    #define LIGHT_SWITCH_BUTTON_OFF           PIN_TASTER_RED                        /**< Button ID used to switch off the light bulb. */
    #define ZIGBEE_NETWORK_REOPEN_BUTTON      PIN_TASTER_WITHE_BIG                  /**< Button which reopens the Zigbee Network. */
    #else
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_2                       /**< LED indicating that network is opened for new nodes. */
    #define BULB_FOUND_LED                    BSP_BOARD_LED_3                       /**< LED indicating that light witch found a light bulb to control. (LED Connected)*/
    #define ZIGBEE_NETWORK_REOPEN_BUTTON      BSP_BOARD_BUTTON_0                    /**< Button which reopens the Zigbee Network. */
    #define LIGHT_SWITCH_BUTTON_ON            BSP_BOARD_BUTTON_1                    /**< Button ID used to switch on the light bulb. */
    #define LIGHT_SWITCH_BUTTON_OFF           BSP_BOARD_BUTTON_2                    /**< Button ID used to switch off the light bulb. */
    #endif
    
    #define ZIGBEE_MANUAL_STEERING              ZB_FALSE                              /**< If set to 1 then device will not open the network after forming or reboot. */
    
    //#define LIGHT_SWITCH_BUTTON_THRESHOLD       ZB_TIME_ONE_SECOND                      /**< Number of beacon intervals the button should be pressed to dimm the light bulb. */
    //#define LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO  ZB_MILLISECONDS_TO_BEACON_INTERVAL(50)  /**< Delay between button state checks used in order to detect button long press. */
    //#define LIGHT_SWITCH_BUTTON_LONG_POLL_TMO   ZB_MILLISECONDS_TO_BEACON_INTERVAL(300) /**< Time after which the button state is checked again to detect button hold - the dimm command is sent again. */
    
    // Defines how long to wait, in seconds, for Configure Reporting Response.
    #define ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT     5
    // Defines how many report attribute requests can be run concurrently.
    #define ZIGBEE_CONFIGURE_REPORT_TSN                  3
    // Defines default value for minimum interval inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL 1
    // Defines default value for maximum interval inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL 60
    // Defines default value for minimum value change inside configure reporting request.
    #define ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE NULL
    
    #define SENSOR_LOGGER_ENDPOINT  12   // Valid Endpoint 1-254
    #define POWER_SOURCE            ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE
    
    #ifndef ZB_COORDINATOR_ROLE
    #error Define ZB_COORDINATOR_ROLE to compile coordinator source code.
    #endif
    
     //----------------------------------------------------------------------------------------
     //__   __               _          _      _            
     //\ \ / /  __ _   _ _  (_)  __ _  | |__  | |  ___   ___
     // \ V /  / _` | | '_| | | / _` | | '_ \ | | / -_) (_-<
     //  \_/   \__,_| |_|   |_| \__,_| |_.__/ |_| \___| /__/
    
    typedef struct _sensor_parameter_
    {
      zb_uint8_t              endpoint;
      zb_uint16_t             short_address;
      zb_bool_t               status;
      zb_bool_t               bind_cluster_1;
      zb_bool_t               bind_cluster_2;
      zb_ieee_addr_t          long_address;
    } sensor_parameter_t;
    
    typedef struct _sensor_logger_button_
    {
      zb_bool_t               button_pressed;
      zb_time_t               timestamp;
    } sensor_logger_button_t;
    
    typedef struct _sensor_logger_params_
    {
      //zb_uint8_t            endpoint;
      //zb_ieee_addr_t        long_address;
    } sensor_logger_params_t; 
                  
    typedef struct _coordinator_ctx_
    {
      sensor_parameter_t              sensor_params;
      sensor_logger_button_t          button;
      sensor_logger_params_t          co_params;
    } sensor_logger_ctx_t;                            //ctx = (Device) context
    
    typedef struct {
        zb_uint16_t   profile_id;
        zb_uint16_t   cluster_id;
        zb_uint16_t   attr_id;
        zb_uint8_t    attr_type;
        zb_uint16_t   interval_min;
        zb_uint16_t   interval_max;
        zb_addr_u     remote_node;
        addr_type_t   remote_addr_mode;
        zb_uint8_t    remote_ep;
    } configure_reporting_req_t;
    
    // This structure allows for binding ZBOSS transaction and CLI object.
    typedef struct {
        //nrf_cli_t const * p_cli;
        uint8_t             tsn;
        bool                taken;
        bool                is_broadcast;
    } tsn_ctx_t;
    
    static sensor_logger_ctx_t  m_device_ctx;
    static zb_uint8_t           m_attr_zcl_version    = ZB_ZCL_VERSION;
    static zb_uint8_t           m_attr_power_source   = POWER_SOURCE;
    static zb_uint16_t          m_attr_identify_time  = 0;
    static tsn_ctx_t m_tsn_ctx[ZIGBEE_CONFIGURE_REPORT_TSN];
    
     //----------------------------------------------------------------------------------------
     //  ___                 __   _                              _     _              
     // / __|  ___   _ _    / _| (_)  __ _   _  _   _ _   __ _  | |_  (_)  ___   _ _  
     //| (__  / _ \ | ' \  |  _| | | / _` | | || | | '_| / _` | |  _| | | / _ \ | ' \ 
     // \___| \___/ |_||_| |_|   |_| \__, |  \_,_| |_|   \__,_|  \__| |_| \___/ |_||_|
     //                              |___/                                            
    
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
    
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CLUSTER_LIST(co_controll_cluster,
                                                  basic_attr_list,
                                                  identify_attr_list);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_EP(co_controll_ep,
                                        SENSOR_LOGGER_ENDPOINT,
                                        co_controll_cluster);
    
    ZB_HA_DECLARE_CONFIGURATION_TOOL_CTX(co_controll_ctx, co_controll_ep);
    
     //----------------------------------------------------------------------------------------
     // ___                      _     _              
     //| __|  _  _   _ _    __  | |_  (_)  ___   _ _  
     //| _|  | || | | ' \  / _| |  _| | | / _ \ | ' \ 
     //|_|    \_,_| |_||_| \__|  \__| |_| \___/ |_||_|
    
    /**@brief Function for initializing the nrf log module.                                   
     */                                                                                       
    static void log_init(void)                                                                
    {                                                                                         
        ret_code_t err_code;
        
        err_code = NRF_LOG_INIT(NULL);                                             
        APP_ERROR_CHECK(err_code);                                                            
                                                                                              
        NRF_LOG_DEFAULT_BACKENDS_INIT();                                                      
    }                                                                                         
                                                                                              
    /**@brief Function for the Timer initialization.                                          
     *                                                                                        
     * @details Initializes the timer module. This creates and starts application timers.     
     */                                                                                       
    static void timers_init(void)                                                             
    {                                                                                         
        ret_code_t err_code;                                                                  
                                                                                              
        // Initialize timer module.                                                           
        err_code = app_timer_init();                                                          
        APP_ERROR_CHECK(err_code);                                                            
    }                                                                                         
    
    /**@brief Callback for button events. (ONLY FOR DONGLE)                          
     *                                                                                        
     * @param[in]   pin      Pin number
     * @param[in]   action   Pin action     
     */    
    #ifdef  BOARD_PCA10059
    static void button_interrup_handle(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        zb_ret_t            zb_err_code;
        zb_bool_t           comm_status;
        zb_uint32_t         button;
        bool send_command = false;
    
        switch (pin)
        {
            case PIN_TASTER_WITHE_BIG:
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                
                if (comm_status)
                {
                    NRF_LOG_INFO("Top level comissioning restated");
                }
                else
                {
                    NRF_LOG_INFO("Top level comissioning hasn't finished yet!");
                }
                break;
    
            case PIN_TASTER_WITHE:
                //button = LIGHT_SWITCH_BUTTON_ON;
                //send_command = true;
                break;
    
            case PIN_TASTER_RED:
                //button = LIGHT_SWITCH_BUTTON_OFF;
                //send_command = true;
                break;
            break;
    
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", pin);
                break;
        }
        //if (send_command)
        //{
        //    if (!m_device_ctx.button.button_pressed)
        //    {
        //         m_device_ctx.button.button_pressed = ZB_TRUE;
        //         m_device_ctx.button.timestamp = ZB_TIMER_GET();
    
        //         zb_err_code = ZB_SCHEDULE_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO);
        //         ZB_ERROR_CHECK(zb_err_code);
        //    }
        //}
    }
    
    
    static void gpio_init()
    {
        ret_code_t err_code;   
    
        err_code = nrf_drv_gpiote_init();
        APP_ERROR_CHECK(err_code);
    
    
        nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); // Falling edge interrupt deetection
        in_config.pull = NRF_GPIO_PIN_PULLUP;
    
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_WITHE_BIG, &in_config, button_interrup_handle); //Initialize the interrupt pin
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_WITHE, &in_config, button_interrup_handle);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_gpiote_in_init(PIN_TASTER_RED, &in_config, button_interrup_handle);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_WITHE_BIG, true); //Enable the interrupt events
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_WITHE, true);
        nrf_drv_gpiote_in_event_enable(PIN_TASTER_RED, true);
    }
    
    //https://www.youtube.com/watch?v=f1A2zWKo6Fk
    #else
    
    /**@brief Callback for button events. (PCA10056)                                                    
     *                                                                                        
     * @param[in]   evt      Incoming event from the BSP subsystem.                           
     */                                                                                       
    static void buttons_handler(bsp_event_t evt)
    {
        NRF_LOG_INFO("Button Pressed %d", evt);
        zb_ret_t            zb_err_code;
        zb_bool_t           comm_status;
        zb_uint32_t         button;
    
        bool send_command = false;
    
        switch(evt)
        {
            case BSP_EVENT_KEY_0:
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                
                if (comm_status)
                {
                    NRF_LOG_INFO("Top level comissioning restated");
                }
                else
                {
                    NRF_LOG_INFO("Top level comissioning hasn't finished yet!");
                }
                break;
    
            case BSP_EVENT_KEY_1:
                //button = LIGHT_SWITCH_BUTTON_ON;
                //send_command = true;
                break;
    
            case BSP_EVENT_KEY_2:
                //button = LIGHT_SWITCH_BUTTON_OFF;
                //send_command = true;
                break;
            case BSP_EVENT_KEY_3:
                NRF_LOG_INFO("Nothing declared Button 4");
                break;
            default:
                NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
                break;
        }
    }
    #endif
    
    /**@brief Function to convert data types                                                                    
     */      
    int zcl_attr_to_str(char * p_str_buf, uint16_t buf_len, zb_uint16_t attr_type, zb_uint8_t * p_attr)
    {
        //NRF_LOG_INFO("zcl_attr_to_str");
        int bytes_written = 0;
        int string_len;
        int i;
    
        if ((p_str_buf == NULL) || (p_attr == NULL))
        {
            return -1;
        }
    
        switch (attr_type)
        {
            /* Boolean */
            case ZB_ZCL_ATTR_TYPE_BOOL:
                bytes_written = snprintf(p_str_buf, buf_len, "%s", *((zb_bool_t *)p_attr) ? "True" : "False");
                break;
    
            /* 1 byte */
            case ZB_ZCL_ATTR_TYPE_8BIT:
            case ZB_ZCL_ATTR_TYPE_8BITMAP:
            case ZB_ZCL_ATTR_TYPE_U8:
            case ZB_ZCL_ATTR_TYPE_8BIT_ENUM:
                bytes_written = snprintf(p_str_buf, buf_len, "%hu", *((zb_uint8_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S8:
                bytes_written = snprintf(p_str_buf, buf_len, "%hd", *((zb_int8_t*)p_attr));
                break;
    
            /* 2 bytes */
            case ZB_ZCL_ATTR_TYPE_16BIT:
            case ZB_ZCL_ATTR_TYPE_16BITMAP:
            case ZB_ZCL_ATTR_TYPE_U16:
            case ZB_ZCL_ATTR_TYPE_16BIT_ENUM:
                bytes_written = snprintf(p_str_buf, buf_len, "%hu", *((zb_uint16_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S16:
                bytes_written = snprintf(p_str_buf, buf_len, "%hd", *((zb_int16_t*)p_attr));
                break;
    
            /* 4 bytes */
            case ZB_ZCL_ATTR_TYPE_32BIT:
            case ZB_ZCL_ATTR_TYPE_32BITMAP:
            case ZB_ZCL_ATTR_TYPE_U32:
                bytes_written = snprintf(p_str_buf, buf_len, "%u", *((zb_uint32_t*)p_attr));
                break;
    
            case ZB_ZCL_ATTR_TYPE_S32:
                bytes_written = snprintf(p_str_buf, buf_len, "%d", *((zb_int32_t*)p_attr));
                break;
    
            /* String */
            case ZB_ZCL_ATTR_TYPE_CHAR_STRING:
                string_len = p_attr[0];
                p_attr++;
    
                if ((buf_len - bytes_written) < (string_len + 1))
                {
                    return -1;
                }
    
                for (i = 0; i < string_len; i++)
                {
                    /*lint -save -e661 */
                    p_str_buf[bytes_written + i] = ((char *)p_attr)[i];
                    /*lint -restore */
                }
                p_str_buf[bytes_written + i] = '\0';
                bytes_written += string_len + 1;
                break;
    
            case ZB_ZCL_ATTR_TYPE_IEEE_ADDR:
                /*lint -e661 -e662 -save */
                bytes_written = to_hex_str(p_str_buf, buf_len, (const uint8_t *)p_attr, sizeof(zb_64bit_addr_t), true);
                /*lint -restore */
                break;
    
            default:
                bytes_written = snprintf(p_str_buf, buf_len, "Value type 0x%x unsupported", attr_type);
                break;
        }
    
        return bytes_written;
    }
    
    /**
     * @brief Return a pointer to context with the given transaction sequence number.
     *
     * @param[in] tsn ZBOSS transaction sequence number
     *
     * @return a pointer to context or NULL if context for given TSN wasn't found.
     */
    static tsn_ctx_t * get_ctx_by_tsn(uint8_t tsn)
    {
        NRF_LOG_INFO("get_ctx_by_tsn");
        for (uint8_t i = 0; i < ARRAY_SIZE(m_tsn_ctx); i++)
        {
            if ((m_tsn_ctx[i].taken == true) && (m_tsn_ctx[i].tsn == tsn))
            {
                return &m_tsn_ctx[i];
            }
        }
    
        return NULL;
    }
    
    /**
     * @brief Get a pointer to a free context.
     *
     * @return a pointer to context structure or NULL if all contexts are taken.
     */
    static tsn_ctx_t * get_free_tsn_ctx(void)
    {
        NRF_LOG_INFO("get_free_tsn_ctx");
        for (uint8_t i = 0; i < ARRAY_SIZE(m_tsn_ctx); i++)
        {
            if (!m_tsn_ctx[i].taken)
            {
                return &m_tsn_ctx[i];
            }
        }
    
        return NULL;
    }
    
    /**
     * Invalidate context.
     *
     * @param[in] p_tsn_ctx a pointer to transaction context.
     */
    static void invalidate_ctx(tsn_ctx_t * p_tsn_ctx)
    {
        p_tsn_ctx->taken = false;
        p_tsn_ctx->tsn   = 0xFF;
        //p_tsn_ctx->p_cli = NULL;
    }
    /*
    static zb_void_t zb_subscribe_timeout(zb_uint8_t param)
    {
        NRF_LOG_INFO("zb_subscribe_timeout");
        tsn_ctx_t * p_tsn_ctx = get_ctx_by_tsn(param);
    
        if (!p_tsn_ctx)
        {
            return;
        }
        invalidate_ctx(p_tsn_ctx);
    }*/
    /*
    static void cmd_zb_subscribe_unsubscribe_cb(tsn_ctx_t * p_tsn_ctx, zb_uint8_t param)
    {
        NRF_LOG_INFO("unsubscribe  callback ");
        
        zb_ret_t                           zb_err_code;
        zb_buf_t                         * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zcl_configure_reporting_res_t * p_resp = NULL;
        zb_bool_t                          failed = ZB_FALSE;
       
        zb_err_code = ZB_SCHEDULE_ALARM_CANCEL(zb_subscribe_timeout, ZB_ALARM_ANY_PARAM);
        if (zb_err_code != RET_OK)
        {
          //  print_error(p_tsn_ctx->p_cli, "Unable to cancel timeout timer");
          //  goto free_tsn_ctx;
    
           NRF_LOG_INFO("Unable to cancel timeout timer");
        }
    
        // Check if response contains only status code.
        if (sizeof(zb_zcl_configure_reporting_res_t) > ZB_BUF_LEN(p_buf))
        {
            p_resp = (zb_zcl_configure_reporting_res_t*)ZB_BUF_BEGIN(p_buf);
            if (p_resp->status == ZB_ZCL_STATUS_SUCCESS)
            {
              NRF_LOG_INFO("  reporting   is ok ");
            }
            else
            {
               NRF_LOG_INFO( "Error: Unable to configure reporting. Status: %d", p_resp->status);
            }
        }
        // Received a full Configure Reporting Response frame.
        ZB_ZCL_GENERAL_GET_NEXT_CONFIGURE_REPORTING_RES(p_buf, p_resp);
        if (p_resp == NULL)
        {
          NRF_LOG_INFO("Unable to parse configure reporting response");
        }
        while (p_resp != NULL)
        {
            if (p_resp->status == ZB_ZCL_STATUS_SUCCESS)
            {
                switch (p_resp->direction)
                {
                    case ZB_ZCL_CONFIGURE_REPORTING_SEND_REPORT:
                        NRF_LOG_INFO("Local subscription to attribute ID %hx updated\r\n",p_resp->attr_id);
                        break;
    
                    case ZB_ZCL_CONFIGURE_REPORTING_RECV_REPORT:
                        NRF_LOG_INFO( "Remote node subscription to receive attribute ID %hx updated\r\n",   p_resp->attr_id);
                        break;
    
                    default:
                        NRF_LOG_INFO( "Unknown reporting configuration direction for attribute %hx",p_resp->attr_id);
                        failed = ZB_TRUE;
                        break;
                }
            }
            else
            {
                NRF_LOG_INFO( "Unable to configure attribute %hx reporting. Status: %hd\r\n",  p_resp->attr_id, p_resp->status);
                failed = ZB_TRUE;
            }
            ZB_ZCL_GENERAL_GET_NEXT_CONFIGURE_REPORTING_RES(p_buf, p_resp);
        }
        if (failed == ZB_TRUE)
        {
            NRF_LOG_INFO("One or more attributes reporting were not configured successfully");
        }
    }*/
    
    static void print_attr(zb_zcl_parsed_hdr_t * p_zcl_hdr, zb_uint8_t param)
    {
        //NRF_LOG_INFO("Print Attr");
        zb_buf_t                 * p_buf         = ZB_BUF_FROM_REF(param);
        zb_zcl_report_attr_req_t * p_attr_resp   = NULL;
        int                        bytes_written = 0;
        char                       print_buf[255];
    
        if (p_zcl_hdr->addr_data.common_data.source.addr_type == ZB_ZCL_ADDR_TYPE_SHORT)
        {
            NRF_LOG_INFO( "Received value  node 0x%04x", p_zcl_hdr->addr_data.common_data.source.u.short_addr);
        }
    
        else
        {
            bytes_written = ieee_addr_to_str(print_buf, sizeof(print_buf), p_zcl_hdr->addr_data.common_data.source.u.ieee_addr);
            if (bytes_written < 0)
            {
               NRF_LOG_INFO( "Received value updates from the remote node (unknown address)");
            }
            else
            {
                NRF_LOG_INFO( "Received value updates from node 0x%s", nrf_log_push(print_buf));
            }
        }
        ZB_ZCL_GENERAL_GET_NEXT_REPORT_ATTR_REQ(p_buf, p_attr_resp);
    
        /*NRF_LOG_INFO("Profile: 0x%04x Cluster: 0x%04x Attribute: 0x%04x Type: %hu Valuesss: %s",
                      p_zcl_hdr->profile_id, 
                      p_zcl_hdr->cluster_id, 
                      p_attr_resp->attr_id,
                      p_attr_resp->attr_type, 
                      nrf_log_push(print_buf));*/
    
        bytes_written = 0;
    
        while (p_attr_resp != NULL)
        {
            bytes_written = zcl_attr_to_str(&print_buf[bytes_written],
                                            sizeof(print_buf) - bytes_written,
                                            p_attr_resp->attr_type,
                                            p_attr_resp->attr_value);
    
            if (bytes_written < 0)
            {
                NRF_LOG_ERROR("Unable to print updated attribute value");
            }
    
            else
            {
                NRF_LOG_INFO("Profile: 0x%04x Cluster: 0x%04x Attribute: 0x%04x Type: %hu Value: %s",
                              p_zcl_hdr->profile_id, 
                              p_zcl_hdr->cluster_id, 
                              p_attr_resp->attr_id,
                              p_attr_resp->attr_type, 
                              nrf_log_push(print_buf));
            }
            ZB_ZCL_GENERAL_GET_NEXT_REPORT_ATTR_REQ(p_buf, p_attr_resp);
        }
    }
    
    /**@brief The Handler to 'intercept' every frame coming to the endpoint
     *
     * @param param[in]  Reference to a ZBOSS buffer
     *
     * @returns ZB_TRUE if ZCL command was processed.
     */
    static zb_uint8_t ep_handler_report(zb_uint8_t param)
    {
        //NRF_LOG_INFO("Ep Handler Report");
        zb_buf_t            *  p_zcl_cmd_buf = (zb_buf_t *)ZB_BUF_FROM_REF(param);
        zb_zcl_parsed_hdr_t *  p_cmd_info    = ZB_GET_BUF_PARAM(p_zcl_cmd_buf, zb_zcl_parsed_hdr_t);
        //tsn_ctx_t           *  p_tsn_ctx;
    
        if (p_cmd_info->cmd_id == ZB_ZCL_CMD_REPORT_ATTRIB)
        {
            //NRF_LOG_INFO("print_attr");
            print_attr(p_cmd_info, param);
            ZB_FREE_BUF_BY_REF(param);
            return ZB_TRUE;
        }
        else if (p_cmd_info->cmd_id == ZB_ZCL_CMD_CONFIG_REPORT_RESP)
        {
            // Find command context by ZCL sequence number.
            /*p_tsn_ctx = get_ctx_by_tsn(p_cmd_info->seq_number);
            if (p_tsn_ctx != NULL)
            {
    
                NRF_LOG_WARNING("Unsubscribe cb");
                //cmd_zb_subscribe_unsubscribe_cb(p_tsn_ctx, param);
                return ZB_TRUE;
            }*/
        }
        NRF_LOG_INFO("False Handler report");
        ZB_FREE_BUF_BY_REF(param);
        return ZB_FALSE;
    }
    
     //----------------------------------------------------------------------------------------
     // _ _      ___          _                      _   _          
     //| | |    / __|  _  _  | |__   ___  __   _ _  (_) | |__   ___ 
     //|_  _|   \__ \ | || | | '_ \ (_-< / _| | '_| | | | '_ \ / -_)
     //  |_|    |___/  \_,_| |_.__/ /__/ \__| |_|   |_| |_.__/ \___|
                                                                  
    /*@brief Step 4: Send a subscribe request
     *
     * @param param[in]  Reference to a ZBOSS buffer
     *//*
    static void subscribe_device(zb_uint8_t param)
    {
        zb_buf_t                         * p_buf; //  = ZB_BUF_FROM_REF(param);
        configure_reporting_req_t          req;
        tsn_ctx_t                        * p_tsn_cli;
        zb_uint8_t                       * p_cmd_ptr;
        zb_ret_t                           zb_err_code;
        //zb_bool_t                          subscribe;
        zb_ieee_addr_t                     sensor_ieee_adr;
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 4: subscribe_device");
    
    
        req.profile_id   = ZB_AF_HA_PROFILE_ID;
        req.cluster_id   = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;    //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT; //
        req.attr_id      = ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID;
        req.attr_type    = ZB_ZCL_ATTR_TYPE_16BIT;                //ZB_ZCL_ATTR_TYPE_S16;
    
        req.interval_min = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MIN_INTERVAL;
        req.interval_max = ZIGBEE_CONFIGURE_REPORT_DEFAULT_MAX_INTERVAL;
    
        req.remote_node.addr_short = m_device_ctx.sensor_params.short_address;
        req.remote_addr_mode       = ZB_APS_ADDR_MODE_16_ENDP_PRESENT;      //= parse_address(addr_buf, &req.remote_node, ADDR_ANY);
        req.remote_ep              = m_device_ctx.sensor_params.endpoint; 
        
        //p_buf = ZB_GET_OUT_BUF();        <-------------
    
        NRF_LOG_INFO("Configure Reporting");
    
        p_tsn_cli = get_free_tsn_ctx();
        if (!p_tsn_cli)
        {
            NRF_LOG_ERROR("Too many configure reporting requests");
            ZB_FREE_BUF(p_buf);
            return;
        }
       
        // Configure new tsn context.
        p_tsn_cli->taken = true;
        //p_tsn_cli->p_cli = p_cli;
        p_tsn_cli->tsn   = ZCL_CTX().seq_number;
    
        ZB_ZCL_GENERAL_INIT_CONFIGURE_REPORTING_SRV_REQ(p_buf, 
                                                        p_cmd_ptr, 
                                                        ZB_ZCL_ENABLE_DEFAULT_RESPONSE);
    
        ZB_ZCL_GENERAL_ADD_SEND_REPORT_CONFIGURE_REPORTING_REQ(p_cmd_ptr,
                                                               req.attr_id, 
                                                               req.attr_type, 
                                                               req.interval_min, 
                                                               req.interval_max,
                                                               ZIGBEE_CONFIGURE_REPORT_DEFAULT_VALUE_CHANGE);
    
        ZB_ZCL_GENERAL_SEND_CONFIGURE_REPORTING_REQ(p_buf, 
                                                    p_cmd_ptr,
                                                    req.remote_node, 
                                                    req.remote_addr_mode, 
                                                    req.remote_ep, 
                                                    SENSOR_LOGGER_ENDPOINT, //CONTROLL_ENDPOINT
                                                    req.profile_id, 
                                                    req.cluster_id, 
                                                    NULL);
    
        NRF_LOG_INFO("Report sended Waiting for Values");
        //zb_err_code = ZB_SCHEDULE_ALARM(zb_subscribe_timeout, p_tsn_cli->tsn, ZIGBEE_CLI_CONFIGURE_REPORT_RESP_TIMEOUT * ZB_TIME_ONE_SECOND);
        if (zb_err_code != RET_OK)
        {
            NRF_LOG_ERROR("Unable to schedule timeout timer");
            invalidate_ctx(p_tsn_cli);
        }
        NRF_LOG_INFO("End");
    }*/
    
     //----------------------------------------------------------------------------------------
     //  ____    _      _             _ 
     // |__ /   | |__  (_)  _ _    __| |
     //  |_ \   | '_ \ | | | ' \  / _` |
     // |___/   |_.__/ |_| |_||_| \__,_|
    
    /*@brief A callback function for binding 
     *
     * @param[in]  index of buffer
     */
    
    static zb_void_t zb_bind_callback_pressure(zb_uint8_t param)
    {
    
        zb_buf_t           * p_buf  = (zb_buf_t*)ZB_BUF_FROM_REF(param);
        zb_zdo_bind_resp_t * p_resp = (zb_zdo_bind_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ret_t             zb_err_code;
    
        if (p_resp->status == ZB_ZDP_STATUS_SUCCESS)
        {	
            NRF_LOG_INFO("Bind successfully on Target Pressure: 0x%04x, Endpoint: %d, Cluster 0x%04x", m_device_ctx.sensor_params.short_address, m_device_ctx.sensor_params.endpoint, ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT);
            m_device_ctx.sensor_params.bind_cluster_2 = true;
            NRF_LOG_INFO("Temperature Measurement Cluster ID: 0x402");
            NRF_LOG_INFO("Pressure    Measurement Cluster ID: 0x403");
        }
        else
        {  
            NRF_LOG_WARNING("bind faild %d :(",p_resp->status);
        }
        ZB_FREE_BUF_BY_REF(param);	
    }
                         
    /*@brief Function send a binding request to pressure cluster ID
     *
     * @param[in]  index of buffer
     */
    static zb_void_t bind_device_pressure(void)
    {   
        zb_buf_t                  * p_buf;;
        zb_zdo_bind_req_param_t   * p_req;
        uint8_t			tsn;
        zb_ieee_addr_t              dst_ieee_addr;
        zb_ret_t                    zb_err_code;
        zb_osif_get_ieee_eui64(dst_ieee_addr);
    
        p_buf = ZB_GET_OUT_BUF();
        p_req = ZB_GET_BUF_PARAM(p_buf, zb_zdo_bind_req_param_t);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Try to bind Pressure");
    
        for (uint8_t i = 0; i < 8; i++)
        {
            p_req->src_address[i] = m_device_ctx.sensor_params.long_address[i];   //ieee address of sensor
            p_req->dst_address.addr_long[i] = dst_ieee_addr[i];                   //ieee address of coordinator
        }
    
        p_req->dst_addr_mode = ZB_APS_ADDR_MODE_64_ENDP_PRESENT;                  //ZB_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
    
        p_req->src_endp      = m_device_ctx.sensor_params.endpoint;               //endpoint of sensor
        p_req->dst_endp      = SENSOR_LOGGER_ENDPOINT;                            //endpoint of coordinator
    
        p_req->cluster_id    = ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;            //ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;
        p_req->req_dst_addr  = m_device_ctx.sensor_params.short_address;          //short address of sensor
    
        tsn = zb_zdo_bind_req(ZB_REF_FROM_BUF(p_buf), zb_bind_callback_pressure);
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_INFO("failed to send request, %d", tsn);
            ZB_FREE_BUF(p_buf);
        }
        return;
    }
    
    /*@brief A callback function for binding 
     *
     * @param[in]  index of buffer
     */
    static zb_void_t zb_bind_callback_temperature(zb_uint8_t param)
    {
    
        zb_buf_t           * p_buf  = ZB_BUF_FROM_REF(param);
        zb_zdo_bind_resp_t * p_resp = (zb_zdo_bind_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ret_t             zb_err_code;
    
        if (p_resp->status == ZB_ZDP_STATUS_SUCCESS)
        {	
            NRF_LOG_INFO("Bind successfully on Target Measurement: 0x%04x, Endpoint: %d, Cluster 0x%04x", m_device_ctx.sensor_params.short_address, m_device_ctx.sensor_params.endpoint, ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT);
            m_device_ctx.sensor_params.bind_cluster_1 = true;
            //subscribe_device(param);
        }
        else
        {  
            NRF_LOG_WARNING("bind faild %d :(",p_resp->status);
        }
        ZB_FREE_BUF_BY_REF(param);	
    }
                         
    /*@brief Step 3: Function send a binding request temperature cluster ID
     *
     * @param[in]  index of buffer
     */
    static zb_void_t bind_device_temperature(void)
    {   
        zb_buf_t                  * p_buf;
        zb_zdo_bind_req_param_t   * p_req;
        uint8_t			tsn;
        zb_ieee_addr_t              dst_ieee_addr;
        zb_ret_t                    zb_err_code;
        zb_osif_get_ieee_eui64(dst_ieee_addr);
    
        p_buf = ZB_GET_OUT_BUF();
        p_req = ZB_GET_BUF_PARAM(p_buf, zb_zdo_bind_req_param_t);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Try to bind Measurement");
    
        for (uint8_t i = 0; i < 8; i++)
        {
            p_req->src_address[i] = m_device_ctx.sensor_params.long_address[i];   //ieee address of sensor
            p_req->dst_address.addr_long[i] = dst_ieee_addr[i];                   //ieee address of coordinator
        }
    
        p_req->dst_addr_mode = ZB_APS_ADDR_MODE_64_ENDP_PRESENT;                  //ZB_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
    
        p_req->src_endp      = m_device_ctx.sensor_params.endpoint;               //endpoint of sensor
        p_req->dst_endp      = SENSOR_LOGGER_ENDPOINT;                            //endpoint of coordinator
    
        p_req->cluster_id    = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;                //ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;
        p_req->req_dst_addr  = m_device_ctx.sensor_params.short_address;          //short address of sensor
    
    /*
        //Enclosed the data are output again
        NRF_LOG_INFO("Long address of Sensor");  
        for (uint8_t i = 0; i < 8; i++)
        {
            NRF_LOG_INFO("src_address:    %hx", p_req->src_address[i]);
        }
        NRF_LOG_INFO("Long address of Coordinator");  
        for (uint8_t i = 0; i < 8; i++)
        {
            NRF_LOG_INFO("dst_address:    %hx", p_req->dst_address.addr_long[i]);
        }  
    
        NRF_LOG_INFO("dst_addr_mode:  %d", p_req->dst_addr_mode);
        NRF_LOG_INFO("src_endp:       %d", p_req->src_endp);
        NRF_LOG_INFO("dst_endp:       %d", p_req->dst_endp);
        NRF_LOG_INFO("cluster_id:     0x%04x", p_req->cluster_id);
        NRF_LOG_INFO("req_dst_addr:   0x%04x", p_req->req_dst_addr);
    */
        //----
        tsn = zb_zdo_bind_req(ZB_REF_FROM_BUF(p_buf), zb_bind_callback_temperature);
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_INFO("failed to send request, %d", tsn);
            ZB_FREE_BUF(p_buf);
        }
        return;
    }
    
     //----------------------------------------------------------------------------------------
     //  ___     _                                     _      _       
     // |_  )   (_)  ___   ___   ___         __ _   __| |  __| |  _ _ 
     //  / /    | | / -_) / -_) / -_)       / _` | / _` | / _` | | '_|
     // /___|   |_| \___| \___| \___|  ___  \__,_| \__,_| \__,_| |_|  
     //                               |___|                           
    
    /**@brief A callback function for EUI64 address response. Get tthe long Address from Sensor to create a binding request.
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    static zb_void_t ieee_addr_cb(uint8_t param)
    {
        zb_buf_t                   * p_buf        = ZB_BUF_FROM_REF(param);    
        zb_zdo_ieee_addr_resp_t    * p_resp       = (zb_zdo_ieee_addr_resp_t *)ZB_BUF_BEGIN(p_buf);
        zb_ieee_addr_t               ieee_addr;
        zb_uint16_t                  nwk_addr;
        zb_address_ieee_ref_t        addr_ref;
        zb_ret_t                     zb_err_code;
        zb_char_t                    addr_buf[8 * 2 + 1];  //   8 bytes (2 characters) plus one byte for null-terminator. 
    
        if (p_resp->status == ZB_ZDP_STATUS_SUCCESS)
        { 
            for (uint8_t i=0; i<8; i++)
            {
                m_device_ctx.sensor_params.long_address[i] = p_resp->ieee_addr_remote_dev[i];
            }
            UNUSED_RETURN_VALUE(ieee_addr_to_str(addr_buf, sizeof(addr_buf), p_resp->ieee_addr_remote_dev));
            NRF_LOG_INFO("Received EUI64 address for device 0x%04x -> %s.", m_device_ctx.sensor_params.short_address, NRF_LOG_PUSH(addr_buf));
            m_device_ctx.sensor_params.status = true;
        }
        else
        {
            NRF_LOG_WARNING("Unable to resolve EUI64 source address. Status: %d\r\n", p_resp->status);
        }
        ZB_FREE_BUF_BY_REF(param);
    }
    
    /**@brief STEP 2: Sending a EUI64 request
     *
     * @param[in] bufid     Reference number to ZBOSS memory buffer.
     */
    static zb_void_t zb_ieee_addr_req(zb_uint8_t param)
    {
        zb_buf_t               *p_buf;
        zb_zdo_ieee_addr_req_t *p_req;
        zb_uint8_t              tsn;
    
        p_buf = ZB_GET_OUT_BUF();
        ZB_BUF_INITIAL_ALLOC(p_buf, sizeof(zb_zdo_ieee_addr_req_t), p_req);
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 2: Send an EUI64 request: Device: 0x%04x, Endpoint: %d", m_device_ctx.sensor_params.short_address, m_device_ctx.sensor_params.endpoint);
        
        // Create new IEEE address request and fill with default values.
        p_req->start_index  = 0;
        p_req->request_type = 0;
        p_req->nwk_addr     = m_device_ctx.sensor_params.short_address;
    
        tsn = zb_zdo_ieee_addr_req(ZB_REF_FROM_BUF(p_buf), ieee_addr_cb);
        
        if (tsn == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_WARNING("Failed to send IEEE address request for address: 0x%04x, error code: %d", m_device_ctx.sensor_params.short_address, tsn);
            ZB_FREE_BUF(p_buf);
        }
    }
    
     //----------------------------------------------------------------------------------------
     //  _                    _          _               _                 
     // / |    _ __    __ _  | |_   __  | |_          __| |  ___   ___  __ 
     // | |   | '  \  / _` | |  _| / _| | ' \        / _` | / -_) (_-< / _|
     // |_|   |_|_|_| \__,_|  \__| \__| |_||_|  ___  \__,_| \___| /__/ \__|
     //                                        |___|             
               
    /**@brief A callback function for send match desc. Get the short Adress and the Endpoint number from Sensor.
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    static void cmd_zb_match_desc_cb(zb_uint8_t param)
    {
        zb_buf_t                   * p_buf       = ZB_BUF_FROM_REF(param);                               // Resolve buffer number to buffer address
        zb_zdo_match_desc_resp_t   * p_req       = (zb_zdo_match_desc_resp_t *)ZB_BUF_BEGIN(p_buf);      // Get the begining of the response
        zb_apsde_data_indication_t * p_ind       = ZB_GET_BUF_PARAM(p_buf, zb_apsde_data_indication_t);  // Get the pointer to the parameters buffer, which stores APS layer response
        zb_uint8_t                 * p_match_ep;   
        zb_ret_t                     zb_err_code;
    
        if ((p_req->status == ZB_ZDP_STATUS_SUCCESS) && (p_req->match_len > 0))
        {
            p_match_ep = (zb_uint8_t *)(p_req + 1);
    
            /* We are searching for exact cluster, so only 1 EP may be found */
            m_device_ctx.sensor_params.endpoint      = *p_match_ep;
            m_device_ctx.sensor_params.short_address =  p_ind->src_addr;
    
            /* Match EP list follows right after response header */
            NRF_LOG_INFO("Sensor found on Address: src_addr= %hx ep= %d", p_ind->src_addr, *p_match_ep);
            
            // Netzwerk constant
            zb_err_code = ZB_SCHEDULE_ALARM(zb_ieee_addr_req, param, IEEE_ADDRESSS_REQ_DELAY);
            APP_ERROR_CHECK(zb_err_code);
        }
        else
        {
            NRF_LOG_INFO("Error in callback");
        }
    
        ZB_FREE_BUF_BY_REF(param);
    }
    
    /**@brief STEP 1: Send match request to sensor
     *
     * @param[in] bufid Reference number to ZBOSS memory buffer.
     */
    void send_match_desc_req(zb_uint8_t param)
    {
        zb_buf_t                  *p_buf;
        zb_zdo_match_desc_param_t *p_req;
        zb_ret_t                   zb_err_code;                  
    
        p_buf = ZB_GET_OUT_BUF();
        ZB_BUF_INITIAL_ALLOC(p_buf, sizeof(*p_req), p_req);
    
        p_req->nwk_addr = ZB_NWK_BROADCAST_ALL_DEVICES;                   //send to coordinator
        p_req->addr_of_interest = p_req->nwk_addr;
        p_req->profile_id = ZB_AF_HA_PROFILE_ID;                          //0x0104;
        p_req->num_in_clusters = 2;
        p_req->num_out_clusters = 0;
        p_req->cluster_list[0] = ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT;      //0x0402;
        p_req->cluster_list[1] = ZB_ZCL_CLUSTER_ID_PRESSURE_MEASUREMENT;  //0x0403;
    
        NRF_LOG_INFO("----------------------------------------");
        NRF_LOG_INFO("Step 1: Send match request to sensor");
    
        zb_err_code = zb_zdo_match_desc_req(ZB_REF_FROM_BUF(p_buf), cmd_zb_match_desc_cb);
        if(zb_err_code == ZB_ZDO_INVALID_TSN)
        {
            NRF_LOG_ERROR("Failed send match request: %d", zb_err_code);
            ZB_FREE_BUF(p_buf);
        }
    }
    
    /**@brief Function for initializing LEDs and Buttons.
     */
    static void leds_buttons_init(void)
    {
    #ifdef  BOARD_PCA10056
        uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
        APP_ERROR_CHECK(err_code);
        /* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
    #else 
        bsp_board_init(BSP_INIT_LEDS);
    #endif
        bsp_board_leds_off();
    }
    
    /**@brief Callback used in order to visualise network steering period.
     *
     * @param[in]   param   Not used. Required by callback type definition.
     */
    static zb_void_t steering_finished(zb_uint8_t param)
    {
        UNUSED_PARAMETER(param);
        NRF_LOG_INFO("Network steering finished");
        bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #ifdef  BOARD_PCA10059
        LED(LED_JOINING, 0);
    #else
        bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
    }
    
    /**@brief Retry to form a Zigbee network. */
    static zb_void_t bdb_restart_top_level_commissioning(zb_uint8_t param)
    {
        UNUSED_RETURN_VALUE(bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING));
    }
    
     //----------------------------------------------------------------------------------------
     // ___   _                        _     _  _                    _   _             
     /// __| (_)  __ _   _ _    __ _  | |   | || |  __ _   _ _    __| | | |  ___   _ _ 
     //\__ \ | | / _` | | ' \  / _` | | |   | __ | / _` | | ' \  / _` | | | / -_) | '_|
     //|___/ |_| \__, | |_||_| \__,_| |_|   |_||_| \__,_| |_||_| \__,_| |_| \___| |_|  
     //          |___/                                                                 
    
    /**@brief ZigBee stack event handler.
     *
     * @param[in]   param   Reference to ZigBee stack buffer used to pass arguments (signal).
     */
    void zboss_signal_handler(zb_uint8_t param)
    {
        /* Read signal description out of memory buffer. */
        zb_zdo_app_signal_hdr_t * p_sg_p      = NULL;
        zb_zdo_app_signal_type_t  sig         = zb_get_app_signal(param, &p_sg_p);
        zb_ret_t                  status      = ZB_GET_APP_SIGNAL_STATUS(param);
        zb_buf_t                 *p_buf       = ZB_BUF_FROM_REF(param);
        zb_ret_t                  zb_err_code;
        zb_bool_t                 comm_status;
    
        switch(sig)
        {
            case ZB_ZDO_SIGNAL_SKIP_STARTUP:
                if (zb_bdb_is_factory_new())
                {
                    NRF_LOG_INFO("Start network steering & formation.");
                    comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING | ZB_BDB_NETWORK_FORMATION);
                    ZB_COMM_STATUS_CHECK(comm_status);
                }
                else
                {
                    comm_status = bdb_start_top_level_commissioning(ZB_BDB_INITIALIZATION);
                    ZB_COMM_STATUS_CHECK(comm_status);
                }
                break;
    
            case ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Device started and commissioned first time after NVRAM erase.
                if (status == RET_OK)
                {
                    if (ZIGBEE_MANUAL_STEERING == ZB_FALSE)
                    {
                        NRF_LOG_INFO("Start network steering.");
                        comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                        ZB_COMM_STATUS_CHECK(comm_status);
                    }
                }
                else
                {
                    NRF_LOG_ERROR("Failed to form network.");
                }
                break;
    
            case ZB_BDB_SIGNAL_DEVICE_REBOOT:      // BDB initialization completed after device reboot, use NVRAM contents during initialization. Device joined/rejoined and started.
                if (status != RET_OK)
                {
                    NRF_LOG_ERROR("Device startup failed. Status: %d. Retry network formation after 1 second.", status);
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 0);
    #else
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(bdb_restart_top_level_commissioning, 0, ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            case ZB_BDB_SIGNAL_STEERING:
                if (status == RET_OK)
                {
                    /* Schedule an alarm to notify about the end of steering period */
                    NRF_LOG_INFO("Network steering started");
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 1);
    #else
                    bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(steering_finished, 0, ZB_TIME_ONE_SECOND * ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                else
                {
                    NRF_LOG_INFO("Network steering failed to start. Status: %d. Retry network formation after 1 second.", status);
    #ifdef  BOARD_PCA10059
                    LED(LED_JOINING, 0);
    #else
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    #endif
                    zb_err_code = ZB_SCHEDULE_ALARM(bdb_restart_top_level_commissioning, 0, ZB_TIME_ONE_SECOND);
                    ZB_ERROR_CHECK(zb_err_code);
                }
                break;
    
            case ZB_ZDO_SIGNAL_DEVICE_ANNCE:
                {
                    zb_zdo_signal_device_annce_params_t * dev_annce_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_device_annce_params_t);
                    NRF_LOG_INFO("Device with a short address 0x%04x commissionned", dev_annce_params->device_short_addr);
    
                     /* Check the device address */
                    if (m_device_ctx.sensor_params.short_address == 0xFFFF)
                    {
                          zb_err_code = ZB_SCHEDULE_ALARM(send_match_desc_req, param, MATCH_DESC_REQ_START_DELAY);
                          ZB_ERROR_CHECK(zb_err_code);
                    }
                }
                break;
    
            case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
                if (status != RET_OK)
                {
                    NRF_LOG_WARNING("Production config is not present or invalid");
                }
                break;
    
            case ZB_ZDO_SIGNAL_DEVICE_UPDATE:
                {
                    char ieee_addr_buf[17] = {0};
                    zb_zdo_signal_device_update_params_t * p_update_params;
                    p_update_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_device_update_params_t);
                    UNUSED_RETURN_VALUE(ieee_addr_to_str(ieee_addr_buf, sizeof(ieee_addr_buf), p_update_params->long_addr));//p_update_params->long_addr));
                    NRF_LOG_INFO("(Safety Check) Device has updated its status in the network, short address: 0x%04x, long address: %s, status: %d",
                                  p_update_params->short_addr, 
                                  NRF_LOG_PUSH(ieee_addr_buf), 
                                  p_update_params->status);
                }
                break;
    
            default:
                /* Unhandled signal. For more information see: zb_zdo_app_signal_type_e and zb_ret_e */
                NRF_LOG_INFO("Unhandled signal %d. Status: %d", sig, status);
                break;
        }
    
        /* All callbacks should either reuse or free passed buffers. If param == 0, the buffer is invalid (not passed) */
        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
    
     //----------------------------------------------------------------------------------------
     // __  __          _        
     //|  \/  |  __ _  (_)  _ _  
     //| |\/| | / _` | | | | ' \ 
     //|_|  |_| \__,_| |_| |_||_|
                               
    /**@brief Function for application main entry.
     */
    int main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
        // Initialize.
        timers_init();
        log_init();
        #ifdef  BOARD_PCA10059
         // Harware_init(); 
          gpio_init();
        #else
          leds_buttons_init(); 
        #endif
    
        /* Set ZigBee stack logging level and traffic dump subsystem. */
        ZB_SET_TRACE_LEVEL(ZIGBEE_TRACE_LEVEL);
        ZB_SET_TRACE_MASK(ZIGBEE_TRACE_MASK);
        ZB_SET_TRAF_DUMP_OFF();
    
        /* Initialize ZigBee stack. */
        ZB_INIT("Sensor logger");
    
        /* Set device address to the value read from FICR registers. */
        zb_osif_get_ieee_eui64(ieee_addr);
        zb_set_long_address(ieee_addr);
    
        /* Set channels on which the coordinator will try to create a new network. */
        zb_set_network_coordinator_role(IEEE_CHANNEL_MASK);
        zb_set_max_children(MAX_CHILDREN);
    
        zb_set_ed_timeout(ED_AGING_TIMEOUT_64MIN);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
    
        /* Initialize application context structure. */
        UNUSED_RETURN_VALUE(ZB_MEMSET(&m_device_ctx, 0, sizeof(sensor_logger_ctx_t)));
        /* Set default sensor short_addr. */
        m_device_ctx.sensor_params.short_address = 0xFFFF;
    
        /* Register dimmer switch device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&co_controll_ctx);
    
        /* Register callback for handling ZCL commands. */
        ZB_AF_SET_ENDPOINT_HANDLER(SENSOR_LOGGER_ENDPOINT, ep_handler_report);
    
        /* Keep or erase NVRAM to save the network parameters after device reboot or power-off. */
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
    
        /** Start Zigbee Stack. */
        if (ZIGBEE_MANUAL_STEERING == ZB_TRUE)
        {
            zb_err_code = zboss_start_no_autostart();
        }
        else
        {
            zb_err_code = zboss_start();
        }
    
        ZB_ERROR_CHECK(zb_err_code);
        NRF_LOG_INFO("Starting While Loop");
    
    
        // Vairabels for go only ONE trought binding function. 
        zb_bool_t val = false;
        zb_bool_t val2 = false;
        m_device_ctx.sensor_params.status = false;
        m_device_ctx.sensor_params.bind_cluster_1 = false;
        m_device_ctx.sensor_params.bind_cluster_2 = false;
    
        while(1)
        {
            zboss_main_loop_iteration();
            UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
    
            if(m_device_ctx.sensor_params.status && !val)
            {
                bind_device_temperature();
                val = true;
            }
            if(m_device_ctx.sensor_params.bind_cluster_1 && !val2)
            {
                bind_device_pressure();
                val2 = true;
            }
        }
    }
    
    
    /**
     * @}
     */
    

    On the sensor side, I have of course replaced the two measured (temperature and pressure) values by potentiometers. If someone needs the code for this, please contact me.

    Thank you, Marte, for answering the questions.

    Best regards,

    Jonas T

Related