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