Zigbee Battery Voltage Reporting

Hi, I have a few questions about reporting battery voltage as specified in the genPowerCfg Zigbee Cluster Library spec. I modified the zigbee light switch example to include the genPowerCfg cluster. I'm using an nRF52840 DK NRF52840 dev board and the v2.5.1 SDK. I can:

  1. Set the genPowerCfg cluster battery percentage remaining attribute reporting interval over the Zigbee network.
  2. Read the battery percentage remaining attribute over the Zigbee network.
  3. Read the battery voltage attribute over the Zigbee network.
  4. Set the battery percentage remaining attribute in my nRF52840 code.
  5. Set the battery voltage attribute in my nRF52840 code.
  6. Use the ADC to read the voltage on the VDD pin and update the battery voltage attribute.

This is all great and wonderful. The battery percentage remaining is great but what I'm really interesting in are periodic reports of the battery voltage. Here's what I'm trying to figure out:

First, if I try to set the genPowerCfg cluster battery voltage attribute reporting interval over the network, I get an unreportable attribute response. I assume that since the ZCL spec does not say this shall be a reportable attribute, it's not reportable. Is there a way to make it reportable using the zboss stack?

Second, this will be a battery operated device. If the battery voltage is not reportable, what's the best way to get the battery voltage to the network coordinator? Attribute reads won't work when the device is asleep. Is there a way to send the battery percentage remaining and battery voltage to the network coordinator whenever the device wakes up? The ZCL spec does not define a genPowerCfg client. Or does the network coordinator need to poll for the battery voltage in that brief window after a keep alive or other event where the device is otherwise awake?

Third, is there better documentation on the reporting_info_t structure and what exactly I'm supposed to do with them? For example, I've added them to the endpoint declaration but it doesn't seem to matter if they're there or not:

/** Number of attribute for reporting on Dimmer Switch device */
#define ZB_DIMMER_SWITCH_REPORT_ATTR_COUNT (ZB_ZCL_POWER_CONFIG_REPORT_ATTR_COUNT)
#define ZB_DECLARE_DIMMER_SWITCH_EP(ep_name, ep_id, cluster_list)             \
    ZB_ZCL_DECLARE_DIMMER_SWITCH_SIMPLE_DESC(ep_name, ep_id,              \
          ZB_DIMMER_SWITCH_IN_CLUSTER_NUM, ZB_DIMMER_SWITCH_OUT_CLUSTER_NUM); \
    ZBOSS_DEVICE_DECLARE_REPORTING_CTX(reporting_info## ep_name,              \
        ZB_DIMMER_SWITCH_REPORT_ATTR_COUNT);                      \
    ZB_AF_DECLARE_ENDPOINT_DESC(ep_name, ep_id, ZB_AF_HA_PROFILE_ID, 0, NULL,     \
        ZB_ZCL_ARRAY_SIZE(cluster_list, zb_zcl_cluster_desc_t), cluster_list, \
        (zb_af_simple_desc_1_1_t *)&simple_desc_##ep_name,            \
        ZB_DIMMER_SWITCH_REPORT_ATTR_COUNT, reporting_info## ep_name,                           \
        0, NULL) /* No CVC ctx */

Thanks, Glen.

  • Addendum: Is there a function I can call that will send an attribute report? This might be the path of least resistance.

  • I don't have any idea if this is compliant with the zigbee spec or is how the API is supposed to be used, but it lets me send an attribute report after a button press:

    During initialization, I run the following the code:

        zb_ret_t status;
        
        zb_zcl_reporting_info_t batt_rep_info;
        memset(&batt_rep_info, 0, sizeof(batt_rep_info));
        
        batt_rep_info.direction = ZB_ZCL_CONFIGURE_REPORTING_SEND_REPORT;
        batt_rep_info.ep = LIGHT_SWITCH_ENDPOINT;
        batt_rep_info.cluster_id = ZB_ZCL_CLUSTER_ID_POWER_CONFIG;
        batt_rep_info.cluster_role = ZB_ZCL_CLUSTER_SERVER_ROLE;
        batt_rep_info.attr_id = ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID;
        batt_rep_info.dst.profile_id = ZB_AF_HA_PROFILE_ID;
        batt_rep_info.u.send_info.min_interval = 3;       // 3 seconds
        batt_rep_info.u.send_info.max_interval = 15;     // 15 seconds
        batt_rep_info.u.send_info.delta.u8 = 0x00;         // x 100 mV
            
        status = zb_zcl_put_reporting_info(&batt_rep_info, ZB_TRUE);       
    
        status = zb_zcl_start_attr_reporting(
                LIGHT_SWITCH_ENDPOINT,
                ZB_ZCL_CLUSTER_ID_POWER_CONFIG,  
                ZB_ZCL_CLUSTER_SERVER_ROLE,  
                ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID);

    Then after a button press, I run the following code:

        zb_zcl_set_attr_val(LIGHT_SWITCH_ENDPOINT,
                                         ZB_ZCL_CLUSTER_ID_POWER_CONFIG, 
                                         ZB_ZCL_CLUSTER_SERVER_ROLE, 
                                         ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID,
                                         &battery_voltage, 
                                         ZB_FALSE);
        zb_zcl_mark_attr_for_reporting (
               LIGHT_SWITCH_ENDPOINT,
               ZB_ZCL_CLUSTER_ID_POWER_CONFIG,
               ZB_ZCL_CLUSTER_SERVER_ROLE,
               ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID);

    This gets me an attribute report after the button press containing the battery voltage but no periodic reports.

    What do I need to kick off the report timers?



            

  • I may have figured it out. I initialized most of the fields in the reporting info struct. Setting the default min interval and default max interval fields seems to have done the trick. I'm getting battery voltage attribute reports every 10 to 30 seconds or so. Now to move these from the dev board and sandbox project to my real hardware and real project.

        batt_rep_info.direction = ZB_ZCL_CONFIGURE_REPORTING_SEND_REPORT;
        batt_rep_info.ep = LIGHT_SWITCH_ENDPOINT;
        batt_rep_info.cluster_id = ZB_ZCL_CLUSTER_ID_POWER_CONFIG;
        batt_rep_info.cluster_role = ZB_ZCL_CLUSTER_SERVER_ROLE;
        batt_rep_info.attr_id = ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID;
        batt_rep_info.dst.short_addr = 0x0000;
        batt_rep_info.dst.endpoint = 1;
        batt_rep_info.dst.profile_id = ZB_AF_HA_PROFILE_ID;
        batt_rep_info.u.send_info.min_interval = 3;       // 3 seconds
        batt_rep_info.u.send_info.max_interval = 15;     // 15 seconds
        batt_rep_info.u.send_info.delta.u8 = 0x00;         // x 100 mV
        batt_rep_info.u.send_info.reported_value.u8 = 0xFF;
        batt_rep_info.u.send_info.def_min_interval = 10;
        batt_rep_info.u.send_info.def_max_interval = 30;
  • Hi,

    Great to hear that you managed to figure it out!

    You are correct that you need to set the reporting intervals. If the maximum reporting interval is set to 0xffff then the device shall not issue any reports for the attribute. If it is set to 0x0000 and minimum reporting interval is set to something other than 0xffff then the device shall not do periodic reporting. It can still send reports on value change in the last case, but not periodic.

    Best regards,
    Marte

  • Hi, Marte. Thanks for the clarification on the way those fields work! I'm working through an interrupt issue at the moment then hope to post the code on github later in the week or this weekend. Once the code is there, I'll mark my reply with the link to the code as the correct answer.

Related