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

Zigbee Attribute request and response

Hi and happy new year everyone,

I am a developer for Raytheon Anschütz GmbH in Kiel Germany and working on a Zigbee mesh sensor network. Unfortunately I am an absolute beginner for Zigbee and have a lot of basic questions I can not figure out the the documentation. 

My goal is to provide temperature and voltage level from a router to the coordinator. The coordinator should request the values within an interval. 

I took the Zigbee light switch example as a base and included the temp_measurement zcl for the router. What I understood from the zcl documentation a general attribute request is needed to receive the values. 

I created a readTemp() function where I set up the read attribute request according to the documentation here https://www.nordicsemi.com/DocLib/Content/SDK_Doc/Thread_SDK/v2-0-0/group__read__attr__command

Unfortunately I am not sure if I did everything correct as I do not receive any data. For example I do not understand what the cmd_ptr. is for. Should I fill it or is it filled the the response. Did I call the ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT_SERVER_ROLE_INIT()  and ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT_CLIENT_ROLE_INIT(), correctly?

For the el_measurement zcl I wonder how to add the DC_Volt attribute to the attribute list as the Makro ZB_ZCL_DECLARE_ELECTRICAL_MEASUREMENT_ATTRIB_LIST contains only the measurement_type and dcpower attribute. 

I attached the code for the router and coordinator and hope you can help me with a simple request as I am stucked and do not know how I can solve it on my own. 

Thank you in advance for your help. 

Best regards

Marco Runge

/**
 * Copyright (c) 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.
 *
 */
/** @file
 *
 * @defgroup zigbee_examples_light_coordinator main.c
 * @{
 * @ingroup zigbee_examples
 * @brief Simple ZigBee network coordinator implementation.
 */

#include "nrf.h"
#include "nrfx_timer.h"
#include "bsp.h"
#include "app_error.h"

#include "zboss_api.h"
#include "zboss_api_zdo.h"

#include "zb_mem_config_max.h"
#include "zb_error_handler.h"

#include "boards.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "zb_zcl_temp_measurement.h"

#define ERASE_PERSISTENT_CONFIG           ZB_FALSE                              /**< 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 ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_2                       /**< LED indicating that network is opened for new nodes. */

#define BMS_TEMP_ENDPOINT                 1                                   /**< Source endpoint used to control light bulb. */

#define TEMP_FOUND_LED                      BSP_BOARD_LED_3                     /**< LED indicating that light witch found a light bulb to control. */
#define MATCH_DESC_REQ_ROLE                 ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE    /**< Find only non-sleepy device. */
#define MATCH_DESC_REQ_START_DELAY          (2 * ZB_TIME_ONE_SECOND)            /**< Delay between the light switch startup and light bulb finding procedure. */


const nrfx_timer_t TIMER = NRFX_TIMER_INSTANCE(0);

uint16_t devList[500] = {0};
static uint16_t iter = 0;

static zb_void_t zcl_device_cb(zb_uint8_t param);
void readTemp();

#ifndef ZB_COORDINATOR_ROLE
#error Define ZB_COORDINATOR_ROLE to compile coordinator source code.
#endif

// temp measurement cluster attributes
typedef struct
{
  zb_int16_t value;
  zb_int16_t min_value;
  zb_int16_t max_value;
  zb_uint16_t tolerance;
} bms_temp_attr_t;

typedef struct temp_sensor_params_s
{
  zb_uint8_t  endpoint;
  zb_uint16_t short_addr;
} temp_sensor_params_t;

typedef struct bms_sensor_ctx_s
{
  temp_sensor_params_t sensor_params;
  bms_temp_attr_t temp_attr;
} bms_sensor_ctx_t;

static bms_sensor_ctx_t m_device_ctx;

/**
 * @brief Handler for timer events.
 */
void timer_event_handler(nrf_timer_event_t event_type, void* p_context)
{
    switch (event_type)
    {
        case NRF_TIMER_EVENT_COMPARE0:
              if(devList[0] != 0)
                readTemp();
            break;

        default:
            //Do nothing.
            break;
    }
}
static zb_void_t send_cb(zb_uint8_t param);

