cancel
Showing results for 
Search instead for 
Did you mean: 

STM32WB Zigbee: How to set the PowerSource to Battery and report Battery Voltage and Remaining percentage

earlish
Associate II

Hello, I'm trying to make a Zigbee application for a battery powered device (currently using the ZHA integration on Home Assistant) and I am having trouble to set the attribute for a battery power source, (it seems to be stuck on the default of Mains), however setting the manufacturer and model strings are working.

static const struct ZbZclAttrT optional_attr_list[] =
{
	{
		ZCL_POWER_CONFIG_ATTR_BATTERY_VOLTAGE,
		ZCL_DATATYPE_UNSIGNED_8BIT,
		ZCL_ATTR_FLAG_REPORTABLE | ZCL_ATTR_FLAG_PERSISTABLE,
		0,
		NULL,
		{0, 100},
		{10, 300}
	},
	{
		ZCL_POWER_CONFIG_ATTR_BATTERY_PCT,
		ZCL_DATATYPE_UNSIGNED_8BIT,
		ZCL_ATTR_FLAG_REPORTABLE | ZCL_ATTR_FLAG_PERSISTABLE,
		0,
		NULL,
		{0, 100},
		{10, 300}
	}
};
 
static void APP_ZIGBEE_ConfigEndpoints(void)
{
  struct ZbApsmeAddEndpointReqT req;
  struct ZbApsmeAddEndpointConfT conf;
 
  memset(&req, 0, sizeof(req));
 
  /* Endpoint: SW1_ENDPOINT */
  req.profileId = ZCL_PROFILE_HOME_AUTOMATION;
  req.deviceId = ZCL_DEVICE_SIMPLE_SENSOR;
  req.endpoint = SW1_ENDPOINT;
  ZbZclAddEndpoint(zigbee_app_info.zb, &req, &conf);
  assert(conf.status == ZB_STATUS_SUCCESS);
 
  /* Power config server */
  zigbee_app_info.power_config_server_1 = ZbZclPowerConfigServerAlloc(zigbee_app_info.zb, SW1_ENDPOINT);
  assert(zigbee_app_info.power_config_server_1 != NULL);
  ZbZclAttrAppendList(zigbee_app_info.power_config_server_1, optional_attr_list, ZCL_ATTR_LIST_LEN(optional_attr_list)); //not working...
  ZbZclClusterEndpointRegister(zigbee_app_info.power_config_server_1);
 
APP_ZIGBEE_ConfigBasic();
}
 static void APP_ZIGBEE_ConfigBasic(void) {
 
 	char *mfr_str = "stm32";
 	uint8_t zb_mfr_str[10];
 	memcpy(&zb_mfr_str[1], mfr_str, strlen(mfr_str));
 	zb_mfr_str[0] = strlen(mfr_str);
 	ZbZclBasicWriteDirect(zigbee_app_info.zb, SW1_ENDPOINT,
 			ZCL_BASIC_ATTR_MFR_NAME, zb_mfr_str, 6);
 
 	char *model_str = "wb55";
 	uint8_t zb_model_str[7];
 	memcpy(&zb_model_str[1], model_str, strlen(model_str));
 	zb_model_str[0] = strlen(model_str);
 	ZbZclBasicWriteDirect(zigbee_app_info.zb, SW1_ENDPOINT,
 			ZCL_BASIC_ATTR_MODEL_NAME, zb_model_str, 5);
 
 	uint8_t power_source = ZCL_BASIC_POWER_BATTERY;
 	ZbZclBasicWriteDirect(zigbee_app_info.zb, SW1_ENDPOINT,
 			ZCL_BASIC_ATTR_POWER_SOURCE, &power_source, 1); //not working...
 
 	ZbZclAttrIntegerWrite(zigbee_app_info.power_config_server_1,
 			ZCL_BASIC_ATTR_POWER_SOURCE, ZCL_BASIC_POWER_BATTERY); //also not working...
 
 	struct ZbZclBasicServerDefaults basic_config;
 	basic_config.power_source = ZCL_BASIC_POWER_BATTERY;
 	ZbZclBasicServerConfigDefaults(zigbee_app_info.zb, &basic_config); //also not working...
 }

