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


/**
 * @}
 */

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

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

Children
No Data
Related