//void readTemp(zb_uint8_t param)
void readTemp()
{
    NRF_LOG_INFO("read Temp...\n\r");

    zb_buf_t * p_buf;

    zb_uint8_t *cmd_ptr = NULL;

    ZB_ZCL_GENERAL_INIT_READ_ATTR_REQ(p_buf, cmd_ptr, ZB_ZCL_ENABLE_DEFAULT_RESPONSE);

    ZB_ZCL_GENERAL_ADD_ID_READ_ATTR_REQ(cmd_ptr, ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID);

    ZB_ZCL_GENERAL_SEND_READ_ATTR_REQ(p_buf,
                                      cmd_ptr,
                                      devList[0],
                                      ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
                                      1,
                                      BMS_TEMP_ENDPOINT,
                                      ZB_AF_HA_PROFILE_ID,
                                      ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT,
                                      send_cb);

    
    zb_buf_t *buf;
    zb_zcl_read_attr_res_t *read_attr_resp;

    ZB_ZCL_GENERAL_GET_NEXT_READ_ATTR_RES(buf, read_attr_resp);


     NRF_LOG_INFO("cmd = %d", *cmd_ptr);
     NRF_LOG_INFO("buf = %d", *(int16_t*)buf->buf);
    
}

/**@brief Function for initializing the nrf log module.
 */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}

/**@brief Function for initializing LEDs.
 */
static void leds_init(void)
{
    bsp_board_init(BSP_INIT_LEDS);
}

/**@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);
}

/**@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 Add device to device list on join */
//void simple_gw_dev_annce_cb(uint16_t addr)
//{
//  NRF_LOG_INFO("addr = %d\r\n", addr);
//  devList[iter] = addr;
//  iter++;
//  int i = 0;
//  while(devList[i] != 0)
//  {
//    NRF_LOG_INFO("devList[%d] = %d\r\n", i, devList[i]);
//    i++;
//  }
//}

static zb_void_t send_cb(zb_uint8_t param)
{
    NRF_LOG_INFO("Send CB");
}

/**@brief Callback function for handling ZCL commands.
 *
 * @param[in]   param   Reference to ZigBee stack buffer used to pass received data.
 */
static zb_void_t zcl_device_cb(zb_uint8_t param)
{
    NRF_LOG_INFO("zcl_device_cb");
   
    zb_uint8_t                       cluster_id;
    zb_uint8_t                       attr_id;
    zb_buf_t                       * p_buffer = ZB_BUF_FROM_REF(param);
    zb_zcl_device_callback_param_t * p_device_cb_param = ZB_GET_BUF_PARAM(p_buffer, zb_zcl_device_callback_param_t);

    NRF_LOG_INFO("zcl_device_cb id %hd", p_device_cb_param->device_cb_id);

    /* Set default response value. */
    p_device_cb_param->status = RET_OK;
    NRF_LOG_INFO("device_cb_id: %d", p_device_cb_param->device_cb_id);

    switch (p_device_cb_param->device_cb_id)
    {
        case ZB_ZCL_SHADE_GET_VALUE_CB_ID:
            cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
            attr_id    = p_device_cb_param->cb_param.set_attr_value_param.attr_id;
            NRF_LOG_INFO("cluster_id: %d", cluster_id);
            NRF_LOG_INFO("attr_id: %d", attr_id);
            switch (attr_id)
            {
              case ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID:
                NRF_LOG_INFO("Get temp value: %d", attr_id);
              break;
              case ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID:
                NRF_LOG_INFO("Get bat volt value: %d", attr_id);
              break;
              default:
                NRF_LOG_INFO("Unhandled cluster attribute id: %d", cluster_id);
              break;
            }
        break;
        case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
            cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
            attr_id    = p_device_cb_param->cb_param.set_attr_value_param.attr_id;

            if (cluster_id == ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT)
            {
                uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;

                NRF_LOG_INFO("attribute id %d", attr_id);
                if (attr_id == ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID)
                {
                    NRF_LOG_INFO("Get temp value: %d", value);
                }
            }
        default:
            p_device_cb_param->status = RET_ERROR;
            break;
    }

    NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
}

