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

nRF52840 dongle: color light bulb

Hi,

I'm trying to mimic a fully functional zigbee color light bulb using the nRF52840 dongle.

Starting with the NRF5 Zigbee example light_bulb (examples/zigbee/light_control/), I began familiarizing with the code using EmStudio as recommended.

After flashing the build HEX (nRF connect -> Programmer) to the nRF52840 dongle, I was able to control the nRF52840 dongle using a 3rd party zigbee controller: great!

The next step would be to add the different missing parameters, starting with hue parameter, to make the light_bulb a color_light_bulb. This is where I am reaching out for support.

The closest example code I found to use as a starting point is the ble_zigbee_dynamic_color_light_bulb_thingy (examples/multiprotocol/experiemental/).

I tried to salvage some of its code back into the light_bulb ones, including the "zb_ha_dimmable_color_light.h" and "zigbee_color_light.h" and adapting on the go without success.

Unfortunately, the gap from light_bulb to ble_zigbee_dynamic_color_light_bulb_thingy is too complicated for my current skill level.

I am adding the code below, where I am at now.

Am I going in the right direction? Any tips?

Thanks!

/**
 * 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_color_light.h"
#include "zb_error_handler.h"
#include "zb_nrf52_internal.h"
#include "zigbee_helpers.h"
#include "zigbee_color_light.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"

#define MAX_CHILDREN                      10                                    /**< The maximum amount of connected devices. Setting this value to 0 disables association to this device.  */
#define IEEE_CHANNEL_MASK                 0x07fff800U                            /**< Scan only one, predefined channel to find the coordinator.(1l << ZIGBEE_CHANNEL) */
#define HA_COLOR_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 !defined ZB_ROUTER_ROLE
#error Define ZB_ROUTER_ROLE to compile light bulb (Router) source code.
#endif


/* Declare context variable and cluster attribute list for first endpoint */
zb_color_light_ctx_t m_color_light_ctx_1;

ZB_DECLARE_COLOR_CONTROL_CLUSTER_ATTR_LIST(m_color_light_ctx_1,
                                           m_color_light_clusters_1);
                                           
/* Declare two endpoints for color controllable and dimmable light bulbs */
ZB_ZCL_DECLARE_COLOR_DIMMABLE_LIGHT_EP(m_color_light_ep_1,
                                       HA_COLOR_LIGHT_ENDPOINT,
                                       m_color_light_clusters_1);
                                       
/* Declare context for endpoints */
ZBOSS_DECLARE_DEVICE_CTX_1_EP(m_color_light_ctx,
                              m_color_light_ep_1);

APP_PWM_INSTANCE(BULB_PWM_NAME, BULB_PWM_TIMER);
//static bulb_device_ctx_t m_dev_ctx;


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



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

/**@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_COLOR_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_COLOR_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_COLOR_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 setting the light bulb color.
  *
  * @param[in]   new_level   Light bulb color hue value.
 */
static void color_control_set_value(zb_uint16_t new_level)
{
    NRF_LOG_INFO("Set color hue value: %i", new_level);

    ZB_ZCL_SET_ATTRIBUTE(HA_COLOR_LIGHT_ENDPOINT,                                       
                         ZB_ZCL_CLUSTER_ID_LEVEL_CONTROL,            
                         ZB_ZCL_CLUSTER_SERVER_ROLE,                 
                         ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_HUE_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_COLOR_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_COLOR_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); //need to call func to change LED
}



