Skip to content

feat(zigbee): Add check, boolean returns, fix Analog, add optional reset on factoryReset #11153

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 49 additions & 17 deletions libraries/Zigbee/src/ZigbeeEP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ void ZigbeeEP::setVersion(uint8_t version) {
_ep_config.app_device_version = version;
}

void ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
bool ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
// Convert manufacturer to ZCL string
size_t length = strlen(name);
if (length > 32) {
log_e("Manufacturer name is too long");
return;
return false;
}
// Allocate a new array of size length + 2 (1 for the length, 1 for null terminator)
char *zb_name = new char[length + 2];
Expand All @@ -53,7 +53,7 @@ void ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
if (length > 32) {
log_e("Model name is too long");
delete[] zb_name;
return;
return false;
}
char *zb_model = new char[length + 2];
zb_model[0] = static_cast<char>(length);
Expand All @@ -62,8 +62,13 @@ void ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {

// Get the basic cluster and update the manufacturer and model attributes
esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)zb_name);
esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)zb_model);
esp_err_t ret_manufacturer = esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)zb_name);
esp_err_t ret_model = esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)zb_model);
if(ret_manufacturer != ESP_OK || ret_model != ESP_OK) {
log_e("Failed to set manufacturer (0x%x) or model (0x%x)", ret_manufacturer, ret_model);
return false;
}
return true;
}

void ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage) {
Expand All @@ -72,6 +77,9 @@ void ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_pe

if (power_source == ZB_POWER_SOURCE_BATTERY) {
// Add power config cluster and battery percentage attribute
if (battery_percentage > 100) {
battery_percentage = 100;
}
battery_percentage = battery_percentage * 2;
esp_zb_attribute_list_t *power_config_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG);
esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, (void *)&battery_percentage);
Expand All @@ -80,23 +88,29 @@ void ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_pe
_power_source = power_source;
}