/**@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_type_t sig = zb_get_app_signal(param, NULL);
    zb_ret_t                 status = ZB_GET_APP_SIGNAL_STATUS(param);
    zb_ret_t                 zb_err_code;
    zb_bool_t                comm_status;

    NRF_LOG_INFO("signal %d. Status: %d", sig, status);

    switch(sig)
    {
        case ZB_BDB_SIGNAL_DEVICE_FIRST_START: // Device started and commissioned first time after NVRAM erase.
        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_INFO("Device started OK. Start network steering.");
                bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);
                comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                ZB_COMM_STATUS_CHECK(comm_status);
            }
            else
            {
                NRF_LOG_ERROR("Device startup failed. Status: %d. Retry network formation after 1 second.", status);
                bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
                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)
            {
                memset(devList, 0, sizeof(devList));
                /* Schedule an alarm to notify about the end of steering period */
                NRF_LOG_INFO("Network steering started");
                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);
                bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
                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_PRODUCTION_CONFIG_READY:
            if (status != RET_OK)
            {
                NRF_LOG_WARNING("Production config is not present or invalid");
            }
            break;
        case ZB_ZDO_SIGNAL_DEVICE_ANNCE:
        {
             NRF_LOG_INFO("JOIND! \r\n");
              zb_buf_t                    * p_buf = ZB_BUF_FROM_REF(param);
              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
             devList[iter] = p_ind->src_addr;
             NRF_LOG_INFO("Addr = 0x%02x\r\n", devList[iter]);
//             zb_err_code = ZB_SCHEDULE_CALLBACK(readTemp, param);
//              ZB_ERROR_CHECK(zb_err_code);
              param = 0; // Do not free buffer - it will be reused by find_light_bulb callback
   
              nrfx_timer_enable(&TIMER);

            iter++;
         }
         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)
{
    uint32_t time_ms = 500; //Time(in miliseconds) between consecutive compare events.
    uint32_t time_ticks;
    uint32_t err_code = NRF_SUCCESS;

    zb_ret_t       zb_err_code;
    zb_ieee_addr_t ieee_addr;

    // Initialize.
    log_init();
    leds_init();
 
    /* 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. Pass "zdo_zc" to the stack logging system. */
    ZB_INIT("zdo_zc");

    /* 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);

    /* Keep or erase NVRAM to save the network parameters after device reboot or power-off. */
    zb_set_nvram_erase_at_start(ERASE_PERSISTENT_CONFIG);

    /* Register callback for handling ZCL commands. */
    ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);

    ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT_CLIENT_ROLE_INIT();

    /** Start Zigbee Stack. */
    zb_err_code = zboss_start();
    ZB_ERROR_CHECK(zb_err_code);

    nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
    err_code = nrfx_timer_init(&TIMER, &timer_cfg, timer_event_handler);
    APP_ERROR_CHECK(err_code);

    time_ticks = nrfx_timer_ms_to_ticks(&TIMER, time_ms);

    nrfx_timer_extended_compare( &TIMER,
                                    NRF_TIMER_CC_CHANNEL0,
                                    time_ticks, 
                                    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                    true);

    while(1)
    {
        zboss_main_loop_iteration();
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
    }
}


/**
 * @}
 */
/**
 * Copyright (c) 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.
 *
 */
/** @file
 *
 */

#include "zboss_api.h"
#include "zb_mem_config_med.h"
#include "zb_error_handler.h"
#include "zb_nrf52840_internal.h"

#include "zboss_api_zcl.h"
#include "zb_zcl_power_config.h"
#include "zb_zcl_el_measurement.h"
#include "zb_zcl_temp_measurement.h"

#include "boards.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"


#define ZB_HA_DEFINE_DEVICE_TEMPERATURE_SENSOR

#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 ERASE_PERSISTENT_CONFIG           ZB_FALSE                              /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. */

