Skip to content

Commit 4ce23ce

Browse files
authored
Merge pull request #11817 from espressif/feat/zigbee-write-handler-multiendpoint
feat(zigbee): Add Write Response Handler + option to allow multi endpoint binding
2 parents 54ed29c + 93c5e9f commit 4ce23ce

File tree

5 files changed

+53
-5
lines changed

5 files changed

+53
-5
lines changed

libraries/Zigbee/keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ scanComplete KEYWORD2
7676
getScanResult KEYWORD2
7777
scanDelete KEYWORD2
7878
factoryReset KEYWORD2
79+
allowMultiEndpointBinding KEYWORD2
7980

8081
# Common ZigbeeEP
8182
setEpConfig KEYWORD2

libraries/Zigbee/src/ZigbeeCore.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ ZigbeeCore::ZigbeeCore() {
4646
_scan_duration = 3; // default scan duration
4747
_rx_on_when_idle = true;
4848
_debug = false;
49+
_allow_multi_endpoint_binding = false;
4950
_global_default_response_cb = nullptr; // Initialize global callback to nullptr
5051
if (!lock) {
5152
lock = xSemaphoreCreateBinary();
@@ -392,7 +393,9 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
392393
log_d("Device not bound to endpoint %d and it is free to bound!", (*it)->getEndpoint());
393394
(*it)->findEndpoint(&cmd_req);
394395
log_d("Endpoint %d is searching for device", (*it)->getEndpoint());
395-
break; // Only one endpoint per device
396+
if (!Zigbee.allowMultiEndpointBinding()) { // If multi endpoint binding is not allowed, break the loop to keep backwards compatibility
397+
break;
398+
}
396399
}
397400
}
398401
}
@@ -422,11 +425,13 @@ void esp_zb_app_signal_handler(esp_zb_app_signal_t *signal_struct) {
422425
break;
423426
}
424427
}
425-
log_d("Device not bound to endpoint %d and it is free to bound!", (*it)->getEndpoint());
426428
if (!found) {
429+
log_d("Device not bound to endpoint %d and it is free to bound!", (*it)->getEndpoint());
427430
(*it)->findEndpoint(&cmd_req);
428431
log_d("Endpoint %d is searching for device", (*it)->getEndpoint());
429-
break; // Only one endpoint per device
432+
if (!Zigbee.allowMultiEndpointBinding()) { // If multi endpoint binding is not allowed, break the loop to keep backwards compatibility
433+
break;
434+
}
430435
}
431436
}
432437
}

libraries/Zigbee/src/ZigbeeCore.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class ZigbeeCore {
117117
zigbee_scan_result_t *_scan_result;
118118
SemaphoreHandle_t lock;
119119
bool _debug;
120+
bool _allow_multi_endpoint_binding;
120121

121122
// Global default response callback
122123
void (*_global_default_response_cb)(zb_cmd_type_t resp_to_cmd, esp_zb_zcl_status_t status, uint8_t endpoint, uint16_t cluster);
@@ -196,6 +197,13 @@ class ZigbeeCore {
196197
return _debug;
197198
}
198199

200+
void allowMultiEndpointBinding(bool allow) {
201+
_allow_multi_endpoint_binding = allow;
202+
}
203+
bool allowMultiEndpointBinding() {
204+
return _allow_multi_endpoint_binding;
205+
}
206+
199207
// Set global default response callback
200208
void onGlobalDefaultResponse(void (*callback)(zb_cmd_type_t resp_to_cmd, esp_zb_zcl_status_t status, uint8_t endpoint, uint16_t cluster)) {
201209
_global_default_response_cb = callback;

libraries/Zigbee/src/ZigbeeEP.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ class ZigbeeEP {
149149
// list of all handlers function calls, to be override by EPs implementation
150150
virtual void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {};
151151
virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) {};
152+
virtual void
153+
zbWriteAttributeResponse(uint16_t cluster_id, uint16_t attribute_id, esp_zb_zcl_status_t status, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) {};
152154
virtual void zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented
153155
virtual void zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message);
154156
virtual void zbWindowCoveringMovementCmd(const esp_zb_zcl_window_covering_movement_message_t *message) {};

libraries/Zigbee/src/ZigbeeHandlers.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ static bool s_tagid_received = false;
4242
static esp_err_t zb_attribute_set_handler(const esp_zb_zcl_set_attr_value_message_t *message);
4343
static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_message_t *message);
4444
static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message);
45+
static esp_err_t zb_cmd_write_attr_resp_handler(const esp_zb_zcl_cmd_write_attr_resp_message_t *message);
4546
static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message);
4647
static esp_err_t zb_cmd_ias_zone_status_change_handler(const esp_zb_zcl_ias_zone_status_change_notification_message_t *message);
4748
static esp_err_t zb_cmd_ias_zone_enroll_response_handler(const esp_zb_zcl_ias_zone_enroll_response_message_t *message);
@@ -72,8 +73,9 @@ static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id,
7273
case ESP_ZB_CORE_OTA_UPGRADE_QUERY_IMAGE_RESP_CB_ID:
7374
ret = zb_ota_upgrade_query_image_resp_handler((esp_zb_zcl_ota_upgrade_query_image_resp_message_t *)message);
7475
break;
75-
case ESP_ZB_CORE_CMD_DEFAULT_RESP_CB_ID: ret = zb_cmd_default_resp_handler((esp_zb_zcl_cmd_default_resp_message_t *)message); break;
76-
default: log_w("Receive unhandled Zigbee action(0x%x) callback", callback_id); break;
76+
case ESP_ZB_CORE_CMD_DEFAULT_RESP_CB_ID: ret = zb_cmd_default_resp_handler((esp_zb_zcl_cmd_default_resp_message_t *)message); break;
77+
case ESP_ZB_CORE_CMD_WRITE_ATTR_RESP_CB_ID: ret = zb_cmd_write_attr_resp_handler((esp_zb_zcl_cmd_write_attr_resp_message_t *)message); break;
78+
default: log_w("Receive unhandled Zigbee action(0x%x) callback", callback_id); break;
7779
}
7880
return ret;
7981
}
@@ -170,6 +172,36 @@ static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_re
170172
return ESP_OK;
171173
}
172174

175+
static esp_err_t zb_cmd_write_attr_resp_handler(const esp_zb_zcl_cmd_write_attr_resp_message_t *message) {
176+
if (!message) {
177+
log_e("Empty message");
178+
return ESP_FAIL;
179+
}
180+
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
181+
log_e("Received message: error status(%d)", message->info.status);
182+
return ESP_ERR_INVALID_ARG;
183+
}
184+
log_v(
185+
"Write attribute response: from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->info.src_address.u.short_addr,
186+
message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster
187+
);
188+
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
189+
if (message->info.dst_endpoint == (*it)->getEndpoint()) {
190+
esp_zb_zcl_write_attr_resp_variable_t *variable = message->variables;
191+
while (variable) {
192+
log_v("Write attribute response: status(%d), cluster(0x%x), attribute(0x%x)", variable->status, message->info.cluster, variable->attribute_id);
193+
if (variable->status == ESP_ZB_ZCL_STATUS_SUCCESS) {
194+
(*it)->zbWriteAttributeResponse(
195+
message->info.cluster, variable->attribute_id, variable->status, message->info.src_endpoint, message->info.src_address
196+
);
197+
}
198+
variable = variable->next;
199+
}
200+
}
201+
}
202+
return ESP_OK;
203+
}
204+
173205
static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message) {
174206
if (!message) {
175207
log_e("Empty message");

0 commit comments

Comments
 (0)