Skip to content

feat(zigbee): Add callback option for default response message #11613

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 8 commits into from
Jul 21, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ uint8_t button = BOOT_PIN;

ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER);

uint8_t dataToSend = 2; // Temperature and humidity values are reported in same endpoint, so 2 values are reported
bool resend = false;

/************************ Temp sensor *****************************/
void meausureAndSleep() {
// Measure temperature sensor value
Expand All @@ -55,17 +58,34 @@ void meausureAndSleep() {
zbTempSensor.setHumidity(humidity);

// Report temperature and humidity values
zbTempSensor.report();
zbTempSensor.report(); // reports temperature and humidity values (if humidity sensor is not added, only temperature is reported)
Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity);

// Add small delay to allow the data to be sent before going to sleep
delay(100);
// Wait until data was succesfully sent
while(dataToSend != 0){
if(resend){
Serial.println("Resending data on failure!");
resend = false;
dataToSend = 2;
zbTempSensor.report(); // report again
}
}

// Put device to deep sleep
// Put device to deep sleep after data was sent successfully
Serial.println("Going to sleep now");
esp_deep_sleep_start();
}

void onResponse(zb_cmd_type_t command, esp_zb_zcl_status_t status){
Serial.printf("Response status recieved %s", zbTempSensor.esp_zb_zcl_status_to_name(status));
if(command == ZB_CMD_REPORT_ATTRIBUTE){
switch (status){
case ESP_ZB_ZCL_STATUS_SUCCESS: dataToSend--; break;
case ESP_ZB_ZCL_STATUS_FAIL: resend = true; break;
default: break;// add more statuses like ESP_ZB_ZCL_STATUS_INVALID_VALUE, ESP_ZB_ZCL_STATUS_TIMEOUT etc.
}
}
}
/********************* Arduino functions **************************/
void setup() {
Serial.begin(115200);
Expand All @@ -92,6 +112,9 @@ void setup() {
// Add humidity cluster to the temperature sensor device with min, max and tolerance values
zbTempSensor.addHumiditySensor(0, 100, 1);

// Set callback for default response to handle status of reported data
zbTempSensor.onDefaultResponse(onResponse);

// Add endpoint to Zigbee Core
Zigbee.addEndpoint(&zbTempSensor);

Expand All @@ -116,9 +139,6 @@ void setup() {
}
Serial.println();
Serial.println("Successfully connected to Zigbee network");

// Delay approx 1s (may be adjusted) to allow establishing proper connection with coordinator, needed for sleepy devices
delay(1000);
}

void loop() {
Expand Down
2 changes: 2 additions & 0 deletions libraries/Zigbee/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ zb_power_source_t KEYWORD1
ZigbeeWindowCoveringType KEYWORD1
ZigbeeFanMode KEYWORD1
ZigbeeFanModeSequence KEYWORD1
zb_cmd_type_t KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
Expand Down Expand Up @@ -96,6 +97,7 @@ getTime KEYWORD2
getTimezone KEYWORD2
addOTAClient KEYWORD2
clearBoundDevices KEYWORD2
onDefaultResponse KEYWORD2

# ZigbeeLight + ZigbeeColorDimmableLight
onLightChange KEYWORD2
Expand Down
9 changes: 9 additions & 0 deletions libraries/Zigbee/src/ZigbeeEP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,15 @@ void ZigbeeEP::removeBoundDevice(zb_device_params_t *device) {
log_w("No matching device found for removal");
}

void ZigbeeEP::zbDefaultResponse(const esp_zb_zcl_cmd_default_resp_message_t *message) {
log_v("Default response received for endpoint %d", _endpoint);
log_v("Status code: %s", esp_zb_zcl_status_to_name(message->status_code));
log_v("Response to command: %d", message->resp_to_cmd);
if (_on_default_response) {
_on_default_response((zb_cmd_type_t)message->resp_to_cmd, message->status_code);
}
}

const char *ZigbeeEP::esp_zb_zcl_status_to_name(esp_zb_zcl_status_t status) {
switch (status) {
case ESP_ZB_ZCL_STATUS_SUCCESS: return "Success";
Expand Down
37 changes: 35 additions & 2 deletions libraries/Zigbee/src/ZigbeeEP.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,32 @@
#define ZB_CMD_TIMEOUT 10000 // 10 seconds
#define OTA_UPGRADE_QUERY_INTERVAL (1 * 60) // 1 hour = 60 minutes

typedef enum {
ZB_CMD_READ_ATTRIBUTE = 0x00U, /*!< Read attributes command */
ZB_CMD_READ_ATTRIBUTE_RESPONSE = 0x01U, /*!< Read attributes response command */
ZB_CMD_WRITE_ATTRIBUTE = 0x02U, /*!< Write attributes foundation command */
ZB_CMD_WRITE_ATTRIBUTE_UNDIVIDED = 0x03U, /*!< Write attributes undivided command */
ZB_CMD_WRITE_ATTRIBUTE_RESPONSE = 0x04U, /*!< Write attributes response command */
ZB_CMD_WRITE_ATTRIBUTE_NO_RESPONSE = 0x05U, /*!< Write attributes no response command */
ZB_CMD_CONFIGURE_REPORTING = 0x06U, /*!< Configure reporting command */
ZB_CMD_CONFIGURE_REPORTING_RESPONSE = 0x07U, /*!< Configure reporting response command */
ZB_CMD_READ_REPORTING_CONFIG = 0x08U, /*!< Read reporting config command */
ZB_CMD_READ_REPORTING_CONFIG_RESPONSE= 0x09U, /*!< Read reporting config response command */
ZB_CMD_REPORT_ATTRIBUTE = 0x0aU, /*!< Report attribute command */
ZB_CMD_DEFAULT_RESPONSE = 0x0bU, /*!< Default response command */
ZB_CMD_DISCOVER_ATTRIBUTES = 0x0cU, /*!< Discover attributes command */
ZB_CMD_DISCOVER_ATTRIBUTES_RESPONSE = 0x0dU, /*!< Discover attributes response command */
ZB_CMD_READ_ATTRIBUTE_STRUCTURED = 0x0eU, /*!< Read attributes structured */
ZB_CMD_WRITE_ATTRIBUTE_STRUCTURED = 0x0fU, /*!< Write attributes structured */
ZB_CMD_WRITE_ATTRIBUTE_STRUCTURED_RESPONSE = 0x10U, /*!< Write attributes structured response */
ZB_CMD_DISCOVER_COMMANDS_RECEIVED = 0x11U, /*!< Discover Commands Received command */
ZB_CMD_DISCOVER_COMMANDS_RECEIVED_RESPONSE = 0x12U, /*!< Discover Commands Received response command */
ZB_CMD_DISCOVER_COMMANDS_GENERATED = 0x13U, /*!< Discover Commands Generated command */
ZB_CMD_DISCOVER_COMMANDS_GENERATED_RESPONSE = 0x14U, /*!< Discover Commands Generated response command */
ZB_CMD_DISCOVER_ATTRIBUTES_EXTENDED = 0x15U, /*!< Discover attributes extended command */
ZB_CMD_DISCOVER_ATTRIBUTES_EXTENDED_RESPONSE = 0x16U, /*!< Discover attributes extended response command */
} zb_cmd_type_t;

#define ZB_ARRAY_LENGHT(arr) (sizeof(arr) / sizeof(arr[0]))

#define RGB_TO_XYZ(r, g, b, X, Y, Z) \
Expand Down Expand Up @@ -138,6 +164,7 @@ class ZigbeeEP {
virtual void zbReadTimeCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented
virtual void zbIASZoneStatusChangeNotification(const esp_zb_zcl_ias_zone_status_change_notification_message_t *message) {};
virtual void zbIASZoneEnrollResponse(const esp_zb_zcl_ias_zone_enroll_response_message_t *message) {};
virtual void zbDefaultResponse(const esp_zb_zcl_cmd_default_resp_message_t *message); //already implemented

virtual void addBoundDevice(zb_device_params_t *device) {
_bound_devices.push_back(device);
Expand All @@ -156,16 +183,22 @@ class ZigbeeEP {
_on_identify = callback;
}

void onDefaultResponse(void (*callback)(zb_cmd_type_t resp_to_cmd, esp_zb_zcl_status_t status)) {
_on_default_response = callback;
}

// Convert ZCL status to name
const char *esp_zb_zcl_status_to_name(esp_zb_zcl_status_t status);

private:
char *_read_manufacturer;
char *_read_model;
void (*_on_identify)(uint16_t time);
void (*_on_default_response)(zb_cmd_type_t resp_to_cmd, esp_zb_zcl_status_t status);
time_t _read_time;
int32_t _read_timezone;

protected:
// Convert ZCL status to name
const char *esp_zb_zcl_status_to_name(esp_zb_zcl_status_t status);

uint8_t _endpoint;
esp_zb_ha_standard_devices_t _device_id;
Expand Down
7 changes: 7 additions & 0 deletions libraries/Zigbee/src/ZigbeeHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,13 @@ static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_m
"Received default response: from address(0x%x), src_endpoint(%d) to dst_endpoint(%d), cluster(0x%x) with status 0x%x",
message->info.src_address.u.short_addr, message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster, message->status_code
);

// List through all Zigbee EPs and call the callback function, with the message
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
if (message->info.dst_endpoint == (*it)->getEndpoint()) {
(*it)->zbDefaultResponse(message); //method zbDefaultResponse is implemented in the common EP class
}
}
return ESP_OK;
}

Expand Down
Loading