/* Basic cluster attributes initial values. */
#define BMS_INIT_BASIC_APP_VERSION       01                                    /**< Version of the application software (1 byte). */
#define BMS_INIT_BASIC_STACK_VERSION     30                                    /**< Version of the implementation of the ZigBee stack (1 byte). */
#define BMS_INIT_BASIC_HW_VERSION        11                                    /**< Version of the hardware of the device (1 byte). */
#define BMS_INIT_BASIC_MANUF_NAME        "RAn"                              /**< Manufacturer name (32 bytes). */
#define BMS_INIT_BASIC_MODEL_ID          "BMS_v0.1"                  /**< Model number assigned by manufacturer (32-bytes long string). */
#define BMS_INIT_BASIC_DATE_CODE         "20181216"                            /**< First 8 bytes specify the date of manufacturer of the device in ISO 8601 format (YYYYMMDD). Th rest (8 bytes) are manufacturer specific. */
#define BMS_INIT_BASIC_POWER_SOURCE      ZB_ZCL_BASIC_POWER_SOURCE_BATTERY   /**< Type of power sources available for the device. For possible values see section 3.2.2.2.8 of ZCL specification. */
#define BMS_INIT_BASIC_LOCATION_DESC     "Battery Room"                         /**< Describes the physical location of the device (16 bytes). May be modified during commisioning process. */
#define BMS_INIT_BASIC_PH_ENV            ZB_ZCL_BASIC_ENV_UNSPECIFIED          /**< Describes the type of physical environment. For possible values see section 3.2.2.2.10 of ZCL specification. */

// Default values
#define BMS_TEMP_MIN_VALUE_DEG    0
#define BMS_TEMP_MAX_VALUE_DEG   8000
#define BMS_TEMP_TOL_VALUE_DEG   2

// Device Endpoints
#define HA_TEMP_SENSOR_ENDPOINT    1                                    /**< Device endpoint, used to receive light controlling commands. */

// LED 
#define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_2                       /**< LED indicating that light switch successfully joind ZigBee network. */
#define ZIGBEE_TRANSFER_LED               BSP_BOARD_LED_1                       /**< LED indicating that light switch successfully joind ZigBee network. */

#if !defined ZB_ROUTER_ROLE
#error Define ZB_ROUTER_ROLE to compile light BMS (Router) source code.
#endif


// Basic cluster attributes
typedef struct
{
    zb_uint8_t zcl_version;
    zb_uint8_t app_version;
    zb_uint8_t stack_version;
    zb_uint8_t hw_version;
    zb_char_t  mf_name[32];
    zb_char_t  model_id[32];
    zb_char_t  date_code[16];
    zb_uint8_t power_source;
    zb_char_t  location_id[17];
    zb_uint8_t ph_env;
} bms_basic_attr_t;

// Identify cluster attributes
typedef struct
{
  zb_uint16_t identify_time;
  zb_uint8_t  commission_state;
} bms_identify_attr_t;

// temp measurement cluster attributes
typedef struct
{
  zb_int16_t value;
  zb_int16_t min_value;
  zb_int16_t max_value;
  zb_uint16_t tolerance;
} bms_temp_attr_t;

// Main application customizable context. Stores all settings and static values
typedef struct
{
    bms_basic_attr_t        bms_basic_attr;
    bms_identify_attr_t     bms_identify_attr;
    bms_temp_attr_t         bms_temp_attr;
} bms_ctx_t;

static bms_ctx_t m_bms_dev_ctx;

// Declare Attribute Lists
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_HA_ADDS_FULL(basic_attr_list,
                                              &m_bms_dev_ctx.bms_basic_attr.zcl_version,
                                              &m_bms_dev_ctx.bms_basic_attr.app_version,
                                              &m_bms_dev_ctx.bms_basic_attr.stack_version,
                                              &m_bms_dev_ctx.bms_basic_attr.hw_version,
                                              &m_bms_dev_ctx.bms_basic_attr.mf_name,
                                              &m_bms_dev_ctx.bms_basic_attr.model_id,
                                              &m_bms_dev_ctx.bms_basic_attr.date_code,
                                              &m_bms_dev_ctx.bms_basic_attr.power_source,
                                              &m_bms_dev_ctx.bms_basic_attr.location_id,
                                              &m_bms_dev_ctx.bms_basic_attr.ph_env);

ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST_HA(identify_attr_list,
                                       &m_bms_dev_ctx.bms_identify_attr.identify_time,
                                       &m_bms_dev_ctx.bms_identify_attr.commission_state);