0693W00000Su1QjQAJ.jpg 

I am using the following stack:

[M4 APPLICATION] WIRELESS COPROCESSOR FW:

[M4 APPLICATION] VERSION ID = 1.14.0

[M4 APPLICATION] FW Type : FFD Zigbee stack

Thank you.

1 ACCEPTED SOLUTION

Accepted Solutions
earlish
Associate II

If anyone else come across this thread and is interested, I was able to change the node descriptor with the following line of code:

config.capability &= ~(MCP_ASSOC_CAP_PWR_SRC);

I added it to the APP_ZIGBEE_NwkForm() function, so now my startup code looks like this:

static void APP_ZIGBEE_NwkForm(void)
{
  if ((zigbee_app_info.join_status != ZB_STATUS_SUCCESS) && (HAL_GetTick() >= zigbee_app_info.join_delay))
  {
    struct ZbStartupT config;
    enum ZbStatusCodeT status;
 
    /* Configure Zigbee Logging */
    ZbSetLogging(zigbee_app_info.zb, ZB_LOG_MASK_LEVEL_5, NULL);
 
    /* Attempt to join a zigbee network */
    ZbStartupConfigGetProDefaults(&config);
 
    /* Set the centralized network */
    APP_DBG("Network config : APP_STARTUP_CENTRALIZED_ROUTER");
    zigbee_app_info.startupControl = ZbStartTypeJoin;
    config.startupControl = zigbee_app_info.startupControl;
 
    /* Using the default HA preconfigured Link Key */
    memcpy(config.security.preconfiguredLinkKey, sec_key_ha, ZB_SEC_KEYSIZE);
 
    config.channelList.count = 1;
    config.channelList.list[0].page = 0;
    config.channelList.list[0].channelMask = 1 << CHANNEL; /*Channel in use */
 
    ///* Add End device configuration */
    config.capability &= ~(MCP_ASSOC_CAP_PWR_SRC); //battery powered
 
    /* Using ZbStartupWait (blocking) */
    status = ZbStartupWait(zigbee_app_info.zb, &config);
 
    APP_DBG("ZbStartup Callback (status = 0x%02x)", status);
    zigbee_app_info.join_status = status;
 
    if (status == ZB_STATUS_SUCCESS) {
      /* USER CODE BEGIN 0 */
      zigbee_app_info.join_delay = 0U;
 
      /* Register Persistent data change notification */
      ZbPersistNotifyRegister(zigbee_app_info.zb,APP_ZIGBEE_persist_notify_cb,NULL);
      /* Call the callback once here to save persistence data */
      APP_ZIGBEE_persist_notify_cb(zigbee_app_info.zb,NULL);
    }
    else
    {
      /* USER CODE END 0 */
      APP_DBG("Startup failed, attempting again after a short delay (%d ms)", APP_ZIGBEE_STARTUP_FAIL_DELAY);
      zigbee_app_info.join_delay = HAL_GetTick() + APP_ZIGBEE_STARTUP_FAIL_DELAY;
    }
  }

View solution in original post

3 REPLIES 3
Remy ISSALYS
ST Employee

Hello,

Can you give more informations about the meaning of your "Not working" comment ?

Best Regards

Hello Remy,

I could not get the function ZbZclBasicServerConfigDefaults to write any attribute values.

Possibly it is an issue with my code.

However I did get the PowerSource attribute working with the following code:

static void APP_ZIGBEE_ConfigBasic(void) {
 
	struct ZbZclBasicServerDefaults basic_config;
 	char *mfr_str = "stm32";
 	memcpy(&basic_config.mfr_name[1], mfr_str, strlen(mfr_str));
 	basic_config.mfr_name[0] = strlen(mfr_str);
 
 	char *model_str = "wb55";
 	memcpy(&basic_config.model_name[1], model_str, strlen(model_str));
 	basic_config.model_name[0] = strlen(model_str);
 
 	basic_config.power_source = ZCL_BASIC_POWER_BATTERY;
 
 	enum ZclStatusCodeT status;
 
 	status = ZbZclBasicWriteDirect(zigbee_app_info.zb, SW1_ENDPOINT, ZCL_BASIC_ATTR_MFR_NAME, &basic_config.mfr_name, 6);
 	status = ZbZclBasicWriteDirect(zigbee_app_info.zb, SW1_ENDPOINT, ZCL_BASIC_ATTR_MODEL_NAME, &basic_config.model_name, 5);
 	status = ZbZclBasicWriteDirect(zigbee_app_info.zb, SW1_ENDPOINT, ZCL_BASIC_ATTR_POWER_SOURCE, &basic_config.power_source, 1);
 }

Even after changing the Basic cluster Power Source attribute, the issue in Home Assistant still remains; the Node Descriptor is still reporting that the device is mains powered.

Is it possible to edit the Power Source bit in the Node Descriptor MAC Capabilitiy Flag per the table from the zigbee standard? Thanks

0693W00000SubolQAB.png 0693W00000SubnnQAB.png0693W00000SulsnQAB.png

earlish
Associate II

If anyone else come across this thread and is interested, I was able to change the node descriptor with the following line of code:

config.capability &= ~(MCP_ASSOC_CAP_PWR_SRC);

I added it to the APP_ZIGBEE_NwkForm() function, so now my startup code looks like this:

static void APP_ZIGBEE_NwkForm(void)
{
  if ((zigbee_app_info.join_status != ZB_STATUS_SUCCESS) && (HAL_GetTick() >= zigbee_app_info.join_delay))
  {
    struct ZbStartupT config;
    enum ZbStatusCodeT status;
 
    /* Configure Zigbee Logging */
    ZbSetLogging(zigbee_app_info.zb, ZB_LOG_MASK_LEVEL_5, NULL);
 
    /* Attempt to join a zigbee network */
    ZbStartupConfigGetProDefaults(&config);
 
    /* Set the centralized network */
    APP_DBG("Network config : APP_STARTUP_CENTRALIZED_ROUTER");
    zigbee_app_info.startupControl = ZbStartTypeJoin;
    config.startupControl = zigbee_app_info.startupControl;
 
    /* Using the default HA preconfigured Link Key */
    memcpy(config.security.preconfiguredLinkKey, sec_key_ha, ZB_SEC_KEYSIZE);
 
    config.channelList.count = 1;
    config.channelList.list[0].page = 0;
    config.channelList.list[0].channelMask = 1 << CHANNEL; /*Channel in use */
 
    ///* Add End device configuration */
    config.capability &= ~(MCP_ASSOC_CAP_PWR_SRC); //battery powered
 
    /* Using ZbStartupWait (blocking) */
    status = ZbStartupWait(zigbee_app_info.zb, &config);
 
    APP_DBG("ZbStartup Callback (status = 0x%02x)", status);
    zigbee_app_info.join_status = status;
 
    if (status == ZB_STATUS_SUCCESS) {
      /* USER CODE BEGIN 0 */
      zigbee_app_info.join_delay = 0U;
 
      /* Register Persistent data change notification */
      ZbPersistNotifyRegister(zigbee_app_info.zb,APP_ZIGBEE_persist_notify_cb,NULL);
      /* Call the callback once here to save persistence data */
      APP_ZIGBEE_persist_notify_cb(zigbee_app_info.zb,NULL);
    }
    else
    {
      /* USER CODE END 0 */
      APP_DBG("Startup failed, attempting again after a short delay (%d ms)", APP_ZIGBEE_STARTUP_FAIL_DELAY);
      zigbee_app_info.join_delay = HAL_GetTick() + APP_ZIGBEE_STARTUP_FAIL_DELAY;
    }
  }