void ZigbeeEP::setBatteryPercentage(uint8_t percentage) {
bool ZigbeeEP::setBatteryPercentage(uint8_t percentage) {
// 100% = 200 in decimal, 0% = 0
// Convert percentage to 0-200 range
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
if (percentage > 100) {
percentage = 100;
}
percentage = percentage * 2;
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_set_attribute_val(
ret = esp_zb_zcl_set_attribute_val(
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, &percentage,
false
);
esp_zb_lock_release();
if(ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
log_e("Failed to set battery percentage: 0x%x", ret);
return false;
}
log_v("Battery percentage updated");
return true;
}

void ZigbeeEP::reportBatteryPercentage() {
bool ZigbeeEP::reportBatteryPercentage() {
/* Send report attributes command */
esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
Expand All @@ -107,9 +121,14 @@ void ZigbeeEP::reportBatteryPercentage() {
report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC;

esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
esp_zb_lock_release();
if(ret != ESP_OK) {
log_e("Failed to report battery percentage: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
log_v("Battery percentage reported");
return true;
}

char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
Expand Down Expand Up @@ -260,18 +279,31 @@ void ZigbeeEP::addTimeCluster(tm time, int32_t gmt_offset) {
esp_zb_cluster_list_add_time_cluster(_cluster_list, time_cluster_client, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
}

void ZigbeeEP::setTime(tm time) {
bool ZigbeeEP::setTime(tm time) {
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
time_t utc_time = mktime(&time);
log_d("Setting time to %lld", utc_time);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, &utc_time, false);
ret = esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ID, &utc_time, false);
esp_zb_lock_release();
if(ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
log_e("Failed to set time: 0x%x", ret);
return false;
}
return true;
}

void ZigbeeEP::setTimezone(int32_t gmt_offset) {
bool ZigbeeEP::setTimezone(int32_t gmt_offset) {
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
log_d("Setting timezone to %d", gmt_offset);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, &gmt_offset, false);
ret = esp_zb_zcl_set_attribute_val(_endpoint, ESP_ZB_ZCL_CLUSTER_ID_TIME, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_TIME_TIME_ZONE_ID, &gmt_offset, false);
esp_zb_lock_release();
if(ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
log_e("Failed to set timezone: 0x%x", ret);
return false;
}
return true;
}

tm ZigbeeEP::getTime(uint8_t endpoint, int32_t short_addr, esp_zb_ieee_addr_t ieee_addr) {
Expand Down Expand Up @@ -410,11 +442,11 @@ void ZigbeeEP::addOTAClient(
uint16_t ota_upgrade_server_addr = 0xffff;
uint8_t ota_upgrade_server_ep = 0xff;

ESP_ERROR_CHECK(esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_CLIENT_DATA_ID, (void *)&variable_config));
ESP_ERROR_CHECK(esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ADDR_ID, (void *)&ota_upgrade_server_addr));
ESP_ERROR_CHECK(esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ENDPOINT_ID, (void *)&ota_upgrade_server_ep));
esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_CLIENT_DATA_ID, (void *)&variable_config);
esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ADDR_ID, (void *)&ota_upgrade_server_addr);
esp_zb_ota_cluster_add_attr(ota_cluster, ESP_ZB_ZCL_ATTR_OTA_UPGRADE_SERVER_ENDPOINT_ID, (void *)&ota_upgrade_server_ep);

ESP_ERROR_CHECK(esp_zb_cluster_list_add_ota_cluster(_cluster_list, ota_cluster, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE));
esp_zb_cluster_list_add_ota_cluster(_cluster_list, ota_cluster, ESP_ZB_ZCL_CLUSTER_CLIENT_ROLE);
}

static void findOTAServer(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t endpoint, void *user_ctx) {
Expand Down
10 changes: 5 additions & 5 deletions libraries/Zigbee/src/ZigbeeEP.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,21 @@ class ZigbeeEP {
}

// Set Manufacturer name and model
void setManufacturerAndModel(const char *name, const char *model);
bool setManufacturerAndModel(const char *name, const char *model);

// Methods to read manufacturer and model name from selected endpoint and short address
char *readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);

// Set Power source and battery percentage for battery powered devices
void setPowerSource(zb_power_source_t power_source, uint8_t percentage = 255);
void setBatteryPercentage(uint8_t percentage);
void reportBatteryPercentage();
bool setBatteryPercentage(uint8_t percentage);
bool reportBatteryPercentage();

// Set time
void addTimeCluster(tm time = {}, int32_t gmt_offset = 0); // gmt offset in seconds
void setTime(tm time);
void setTimezone(int32_t gmt_offset);
bool setTime(tm time);
bool setTimezone(int32_t gmt_offset);

// Get time from Coordinator or specific endpoint (blocking until response)
struct tm getTime(uint8_t endpoint = 1, int32_t short_addr = 0x0000, esp_zb_ieee_addr_t ieee_addr = {0});
Expand Down
71 changes: 53 additions & 18 deletions libraries/Zigbee/src/ep/ZigbeeAnalog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,34 @@ ZigbeeAnalog::ZigbeeAnalog(uint8_t endpoint) : ZigbeeEP(endpoint) {
_ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0};
}

void ZigbeeAnalog::addAnalogValue() {
esp_zb_cluster_list_add_analog_value_cluster(_cluster_list, esp_zb_analog_value_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
bool ZigbeeAnalog::addAnalogValue() {
esp_err_t ret = esp_zb_cluster_list_add_analog_value_cluster(_cluster_list, esp_zb_analog_value_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
if (ret != ESP_OK) {
log_e("Failed to add Analog Value cluster: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
_analog_clusters |= ANALOG_VALUE;
return true;
}

void ZigbeeAnalog::addAnalogInput() {
esp_zb_cluster_list_add_analog_input_cluster(_cluster_list, esp_zb_analog_input_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
bool ZigbeeAnalog::addAnalogInput() {
esp_err_t ret = esp_zb_cluster_list_add_analog_input_cluster(_cluster_list, esp_zb_analog_input_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
if (ret != ESP_OK) {
log_e("Failed to add Analog Input cluster: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
_analog_clusters |= ANALOG_INPUT;
return true;
}

void ZigbeeAnalog::addAnalogOutput() {
esp_zb_cluster_list_add_analog_output_cluster(_cluster_list, esp_zb_analog_output_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
bool ZigbeeAnalog::addAnalogOutput() {
esp_err_t ret = esp_zb_cluster_list_add_analog_output_cluster(_cluster_list, esp_zb_analog_output_cluster_create(NULL), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
if (ret != ESP_OK) {
log_e("Failed to add Analog Output cluster: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
_analog_clusters |= ANALOG_OUTPUT;
return true;
}

//set attribute method -> method overridden in child class
Expand All @@ -57,35 +72,45 @@ void ZigbeeAnalog::analogOutputChanged(float analog_output) {
}
}

void ZigbeeAnalog::setAnalogValue(float analog) {
bool ZigbeeAnalog::setAnalogValue(float analog) {
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
if (!(_analog_clusters & ANALOG_VALUE)) {
log_e("Analog Value cluster not added");
return;
return false;
}
// float zb_analog = analog;
log_d("Setting analog value to %.1f", analog);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_set_attribute_val(
ret = esp_zb_zcl_set_attribute_val(
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_VALUE, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_VALUE_PRESENT_VALUE_ID, &analog, false
);
esp_zb_lock_release();
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
log_e("Failed to set analog value: 0x%x", ret);
return false;
}
return true;
}

void ZigbeeAnalog::setAnalogInput(float analog) {
bool ZigbeeAnalog::setAnalogInput(float analog) {
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
if (!(_analog_clusters & ANALOG_INPUT)) {
log_e("Analog Input cluster not added");
return;
return false;
}
// float zb_analog = analog;
log_d("Setting analog input to %.1f", analog);
esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_set_attribute_val(
ret = esp_zb_zcl_set_attribute_val(
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID, &analog, false
);
esp_zb_lock_release();
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
log_e("Failed to set analog input: 0x%x", ret);
return false;
}
return true;
}

void ZigbeeAnalog::reportAnalogInput() {
bool ZigbeeAnalog::reportAnalogInput() {
/* Send report attributes command */
esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
Expand All @@ -96,12 +121,17 @@ void ZigbeeAnalog::reportAnalogInput() {
report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC;

esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
esp_zb_lock_release();
if (ret != ESP_OK) {
log_e("Failed to send Analog Input report: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
log_v("Analog Input report sent");
return true;
}

void ZigbeeAnalog::setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta) {
bool ZigbeeAnalog::setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta) {
esp_zb_zcl_reporting_info_t reporting_info;
memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t));
reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV;
Expand All @@ -118,8 +148,13 @@ void ZigbeeAnalog::setAnalogInputReporting(uint16_t min_interval, uint16_t max_i
reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC;

esp_zb_lock_acquire(portMAX_DELAY);
esp_zb_zcl_update_reporting_info(&reporting_info);
esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info);
esp_zb_lock_release();
if (ret != ESP_OK) {
log_e("Failed to set Analog Input reporting: 0x%x: %s", ret, esp_err_to_name(ret));
return false;
}
return true;
}

#endif // CONFIG_ZB_ENABLED
14 changes: 7 additions & 7 deletions libraries/Zigbee/src/ep/ZigbeeAnalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,24 @@ class ZigbeeAnalog : public ZigbeeEP {
~ZigbeeAnalog() {}

// Add analog clusters
void addAnalogValue();
void addAnalogInput();
void addAnalogOutput();
bool addAnalogValue();
bool addAnalogInput();
bool addAnalogOutput();

// Use to set a cb function to be called on analog output change
void onAnalogOutputChange(void (*callback)(float analog)) {
_on_analog_output_change = callback;
}

// Set the analog value / input
void setAnalogValue(float analog);
void setAnalogInput(float analog);
bool setAnalogValue(float analog);
bool setAnalogInput(float analog);

// Report Analog Input
void reportAnalogInput();
bool reportAnalogInput();

// Set reporting for Analog Input
void setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta);
bool setAnalogInputReporting(uint16_t min_interval, uint16_t max_interval, float delta);

private:
void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override;
Expand Down
Loading
Loading