ZB_ZCL_DECLARE_TEMP_MEASUREMENT_ATTRIB_LIST(temp_attr_list,
                                            &m_bms_dev_ctx.bms_temp_attr.value,
                                            &m_bms_dev_ctx.bms_temp_attr.min_value,
                                            &m_bms_dev_ctx.bms_temp_attr.max_value,
                                            &m_bms_dev_ctx.bms_temp_attr.tolerance);

// Declare Cluster Lists
ZB_HA_DECLARE_TEMPERATURE_SENSOR_CLUSTER_LIST(temp_sensor_clusters,
                                              basic_attr_list,
                                              identify_attr_list,
                                              temp_attr_list);
// Declare Endpoints
ZB_HA_DECLARE_TEMPERATURE_SENSOR_EP(bms_temp_ep,
                                    HA_TEMP_SENSOR_ENDPOINT,
                                    temp_sensor_clusters);

// Declare Device Contexts
ZB_HA_DECLARE_TEMPERATURE_SENSOR_CTX(bms_temp_ctx, bms_temp_ep);


/**@brief Function for initializing the nrf log module.
 */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);
    NRF_LOG_DEFAULT_BACKENDS_INIT();
}

/**@brief Function for setting temperature.
  *
  * @param[in]   new_level   Light bulb brightness value.
 */
static void temp_set_value(zb_int16_t new_temp)
{
    m_bms_dev_ctx.bms_temp_attr.value = new_temp;

    NRF_LOG_INFO("Set new temp value: %i", new_temp);
}

/**@brief Function for initializing all clusters attributes.
 */
static void bms_clusters_attr_init(void)
{
    // Basic cluster attr init
    m_bms_dev_ctx.bms_basic_attr.zcl_version   = ZB_ZCL_VERSION;
    m_bms_dev_ctx.bms_basic_attr.app_version   = BMS_INIT_BASIC_APP_VERSION;
    m_bms_dev_ctx.bms_basic_attr.stack_version = BMS_INIT_BASIC_STACK_VERSION;
    m_bms_dev_ctx.bms_basic_attr.hw_version    = BMS_INIT_BASIC_HW_VERSION;

    /* Use ZB_ZCL_SET_STRING_VAL to set strings, because the first byte should
     * contain string length without trailing zero.
     *
     * For example "test" string wil be encoded as:
     *   [(0x4), 't', 'e', 's', 't']
     */
    ZB_ZCL_SET_STRING_VAL(m_bms_dev_ctx.bms_basic_attr.mf_name,
                          BMS_INIT_BASIC_MANUF_NAME,
                          ZB_ZCL_STRING_CONST_SIZE(BMS_INIT_BASIC_MANUF_NAME));

    ZB_ZCL_SET_STRING_VAL(m_bms_dev_ctx.bms_basic_attr.model_id,
                          BMS_INIT_BASIC_MODEL_ID,
                          ZB_ZCL_STRING_CONST_SIZE(BMS_INIT_BASIC_MODEL_ID));

    ZB_ZCL_SET_STRING_VAL(m_bms_dev_ctx.bms_basic_attr.date_code,
                          BMS_INIT_BASIC_DATE_CODE,
                          ZB_ZCL_STRING_CONST_SIZE(BMS_INIT_BASIC_DATE_CODE));

    m_bms_dev_ctx.bms_basic_attr.power_source = BMS_INIT_BASIC_POWER_SOURCE;

    ZB_ZCL_SET_STRING_VAL(m_bms_dev_ctx.bms_basic_attr.location_id,
                          BMS_INIT_BASIC_LOCATION_DESC,
                          ZB_ZCL_STRING_CONST_SIZE(BMS_INIT_BASIC_LOCATION_DESC));


    m_bms_dev_ctx.bms_basic_attr.ph_env = BMS_INIT_BASIC_PH_ENV;

    // Identify cluster attributes init
    m_bms_dev_ctx.bms_identify_attr.identify_time    = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;
    m_bms_dev_ctx.bms_identify_attr.commission_state = ZB_ZCL_ATTR_IDENTIFY_COMMISSION_STATE_HA_ID_DEF_VALUE;

    // Temp cluster attr init
    m_bms_dev_ctx.bms_temp_attr.value = 0;
    m_bms_dev_ctx.bms_temp_attr.min_value = BMS_TEMP_MIN_VALUE_DEG;
    m_bms_dev_ctx.bms_temp_attr.max_value = BMS_TEMP_MAX_VALUE_DEG;
    m_bms_dev_ctx.bms_temp_attr.tolerance = BMS_TEMP_TOL_VALUE_DEG;
}

