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

Thermostat cluster enable issue

Hi All,

I am developing product using nRF52840 and SDK nRF5_SDK_for_Thread_and_Zigbee_v3.0.0_d310e71.

This product is basically, using the Thermostat cluster and Zigbee protocol to communicate with the Zigbee gateway.

So, I referred light_bulb example and followed steps to enable "Thermostat cluster and attributes".

I have included the respective files also but I am unable to execute the below callback function case statement,

static zb_void_t zcl_device_cb(zb_uint8_t param)
{
    zb_uint8_t                       cluster_id;
    zb_uint8_t                       attr_id;
    zb_buf_t                       * p_buffer = ZB_BUF_FROM_REF(param);
    zb_zcl_device_callback_param_t * p_device_cb_param =
                     ZB_GET_BUF_PARAM(p_buffer, zb_zcl_device_callback_param_t);

    NRF_LOG_INFO("zcl_device_cb id %hd", p_device_cb_param->device_cb_id);

    /* Set default response value. */
    p_device_cb_param->status = RET_OK;

    switch (p_device_cb_param->device_cb_id)
    {
        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_THERMOSTAT)
            {
                uint16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;

                NRF_LOG_INFO("thermostat local temperature: %d", value);
                if (attr_id == ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID)
                {
                    local_temperature_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);
}

Also, I am attaching code for reference please let me know what else I forgot to enable the functions. It is urgent for me to solve this issue.

Radiator_nRF_v0.9.0.zip

And, with these attributes, for some of the commands, I need to implement custom attributes so if you share how to add custom attributes to this cluster.

Thanks in advance.

Regards,

Rohit R

Parents
  • Hi Marte,

    Thank you for the details, 

    As of now, sending custom command is pending. I will work on this in some time. 

    But current requirement I am trying to enabled the required attributes list. With reference to your code and other I have created extended list also. 

    But unoccupied, min and max, local_calibration and etc are not getting highlighted from thermostat cluster. And also Battery percentage attribute also facing same problem. they are not getting highlighted and these are must attributes (mandatory ids). 

    I have tested in SDK 3.0 I am getting highlighted below points but in SDK 4.1 i am facing this issue. Let me know why?

    Below is the image attached for both cluster. And also my thermostat.h file please check what is wrong. Why I am not getting these attributes highlighted. 

    0508.zb_zcl_thermostat.h

    5807.zb_zcl_power_config.h

    Thanks and regards

    Rohit 

  • Hi Marte, 

    Any update on this. 

    Urgent!

    Is there any difference in my file. 

    Thanks and Regards

    Rohit R

  • Hi Marte, 

    Thank you for the response and support. 

    yes, I had compared both project as per my knowledge. But due to completion pressure we have decided to develop product using SDK 3.0 has we can see attribute access and edit is possible here. And when product in testing phase we will look into the issue with SDK 4.1. 

    So, I have started degrading the code to SDK 3.0 and my development is in progress. 

    I will inform you once if i get anything and you also let me know if you found the issue here. 

    Along with this I need one more information regarding power management. As you know we are developing Radiator device using nRF52840 and this device is powered up using 2xAA batteries. 

    Requirement of device is battery should last long for 2 year. It should in hibernation unless and until any interrupts. 

    I have one GPIO interrupt and any Zigbee commands from gateway. If either of interrupt device it should wake up from sleep. 

    Can you guide me what all things I should take care while implementing sleep mode. And I get maximum battery life. 

    If you have any example with similar configuration it will help me to quick implementation. 

    Let me know your feedback on this sleep configuration. 

    Thanks and Regards

    Rohit R

  • Hi Rohit,

    All the Zigbee examples in our SDK are by default power optimized such that the CPU enter low power mode in times of inactivity.

    If your device is an end device, you can use Sleepy End Device to reduce current consumption. You can see Power saving for ZED for more information. This is used in the light switch example in our SDK. With this, the CPU enter sleep mode when there is nothing happening on the stack, and the device will automatically wake up on an event, as well as waking up from time to time to ensure correct processing of the stack.

    In the projects I have received from you, your device has had the router role. Routers enter low power mode, instead of sleep mode, when the stack has nothing to do. You can for example use the weak function zb_osif_go_idle(), which can be found in external/zboss/osif/zb_nrf52_common.c. This functions is defined to check if the logger has anything to process, and if it does not, then the CPU goes idle. You can also redefine this function to check for other things or to do something else. An example of this is used in the light bulb example.

    Please make sure to do power consumption measurements. For more information you can check out this page.

    Best regards,

    Marte

  • Hi Marte, 

    Thank you so much for the details.

    In the projects I have received from you, your device has had the router role.

    - With reference to multi sensor example I have changed to end point role. 

    This is used in the light switch example in our SDK

    - Okay, I will check the switch example. Is there any explanation regarding switch example work flow to understand sleep?. 

    I will go through the links and If any unclear points i will get back to you. 

    Thanks and Regards

    Rohit R

  • Hi Rohit,

    If you enable sleepy end device, then the signal ZB_COMMON_SIGNAL_CAN_SLEEP is generated when the device can be put to sleep. In the light switch example, sleepy end device is enabled by pressing Button 3 on the board while resetting the board. However, you can enable it by simply calling zb_set_rx_on_when_idle(ZB_FALSE) in main(), as in the multi sensor example.

    Since you are using SDK v3.0.0, which does not have the default signal handler in zigbee_helpers.c, you will have to handle the signal ZB_COMMON_SIGNAL_CAN_SLEEP in zboss_signal_handler(). You should call the function zb_sleep_now() to put the device to sleep when this signal is received. This is done in multiple examples in v3.0.0 already, such as the light switch and the multi sensor examples, so you can look at those to see how to do this. 

    Best regards,

    Marte

  • Hi Marte, 

    Thank you for the response. 

    In the light switch example, sleepy end device is enabled by pressing Button 3 on the board while resetting the board.

    - I saw the code, this means If button is pressed device will not go into sleep correct? or is it wake up from sleep when button pressed?

    you can enable it by simply calling zb_set_rx_on_when_idle(ZB_FALSE) in main()

    - Means, only calling this function device will go to sleep correct? But when it wake up ? Is it wake up periodically or any other way? 

    you will have to handle the signal ZB_COMMON_SIGNAL_CAN_SLEEP in zboss_signal_handler().

    - Okay, I will enable this by referring both codes. 

    My wake up mechanism should be. 

    - If there is no activity or any data on UART  go to sleep. 

    - Wake up if there is interrupt from GPIO or any UART data 

    - Wake up if there is Zigbee command. 

    Let me know your feedback. 

    Thanks and Regards

    Rohit R

Reply
  • Hi Marte, 

    Thank you for the response. 

    In the light switch example, sleepy end device is enabled by pressing Button 3 on the board while resetting the board.

    - I saw the code, this means If button is pressed device will not go into sleep correct? or is it wake up from sleep when button pressed?

    you can enable it by simply calling zb_set_rx_on_when_idle(ZB_FALSE) in main()

    - Means, only calling this function device will go to sleep correct? But when it wake up ? Is it wake up periodically or any other way? 

    you will have to handle the signal ZB_COMMON_SIGNAL_CAN_SLEEP in zboss_signal_handler().

    - Okay, I will enable this by referring both codes. 

    My wake up mechanism should be. 

    - If there is no activity or any data on UART  go to sleep. 

    - Wake up if there is interrupt from GPIO or any UART data 

    - Wake up if there is Zigbee command. 

    Let me know your feedback. 

    Thanks and Regards

    Rohit R

Children
  • Hi Rohit,

    Rohit Rajapure said:
    this means If button is pressed device will not go into sleep correct? or is it wake up from sleep when button pressed?

     The button does not make the device go into sleep mode or wake up from sleep when it is pressed. What it does is to enable sleepy end device behavior. This is there so that the user can decide, when resetting the device, whether they want the behavior enabled or not. In the multi sensor example it is enabled from start, as zb_set_rx_on_when_idle(ZB_FALSE) is called in main() before the Zigbee stack is started. Light switch instead calls sleepy_device_setup(), which checks whether the button for enabling sleepy end device is pressed or not, and will enable the behavior if the button is pressed. Additionally, the button must be pressed while resetting the board. Pressing the button while the device is on will not affect the sleepy end device behavior.

    Rohit Rajapure said:
    Means, only calling this function device will go to sleep correct? But when it wake up ? Is it wake up periodically or any other way? 

     No, it will not go to sleep. As I explained in my previous reply and above, zb_set_rx_on_when_idle(ZB_FALSE) will not make it go to sleep, it will enable sleepy end device behavior. It will go to sleep when there is nothing to do and the signal ZB_COMMON_SIGNAL_CAN_SLEEP is generated. This happens when there is no immediate callback for execution and there is no outgoing packet on the MAC level. If there are any alarms in the queue, then the device will wake up when the first alarm is called. If there are no alarms in the queue, then the sleep duration is set to 10 seconds.

     

    You will not be able to use sleepy end device if you want your device to wake up if there is a Zigbee command. When using sleepy end device, the device will not receive messages while it is asleep, but will poll it's parent at intervals to see if there are any messages waiting for it. 

    You can also change the sleep functionality if you do not want to use the default behavior by using the weak functions zb_osif_go_idle or zb_nrf52840_sleep. See Zigbee stack sleep routines for more information. This documentation is for v4.1.0, as the "Zigbee application helper functions" is not in the documentation for v3.0.0, but the weak functions exist in both versions.

    Please also see Power saving for ZED to get a clearer understanding of the power saving mechanisms for end devices in the SDK.

    Best regards,

    Marte

  • Hi Marte, 

    Thank you for the response. 

    The button does not make the device go into sleep mode or wake up from sleep when it is pressed. What it does is to enable sleepy end device behavior. This is there so that the user can decide, when resetting the device, whether they want the behavior enabled or not. In the multi sensor example it is enabled from start, as zb_set_rx_on_when_idle(ZB_FALSE) is called in main() before the Zigbee stack is started. Light switch instead calls sleepy_device_setup(), which checks whether the button for enabling sleepy end device is pressed or not, and will enable the behavior if the button is pressed. Additionally, the button must be pressed while resetting the board. Pressing the button while the device is on will not affect the sleepy end device behavior.

    - Okay, my understanding is wrong. 

    above, zb_set_rx_on_when_idle(ZB_FALSE) will not make it go to sleep, it will enable sleepy end device behavior. It will go to sleep when there is nothing to do and the signal ZB_COMMON_SIGNAL_CAN_SLEEP is generated. This happens when there is no immediate callback for execution and there is no outgoing packet on the MAC level. If there are any alarms in the queue, then the device will wake up when the first alarm is called. If there are no alarms in the queue, then the sleep duration is set to 10 seconds.

    -Okay, as per your suggestion I have referred the multi sensor example and made the respected changes in zigbee_signal_handler() as done in multi sensor done. 

    - as per explanation it in sleep mode is configured and it will enter into sleep if there is no signal. Correct? Correct me if I am wrong. 

    And wake up from sleep every 10sec default time. Correct?

    You will not be able to use sleepy end device if you want your device to wake up if there is a Zigbee command.

    - Okay, then How to configure it then? 

    You can also change the sleep functionality if you do not want to use the default behavior by using the weak functions zb_osif_go_idle or zb_nrf52840_sleep.

    - Sorry, It is unclear. 

    - And, we can not use this "ZB_COMMON_SIGNAL_CAN_SLEEP ". If we are waking up device using Zigbee command and GPIO interrupt. Correct? If yes, then let me know which example explain this 2 waking mechanism. I will refer the that example for my implementation. 

     

    Thanks and Regards

    Rohit R

  • Hi Marte, 

    I had gone through the link that you have shared regarding Zigbee stack sleep. 

    But for me points are unclear. Means I am not getting how to handle go to sleep and wake up from sleep in this, 


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

    can you please guide me here, 

    I have one GPIO pins which toggles as input and output pin during command sharing between nRF and STM8 board over UART. Means this gpio pins first configured as input and if interrupt it switch to output pin and stay for 5msec high to send commands over UART. 

    So, my plan is to use this gpio for waking up device from sleep mode. Is it possible? 

    And also wake up using wake up timer?

    I have referred ble_peripheral examples here for GPIO interrupt. Can I use same method in Zigbee code ? 

    As per your suggestion, I have referred multi sensor example to enable sleep_now() function in my code. I have included it my code zigbee_signal_handler().

    Attached is my main.c file. Let me know your feed back on this. 

    /**
     * Copyright (c) 2018 - 2019, 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 "zb_mem_config_med.h"
    #include "zb_error_handler.h"
    #include "zb_nrf52840_internal.h"
    #include "zigbee_helpers.h"
    
    #include "bsp.h"
    #include "boards.h"
    #include "app_pwm.h"
    #include "app_timer.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "app_uart.h"
    #include "app_error.h"
    #include "nrf_delay.h"
    #include "nrf.h"
    
    /**User Include file*********/
    #include "uart_config.h"
    #include "gpio_config.h"
    #include "timer_config.h"
    #include "commands.h" 
    #include "uart_statemachine.h" 
    #include "app_flash_memory.h"
    
    #include "zb_custom1_thermostat.h"
    #include "custom_app_event.h"
    
    
                                    
    /**< Scan only one, predefined channel to find the coordinator. */
    #define IEEE_CHANNEL_MASK                (ZB_TRANSCEIVER_ALL_CHANNELS_MASK)    // (1l << ZIGBEE_CHANNEL)
    
    #define ERASE_PERSISTENT_CONFIG           ZB_FALSE                              /**< Do not erase NVRAM to save the network parameters after device reboot or power-off. */
    
    
    #define ZIGBEE_NETWORK_STATE_LED          BSP_BOARD_LED_2                       /**< LED indicating that light switch successfully joind ZigBee network. */
    
    
    #if !defined ZB_ED_ROLE
    #error Define ZB_ED_ROLE to compile End Device source code.
    #endif
    
    
    
    /******************************************************************
    * GLOBAL VARIABLES
    *
    *******************************************************************/
    uint16_t ui16CurrentTemp =0, ui16OccupiedHeatSetpoint = 0, ui16UnOccupiedHeatSetpoint = 0;
    uint8_t  ui8LocalTemperatureCalibration = 0;
    uint32_t ui32HostflagsData = 0;
    
    bool boolSetTemperature = false;
    bool boolGetStatus = false;
    bool boolSetHostflags = false;
    bool boolSendDeviceConfig = false;
    /******************************************************************************************
    *EXTERNAL VARIABLES
    *
    *******************************************************************************************/
    extern bool boolReady;
    extern bool boolMCUInterrupt;
    extern bool boolSetCommand;
    extern uint8_t ui8SendDeviceConfig[BUFFER_SIZE];
    
    extern App_tsEventUart sAppUartEvent;
    extern E_StateMachineThermostat e_StateMachineThermostat;
    /******************************************************************************************
    *FUNCTIONS 
    *
    *******************************************************************************************/
    /* Declare attribute list for Basic cluster. */
    ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(basic_attr_list,
                                         &m_dev_ctx.basic_attr.zcl_version,
                                         &m_dev_ctx.basic_attr.app_version,
                                         &m_dev_ctx.basic_attr.stack_version,
                                         &m_dev_ctx.basic_attr.hw_version,
                                         m_dev_ctx.basic_attr.mf_name,
                                         m_dev_ctx.basic_attr.model_id,
                                         m_dev_ctx.basic_attr.date_code,
                                         &m_dev_ctx.basic_attr.power_source,
                                         m_dev_ctx.basic_attr.location_id,
                                         &m_dev_ctx.basic_attr.ph_env,
                                         m_dev_ctx.basic_attr.sw_ver);
    
    /* Declare attribute list for Identify cluster. */
    ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST(identify_attr_list,
                                        &m_dev_ctx.identify_attr.identify_time);
    
    /**power attributes**/
    ZB_ZCL_DECLARE_POWER_CONFIG_BATTERY_ATTRIB_LIST_EXT(power_config_attr_list,
                                            &m_dev_ctx.power_attr.battery_voltage,
                                            &m_dev_ctx.power_attr.battery_size,
                                            &m_dev_ctx.power_attr.battery_quantity,
                                            &m_dev_ctx.power_attr.battery_rated_voltage,
                                            &m_dev_ctx.power_attr.battery_alarm_mask,
                                            &m_dev_ctx.power_attr.battery_voltage_min_threshold,
                                            &m_dev_ctx.power_attr.battery_percentage_remaining,
                                            &m_dev_ctx.power_attr.battery_voltage_threshold1,
                                            &m_dev_ctx.power_attr.battery_voltage_threshold2,
                                            &m_dev_ctx.power_attr.battery_voltage_threshold3,
                                            &m_dev_ctx.power_attr.battery_percentage_min_threshold,
                                            &m_dev_ctx.power_attr.battery_percentage_threshold1,
                                            &m_dev_ctx.power_attr.battery_percentage_threshold2,
                                            &m_dev_ctx.power_attr.battery_percentage_threshold3,
                                            &m_dev_ctx.power_attr.battery_alarm_state);
    
    ZB_ZCL_DECLARE_TIME_ATTRIB_LIST(time_attr_list,
                                    &m_dev_ctx.time_attr.timeId,
                                    &m_dev_ctx.time_attr.time_status,
                                    &m_dev_ctx.time_attr.time_zone,
                                    &m_dev_ctx.time_attr.dst_start,
                                    &m_dev_ctx.time_attr.dst_end,
                                    &m_dev_ctx.time_attr.dst_shift,
                                    &m_dev_ctx.time_attr.standard_time,
                                    &m_dev_ctx.time_attr.local_time,
                                    &m_dev_ctx.time_attr.last_settime,
                                    &m_dev_ctx.time_attr.valid_untilTime);
    
    /* Declare extended attribute list for Thermostat cluster. */
    ZB_ZCL_DECLARE_THERMOSTAT_ATTRIB_LIST_EXT(thermostat_attr_list,
                                              &m_dev_ctx.thermostat_attr.local_temperature,
                                              &m_dev_ctx.thermostat_attr.local_temperature_calibration,
                                              &m_dev_ctx.thermostat_attr.occupied_heating_setpoint,
                                              &m_dev_ctx.thermostat_attr.unoccupied_heating_setpoint,
                                              &m_dev_ctx.thermostat_attr.pi_heating_demand,
                                              &m_dev_ctx.thermostat_attr.min_heating_setpoint_limit,
                                              &m_dev_ctx.thermostat_attr.max_heating_setpoint_limit,
                                              &m_dev_ctx.thermostat_attr.remote_sensing,
                                              &m_dev_ctx.thermostat_attr.control_seq_of_operation,
                                              &m_dev_ctx.thermostat_attr.system_mode,
                                              &m_dev_ctx.thermostat_attr.trv_mode,
                                              &m_dev_ctx.thermostat_attr.set_valve_position,
                                              &m_dev_ctx.thermostat_attr.error,
                                              &m_dev_ctx.thermostat_attr.current_setpoint,
                                              &m_dev_ctx.thermostat_attr.host_flags);
    
    /* Declare cluster list for Thermostat device (Basic, Identify, Thermostat, Fan Control, Thermostat UI). */
    ZB_DECLARE_CUSTOM_THERMOSTAT_CLUSTER_LIST(thermostat_clusters,
                                          basic_attr_list,
                                          identify_attr_list,
                                          power_config_attr_list,
                                          thermostat_attr_list,
                                          time_attr_list);
    
    
    ZB_HA_DECLARE_CUSTOM_THERMOSTAT_EP(thermostat_ep,
                                   THERMOSTAT_SENSOR_ENDPOINT,
                                   thermostat_clusters);
    
    ZB_HA_DECLARE_CUSTOM_THERMOSTAT_CTX(thermostat_ctx, thermostat_ep);
    
    /**@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 Function for initializing LEDs.
     */
    static void leds_init(void)
    {
        bsp_board_init(BSP_INIT_LEDS);
    }
    
    /**@brief Function for initializing all clusters attributes.
    */
    static void thermostat_clusters_attr_init(void)
    {
         /* Basic cluster attributes data */
         m_dev_ctx.basic_attr.zcl_version = ZB_ZCL_VERSION;
         m_dev_ctx.basic_attr.app_version = THERMOSTAT_INIT_BASIC_APP_VERSION;
         m_dev_ctx.basic_attr.stack_version = THERMOSTAT_INIT_BASIC_STACK_VERSION;
         m_dev_ctx.basic_attr.hw_version = THERMOSTAT_INIT_BASIC_HW_VERSION;
       
        /* Use ZB_ZCL_SET_STRING_VAL to set strings, because the first byte should
         * contain string length without trailing zero.
         *
         * For example "test" string wil be encoded as:
         *   [(0x4), 't', 'e', 's', 't']
         */
          ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.mf_name,
                              THERMOSTAT_INIT_BASIC_MANUF_NAME,
                              ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_MANUF_NAME));
    
          ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.model_id,
                              THERMOSTAT_INIT_BASIC_MODEL_ID,
                              ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_MODEL_ID));
    
          ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.date_code,
                              THERMOSTAT_INIT_BASIC_DATE_CODE,
                              ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_DATE_CODE));
    
          m_dev_ctx.basic_attr.power_source = THERMOSTAT_INIT_BASIC_POWER_SOURCE;
    
          ZB_ZCL_SET_STRING_VAL(m_dev_ctx.basic_attr.location_id,
                              THERMOSTAT_INIT_BASIC_LOCATION_DESC,
                              ZB_ZCL_STRING_CONST_SIZE(THERMOSTAT_INIT_BASIC_LOCATION_DESC));
    
    
          m_dev_ctx.basic_attr.ph_env = THERMOSTAT_INIT_BASIC_PH_ENV;
          //m_dev_ctx.basic_attr.sw_ver = "00000000";
          memcpy( m_dev_ctx.basic_attr.sw_ver,"00000000", 8);
        
        /* Identify cluster attributes data */
        m_dev_ctx.identify_attr.identify_time        = ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE;
    
    //    /**power configuration attributes data**/
        m_dev_ctx.power_attr.battery_percentage_remaining = 0x02;
        m_dev_ctx.power_attr.battery_quantity = ZB_POWER_CONFIG_BATTERY_QUANTITY;
        m_dev_ctx.power_attr.battery_size = ZB_ZCL_POWER_CONFIG_BATTERY_SIZE_AA;
    
       /* Thermostat cluster attributes data */
        m_dev_ctx.thermostat_attr.local_temperature             = 0x07D0;
        m_dev_ctx.thermostat_attr.local_temperature_calibration = 0x00;
        m_dev_ctx.thermostat_attr.pi_heating_demand             = 0xFF;
        m_dev_ctx.thermostat_attr.occupied_heating_setpoint     = 0x07D0;
        m_dev_ctx.thermostat_attr.unoccupied_heating_setpoint   = 0x07D0;
        m_dev_ctx.thermostat_attr.min_heating_setpoint_limit    = 0x01F4;
        m_dev_ctx.thermostat_attr.max_heating_setpoint_limit    = 0x0BB8;
        m_dev_ctx.thermostat_attr.control_seq_of_operation      = ZB_ZCL_THERMOSTAT_CONTROL_SEQ_OF_OPERATION_HEATING_ONLY;
        m_dev_ctx.thermostat_attr.system_mode                   = ZB_ZCL_THERMOSTAT_SYSTEM_MODE_HEAT;
        m_dev_ctx.thermostat_attr.current_setpoint             = 0x0898;
        m_dev_ctx.thermostat_attr.trv_mode                     = ZB_ZCL_THERMOSTAT_TRV_MODE_DEFAULT_VALUE;
        m_dev_ctx.thermostat_attr.set_valve_position           = 0;
        m_dev_ctx.thermostat_attr.error                        = 0;
    
             /***time cluster attributes data**/
        m_dev_ctx.time_attr.timeId = ZB_ZCL_TIME_TIME_DEFAULT_VALUE;
        m_dev_ctx.time_attr.time_status = ZB_ZCL_TIME_TIME_STATUS_DEFAULT_VALUE;
    
        /*local temperature set attribute**/
       ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                            ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                            ZB_ZCL_CLUSTER_SERVER_ROLE,
                            ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID,
                            (zb_uint8_t *)&m_dev_ctx.thermostat_attr.local_temperature,
                            ZB_FALSE);
     
        ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                            ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                            ZB_ZCL_CLUSTER_SERVER_ROLE,
                            ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID,
                            (zb_uint8_t *)&m_dev_ctx.thermostat_attr.occupied_heating_setpoint,
                            ZB_FALSE);
    
        ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                            ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                            ZB_ZCL_CLUSTER_SERVER_ROLE,
                            ZB_ZCL_ATTR_THERMOSTAT_UNOCCUPIED_HEATING_SETPOINT_ID,
                            (zb_uint8_t *)&m_dev_ctx.thermostat_attr.unoccupied_heating_setpoint,
                            ZB_FALSE);
    
        ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT, 
                             ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                             ZB_ZCL_CLUSTER_SERVER_ROLE, 
                             ZB_ZCL_ATTR_THERMOSTAT_HOST_FLAG_ID, 
                             (zb_uint8_t *)&m_dev_ctx.thermostat_attr.host_flags, 
                             ZB_FALSE);
    
        ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT, 
                             ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                             ZB_ZCL_CLUSTER_SERVER_ROLE, 
                             ZB_ZCL_ATTR_THERMOSTAT_TRV_MODE_ID, 
                             (zb_uint8_t *)& m_dev_ctx.thermostat_attr.trv_mode, 
                             ZB_FALSE);
    
       /**Battery percentage value**/
       ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                            ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
                            ZB_ZCL_CLUSTER_SERVER_ROLE,
                            ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_REMAINING_ID,
                            (zb_uint8_t *)&m_dev_ctx.power_attr.battery_percentage_remaining,
                            ZB_FALSE);  
                                      
       ZB_ZCL_SET_ATTRIBUTE(THERMOSTAT_SENSOR_ENDPOINT,
                            ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
                            ZB_ZCL_CLUSTER_SERVER_ROLE,
                            ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_QUANTITY_ID,
                            (zb_uint8_t *)&m_dev_ctx.power_attr.battery_quantity,
                            ZB_FALSE);
    }
    
    /**@brief Function for local temperature
     *
     * @param[in]   new_value local temp value
     */
    void localTemperatureValue(zb_uint16_t ui16local_tempvalue)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                         ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                                         ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                         ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_ID, 
                                         (zb_uint8_t *)&ui16local_tempvalue , 
                                         ZB_FALSE);
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Set local temperature value fail. zcl_status: %d", zcl_status);
       }
    }
    void CurrentSetpointChangeValue(zb_uint16_t ui16CurrentSetpoint)
    {
       zb_zcl_status_t zcl_status;
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_CURRENT_SETPOINT_CHANGE_ID,
                                        (zb_uint8_t *)&ui16CurrentSetpoint,
                                        ZB_FALSE);
       
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Setc current set point temperature value fail. zcl_status: %d", zcl_status);
       }
    
       
       if(ui16CurrentSetpoint != 0xFFFF)
       {
          ui16CurrentTemp = ui16CurrentSetpoint;
       }
       else
       {
          ui16CurrentTemp = 0xFFFF;
       }
    
    }
    
    /**
    **function to read/write the occupied heating setpoint 
    **Any change in occupied heating value will automatically copied to set point change attribute
    **
    **/
    void OccupiedHeatingSetpoint(zb_uint16_t ui16OccupiedSetpoint)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID,
                                        (zb_uint8_t *)&ui16OccupiedSetpoint,
                                        ZB_FALSE);
       
         
       if(ui16OccupiedSetpoint != 0xFFFF)
       {
          ui16OccupiedHeatSetpoint = ui16OccupiedSetpoint;
          ui16CurrentTemp = ui16OccupiedSetpoint;
          CurrentSetpointChangeValue(ui16CurrentTemp);
       }
       else
       {
          ui16OccupiedHeatSetpoint == 0xFFFF;
       }
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Set occupied heating setpoint temperature value fail. zcl_status: %d", zcl_status);
       }
    }
    
    void ReadOccupiedHeatingSetpoint(zb_uint16_t ui16ReadOccupiedSetpoint)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID,
                                        (zb_uint8_t *)&ui16ReadOccupiedSetpoint,
                                        ZB_FALSE);
    
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Set occupied heating setpoint temperature value fail. zcl_status: %d", zcl_status);
       }
    }
    /**
    **function to read/write the unoccupied heating setpoint 
    **Any change in unoccupied heating value will automatically copied to set point change attribute
    **
    **/
    void UnOccupiedHeatingSetpoint(zb_uint16_t ui16UnOccupiedSetpoint)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_UNOCCUPIED_HEATING_SETPOINT_ID,
                                        (zb_uint8_t *)&ui16UnOccupiedSetpoint,
                                        ZB_FALSE);
       
       if(ui16UnOccupiedSetpoint != 0xFFFF)
       {
         ui16UnOccupiedHeatSetpoint = ui16UnOccupiedSetpoint;
         ui16CurrentTemp = ui16UnOccupiedSetpoint;
         CurrentSetpointChangeValue(ui16CurrentTemp);
       }
       else
       {
         ui16UnOccupiedHeatSetpoint =  0xFFFF;
       }
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Set unoccupied heating setpoint temperature value fail. zcl_status: %d", zcl_status);
       }
    }
    
    /**
    **function to read value of pi heating demand
    **Any change in valve position value will be copied to PI heating demand attribute which only read attribute
    **
    **/
    static void PIHeatingDemand (zb_uint8_t ui8PiHeatingDemand)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_PI_HEATING_DEMAND_ID,
                                        &ui8PiHeatingDemand,
                                        ZB_FALSE);
       
    
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("read pi heating demand value fail. zcl_status: %d", zcl_status);
       }
    }
    /**
    **function for read/write local temperature calibration
    **Any change in local temperature attribute then add this value to D11 and D12 of set temperature command
    **
    **/
    static void LocalTemperatureCalibration(zb_uint8_t ui8localTempCalibration)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_CALIBRATION_ID,
                                        &ui8localTempCalibration,
                                        ZB_FALSE);
       
       ui8LocalTemperatureCalibration = ui8localTempCalibration;
    
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("local temperature calibration value fail. zcl_status: %d", zcl_status);
       }
    }
    /**
    **function to read/write the valve position
    **Any change in valve position value will be copied to PI heating demand attribute which only read attribute
    **
    **/
    void SetValvePosition(zb_uint8_t ui8ValvePosition)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_SET_VALVE_POSITION_ID,
                                        &ui8ValvePosition,
                                        ZB_FALSE);
       
       PIHeatingDemand(ui8ValvePosition);
    
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Set valve position value fail. zcl_status: %d", zcl_status);
       }
    }
    
    void SetTRVMode (zb_uint8_t ui8TRVMode)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT,
                                        ZB_ZCL_CLUSTER_ID_THERMOSTAT,
                                        ZB_ZCL_CLUSTER_SERVER_ROLE,
                                        ZB_ZCL_ATTR_THERMOSTAT_TRV_MODE_ID,
                                        &ui8TRVMode,
                                        ZB_FALSE);
       
       
    
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Set trv mode value fail. zcl_status: %d", zcl_status);
       }
    }
    /**@brief Function for remaining battery percentage 
     *
     * @param[in]   new_value local temp value
     */
    void ReadRemainigBatteryPercentage(zb_uint8_t ui8BatteryPercentage)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                         ZB_ZCL_CLUSTER_ID_POWER_CONFIG, 
                                         ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                         ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_REMAINING_ID, 
                                         &ui8BatteryPercentage , 
                                         ZB_FALSE);
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Set Battery percentage value fail. zcl_status: %d", zcl_status);
       }
    }
    /**
    **function to read the error status for different valve status 
    **Any change in valve status respective error state copied to Error attribute which is read only attribute
    **
    **/
    void ReadErrorStatus(zb_uint8_t ui8ErrorStatus)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                         ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                                         ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                         ZB_ZCL_ATTR_THERMOSTAT_ERROR_ID, 
                                         &ui8ErrorStatus , 
                                         ZB_FALSE);
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("read error status fail. zcl_status: %d", zcl_status);
       }
    }
    /**
    **function to read/write the flag status for different operation 
    **
    **
    **/
    void HostFlagStatus(zb_uint32_t ui32HostFlagsStatus)
    {
       zb_zcl_status_t zcl_status;
    
       zcl_status = zb_zcl_set_attr_val(THERMOSTAT_SENSOR_ENDPOINT, 
                                         ZB_ZCL_CLUSTER_ID_THERMOSTAT, 
                                         ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                         ZB_ZCL_ATTR_THERMOSTAT_HOST_FLAG_ID, 
                                         (zb_uint8_t *)&ui32HostFlagsStatus, 
                                         ZB_FALSE);
       ui32HostflagsData = ui32HostFlagsStatus;
    
        //Rotate LCD by 180
        if((ui32HostflagsData & 0x000002)== 0x02)
        {    
          boolSetHostflags = false;
    
          boolSendDeviceConfig = true;
          if((ui8SendDeviceConfig[5] ^ DEVICE_CONFIG_BYTE_3_LCD_ROTATION) & DEVICE_CONFIG_BYTE_3_LCD_ROTATION ) 
          {
            ui8SendDeviceConfig[5] |= DEVICE_CONFIG_BYTE_3_LCD_ROTATION;        
          }
        }
        //LCD in default position
        if((ui32HostflagsData ^ 0x000002) & 0x02 )
        {
          boolSetHostflags = false;
          boolSendDeviceConfig = true;
          if(ui8SendDeviceConfig[5]  & DEVICE_CONFIG_BYTE_3_LCD_ROTATION) 
          {
            ui8SendDeviceConfig[5]  &= ui8SendDeviceConfig[5] ^ DEVICE_CONFIG_BYTE_3_LCD_ROTATION;		        
          }
        }
    
       if(zcl_status != ZB_ZCL_STATUS_SUCCESS)
       {
          NRF_LOG_INFO("Host flag status fail. zcl_status: %d", zcl_status);
       }
    }
    
    /**@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]   param   Reference to ZigBee stack buffer used to pass received data.
     */
    static zb_void_t zcl_device_cb(zb_uint8_t param)
    {
        zb_uint16_t                cluster_id;
        zb_uint16_t                attr_id;
        zb_buf_t                       * p_buffer = ZB_BUF_FROM_REF(param);
        zb_zcl_device_callback_param_t * p_device_cb_param =
                         ZB_GET_BUF_PARAM(p_buffer, zb_zcl_device_callback_param_t);
    
        NRF_LOG_INFO("zcl_device_cb id %hd", p_device_cb_param->device_cb_id);
    
        /* Set default response value. */
        p_device_cb_param->status = RET_OK;
    
        switch (p_device_cb_param->device_cb_id)
        {
            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_THERMOSTAT)
                 {
                      if (attr_id == ZB_ZCL_ATTR_THERMOSTAT_OCCUPIED_HEATING_SETPOINT_ID)
                      {
                          zb_int16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
                          OccupiedHeatingSetpoint(value);
                           boolSetTemperature = true;
                           boolReady = true;
                           boolMCUInterrupt = false; 
                          
                      }
                      else if (attr_id == ZB_ZCL_ATTR_THERMOSTAT_UNOCCUPIED_HEATING_SETPOINT_ID)
                      {
                          zb_int16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
                          UnOccupiedHeatingSetpoint(value);
                           boolSetTemperature = true;
                           boolReady = true;
                           boolMCUInterrupt = false; 
                         
                      }
                      else if (attr_id ==ZB_ZCL_ATTR_THERMOSTAT_CURRENT_SETPOINT_CHANGE_ID)
                      {
                          zb_int16_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data16;
                          CurrentSetpointChangeValue(value);
                           boolSetTemperature = true;
                           boolReady = true;
                           boolMCUInterrupt = false; 
                           
                      }
                      else if(attr_id ==ZB_ZCL_ATTR_THERMOSTAT_LOCAL_TEMPERATURE_CALIBRATION_ID)
                      {
                          zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
                          LocalTemperatureCalibration(value);
                      }
                      else if (attr_id ==ZB_ZCL_ATTR_THERMOSTAT_SET_VALVE_POSITION_ID)
                      {
                          zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
                          SetValvePosition(value);
                      }
                      else if(attr_id == ZB_ZCL_ATTR_THERMOSTAT_HOST_FLAG_ID)
                      {
                         zb_uint32_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data32;
                         HostFlagStatus(value);
                         boolSetHostflags  = true; 
                         boolReady = true;
                         boolMCUInterrupt = false; 
                      }
                      else if(attr_id == ZB_ZCL_ATTR_THERMOSTAT_TRV_MODE_ID)
                      {
                         zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
                         SetTRVMode(value);
                      }
                 }
                  
              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]   param   Reference to ZigBee stack buffer used to pass arguments (signal).
     */
    void zboss_signal_handler(zb_uint8_t param)
    {
        nrf_delay_ms(1000);
        zb_zdo_app_signal_hdr_t  * p_sg_p = NULL;
        zb_zdo_app_signal_type_t   sig    = zb_get_app_signal(param, &p_sg_p);
        zb_ret_t                   status = ZB_GET_APP_SIGNAL_STATUS(param);
        zb_bool_t                  comm_status;
    
        switch (sig)
        {
            case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
            case ZB_BDB_SIGNAL_DEVICE_REBOOT:
                if (status == RET_OK)
                {
                    NRF_LOG_INFO("Joined network successfully");
                    bsp_board_led_on(ZIGBEE_NETWORK_STATE_LED);                
                    boolSetCommand  = true; 
                    boolReady = true;
                    boolGetStatus = true;
                }
                else
                {
                    NRF_LOG_ERROR("Failed to join network. Status: %d", status);
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
                    comm_status = bdb_start_top_level_commissioning(ZB_BDB_NETWORK_STEERING);
                    ZB_COMM_STATUS_CHECK(comm_status);
                }
                break;
    
            case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
                if (status != RET_OK)
                {
                    NRF_LOG_WARNING("Production config is not present or invalid");
                }
                break;
    
            case ZB_ZDO_SIGNAL_LEAVE:
                if (status == RET_OK)
                {
                    bsp_board_led_off(ZIGBEE_NETWORK_STATE_LED);
    
                    zb_zdo_signal_leave_params_t * p_leave_params = ZB_ZDO_SIGNAL_GET_PARAMS(p_sg_p, zb_zdo_signal_leave_params_t);
                    NRF_LOG_INFO("Network left. Leave type: %d", p_leave_params->leave_type);
                }
                else
                {
                    NRF_LOG_ERROR("Unable to leave network. Status: %d", status);
                }
                break;
    
            case ZB_COMMON_SIGNAL_CAN_SLEEP: //ZBOSS scheduler tracks the callback queue and if there is no immediate callback for execution and there is no outgoing packet on the MAC level, a special signal ZB_COMMON_SIGNAL_CAN_SLEEP is sent for an application. 
                {
                    zb_sleep_now(); //To go to the sleep mode, the application should call the zb_sleep_now() function.
                    zb_sleep_set_threshold(10000); //Set sleep threshold on device;Min = 20msec and Max = 86400000.
                }
                break;
    
            default:
                /* Unhandled signal. For more information see: zb_zdo_app_signal_type_e and zb_ret_e */
                NRF_LOG_INFO("Unhandled signal %d. Status: %d", sig, status);
                break;
        }
    
        if (param)
        {
            ZB_FREE_BUF_BY_REF(param);
        }
    }
    
    
    /**@brief Function for application main entry.
     */
    void main(void)
    {
        zb_ret_t       zb_err_code;
        zb_ieee_addr_t ieee_addr;
    
    //    nrf_delay_ms(1000);
    
        /* Initialize logging system and GPIOs. */
    //    timer_init();
    //    log_init();
    
        leds_init();
    
        Uart_Init_Func();    
    
        timer_config_func();
    
        ulp_input_pin_configuration();
     
        Flashinitialization();
    
        /* 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("thermostat");
    
        /* 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_ed_role(IEEE_CHANNEL_MASK);
        zigbee_erase_persistent_storage(ERASE_PERSISTENT_CONFIG);
    
        zb_set_ed_timeout(ED_AGING_TIMEOUT_128MIN);
        zb_set_keepalive_timeout(ZB_MILLISECONDS_TO_BEACON_INTERVAL(3000));
        zb_set_rx_on_when_idle(ZB_FALSE);
    
        zb_set_node_descriptor_manufacturer_code(ZB_ZCL_MANF_CODE);
    
        /* Initialize application context structure. */
        UNUSED_RETURN_VALUE(ZB_MEMSET(&m_dev_ctx, 0, sizeof(m_dev_ctx)));
    
        /* Register callback for handling ZCL commands. */
        ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
    
        /* Register thermostat device context (endpoints). */
        ZB_AF_REGISTER_DEVICE_CTX(&thermostat_ctx);
    
        thermostat_clusters_attr_init();
        /** Start Zigbee Stack. */
        zb_err_code = zboss_start();
        ZB_ERROR_CHECK(zb_err_code);   
         
       
        CommandBootloader();  //get bootloader command 
        nrf_delay_ms(500);
    
        while(1)
        {
           zboss_main_loop_iteration();
           UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
    
            CommunicationStateExecution();   //MCU and NP communication state     
            DataProcessing();                //Flag bit processing
            UARTStateStateMachine();    
        }
    }
    
    
    /**
     * @}
     */
    

    - With initialization will my sleep work and can I test the current consumption for the same?

    Please guide me how to implement GPIO wake up mechanism here and go to sleep()?

    Thanks and Regards

    Rohit R

  • Hi Rohit,

    Since you want your device to be able to receive Zigbee commands during low power mode, you cannot use sleepy end device. On devices that are not sleepy end devices the stack calls the nrf_pwr_mgmt_run API if the Zigbee scheduler queue is empty. This happens through the function zb_osif_wait_for_event(), and it happens by the stack already, as part of the internal handling of the stack inside zboss_main_loop_iteration()

    As you want to change the default behavior of the stack sleep routines, you should overwrite the function zb_osif_go_idle() to handle it the way you want. The way you can do this is by simply creating a new definition of the function in your main.c file, as this is a weak function. This is already done in the light bulb example, so you can look there for an example of how to do this. You can then implement functionality for putting the device to sleep/low power mode inside this function, as well as implementing GPIO interrupts and wake up timer.

    I also recommend actually measuring the power consumption of the device during development, to make sure that it satisfies your specifications. You can read the part about power consumption measurements on our Zigbee examples page in the documentation for more information about this.

    Best regards,

    Marte

  • Hi Marte, 

    Thank you for the response. 

    Since you want your device to be able to receive Zigbee commands during low power mode, you cannot use sleepy end device.

    - Okay , I will not configure this. 

    On devices that are not sleepy end devices the stack calls the nrf_pwr_mgmt_run API if the Zigbee scheduler queue is empty. This happens through the function zb_osif_wait_for_event(), and it happens by the stack already, as part of the internal handling of the stack inside zboss_main_loop_iteration()

    - Okay, so since it is already declared in my code. It is minimal possible sleep config. As it is already called by stack function. I do not need to call this again and with I can check default current? correct?. 

    The way you can do this is by simply creating a new definition of the function in your main.c file, as this is a weak function. This is already done in the light bulb example, so you can look there for an example of how to do this.

    - I am using light_bulb code only. I can see they have only called below snippet. Not handled any extra things to refer. 

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

    as well as implementing GPIO interrupts and wake up timer.

    - Okay, I will refer the power management code from peripheral example. 

    - In nrf_pwr_mgmt_shutdown() system enters into deep sleep mode and wake up on 4 ways." First is The DETECT signal. optionally generated by GPIO peripheral". This means I can use my ULP pin (GPIO pin as mentioned previous post) to wake up device correct? Let me know if i am wrong here.? 

    - Let me know your feedback as soon as possible. Because I have started this file including process and I would like to complete this today. Urgent for me. 

    Hi, Update from me, 

    - I had gone through the peripheral example and some link online. I tried to execute the system off mode configuration in simple code. Here, I want to wake up device using my ULP (GPIO pin ) interrupt. But I am not finding wake up function. I have put device in sleep in while (1) loop by calling "nrf_pwr_mgmt_run();" function. 

    - To make system OFF enabled I have used "NRF_PWR_MGMT_CONFIG_STANDBY_TIMEOUT_ENABLED 1". Followed the steps but it is waking up only after "RESET" is pressed but it doesn't work for me. 

    - As stated it should work on GPIO interrupt too correct? Then why it is not working on GPIO. 

    - And which function/API I have to call for wake up ? 

    Urgent. Please let me know your feedback. 

    Thanks and Regards

    Rohit R

Related