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

  • Hello,

    I am sorry for the late reply. I will try to run your projects today, and see if I can figure out what is missing.

    Best regards,

    Edvin

  • Hello Marco,

    I am sorry. I am not able to compile your projects, and it seems like it is because of something you either have in your project settings, or something you have in some other files, but I am not sure what files that would be.

    Is it possible to send both of these projects, so that I can run a test? 

    Is it correct that it is the ZigBee coordinator that you are trying to poll the data to from the sensor/server?

  • Hi Edvin,

    Thank you for your effort. I attached a projects dir that should reside in the top level of the SDK, next to examples. The coordinator, router and enddevice folders are based on the light_bulb_switch zigbee example.

    You are right. The coordinator should request sensor data from the router. I tried the the temp_measurement first but need to read voltage levels as well.

    Best regards

    Marco8765.projects.zip 

  • Hello Marco,

    sorry for the late reply. I am working on this. I haven't actually tried to set up a "custom" cluster in ZigBee before, and the lack of a proper gateway is making it a bit difficult. I am waiting for some hardware to act as a BLE to ZigBee gateway. If you intend to do development, I recommend this. Thus, you can set up a zigbee network, connect the temperature sensor that you are developing, and then use a ZigBee app to check the sensor values, just to make sure that the sensor is set up correctly. 

    I will keep this ticket open until I have a better answer to you.

    Best regards,

    Edvin

  • Hello Marco,

    I am sorry that this has taken so long. I am still waiting for the response from our ZigBee team. I received an email last week saying that they will look into it this week, so hopefully I will have an answer for you soon. I just wanted you to know that this ticket is not forgotten.

    Best regards,

    Edvin

Related