/**@brief Function which tries to sleep down the MCU 
 *
 * Function which sleeps the MCU on the non-sleepy End Devices to optimize the power saving.
 * The weak definition inside the OSIF layer provides some minimal working template
 */
zb_void_t zb_osif_go_idle(zb_void_t)
{
    /* A check that we're not a Sleep End Device -- they sleep elsewhere */
    if (ZB_PIBCACHE_RX_ON_WHEN_IDLE())
    {
        //TODO: implement your own logic if needed
        if (NRF_LOG_PROCESS() == false)
        {
            zb_osif_wait_for_event();
        }
    }
}

/**@brief Callback function for handling ZCL commands.
 *
 * @param[in]   param   Reference to ZigBee stack buffer used to pass received data.
 */
static zb_callback_t zcl_device_cb(zb_uint8_t param)
{
    NRF_LOG_INFO("device_cb");

    zb_uint8_t                       cluster_id;
    zb_uint8_t                       attr_id;
    zb_buf_t                       * p_buffer = ZB_BUF_FROM_REF(param);
    zb_zcl_device_callback_param_t * p_device_cb_param = ZB_GET_BUF_PARAM(p_buffer, zb_zcl_device_callback_param_t);

    /* Set default response value. */
    p_device_cb_param->status = RET_OK;

    NRF_LOG_INFO("device_cb_id: %d", p_device_cb_param->device_cb_id);

    switch (p_device_cb_param->device_cb_id)
    {
        case ZB_ZCL_SHADE_GET_VALUE_CB_ID:
        {
            cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
            attr_id    = p_device_cb_param->cb_param.set_attr_value_param.attr_id;
            NRF_LOG_INFO("cluster_id: %d", cluster_id);
            NRF_LOG_INFO("attr_id: %d", attr_id);
            switch (cluster_id)
            {
              case ZB_ZCL_ATTR_TEMP_MEASUREMENT_VALUE_ID:
                NRF_LOG_INFO("Get temp value: %d", attr_id);
              break;
              case ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID:
                NRF_LOG_INFO("Get bat volt value: %d", attr_id);
              break;
              default:
                NRF_LOG_INFO("Unhandled cluster attribute id: %d", cluster_id);
              break;
            }
        }
        break;
        default:
           p_device_cb_param->status = RET_ERROR;
            break;
    }

    NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
}

zb_device_handler_t zcl_endpoint_cb(zb_uint8_t param)
{
    NRF_LOG_INFO("endpoint_cb");  
}

/**@brief Perform local operation - leave network.
 *
 * @param[in]   param   Reference to ZigBee stack buffer that will be used to construct leave request.
 */
static void leave_nwk(zb_uint8_t param)
{
    zb_ret_t zb_err_code;

    /* We are going to leave */
    if (param)
    {
        zb_buf_t                  * p_buf = ZB_BUF_FROM_REF(param);
        zb_zdo_mgmt_leave_param_t * p_req_param;

        p_req_param = ZB_GET_BUF_PARAM(p_buf, zb_zdo_mgmt_leave_param_t);
        UNUSED_RETURN_VALUE(ZB_BZERO(p_req_param, sizeof(zb_zdo_mgmt_leave_param_t)));

        /* Set dst_addr == local address for local leave */
        p_req_param->dst_addr = ZB_PIBCACHE_NETWORK_ADDRESS();
        p_req_param->rejoin   = ZB_FALSE;
        UNUSED_RETURN_VALUE(zdo_mgmt_leave_req(param, NULL));
    }
    else
    {
        zb_err_code = ZB_GET_OUT_BUF_DELAYED(leave_nwk);
        ZB_ERROR_CHECK(zb_err_code);
    }
}

