Hello, Nordic developers.
The ZED, ZR and ZC connections were identified by the example of Zigbee Light Control example.
Based on this example, we are going to develop a ZED bulb because we think we can control it with ZC without ZR.
First, the zigbee_light_switch sdk was ported to the ZC for the required functions and variables in the main.
The results succeeded in controlling the bulb of the ZED using only ZC.
What I want to do here is to send a payload to ZC on whether ZED received it well when sending a payload on/off light bulb to ZED (e.g., ACK).
But it's not being delivered properly to the ZC.
I'll tell you what I've tried.
1. Use ZB_ZCL_ON_OFF_SEND_REQ.
I tried to send a Payload from ZED to ZC just as I sent a Payload to control ZED's light bulb from ZC, but the moment the function was called, ZED's service was interrupted.
ZC send code
static zb_void_t light_switch_send_on_off(zb_bufid_t bufid, zb_uint16_t on_off)
{
zb_uint8_t cmd_id;
if (on_off)
{
cmd_id = ZB_ZCL_CMD_ON_OFF_ON_ID;
}
else
{
cmd_id = ZB_ZCL_CMD_ON_OFF_OFF_ID;
}
ZB_ZCL_ON_OFF_SEND_REQ(bufid,
m_device_ctx.bulb_params.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
m_device_ctx.bulb_params.endpoint,
0,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
cmd_id,
NULL);
}
When transmitted from ZC, ZED calls up handler zcl_device_cb stored in "ZB_ZCL_REGER_DEVICE_CB" to control the bulb.
This handler tried to send it to ZC after processing, but the service was interrupted.
light_bulb code
static zb_void_t zcl_device_cb(zb_bufid_t *bufid)
{
zb_uint8_t cluster_id;
zb_uint8_t attr_id;
zb_zcl_device_callback_param_t * p_device_cb_param = ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
/* SEND TEST 11-25 */
switch (p_device_cb_param->device_cb_id)
{
case ZB_ZCL_LEVEL_CONTROL_SET_VALUE_CB_ID:
NRF_LOG_INFO("Level control setting to %d", p_device_cb_param->cb_param.level_control_set_value_param.new_value);
level_control_set_value(p_device_cb_param->cb_param.level_control_set_value_param.new_value);
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_ON_OFF)
{
uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
//NRF_LOG_INFO("--------------------------> [TEST]on/off attribute setting to %hd", value);
NRF_LOG_INFO("on/off attribute setting to %hd", value);
if (attr_id == ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID)
{
on_off_set_value((zb_bool_t) value);
}
}
else if (cluster_id == ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL)
{
uint16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
NRF_LOG_INFO("level control attribute setting to %hd", value);
if (attr_id == ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID)
{
level_control_set_value(value);
}
}
else
{
/* Other clusters can be processed here */
NRF_LOG_INFO("Unhandled cluster attribute id: %d", cluster_id);
}
break;
default:
p_device_cb_param->status = RET_ERROR;
break;
}
NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
//bulb_ctx.short_addr,
ZB_ZCL_ON_OFF_SEND_REQ(bufid,
bulb_ctx.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
bulb_ctx.endpoint,
10,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
ZB_ZCL_CMD_ON_OFF_ON_ID,
NULL);
}
One of the parameters at the bottom of the code is (bulb ctx)short_addr = 0xffff, and (bulb ctx) used 0 or 64. (ZB_ZCL_ON_OFF_SEND_REQ)
2. ZED has also tried the "match desc" function.
light_bulb full code.
/**
* Copyright (c) 2018 - 2020, 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_bulb main.c
* @{
* @ingroup zigbee_examples
* @brief Dimmable light sample (HA profile)
*/
#include "sdk_config.h"
#include "zboss_api.h"
#include "zboss_api_addons.h"
#include "zb_mem_config_med.h"
#include "zb_ha_dimmable_light.h"
#include "zb_error_handler.h"
#include "zb_nrf52_internal.h"
#include "zigbee_helpers.h"
#include "bsp.h"
#include "boards.h"
#include "app_pwm.h"
#include "app_timer.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "drv_ws2812.h"
#include "zb_zcl_messaging.h"
//#include "bulb_st.h"
//#include "bulb_st.h"
#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 HA_DIMMABLE_LIGHT_ENDPOINT 10 /**< Device endpoint, used to receive light controlling commands. */
#define ERASE_PERSISTENT_CONFIG ZB_FALSE /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. */
#define BULB_PWM_NAME PWM1 /**< PWM instance used to drive dimmable light bulb. */
#define BULB_PWM_TIMER 2 /**< Timer number used by PWM. */
/* Basic cluster attributes initial values. */
#define BULB_INIT_BASIC_APP_VERSION 01 /**< Version of the application software (1 byte). */
#define BULB_INIT_BASIC_STACK_VERSION 10 /**< Version of the implementation of the Zigbee stack (1 byte). */
#define BULB_INIT_BASIC_HW_VERSION 11 /**< Version of the hardware of the device (1 byte). */
#define BULB_INIT_BASIC_MANUF_NAME "Nordic" /**< Manufacturer name (32 bytes). */
#define BULB_INIT_BASIC_MODEL_ID "Dimable_Light_v0.1" /**< Model number assigned by manufacturer (32-bytes long string). */
#define BULB_INIT_BASIC_DATE_CODE "20180416" /**< First 8 bytes specify the date of manufacturer of the device in ISO 8601 format (YYYYMMDD). The rest (8 bytes) are manufacturer specific. */
#define BULB_INIT_BASIC_POWER_SOURCE ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE /**< Type of power sources available for the device. For possible values see section 3.2.2.2.8 of ZCL specification. */
#define BULB_INIT_BASIC_LOCATION_DESC "Office desk" /**< Describes the physical location of the device (16 bytes). May be modified during commisioning process. */
#define BULB_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. */
#ifdef BOARD_PCA10059 /**< If it is Dongle */
#define IDENTIFY_MODE_BSP_EVT BSP_EVENT_KEY_0 /**< Button event used to enter the Bulb into the Identify mode. */
#define ZIGBEE_NETWORK_STATE_LED BSP_BOARD_LED_0 /**< LED indicating that light switch successfully joind Zigbee network. */
#else
#define IDENTIFY_MODE_BSP_EVT BSP_EVENT_KEY_3 /**< Button event used to enter the Bulb into the Identify mode. */
#define ZIGBEE_NETWORK_STATE_LED BSP_BOARD_LED_2 /**< LED indicating that light switch successfully joind Zigbee network. */
#endif
#define BULB_LED BSP_BOARD_LED_3 /**< LED immitaing dimmable light bulb. */
#if (APP_BULB_USE_WS2812_LED_CHAIN)
#define LED_CHAIN_DOUT_PIN NRF_GPIO_PIN_MAP(1,7) /**< GPIO pin used as DOUT (to be connected to DIN pin of the first ws2812 led in chain) */
#endif
#define MATCH_DESC_REQ_START_DELAY (2 * ZB_TIME_ONE_SECOND) /**< Delay between the light switch startup and light bulb finding procedure. */
#define MATCH_DESC_REQ_TIMEOUT (5 * ZB_TIME_ONE_SECOND) /**< Timeout for finding procedure. */
#define ERASR_PERSENT_CONFIG ZB_FALSE
/* Declare endpoint for Dimmable Light device with scenes. */
#define ZB_HA_DECLARE_LIGHT_EP(ep_name, ep_id, cluster_list) \
ZB_ZCL_DECLARE_HA_DIMMABLE_LIGHT_SIMPLE_DESC(ep_name, ep_id, \
ZB_HA_DIMMABLE_LIGHT_IN_CLUSTER_NUM, ZB_HA_DIMMABLE_LIGHT_OUT_CLUSTER_NUM); \
ZBOSS_DEVICE_DECLARE_REPORTING_CTX(reporting_info## device_ctx_name, \
ZB_HA_DIMMABLE_LIGHT_REPORT_ATTR_COUNT); \
ZBOSS_DEVICE_DECLARE_LEVEL_CONTROL_CTX(cvc_alarm_info## device_ctx_name, \
ZB_HA_DIMMABLE_LIGHT_CVC_ATTR_COUNT); \
ZB_AF_DECLARE_ENDPOINT_DESC(ep_name, ep_id, ZB_AF_HA_PROFILE_ID, \
0, \
NULL, \
ZB_ZCL_ARRAY_SIZE(cluster_list, zb_zcl_cluster_desc_t),\
cluster_list, \
(zb_af_simple_desc_1_1_t*)&simple_desc_##ep_name, \
ZB_HA_DIMMABLE_LIGHT_REPORT_ATTR_COUNT, \
reporting_info## device_ctx_name, \
ZB_HA_DIMMABLE_LIGHT_CVC_ATTR_COUNT, \
cvc_alarm_info## device_ctx_name)
#if !defined ZB_ROUTER_ROLE
#error Define ZB_ROUTER_ROLE to compile light bulb (Router) source code.
#endif
/* Main application customizable context. Stores all settings and static values. */
typedef struct
{
zb_zcl_basic_attrs_ext_t basic_attr;
zb_zcl_identify_attrs_t identify_attr;
zb_zcl_scenes_attrs_t scenes_attr;
zb_zcl_groups_attrs_t groups_attr;
zb_zcl_on_off_attrs_ext_t on_off_attr;
zb_zcl_level_control_attrs_t level_control_attr;
} bulb_device_ctx_t;
/* BULB TEST */
typedef struct light_bulb_params_s
{
zb_uint8_t endpoint;
zb_uint16_t short_addr;
} light_bulb_params_t;
/* BULB TEST END */
APP_PWM_INSTANCE(BULB_PWM_NAME, BULB_PWM_TIMER);
static bulb_device_ctx_t m_dev_ctx;
static light_bulb_params_t bulb_ctx;
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_dev_ctx.identify_attr.identify_time);
ZB_ZCL_DECLARE_GROUPS_ATTRIB_LIST(groups_attr_list, &m_dev_ctx.groups_attr.name_support);
ZB_ZCL_DECLARE_SCENES_ATTRIB_LIST(scenes_attr_list,
&m_dev_ctx.scenes_attr.scene_count,
&m_dev_ctx.scenes_attr.current_scene,
&m_dev_ctx.scenes_attr.current_group,
&m_dev_ctx.scenes_attr.scene_valid,
&m_dev_ctx.scenes_attr.name_support);
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(basic_attr_list,
&m_dev_ctx.basic_attr.zcl_version,
&m_dev_ctx.basic_attr.app_version,
&m_dev_ctx.basic_attr.stack_version,
&m_dev_ctx.basic_attr.hw_version,
m_dev_ctx.basic_attr.mf_name,
m_dev_ctx.basic_attr.model_id,
m_dev_ctx.basic_attr.date_code,
&m_dev_ctx.basic_attr.power_source,
m_dev_ctx.basic_attr.location_id,
&m_dev_ctx.basic_attr.ph_env,
m_dev_ctx.basic_attr.sw_ver);
/* On/Off cluster attributes additions data */
ZB_ZCL_DECLARE_ON_OFF_ATTRIB_LIST_EXT(on_off_attr_list,
&m_dev_ctx.on_off_attr.on_off,
&m_dev_ctx.on_off_attr.global_scene_ctrl,
&m_dev_ctx.on_off_attr.on_time,
&m_dev_ctx.on_off_attr.off_wait_time);
ZB_ZCL_DECLARE_LEVEL_CONTROL_ATTRIB_LIST(level_control_attr_list,
&m_dev_ctx.level_control_attr.current_level,
&m_dev_ctx.level_control_attr.remaining_time);
ZB_HA_DECLARE_DIMMABLE_LIGHT_CLUSTER_LIST(dimmable_light_clusters,
basic_attr_list,
identify_attr_list,
groups_attr_list,
scenes_attr_list,
on_off_attr_list,
level_control_attr_list);
ZB_HA_DECLARE_LIGHT_EP(dimmable_light_ep,
HA_DIMMABLE_LIGHT_ENDPOINT,
dimmable_light_clusters);
ZB_HA_DECLARE_DIMMABLE_LIGHT_CTX(dimmable_light_ctx,
dimmable_light_ep);
#if (APP_BULB_USE_WS2812_LED_CHAIN)
/**@brief Timer responsible for triggering periodic led chain refresh */
APP_TIMER_DEF(m_ws2812_refresh_timer);
/* ECDH TEST */
static void print_array(uint8_t const * p_string, size_t size)
{
#if NRF_LOG_ENABLED
size_t i;
NRF_LOG_RAW_INFO(" ");
for(i = 0; i < size; i++)
{
NRF_LOG_RAW_INFO("%02x", p_string[i]);
}
#endif // NRF_LOG_ENABLED
}
static void print_hex(char const * p_msg, uint8_t const * p_data, size_t size)
{
NRF_LOG_INFO(p_msg);
print_array(p_data, size);
NRF_LOG_RAW_INFO("\r\n");
}
/* ECDH TEST END */
static zb_void_t find_coordinator_timeout(zb_bufid_t bufid);
/** @brief Requests a led chain refresh */
static volatile bool m_ws2812_refresh_request;
#endif
/**@brief Function for initializing the application timer.
*/
static void timer_init(void)
{
uint32_t error_code = app_timer_init();
APP_ERROR_CHECK(error_code);
}
/**@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 Sets brightness of on-board LED
*
* @param[in] brightness_level Brightness level, allowed values 0 ... 255, 0 - turn off, 255 - full brightness
*/
static void light_bulb_onboard_set_brightness(zb_uint8_t brightness_level)
{
app_pwm_duty_t app_pwm_duty;
/* Scale level value: APP_PWM uses 0-100 scale, but Zigbee level control cluster uses values from 0 up to 255. */
app_pwm_duty = (brightness_level * 100U) / 255U;
/* Set the duty cycle - keep trying until PWM is ready. */
while (app_pwm_channel_duty_set(&BULB_PWM_NAME, 0, app_pwm_duty) == NRF_ERROR_BUSY)
{
}
}
#if (APP_BULB_USE_WS2812_LED_CHAIN)
/**@brief Sets brightness of ws2812 led chain
*
* @param[in] brightness_level Brightness level, allowed values 0 ... 255, 0 - turn off, 255 - full brightness
*/
static void light_bulb_ws2812_chain_set_brightness(zb_uint8_t brightness_level)
{
uint32_t color;
/* Decrease brightness just to save your eyes. LEDs can be very bright */
if (brightness_level >= 2U)
{
brightness_level /= 2U;
}
color = ((uint32_t)brightness_level << 16); /* Red component */
color |= ((uint32_t)brightness_level << 8); /* Green component */
color |= (uint32_t)brightness_level; /* Blue component */
drv_ws2812_set_pixel_all(color);
/* Main loop will take care of refreshing led chain */
m_ws2812_refresh_request = true;
}
#endif
/**@brief Sets brightness of bulb luminous executive element
*
* @param[in] brightness_level Brightness level, allowed values 0 ... 255, 0 - turn off, 255 - full brightness
*/
static void light_bulb_set_brightness(zb_uint8_t brightness_level)
{
light_bulb_onboard_set_brightness(brightness_level);
#if (APP_BULB_USE_WS2812_LED_CHAIN)
light_bulb_ws2812_chain_set_brightness(brightness_level);
#endif
}
/**@brief Function for setting the light bulb brightness.
*
* @param[in] new_level Light bulb brightness value.
*/
static void level_control_set_value(zb_uint16_t new_level)
{
NRF_LOG_INFO("Set level value: %i", new_level);
ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,
ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL,
ZB_ZCL_CLUSTER_SERVER_ROLE,
ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID,
(zb_uint8_t *)&new_level,
ZB_FALSE);
/* According to the table 7.3 of Home Automation Profile Specification v 1.2 rev 29, chapter 7.1.3. */
if (new_level == 0)
{
zb_uint8_t value = ZB_FALSE;
ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,
ZB_ZCL_CLUSTER_ID_ON_OFF,
ZB_ZCL_CLUSTER_SERVER_ROLE,
ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
&value,
ZB_FALSE);
}
else
{
zb_uint8_t value = ZB_TRUE;
ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,
ZB_ZCL_CLUSTER_ID_ON_OFF,
ZB_ZCL_CLUSTER_SERVER_ROLE,
ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
&value,
ZB_FALSE);
}
light_bulb_set_brightness(new_level);
}
/**@brief Function for turning ON/OFF the light bulb.
*
* @param[in] on Boolean light bulb state.
*/
static void on_off_set_value(zb_bool_t on)
{
NRF_LOG_INFO("Set ON/OFF value: %i", on);
//zb_aps_send_user_payload(
ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,
ZB_ZCL_CLUSTER_ID_ON_OFF,
ZB_ZCL_CLUSTER_SERVER_ROLE,
ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
(zb_uint8_t *)&on,
ZB_FALSE);
if (on)
{
level_control_set_value(m_dev_ctx.level_control_attr.current_level);
}
else
{
NRF_LOG_INFO("Light off\n");
/*
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
NRF_LOG_INFO("Hello\n");
*/
light_bulb_set_brightness(0U);
}
}
/**@brief Callback for button events.
*
* @param[in] evt Incoming event from the BSP subsystem.
*/
static void buttons_handler(bsp_event_t evt)
{
zb_ret_t zb_err_code;
switch(evt)
{
case IDENTIFY_MODE_BSP_EVT:
/* Check if endpoint is in identifying mode, if not put desired endpoint in identifying mode. */
if (m_dev_ctx.identify_attr.identify_time == ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE)
{
NRF_LOG_INFO("Bulb put in identifying mode");
zb_err_code = zb_bdb_finding_binding_target(HA_DIMMABLE_LIGHT_ENDPOINT);
ZB_ERROR_CHECK(zb_err_code);
}
else
{
NRF_LOG_INFO("Cancel F&B target procedure");
zb_bdb_finding_binding_target_cancel();
}
break;
default:
NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
break;
}
}
/**@brief Function for initializing LEDs and a single PWM channel.
*/
static void leds_buttons_init(void)
{
ret_code_t err_code;
app_pwm_config_t pwm_cfg = APP_PWM_DEFAULT_CONFIG_1CH(5000L, bsp_board_led_idx_to_pin(BULB_LED));
/* Initialize all LEDs and buttons. */
err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
APP_ERROR_CHECK(err_code);
/* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
/* Initialize PWM running on timer 1 in order to control dimmable light bulb. */
err_code = app_pwm_init(&BULB_PWM_NAME, &pwm_cfg, NULL);
APP_ERROR_CHECK(err_code);
app_pwm_enable(&BULB_PWM_NAME);
while (app_pwm_channel_duty_set(&BULB_PWM_NAME, 0, 99) == NRF_ERROR_BUSY)
{
}
}
/**@brief Function for initializing all clusters attributes.
*/
static void bulb_clusters_attr_init(void)
{
/* Basic cluster attributes data */
m_dev_ctx.basic_attr.zcl_version = ZB_ZCL_VERSION;
m_dev_ctx.basic_attr.app_version = BULB_INIT_BASIC_APP_VERSION;
m_dev_ctx.basic_attr.stack_version = BULB_INIT_BASIC_STACK_VERSION;
m_dev_ctx.basic_attr.hw_version = BULB_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_dev_ctx.basic_attr.mf_name,
BULB_INIT_BASIC_MANUF_NAME,
ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MANUF_NAME));
ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.model_id,
BULB_INIT_BASIC_MODEL_ID,
ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_MODEL_ID));
ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.date_code,
BULB_INIT_BASIC_DATE_CODE,
ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_DATE_CODE));
m_dev_ctx.basic_attr.power_source = BULB_INIT_BASIC_POWER_SOURCE;
ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.location_id,
BULB_INIT_BASIC_LOCATION_DESC,
ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_LOCATION_DESC));
m_dev_ctx.basic_attr.ph_env = BULB_INIT_BASIC_PH_ENV;
/* Identify cluster attributes data */
m_dev_ctx.identify_attr.identify_time = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;
/* On/Off cluster attributes data */
m_dev_ctx.on_off_attr.on_off = (zb_bool_t)ZB_ZCL_ON_OFF_IS_ON;
m_dev_ctx.level_control_attr.current_level = ZB_ZCL_LEVEL_CONTROL_LEVEL_MAX_VALUE;
m_dev_ctx.level_control_attr.remaining_time = ZB_ZCL_LEVEL_CONTROL_REMAINING_TIME_DEFAULT_VALUE;
NRF_LOG_INFO("ATTR [1]");
ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,
ZB_ZCL_CLUSTER_ID_ON_OFF,
ZB_ZCL_CLUSTER_SERVER_ROLE,
ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID,
(zb_uint8_t *)&m_dev_ctx.on_off_attr.on_off,
ZB_FALSE);
ZB_ZCL_SET_ATTRIBUTE(HA_DIMMABLE_LIGHT_ENDPOINT,
ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL,
ZB_ZCL_CLUSTER_SERVER_ROLE,
ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID,
(zb_uint8_t *)&m_dev_ctx.level_control_attr.current_level,
ZB_FALSE);
}
/**@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)
{
//TODO: implement your own logic if needed
//NRF_LOG_INFO("TEST [1]");
zb_osif_wait_for_event();
}
/**@brief Callback function for handling ZCL commands.
*
* @param[in] bufid Reference to Zigbee stack buffer used to pass received data.
*/
static zb_void_t zcl_device_cb(zb_bufid_t *bufid)
{
zb_uint8_t cluster_id;
zb_uint8_t attr_id;
zb_zcl_device_callback_param_t * p_device_cb_param = ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
/* SEND TEST 11-25 */
switch (p_device_cb_param->device_cb_id)
{
case ZB_ZCL_LEVEL_CONTROL_SET_VALUE_CB_ID:
NRF_LOG_INFO("Level control setting to %d", p_device_cb_param->cb_param.level_control_set_value_param.new_value);
level_control_set_value(p_device_cb_param->cb_param.level_control_set_value_param.new_value);
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_ON_OFF)
{
uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
//NRF_LOG_INFO("--------------------------> [TEST]on/off attribute setting to %hd", value);
NRF_LOG_INFO("on/off attribute setting to %hd", value);
if (attr_id == ZB_ZCL_ATTR_ON_OFF_ON_OFF_ID)
{
on_off_set_value((zb_bool_t) value);
}
}
else if (cluster_id == ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL)
{
uint16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
NRF_LOG_INFO("level control attribute setting to %hd", value);
if (attr_id == ZB_ZCL_ATTR_LEVEL_CONTROL_CURRENT_LEVEL_ID)
{
level_control_set_value(value);
}
}
else
{
/* Other clusters can be processed here */
NRF_LOG_INFO("Unhandled cluster attribute id: %d", cluster_id);
}
break;
default:
p_device_cb_param->status = RET_ERROR;
break;
}
NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
//bulb_ctx.short_addr,
ZB_ZCL_ON_OFF_SEND_REQ(bufid,
bulb_ctx.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
bulb_ctx.endpoint,
10,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
ZB_ZCL_CMD_ON_OFF_ON_ID,
NULL);
}
static zb_void_t find_coordinator(zb_bufid_t bufid){
zb_zdo_match_desc_resp_t * p_resp = (zb_zdo_match_desc_resp_t *) zb_buf_begin(bufid); // Get the beginning of the response
zb_apsde_data_indication_t * p_ind = ZB_BUF_GET_PARAM(bufid, zb_apsde_data_indication_t); // Get the pointer to the parameters buffer, which stores APS layer response
zb_uint8_t * p_match_ep;
zb_ret_t zb_err_code;
NRF_LOG_INFO("BULB [4]");
if ((p_resp->status == ZB_ZDP_STATUS_SUCCESS) && (p_resp->match_len > 0) && (bulb_ctx.short_addr == 0xFFFF))
{
/* Match EP list follows right after response header */
p_match_ep = (zb_uint8_t *)(p_resp + 1);
/* We are searching for exact cluster, so only 1 EP may be found */
bulb_ctx.endpoint = *p_match_ep;
bulb_ctx.short_addr = p_ind->src_addr;
NRF_LOG_INFO("Found bulb addr: %04hx ep: %d", bulb_ctx.short_addr, bulb_ctx.endpoint);
zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(find_coordinator_timeout, ZB_ALARM_ANY_PARAM);
ZB_ERROR_CHECK(zb_err_code);
//bsp_board_led_on(BULB_FOUND_LED);
}
if (bufid)
{
zb_buf_free(bufid);
}
}
static zb_void_t find_coordinator_read(zb_bufid_t bufid){
zb_zdo_match_desc_param_t * p_req;
/* Initialize pointers inside buffer and reserve space for zb_zdo_match_desc_param_t request */
p_req = zb_buf_initial_alloc(bufid, sizeof(zb_zdo_match_desc_param_t) + (1) * sizeof(zb_uint16_t));
p_req->nwk_addr = ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE; // Send to devices specified by MATCH_DESC_REQ_ROLE
p_req->addr_of_interest = ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE; // Get responses from devices specified by MATCH_DESC_REQ_ROLE
p_req->profile_id = ZB_AF_HA_PROFILE_ID; // Look for Home Automation profile clusters
/* We are searching for 2 clusters: On/Off and Level Control Server */
p_req->num_in_clusters = 2;
p_req->num_out_clusters = 0;
/*lint -save -e415 // Suppress warning 415 "likely access of out-of-bounds pointer" */
p_req->cluster_list[0] = ZB_ZCL_CLUSTER_ID_ON_OFF;
p_req->cluster_list[1] = ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL;
/*lint -restore */
bulb_ctx.short_addr = 0xFFFF; // Set 0xFFFF to reset short address in order to parse only one response.
NRF_LOG_INFO("BULB [3]");
UNUSED_RETURN_VALUE(zb_zdo_match_desc_req(bufid, find_coordinator));
}
static zb_void_t find_coordinator_timeout(zb_bufid_t bufid){
zb_ret_t zb_err_code;
if (bufid)
{
NRF_LOG_INFO("Bulb not found, try again");
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_coordinator_read, bufid, MATCH_DESC_REQ_START_DELAY);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_coordinator_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
ZB_ERROR_CHECK(zb_err_code);
}
else
{
zb_err_code = zb_buf_get_out_delayed(find_coordinator_timeout);
ZB_ERROR_CHECK(zb_err_code);
}
}
/*BULB TEST END*/
/**@brief Zigbee stack event handler.
*
* @param[in] bufid Reference to the Zigbee stack buffer used to pass signal.
*/
void zboss_signal_handler(zb_bufid_t bufid)
{
zb_zdo_app_signal_hdr_t * p_sg_p = NULL;
zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &p_sg_p);
zb_uint8_t * p_match_ep;
zb_ret_t zb_err_code;
zigbee_led_status_update(bufid, ZIGBEE_NETWORK_STATE_LED);
/* No application-specific behavior is required. Call default signal handler. */
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
if(sig == ZB_BDB_SIGNAL_DEVICE_REBOOT || sig == ZB_BDB_SIGNAL_STEERING){
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_coordinator,bufid,MATCH_DESC_REQ_START_DELAY);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_coordinator_timeout,0,MATCH_DESC_REQ_TIMEOUT);
}
if (bufid)
{
zb_buf_free(bufid);
}
}
#if (APP_BULB_USE_WS2812_LED_CHAIN)
static void ws2812_refresh_timer_timeout_handler(void *p_context)
{
m_ws2812_refresh_request = true;
}
#endif
/**@brief Function for application main entry.
*/
int main(void)
{
zb_ret_t zb_err_code;
zb_ieee_addr_t ieee_addr;
/* Initialize timer, logging system and GPIOs. */
timer_init();
log_init();
leds_buttons_init();
#if (APP_BULB_USE_WS2812_LED_CHAIN)
ret_code_t ret_code;
ret_code = drv_ws2812_init(LED_CHAIN_DOUT_PIN);
APP_ERROR_CHECK(ret_code);
#endif
/* Set Zigbee stack logging level and traffic dump subsystem. */
ZB_SET_TRACE_LEVEL(ZIGBEE_TRACE_LEVEL); // fix 1
ZB_SET_TRACE_MASK(ZIGBEE_TRACE_MASK); //fix 1
ZB_SET_TRAF_DUMP_OFF();
/* Initialize Zigbee stack. */
ZB_INIT("led_bulb");
/* Set device address to the value read from FICR registers. */
zb_osif_get_ieee_eui64(ieee_addr); // Read IEEE long address from FICR registers
zb_set_long_address(ieee_addr);
/* Set static long IEEE address. */
zb_set_network_router_role(IEEE_CHANNEL_MASK);
zb_set_max_children(MAX_CHILDREN);
zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
/* Initialize application context structure. */
UNUSED_RETURN_VALUE(ZB_MEMSET(&m_dev_ctx, 0, sizeof(m_dev_ctx)));
/* Register callback for handling ZCL commands. */
ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
/* Register dimmer switch device context (endpoints). */
ZB_AF_REGISTER_DEVICE_CTX(&dimmable_light_ctx);
bulb_clusters_attr_init();
NRF_LOG_INFO("[1]");
level_control_set_value(m_dev_ctx.level_control_attr.current_level);
NRF_LOG_INFO("[4]");
#if (APP_BULB_USE_WS2812_LED_CHAIN)
/* Let's have a timer triggering refresh of led state */
ret_code = app_timer_create(&m_ws2812_refresh_timer, APP_TIMER_MODE_REPEATED,
ws2812_refresh_timer_timeout_handler);
APP_ERROR_CHECK(ret_code);
ret_code = app_timer_start(m_ws2812_refresh_timer, APP_TIMER_TICKS(5000U), NULL);
APP_ERROR_CHECK(ret_code);
#endif
/*BULB TEST */
UNUSED_RETURN_VALUE(ZB_MEMSET(&bulb_ctx, 0, sizeof(light_bulb_params_t)));
bulb_ctx.short_addr = 0xFFFF;
/*BULB TEST END */
/** Start Zigbee Stack. */
zb_err_code = zboss_start_no_autostart();
ZB_ERROR_CHECK(zb_err_code);
while(1)
{
//NRF_LOG_INFO("[1]\n");
zboss_main_loop_iteration();
//NRF_LOG_INFO("[2]\n");
UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
#if (APP_BULB_USE_WS2812_LED_CHAIN)
//NRF_LOG_INFO("Hello\n");
if (m_ws2812_refresh_request)
{
if (drv_ws2812_display(NULL, NULL) == NRF_SUCCESS)
{
m_ws2812_refresh_request = false;
}
}
#endif
}
}
/**
* @}
*/
Similar to finding a bulb in ZC, ZED tried to find ZC by creating a find_coordinator,find_coordinator_read,find_coordinator_timeout function,but was not found.
3. I added 'ZB_AF_SET_ENDPOINT_HANDLER' to the main() of 'ZC' by referring to the link in '[nRF52840 with zigbee] How to append user data append to HA profile ?', but it still failed.
4. 'zb_zcl_start_command_header' and 'zb_zcl_finish_and_send_packet' were used but still not. (ref :ZigBee communication -> sending messages from End-Device to Coordinator)
'ZB_ZCL_SET_' was identified using 'multi-sensor' and 'zigbyclip'.ACTURT' was received. However, the cli must be entered directly into the console window to receive the final device payload.
Previously, we asked 'Question) Can I use zigbee and UART at the same time?' to use 'messaging cluster', but no matter how many times we look and we don't know how to use it.
I'd appreciate any help.
The ZC code is as follows.
/**
* Copyright (c) 2018 - 2020, 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 "zboss_api.h"
#include "zb_mem_config_max.h"
#include "zb_error_handler.h"
#include "zigbee_helpers.h"
#include "app_timer.h"
#include "boards.h"
#include "bsp.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_delay.h"
#include "bulb_st.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. */
#ifdef BOARD_PCA10059 /**< If it is Dongle */
#define ZIGBEE_NETWORK_STATE_LED BSP_BOARD_LED_0 /**< LED indicating that network is opened for new nodes. */
#else
#define ZIGBEE_NETWORK_STATE_LED BSP_BOARD_LED_2 /**< LED indicating that network is opened for new nodes. */
#endif
#define ZIGBEE_NETWORK_REOPEN_BUTTON BSP_BOARD_BUTTON_0 /**< Button which reopens the Zigbee Network. */
#define ZIGBEE_MANUAL_STEERING ZB_FALSE /**< If set to 1 then device will not open the network after forming or reboot. */
#define ZIGBEE_PERMIT_LEGACY_DEVICES ZB_FALSE /**< If set to 1 then legacy devices (pre-Zigbee 3.0) can join the network. */
/* BULB TEST */
#define LIGHT_SWITCH_BUTTON_ON BSP_BOARD_BUTTON_0 /**< Button ID used to switch on the light bulb. */
#define LIGHT_SWITCH_BUTTON_OFF BSP_BOARD_BUTTON_1 /**< Button ID used to switch off the light bulb. */
#define LIGHT_SWITCH_BUTTON_THRESHOLD ZB_TIME_ONE_SECOND /**< Number of beacon intervals the button should be pressed to dimm the light bulb. */
#define LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO ZB_MILLISECONDS_TO_BEACON_INTERVAL(50) /**< Delay between button state checks used in order to detect button long press. */
#define LIGHT_SWITCH_BUTTON_LONG_POLL_TMO ZB_MILLISECONDS_TO_BEACON_INTERVAL(300) /**< Time after which the button state is checked again to detect button hold - the dimm command is sent again. */
#define LIGHT_SWITCH_DIMM_STEP 15 /**< Dim step size - increases/decreses current level (range 0x000 - 0xfe). */
#define LIGHT_SWITCH_DIMM_TRANSACTION_TIME 2 /**< Transition time for a single step operation in 0.1 sec units. 0xFFFF - immediate change. */
#define MATCH_DESC_REQ_ROLE ZB_NWK_BROADCAST_RX_ON_WHEN_IDLE
#define LIGHT_SWITCH_ENDPOINT 1
#define MATCH_DESC_REQ_START_DELAY (2 * ZB_TIME_ONE_SECOND) /**< Delay between the light switch startup and light bulb finding procedure. */
#define MATCH_DESC_REQ_TIMEOUT (5 * ZB_TIME_ONE_SECOND) /**< Timeout for finding procedure. */
#define BULB_FOUND_LED BSP_BOARD_LED_0
typedef struct light_switch_bulb_params_s
{
zb_uint8_t endpoint;
zb_uint16_t short_addr;
} light_switch_bulb_params_t;
typedef struct light_switch_button_s
{
zb_bool_t in_progress;
zb_time_t timestamp;
} light_switch_button_t;
typedef struct light_switch_ctx_s
{
light_switch_bulb_params_t bulb_params;
light_switch_button_t button;
} light_switch_ctx_t;
static zb_void_t find_light_bulb_timeout(zb_bufid_t bufid);
static light_switch_ctx_t m_device_ctx;
static zb_uint8_t m_attr_zcl_version = ZB_ZCL_VERSION;
static zb_uint8_t m_attr_power_source = ZB_ZCL_BASIC_POWER_SOURCE_UNKNOWN;
static zb_uint16_t m_attr_identify_time = 0;
/* Declare attribute list for Basic cluster. */
ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST(basic_attr_list, &m_attr_zcl_version, &m_attr_power_source);
/* Declare attribute list for Identify cluster. */
ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list, &m_attr_identify_time);
/* Declare cluster list for Dimmer Switch device (Identify, Basic, Scenes, Groups, On Off, Level Control). */
/* Only clusters Identify and Basic have attributes. */
ZB_HA_DECLARE_DIMMER_SWITCH_CLUSTER_LIST(dimmer_switch_clusters,
basic_attr_list,
identify_attr_list);
/* Declare endpoint for Dimmer Switch device. */
ZB_HA_DECLARE_DIMMER_SWITCH_EP(dimmer_switch_ep,
LIGHT_SWITCH_ENDPOINT,
dimmer_switch_clusters);
/* Declare application's device context (list of registered endpoints) for Dimmer Switch device. */
ZB_HA_DECLARE_DIMMER_SWITCH_CTX(dimmer_switch_ctx, dimmer_switch_ep);
static zb_void_t light_switch_send_on_off(zb_bufid_t bufid, zb_uint16_t on_off)
{
zb_uint8_t cmd_id;
if (on_off)
{
cmd_id = ZB_ZCL_CMD_ON_OFF_ON_ID;
}
else
{
cmd_id = ZB_ZCL_CMD_ON_OFF_OFF_ID;
}
ZB_ZCL_ON_OFF_SEND_REQ(bufid,
m_device_ctx.bulb_params.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
m_device_ctx.bulb_params.endpoint,
0,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
cmd_id,
NULL);
NRF_LOG_INFO("Send ON/OFF command: %d", on_off);
NRF_LOG_INFO("BUF command: %d", test_key);
NRF_LOG_INFO("short_addd = %04hx \n", m_device_ctx.bulb_params.short_addr);
NRF_LOG_INFO("endpoint = %04dx \n ", m_device_ctx.bulb_params.endpoint);
/*
ZB_ZCL_ON_OFF_SEND_REQ(bufid,
m_device_ctx.bulb_params.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
m_device_ctx.bulb_params.endpoint,
LIGHT_SWITCH_ENDPOINT,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
cmd_id,
NULL);
*/
}
/**@brief Function for sending step requests to the light bulb.
*
* @param[in] bufid Non-zero reference to Zigbee stack buffer that will be used to construct step request.
* @param[in] is_step_up Boolean parameter selecting direction of step change.
*/
static zb_void_t light_switch_send_step(zb_bufid_t bufid, zb_uint16_t is_step_up)
{
zb_uint8_t step_dir;
if (is_step_up)
{
step_dir = ZB_ZCL_LEVEL_CONTROL_STEP_MODE_UP;
}
else
{
step_dir = ZB_ZCL_LEVEL_CONTROL_STEP_MODE_DOWN;
}
NRF_LOG_INFO("Send step level command: %d", is_step_up);
ZB_ZCL_LEVEL_CONTROL_SEND_STEP_REQ(bufid,
m_device_ctx.bulb_params.short_addr,
ZB_APS_ADDR_MODE_16_ENDP_PRESENT,
m_device_ctx.bulb_params.endpoint,
0,
ZB_AF_HA_PROFILE_ID,
ZB_ZCL_DISABLE_DEFAULT_RESPONSE,
NULL,
step_dir,
LIGHT_SWITCH_DIMM_STEP,
LIGHT_SWITCH_DIMM_TRANSACTION_TIME);
}
/**@brief Callback function receiving finding procedure results.
*
* @param[in] bufid Reference to Zigbee stack buffer used to pass received data.
*/
static zb_void_t find_light_bulb_cb(zb_bufid_t bufid)
{
zb_zdo_match_desc_resp_t * p_resp = (zb_zdo_match_desc_resp_t *) zb_buf_begin(bufid); // Get the beginning of the response
zb_apsde_data_indication_t * p_ind = ZB_BUF_GET_PARAM(bufid, zb_apsde_data_indication_t); // Get the pointer to the parameters buffer, which stores APS layer response
zb_uint8_t * p_match_ep;
zb_ret_t zb_err_code;
NRF_LOG_INFO("BULB [4]");
if ((p_resp->status == ZB_ZDP_STATUS_SUCCESS) && (p_resp->match_len > 0) && (m_device_ctx.bulb_params.short_addr == 0xFFFF))
{
/* Match EP list follows right after response header */
p_match_ep = (zb_uint8_t *)(p_resp + 1);
/* We are searching for exact cluster, so only 1 EP may be found */
m_device_ctx.bulb_params.endpoint = *p_match_ep;
m_device_ctx.bulb_params.short_addr = p_ind->src_addr;
NRF_LOG_INFO("Found bulb addr: %04hx ep: %d", m_device_ctx.bulb_params.short_addr, m_device_ctx.bulb_params.endpoint);
zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(find_light_bulb_timeout, ZB_ALARM_ANY_PARAM);
ZB_ERROR_CHECK(zb_err_code);
bsp_board_led_on(BULB_FOUND_LED);
}
if (bufid)
{
zb_buf_free(bufid);
}
}
/**@brief Function for sending ON/OFF and Level Control find request.
*
* @param[in] bufid Non-zero reference to Zigbee stack buffer that will be used to construct find request.
*/
static zb_void_t find_light_bulb(zb_bufid_t bufid)
{
zb_zdo_match_desc_param_t * p_req;
/* Initialize pointers inside buffer and reserve space for zb_zdo_match_desc_param_t request */
p_req = zb_buf_initial_alloc(bufid, sizeof(zb_zdo_match_desc_param_t) + (1) * sizeof(zb_uint16_t));
p_req->nwk_addr = MATCH_DESC_REQ_ROLE; // Send to devices specified by MATCH_DESC_REQ_ROLE
p_req->addr_of_interest = MATCH_DESC_REQ_ROLE; // Get responses from devices specified by MATCH_DESC_REQ_ROLE
p_req->profile_id = ZB_AF_HA_PROFILE_ID; // Look for Home Automation profile clusters
/* We are searching for 2 clusters: On/Off and Level Control Server */
p_req->num_in_clusters = 2;
p_req->num_out_clusters = 0;
/*lint -save -e415 // Suppress warning 415 "likely access of out-of-bounds pointer" */
p_req->cluster_list[0] = ZB_ZCL_CLUSTER_ID_ON_OFF;
p_req->cluster_list[1] = ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL;
/*lint -restore */
m_device_ctx.bulb_params.short_addr = 0xFFFF; // Set 0xFFFF to reset short address in order to parse only one response.
NRF_LOG_INFO("BULB [3]");
UNUSED_RETURN_VALUE(zb_zdo_match_desc_req(bufid, find_light_bulb_cb));
}
/**@brief Finding procedure timeout handler.
*
* @param[in] bufid Reference to Zigbee stack buffer that will be used to construct find request.
*/
static zb_void_t find_light_bulb_timeout(zb_bufid_t bufid)
{
zb_ret_t zb_err_code;
if (bufid)
{
NRF_LOG_INFO("Bulb not found, try again");
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb, bufid, MATCH_DESC_REQ_START_DELAY);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
ZB_ERROR_CHECK(zb_err_code);
}
else
{
zb_err_code = zb_buf_get_out_delayed(find_light_bulb_timeout);
ZB_ERROR_CHECK(zb_err_code);
}
}
/**@brief Callback for detecting button press duration.
*
* @param[in] button BSP Button that was pressed.
*/
static zb_void_t light_switch_button_handler(zb_uint8_t button)
{
zb_time_t current_time;
zb_bool_t short_expired;
zb_bool_t on_off;
zb_ret_t zb_err_code;
current_time = ZB_TIMER_GET();
if (button == LIGHT_SWITCH_BUTTON_ON)
{
on_off = ZB_TRUE;
}
else
{
on_off = ZB_FALSE;
}
if (ZB_TIME_SUBTRACT(current_time, m_device_ctx.button.timestamp) > LIGHT_SWITCH_BUTTON_THRESHOLD)
{
short_expired = ZB_TRUE;
}
else
{
short_expired = ZB_FALSE;
}
/* Check if button was released during LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO. */
if (!bsp_button_is_pressed(button))
{
if (!short_expired)
{
/* Allocate output buffer and send on/off command. */
zb_err_code = zb_buf_get_out_delayed_ext(light_switch_send_on_off, on_off, 32);
ZB_ERROR_CHECK(zb_err_code);
}
/* Button released - wait for accept next event. */
m_device_ctx.button.in_progress = ZB_FALSE;
}
else
{
if (short_expired)
{
/* The button is still pressed - allocate output buffer and send step command. */
zb_err_code = zb_buf_get_out_delayed_ext(light_switch_send_step, on_off, 0);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_APP_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_LONG_POLL_TMO);
if (zb_err_code == RET_OVERFLOW)
{
NRF_LOG_WARNING("Can not schedule another alarm, queue is full.");
m_device_ctx.button.in_progress = ZB_FALSE;
}
else
{
ZB_ERROR_CHECK(zb_err_code);
}
}
else
{
/* Wait another LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO, until LIGHT_SWITCH_BUTTON_THRESHOLD will be reached. */
zb_err_code = ZB_SCHEDULE_APP_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO);
if (zb_err_code == RET_OVERFLOW)
{
NRF_LOG_WARNING("Can not schedule another alarm, queue is full.");
m_device_ctx.button.in_progress = ZB_FALSE;
}
else
{
ZB_ERROR_CHECK(zb_err_code);
}
}
}
}
/**@brief Function for initializing LEDs and buttons.
*/
/* BULB TEST END */
#ifndef ZB_COORDINATOR_ROLE
#error Define ZB_COORDINATOR_ROLE to compile coordinator source code.
#endif
/* receive test */
#define LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO ZB_MILLISECONDS_TO_BEACON_INTERVAL(50) /**< Delay between button state checks used in order to detect button long press. */
/* receive test */
/**@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 the Timer initialization.
*
* @details Initializes the timer module. This creates and starts application timers.
*/
static void timers_init(void)
{
ret_code_t err_code;
// Initialize timer module.
err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}
/**@brief Callback 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 Callback for button events.
*
* @param[in] evt Incoming event from the BSP subsystem.
*/
static void buttons_handler(bsp_event_t evt)
{
zb_bool_t comm_status;
/* SWITCH */
zb_ret_t zb_err_code;
zb_uint32_t button;
//user_input_indicate();
if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
{
return;
}
/* SWITCH END */
switch(evt)
{
case BSP_EVENT_KEY_0:
UNUSED_RETURN_VALUE(ZB_SCHEDULE_APP_ALARM_CANCEL(steering_finished, ZB_ALARM_ANY_PARAM));
//nrf_delay_ms(300);
comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
//nrf_delay_ms(300);
if (comm_status)
{
NRF_LOG_INFO("Top level comissioning restated");
}
else
{
NRF_LOG_INFO("Top level comissioning hasn't finished yet!");
}
return;
case BSP_EVENT_KEY_2: /* SWITCH */
button = LIGHT_SWITCH_BUTTON_ON;
break;
case BSP_EVENT_KEY_3: /* SWITCH */
button = LIGHT_SWITCH_BUTTON_OFF;
break;
default:
NRF_LOG_INFO("Unhandled BSP Event received: %d", evt);
break;
}
if (!m_device_ctx.button.in_progress)
{
m_device_ctx.button.in_progress = ZB_TRUE;
m_device_ctx.button.timestamp = ZB_TIMER_GET();
zb_err_code = ZB_SCHEDULE_APP_ALARM(light_switch_button_handler, button, LIGHT_SWITCH_BUTTON_SHORT_POLL_TMO);
if (zb_err_code == RET_OVERFLOW)
{
NRF_LOG_WARNING("Can not schedule another alarm, queue is full.");
m_device_ctx.button.in_progress = ZB_FALSE;
}
else
{
ZB_ERROR_CHECK(zb_err_code);
}
}
}
/**@brief Function for initializing LEDs and Buttons.
*/
static void leds_buttons_init(void)
{
uint32_t err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, buttons_handler);
APP_ERROR_CHECK(err_code);
/* By default the bsp_init attaches BSP_KEY_EVENTS_{0-4} to the PUSH events of the corresponding buttons. */
bsp_board_leds_off();
}
/* receive test */
static zb_void_t zcl_receive(zb_bufid_t *bufid)
{
NRF_LOG_INFO("zcl test");
}
/* receive test */
/**@brief Zigbee stack event handler.
*
* @param[in] bufid Reference to the Zigbee stack buffer used to pass signal.
*/
void zboss_signal_handler(zb_bufid_t bufid)
{
/* Read signal description out of memory buffer. */
zb_zdo_app_signal_hdr_t * p_sg_p = NULL;
zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &p_sg_p);
zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
zb_ret_t zb_err_code;
zb_bool_t comm_status;
zb_time_t timeout_bi;
zb_zcl_report_attr_req_t * p_attr_resp = NULL;
//NRF_LOG_INFO("\n\n\n\n\n\n HEllo world \n\n\n\n\n\n");
NRF_LOG_INFO("\nTEST\n");
switch(sig)
{
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)
{
if (ZIGBEE_MANUAL_STEERING == ZB_FALSE)
{
NRF_LOG_INFO("Start network steering");
comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
ZB_COMM_STATUS_CHECK(comm_status);
}
else
{
NRF_LOG_INFO("Coordinator restarted successfully");
}
}
else
{
NRF_LOG_ERROR("Failed to initialize Zigbee stack using NVRAM data (status: %d)", status);
}
break;
case ZB_BDB_SIGNAL_STEERING:
if (status == RET_OK)
{
if (ZIGBEE_PERMIT_LEGACY_DEVICES == ZB_TRUE)
{
NRF_LOG_INFO("Allow pre-Zigbee 3.0 devices to join the network");
zb_bdb_set_legacy_device_support(1);
}
/* Schedule an alarm to notify about the end of steering period */
NRF_LOG_INFO("Network steering started");
zb_err_code = ZB_SCHEDULE_APP_ALARM(steering_finished, 0, ZB_TIME_ONE_SECOND * ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
/* Swtich bulb */
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
if (status == RET_OK)
{
/* Check the light device address */
NRF_LOG_INFO("BULB [1]");
if (m_device_ctx.bulb_params.short_addr == 0xFFFF)
{
NRF_LOG_INFO("BULB [2]");
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb, bufid, MATCH_DESC_REQ_START_DELAY);
ZB_ERROR_CHECK(zb_err_code);
zb_err_code = ZB_SCHEDULE_APP_ALARM(find_light_bulb_timeout, 0, MATCH_DESC_REQ_TIMEOUT);
ZB_ERROR_CHECK(zb_err_code);
bufid = 0; // Do not free buffer - it will be reused by find_light_bulb callback
}
}
ZB_ERROR_CHECK(zb_err_code);
break;
/* Switch bulb end */
}
#ifndef ZB_ED_ROLE
zb_enable_auto_pan_id_conflict_resolution(ZB_FALSE);
#endif
break;
case ZB_ZDO_SIGNAL_DEVICE_ANNCE:
{
zb_zdo_signal_device_annce_params_t * dev_annce_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_device_annce_params_t);
NRF_LOG_INFO("New device commissioned or rejoined (short: 0x%04hx)", dev_annce_params->device_short_addr);
zb_err_code = ZB_SCHEDULE_APP_ALARM_CANCEL(steering_finished, ZB_ALARM_ANY_PARAM);
if (zb_err_code == RET_OK)
{
NRF_LOG_INFO("Joining period extended.");
zb_err_code = ZB_SCHEDULE_APP_ALARM(steering_finished, 0, ZB_TIME_ONE_SECOND * ZB_ZGP_DEFAULT_COMMISSIONING_WINDOW);
ZB_ERROR_CHECK(zb_err_code);
}
}
break;
default:
/* Call default signal handler. */
NRF_LOG_INFO("SIG = %d ", sig);
ZB_ERROR_CHECK(zigbee_default_signal_handler(bufid));
break;
}
/* Update network status LED */
if (ZB_JOINED() && (ZB_SCHEDULE_GET_ALARM_TIME(steering_finished, ZB_ALARM_ANY_PARAM, &timeout_bi) == RET_OK))
{
bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);
}
else
{
bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
}
/* All callbacks should either reuse or free passed buffers. If bufid == 0, the buffer is invalid (not passed) */
if (bufid)
{
zb_buf_free(bufid);
}
}
/**@brief Function for application main entry. */
int main(void)
{
zb_ret_t zb_err_code;
zb_ieee_addr_t ieee_addr;
// Initialize.
timers_init();
log_init();
leds_buttons_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. */
ZB_INIT("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);
/* zigbee receive test */
//ZB_ZCL_REGISTER_DEVICE_CB(zcl_receive);
ZB_AF_SET_ENDPOINT_HANDLER(64,zcl_receive);
/* receive end */
/* Keep or erase NVRAM to save the network parameters after device reboot or power-off. */
zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
UNUSED_RETURN_VALUE(ZB_MEMSET(&m_device_ctx, 0, sizeof(light_switch_ctx_t)));
m_device_ctx.bulb_params.short_addr = 0xFFFF;
/** Start Zigbee Stack. */
zb_err_code = zboss_start_no_autostart();
ZB_ERROR_CHECK(zb_err_code);
while(1)
{
zboss_main_loop_iteration();
UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
}
}
/**
* @}
*/
Thanks!