/**@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_ZCL_SET_ATTRIBUTE(HA_COLOR_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_color_light_ctx_1.level_control_attr.current_level);
    }
    else
    {
        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_color_light_ctx_1.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_COLOR_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_color_light_ctx_1.basic_attr.zcl_version   = ZB_ZCL_VERSION;
    m_color_light_ctx_1.basic_attr.app_version   = BULB_INIT_BASIC_APP_VERSION;
    m_color_light_ctx_1.basic_attr.stack_version = BULB_INIT_BASIC_STACK_VERSION;
    m_color_light_ctx_1.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_color_light_ctx_1.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_color_light_ctx_1.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_color_light_ctx_1.basic_attr.date_code,
                          BULB_INIT_BASIC_DATE_CODE,
                          ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_DATE_CODE));

    m_color_light_ctx_1.basic_attr.power_source = BULB_INIT_BASIC_POWER_SOURCE;

    ZB_ZCL_SET_STRING_VAL(m_color_light_ctx_1.basic_attr.location_id,
                          BULB_INIT_BASIC_LOCATION_DESC,
                          ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_LOCATION_DESC));


    m_color_light_ctx_1.basic_attr.ph_env = BULB_INIT_BASIC_PH_ENV;

    /* Identify cluster attributes data */
    m_color_light_ctx_1.identify_attr.identify_time = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;

    /* On/Off cluster attributes data */
    m_color_light_ctx_1.on_off_attr.on_off = (zb_bool_t)ZB_ZCL_ON_OFF_IS_ON;

    m_color_light_ctx_1.level_control_attr.current_level  = ZB_ZCL_LEVEL_CONTROL_LEVEL_MAX_VALUE;
    m_color_light_ctx_1.level_control_attr.remaining_time = ZB_ZCL_LEVEL_CONTROL_REMAINING_TIME_DEFAULT_VALUE;

    ZB_ZCL_SET_ATTRIBUTE(HA_COLOR_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_color_light_ctx_1.on_off_attr.on_off,                        
                         ZB_FALSE);                   

    ZB_ZCL_SET_ATTRIBUTE(HA_COLOR_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_color_light_ctx_1.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
    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);

    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;

    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("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 if (cluster_id == ZB_ZCL_CLUSTER_ID_COLOR_CONTROL)
            {
                uint16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;

                NRF_LOG_INFO("color control attribute setting to %hd", value);
                if (attr_id == ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_HUE_ID)
                {
                    color_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);
}

/**@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)
{
    /* Update network status LED */
    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 (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 timer, logging system and GPIOs. */
    timer_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("led_bulb");

    /* 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_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_color_light_ctx_1, 0, sizeof(m_color_light_ctx_1)));

    /* 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(&m_color_light_ctx_1); //warning here during build

    bulb_clusters_attr_init();
    level_control_set_value(m_color_light_ctx_1.level_control_attr.current_level);

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


/**
 * @}
 */

  • Some short update:

    I stumble into two useful githubs which can be re-used for the purpose I'm seeking.

    GitHub ref. [1]

    Github ref. [2]

  • Using the referred GitHub, I try to update the light_bulb example, only taking the Zigbee info.

    I can only modify the brightness using the 3rd party controller. On/Off or Hue/Saturation is not working.

    /**
     * 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_color_light.h"
    #include "zb_error_handler.h"
    #include "zb_nrf52_internal.h"
    #include "zigbee_helpers.h"
    #include "zigbee_color_light.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 "nrf_drv_pwm.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                 0x07fff800U                            /**< Scan only one, predefined channel to find the coordinator.(1l << ZIGBEE_CHANNEL) */
    #define HA_COLOR_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 !defined ZB_ROUTER_ROLE
    #error Define ZB_ROUTER_ROLE to compile light bulb (Router) source code.
    #endif
    
    static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
    static nrf_pwm_values_individual_t m_demo1_seq_values;
    static uint16_t const              m_demo1_top  = 255;
    static nrf_pwm_sequence_t const    m_demo1_seq =
    {
        .values.p_individual = &m_demo1_seq_values,
        .length              = NRF_PWM_VALUES_LENGTH(m_demo1_seq_values),
        .repeats             = 0,
        .end_delay           = 0
    };
    
    /* Declare context variable and cluster attribute list for first endpoint */
    zb_color_light_ctx_t m_color_light_ctx;
    
    ZB_DECLARE_COLOR_CONTROL_CLUSTER_ATTR_LIST(m_color_light_ctx,
                                               m_color_light_clusters);
                                               
    /* Declare two endpoints for color controllable and dimmable light bulbs */
    ZB_ZCL_DECLARE_COLOR_DIMMABLE_LIGHT_EP(color_light_ep,
                                           HA_COLOR_LIGHT_ENDPOINT,
                                           m_color_light_clusters);
                                           
    /* Declare context for endpoints */
    ZBOSS_DECLARE_DEVICE_CTX_1_EP(color_light_ctx,
                                  color_light_ep);
    
    APP_PWM_INSTANCE(BULB_PWM_NAME, BULB_PWM_TIMER);
    //static bulb_device_ctx_t m_dev_ctx;
    
    
    /**@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)
        {
        }
    }
    
    
    
    /**@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);
    }
    
    /**@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_COLOR_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_COLOR_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_COLOR_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);
    }
    
    static void rgb_color_set(uint8_t r_value, uint8_t g_value, uint8_t b_value)
    {
        NRF_LOG_DEBUG("Color set = %d %d %d\n", r_value, g_value, b_value);
    
        m_demo1_seq_values.channel_0 = r_value;
        m_demo1_seq_values.channel_1 = g_value;
        m_demo1_seq_values.channel_2 = b_value;
    
        (void)nrf_drv_pwm_simple_playback(&m_pwm0, &m_demo1_seq, 1,
                                          NRF_DRV_PWM_FLAG_LOOP);
    }
    
    
    
    static void pwm_init(void)
    {
        nrf_drv_pwm_config_t const config0 =
        {
            .output_pins =
            {
                LED2_R | NRF_DRV_PWM_PIN_INVERTED, // channel 0
                LED2_G | NRF_DRV_PWM_PIN_INVERTED, // channel 1
                LED2_B | NRF_DRV_PWM_PIN_INVERTED, // channel 2
            },
            .irq_priority = APP_IRQ_PRIORITY_LOWEST,
            .base_clock   = NRF_PWM_CLK_1MHz,
            .count_mode   = NRF_PWM_MODE_UP,
            .top_value    = m_demo1_top,
            .load_mode    = NRF_PWM_LOAD_INDIVIDUAL,
            .step_mode    = NRF_PWM_STEP_AUTO
        };
        APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
        m_demo1_seq_values.channel_0 = 0;
        m_demo1_seq_values.channel_1 = 0;
        m_demo1_seq_values.channel_2 = 0;
    
        (void)nrf_drv_pwm_simple_playback(&m_pwm0, &m_demo1_seq, 1,
                                          NRF_DRV_PWM_FLAG_LOOP);
    }
    
    
    /**@brief Function to convert hue_stauration to RGB color space.
     *
     * @param[IN]  hue          Hue value of color.
     * @param[IN]  saturation   Saturation value of color.
     * @param[IN]  brightness   Brightness value of color.
     * @param[OUT] p_led_params Pointer to structure containing parameters to write to LED characteristic
     */
    static void convert_hsb_to_rgb(uint8_t hue, uint8_t saturation, uint8_t brightness, led_params_t * p_led_params)
    {
        /* Check if p_leds_params is not NULL pointer */
        if (p_led_params == NULL)
        {
            NRF_LOG_INFO("Incorrect pointer to led params");
            return;
        }
        /* C, X, m are auxiliary variables */
        float C     = 0.0;
        float X     = 0.0;
        float m     = 0.0;
        /* Convertion HSB --> RGB */
        C = (brightness / 255.0f) * (saturation / 254.0f);
        X = (hue / 254.0f) * 6.0f;
        /* Casting in var X is necessary due to implementation of floating-point modulo_2 */
        /*lint -e653 */
        X = (X - (2 * (((uint8_t) X) / 2)));
        /*lint -restore */
        X -= 1.0f;
        X = C * (1.0f - ((X > 0.0f) ? (X) : (-1.0f * X)));
        m = (brightness / 255.0f) - C;
    
        /* Hue value is stored in range (0 - 255) instead of (0 - 360) degree */
        if (hue <= 42) /* hue < 60 degree */
        {
            p_led_params->r = (uint8_t)((C + m) * 255.0f);
            p_led_params->g = (uint8_t)((X + m) * 255.0f);
            p_led_params->b = (uint8_t)((0.0f + m) * 255.0f);
        }
        else if (hue <= 84)  /* hue < 120 degree */
        {
            p_led_params->r = (uint8_t)((X + m) * 255.0f);
            p_led_params->g = (uint8_t)((C + m) * 255.0f);
            p_led_params->b = (uint8_t)((0.0f + m) * 255.0f);
        }
        else if (hue <= 127) /* hue < 180 degree */
        {
            p_led_params->r = (uint8_t)((0.0f + m) * 255.0f);
            p_led_params->g = (uint8_t)((C + m) * 255.0f);
            p_led_params->b = (uint8_t)((X + m) * 255.0f);
        }
        else if (hue < 170)  /* hue < 240 degree */
        {
            p_led_params->r = (uint8_t)((0.0f + m) * 255.0f);
            p_led_params->g = (uint8_t)((X + m) * 255.0f);
            p_led_params->b = (uint8_t)((C + m) * 255.0f);
        }
        else if (hue <= 212) /* hue < 300 degree */
        {
            p_led_params->r = (uint8_t)((X + m) * 255.0f);
            p_led_params->g = (uint8_t)((0.0f + m) * 255.0f);
            p_led_params->b = (uint8_t)((C + m) * 255.0f);
        }
        else                /* hue < 360 degree */
        {
            p_led_params->r = (uint8_t)((C + m) * 255.0f);
            p_led_params->g = (uint8_t)((0.0f + m) * 255.0f);
            p_led_params->b = (uint8_t)((X + m) * 255.0f);
        }
    }
    
    
    
    
    /**@brief Function for setting HSB color value to color LED.
     *
     * @param[IN] hue new value for hue.
     * @param[IN] saturation new value for saturation.
     * @param[IN] brightness new value for brightness.
     */
    static void zb_set_hsb_color_values(zb_uint8_t hue, zb_uint8_t saturation, zb_uint8_t brightness)
    {
        // update new value to device context
        m_color_light_ctx.color_control_attr.set_color_info.current_hue = hue;
        m_color_light_ctx.color_control_attr.set_color_info.current_saturation = saturation;
        m_color_light_ctx.level_control_attr.current_level = brightness;
    
        // convert HSB color model to RGB color model
        convert_hsb_to_rgb(hue, saturation, brightness, &m_color_light_ctx.led_params);
    
        // set RGB value to color LEDs
        rgb_color_set(m_color_light_ctx.led_params.r, m_color_light_ctx.led_params.g, m_color_light_ctx.led_params.b);
    }
    
    
    /**@brief Function for changing the hue of the light bulb.
     *
     * @param[IN] new_hue       New value for hue.
     */
    static void color_control_set_value_hue(zb_uint8_t new_hue)
    {
        NRF_LOG_INFO("Set color hue value: %i", new_hue);
        zb_set_hsb_color_values(new_hue, m_color_light_ctx.color_control_attr.set_color_info.current_saturation, m_color_light_ctx.level_control_attr.current_level);
    }
    
    /**@brief Function for changing the saturation of the light bulb.
     *
     * @param[IN] new_saturation new value for saturation.
     */
    static void color_control_set_value_saturation(zb_uint8_t new_saturation)
    {
        NRF_LOG_INFO("Set color saturation value: %i", new_saturation);
        zb_set_hsb_color_values(m_color_light_ctx.color_control_attr.set_color_info.current_hue, new_saturation, m_color_light_ctx.level_control_attr.current_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_ZCL_SET_ATTRIBUTE(HA_COLOR_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_color_light_ctx.level_control_attr.current_level);
        }
        else
        {
            //light_bulb_set_brightness(0U);
            m_color_light_ctx.led_params.r = 0;
            m_color_light_ctx.led_params.g = 0;
            m_color_light_ctx.led_params.b = 0;
            rgb_color_set(m_color_light_ctx.led_params.r, m_color_light_ctx.led_params.g, m_color_light_ctx.led_params.b);
        }
    }
    
    /**@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_color_light_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_COLOR_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_color_light_ctx.basic_attr.zcl_version   = ZB_ZCL_VERSION;
        m_color_light_ctx.basic_attr.app_version   = BULB_INIT_BASIC_APP_VERSION;
        m_color_light_ctx.basic_attr.stack_version = BULB_INIT_BASIC_STACK_VERSION;
        m_color_light_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_color_light_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_color_light_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_color_light_ctx.basic_attr.date_code,
                              BULB_INIT_BASIC_DATE_CODE,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_DATE_CODE));
    
        m_color_light_ctx.basic_attr.power_source = BULB_INIT_BASIC_POWER_SOURCE;
    
        ZB_ZCL_SET_STRING_VAL(m_color_light_ctx.basic_attr.location_id,
                              BULB_INIT_BASIC_LOCATION_DESC,
                              ZB_ZCL_STRING_CONST_SIZE(BULB_INIT_BASIC_LOCATION_DESC));
    
    
        m_color_light_ctx.basic_attr.ph_env = BULB_INIT_BASIC_PH_ENV;
    
        /* Identify cluster attributes data */
        m_color_light_ctx.identify_attr.identify_time = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;
    
    
        /* On/Off cluster attributes data */
        m_color_light_ctx.on_off_attr.on_off = (zb_bool_t)ZB_ZCL_ON_OFF_IS_ON;
    
        m_color_light_ctx.level_control_attr.current_level  = ZB_ZCL_LEVEL_CONTROL_LEVEL_MAX_VALUE;
        m_color_light_ctx.level_control_attr.remaining_time = ZB_ZCL_LEVEL_CONTROL_REMAINING_TIME_DEFAULT_VALUE;
    
         /* Set to use hue & saturation */
        m_color_light_ctx.color_control_attr.set_color_info.color_mode          = ZB_ZCL_COLOR_CONTROL_COLOR_MODE_HUE_SATURATION;
        m_color_light_ctx.color_control_attr.set_color_info.color_temperature   = ZB_ZCL_COLOR_CONTROL_COLOR_TEMPERATURE_DEF_VALUE;
        m_color_light_ctx.color_control_attr.set_color_info.remaining_time      = ZB_ZCL_COLOR_CONTROL_REMAINING_TIME_MIN_VALUE;
        m_color_light_ctx.color_control_attr.set_color_info.color_capabilities  = ZB_ZCL_COLOR_CONTROL_CAPABILITIES_HUE_SATURATION;
        
        /* According to ZCL spec 5.2.2.2.1.12 0x00 shall be set when CurrentHue and CurrentSaturation are used. */
        m_color_light_ctx.color_control_attr.set_color_info.enhanced_color_mode = 0x00;
    
        /* According to 5.2.2.2.1.10 execute commands when device is off. */
        m_color_light_ctx.color_control_attr.set_color_info.color_capabilities  = ZB_ZCL_COLOR_CONTROL_OPTIONS_EXECUTE_IF_OFF;
    
        /* According to ZCL spec 5.2.2.2.2 0xFF shall be set when specific value is unknown. */
        m_color_light_ctx.color_control_attr.set_defined_primaries_info.number_primaries = 0xff;
    
    
        ZB_ZCL_SET_ATTRIBUTE(HA_COLOR_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_color_light_ctx.on_off_attr.on_off,                        
                             ZB_FALSE);                   
    
        ZB_ZCL_SET_ATTRIBUTE(HA_COLOR_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_color_light_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
        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);
    
        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;
    
        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("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 if (cluster_id == ZB_ZCL_CLUSTER_ID_COLOR_CONTROL)
                {
                    uint16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
    
                    switch (attr_id)
                    {
                        case ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_HUE_ID:
                            NRF_LOG_INFO("color control HUE attribute setting to %hd", value);
                            color_control_set_value_hue(value);
                            break;
    
                        case ZB_ZCL_ATTR_COLOR_CONTROL_CURRENT_SATURATION_ID:
                            NRF_LOG_INFO("color control Saturation attribute setting to %hd", value);
                            color_control_set_value_saturation(value);
                            break;
    
                        default:
                            NRF_LOG_INFO("Unused attribute");
                            break;
                    }
                }
                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;
                NRF_LOG_INFO("Default case, returned error");
                break;
        }
    
        NRF_LOG_INFO("zcl_device_cb status: %hd", p_device_cb_param->status);
    }
    
    /**@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)
    {
        /* Update network status LED */
        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 (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 timer, logging system and GPIOs. */
        timer_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("led_bulb");
    
        /* 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_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_color_light_ctx, 0, sizeof(m_color_light_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(&color_light_ctx); 
    
        bulb_clusters_attr_init();
        level_control_set_value(m_color_light_ctx.level_control_attr.current_level);
    
        /** 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());
        }
    }
    
    
    /**
     * @}
     */
    

  • I tried to salvage some of its code back into the light_bulb ones, including the "zb_ha_dimmable_color_light.h" and "zigbee_color_light.h" and adapting on the go without success.

     So what did you do? Do you have any form of output from the dongle? Is it connecting to the network? Can you adjust the light level, or nothing?

    The challenge related to developing on the nRF52840 dongle is that it doesn't have a programmer. I strongly suggest that you get hold of a DK (which has an on board debugger). Developing without a debugger is like driving blind. Extremely difficult. 

    Best regards,

    Edvin

  • Via the 3rd party controller, I can send and receive info from the nRF52840 dongle.

    The ON/OFF, brightness and hue properties are updated properly (when checking the zigbee message receive) but only the brightness is physically working.

    Indeed, you have a good analogy there. Is there additional debugging info I could retrieve of the nRF52840 dongle, reading it via the USB port, adding library/softdevice into the HEX file?

    A nRF52840 DK would be a great tool to have, hmmm.

    Thanks for your inputs!

  • Well, I could not manage to get a functional color light bulb based on other examples.

    Nevertheless, still using the light bulb example, I repurposed the brightness level to trigger different board LED colors.

    So that is okay Slight smile

    I noticed that the nRF52840 dongle is sending back info relatively often (each 3 seconds) to the controller (see JSON below).

    msromero got nice explanation in the post but I could not reduce the communication. I'm aiming to use the nRF52840 dongle with a coin cell, therefore, minimizing communication. Is there other example(s) with show how to minimize communication from the end device?

    Thanks!

    {
        "attr":
        {   "lastannounced":"2020-08-23T08:53:21Z",
            "lastseen":"2020-08-23T19:54:47Z",
            "manufacturername":"Nordic",
            "modelid":"Dimable_Light_v0.1",
            "name":"Dimmable light 20",
            "type":"Dimmable light",
            "uniqueid":"************"
        },
        "e":"changed",
        "id":"20",
        "r":"lights",
        "t":"event",
        "uniqueid":"*************"
    }

Related