/**@brief Function for starting join/rejoin procedure.
 *
 * param[in]   leave_type   Type of leave request (with or without rejoin).
 */
static zb_void_t retry_join(zb_uint8_t leave_type)
{
    zb_bool_t comm_status;

    if (leave_type == ZB_NWK_LEAVE_TYPE_RESET)
    {
        comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
        ZB_COMM_STATUS_CHECK(comm_status);
    }
}

/**@brief Function for leaving current network and starting join procedure afterwards.
 *
 * @param[in]   param   Optional reference to ZigBee stack buffer to be reused by leave and join procedure.
 */
static zb_void_t leave_and_join(zb_uint8_t param)
{
    if (ZB_JOINED())
    {
        /* Leave network. Joining procedure will be initiated inisde ZigBee stack signal handler. */
        leave_nwk(param);
    }
    else
    {
        /* Already left network. Start joining procedure. */
        retry_join(ZB_NWK_LEAVE_TYPE_RESET);

        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
}

/**@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)
{
    zb_zdo_app_signal_hdr_t      * p_sg_p         = NULL;
    zb_zdo_signal_leave_params_t * p_leave_params = NULL;
    zb_zdo_app_signal_type_t sig    = zb_get_app_signal(param, NULL);
    zb_ret_t                 status = ZB_GET_APP_SIGNAL_STATUS(param);
    zb_ret_t                 zb_err_code;

    switch (sig)
    {
        case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
        case ZB_BDB_SIGNAL_DEVICE_REBOOT:
            if (status == RET_OK)
            {
                NRF_LOG_INFO("Joined network successfully");
                bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);
            }
            else
            {
                NRF_LOG_ERROR("Failed to join network. Status: %d", status);
                bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
                zb_err_code = ZB_SCHEDULE_ALARM(leave_and_join, 0, ZB_TIME_ONE_SECOND);
                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_LEAVE:
            if (status == RET_OK)
            {
                bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
                p_leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_leave_params_t);
                NRF_LOG_INFO("Network left. Leave type: %d", p_leave_params->leave_type);
                retry_join(p_leave_params->leave_type);
            }
            else
            {
                NRF_LOG_ERROR("Unable to leave network. Status: %d", status);
            }
            break;
        case ZB_ZDO_SIGNAL_DEVICE_ANNCE:
        {
            zb_buf_t                    * p_buf = ZB_BUF_FROM_REF(param);
            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
           NRF_LOG_INFO("Joined at Addr = 0x02%x\r\n", p_ind->src_addr);
            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;
    }

    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 loging system and GPIOs. */
    log_init();
    /* Initialize LEDs */
    bsp_board_init(BSP_INIT_LEDS);
    bsp_board_leds_off();

    /* 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("bms_router");

    /* Set device address to the value read from FICR registers. */
    zb_osif_get_ieee_eui64(ieee_addr);
    zb_set_long_address(ieee_addr);

    /* Set static long IEEE address. */
    zb_set_network_router_role(IEEE_CHANNEL_MASK);
    zb_set_nvram_erase_at_start(ERASE_PERSISTENT_CONFIG);

   zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));

    /* Initialize application context structure. */
    UNUSED_RETURN_VALUE(ZB_MEMSET(&m_bms_dev_ctx, 0, sizeof(m_bms_dev_ctx)));
    
    bms_clusters_attr_init();
 
    /* Register device context (endpoints). */
    ZB_AF_REGISTER_DEVICE_CTX(&bms_temp_ctx);

   /* Register callback for handling ZCL commands. */
    ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);

    ZB_AF_SET_ENDPOINT_HANDLER(HA_TEMP_SENSOR_ENDPOINT, zcl_endpoint_cb);

    ZB_ZCL_CLUSTER_ID_TEMP_MEASUREMENT_SERVER_ROLE_INIT();
 
    temp_set_value(1234);

    /** Start Zigbee Stack. */
    zb_err_code = zboss_start();
    ZB_ERROR_CHECK(zb_err_code);

    while(1)
    {
        zboss_main_loop_iteration();
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
    }
}
/**
 * @}
 */

Related