475 lines
21 KiB
C++
475 lines
21 KiB
C++
// Copyright 2025 Espressif Systems (Shanghai) PTE LTD
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/* Zigbee Common Functions */
|
|
#include "ZigbeeCore.h"
|
|
#include "Arduino.h"
|
|
|
|
#if CONFIG_ZB_ENABLED
|
|
|
|
#include "esp_ota_ops.h"
|
|
#if CONFIG_ZB_DELTA_OTA // Delta OTA, code is prepared for this feature but not enabled by default
|
|
#include "esp_delta_ota_ops.h"
|
|
#endif
|
|
|
|
//OTA Upgrade defines and variables
|
|
#define OTA_ELEMENT_HEADER_LEN 6 /* OTA element format header size include tag identifier and length field */
|
|
|
|
/**
|
|
* @name Enumeration for the tag identifier denotes the type and format of the data within the element
|
|
* @anchor esp_ota_element_tag_id_t
|
|
*/
|
|
typedef enum esp_ota_element_tag_id_e {
|
|
UPGRADE_IMAGE = 0x0000, /*!< Upgrade image */
|
|
} esp_ota_element_tag_id_t;
|
|
|
|
static const esp_partition_t *s_ota_partition = NULL;
|
|
static esp_ota_handle_t s_ota_handle = 0;
|
|
static bool s_tagid_received = false;
|
|
|
|
// forward declaration of all implemented handlers
|
|
static esp_err_t zb_attribute_set_handler(const esp_zb_zcl_set_attr_value_message_t *message);
|
|
static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_message_t *message);
|
|
static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message);
|
|
static esp_err_t zb_cmd_write_attr_resp_handler(const esp_zb_zcl_cmd_write_attr_resp_message_t *message);
|
|
static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message);
|
|
static esp_err_t zb_cmd_ias_zone_status_change_handler(const esp_zb_zcl_ias_zone_status_change_notification_message_t *message);
|
|
static esp_err_t zb_cmd_ias_zone_enroll_response_handler(const esp_zb_zcl_ias_zone_enroll_response_message_t *message);
|
|
static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_message_t *message);
|
|
static esp_err_t zb_window_covering_movement_resp_handler(const esp_zb_zcl_window_covering_movement_message_t *message);
|
|
static esp_err_t zb_ota_upgrade_status_handler(const esp_zb_zcl_ota_upgrade_value_message_t *message);
|
|
static esp_err_t zb_ota_upgrade_query_image_resp_handler(const esp_zb_zcl_ota_upgrade_query_image_resp_message_t *message);
|
|
|
|
// Zigbee action handlers
|
|
[[maybe_unused]]
|
|
static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message) {
|
|
esp_err_t ret = ESP_OK;
|
|
switch (callback_id) {
|
|
case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID: ret = zb_attribute_set_handler((esp_zb_zcl_set_attr_value_message_t *)message); break;
|
|
case ESP_ZB_CORE_REPORT_ATTR_CB_ID: ret = zb_attribute_reporting_handler((esp_zb_zcl_report_attr_message_t *)message); break;
|
|
case ESP_ZB_CORE_CMD_READ_ATTR_RESP_CB_ID: ret = zb_cmd_read_attr_resp_handler((esp_zb_zcl_cmd_read_attr_resp_message_t *)message); break;
|
|
case ESP_ZB_CORE_CMD_REPORT_CONFIG_RESP_CB_ID: ret = zb_configure_report_resp_handler((esp_zb_zcl_cmd_config_report_resp_message_t *)message); break;
|
|
case ESP_ZB_CORE_CMD_IAS_ZONE_ZONE_STATUS_CHANGE_NOT_ID:
|
|
ret = zb_cmd_ias_zone_status_change_handler((esp_zb_zcl_ias_zone_status_change_notification_message_t *)message);
|
|
break;
|
|
case ESP_ZB_CORE_IAS_ZONE_ENROLL_RESPONSE_VALUE_CB_ID:
|
|
ret = zb_cmd_ias_zone_enroll_response_handler((esp_zb_zcl_ias_zone_enroll_response_message_t *)message);
|
|
break;
|
|
case ESP_ZB_CORE_WINDOW_COVERING_MOVEMENT_CB_ID:
|
|
ret = zb_window_covering_movement_resp_handler((esp_zb_zcl_window_covering_movement_message_t *)message);
|
|
break;
|
|
case ESP_ZB_CORE_OTA_UPGRADE_VALUE_CB_ID: ret = zb_ota_upgrade_status_handler((esp_zb_zcl_ota_upgrade_value_message_t *)message); break;
|
|
case ESP_ZB_CORE_OTA_UPGRADE_QUERY_IMAGE_RESP_CB_ID:
|
|
ret = zb_ota_upgrade_query_image_resp_handler((esp_zb_zcl_ota_upgrade_query_image_resp_message_t *)message);
|
|
break;
|
|
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;
|
|
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;
|
|
default: log_w("Receive unhandled Zigbee action(0x%x) callback", callback_id); break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static esp_err_t zb_attribute_set_handler(const esp_zb_zcl_set_attr_value_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
log_v(
|
|
"Received message: endpoint(%d), cluster(0x%x), attribute(0x%x), data size(%d)", message->info.dst_endpoint, message->info.cluster, message->attribute.id,
|
|
message->attribute.data.size
|
|
);
|
|
|
|
// 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()) {
|
|
if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_IDENTIFY) {
|
|
(*it)->zbIdentify(message); //method zbIdentify implemented in the common EP class
|
|
} else {
|
|
(*it)->zbAttributeSet(message); //method zbAttributeSet must be implemented in specific EP class
|
|
}
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
log_v(
|
|
"Received report from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->src_address.u.short_addr, message->src_endpoint,
|
|
message->dst_endpoint, message->cluster
|
|
);
|
|
// 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->dst_endpoint == (*it)->getEndpoint()) {
|
|
(*it)->zbAttributeRead(
|
|
message->cluster, &message->attribute, message->src_endpoint, message->src_address
|
|
); //method zbAttributeRead must be implemented in specific EP class
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
log_v(
|
|
"Read attribute response: from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->info.src_address.u.short_addr,
|
|
message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster
|
|
);
|
|
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
if (message->info.dst_endpoint == (*it)->getEndpoint()) {
|
|
esp_zb_zcl_read_attr_resp_variable_t *variable = message->variables;
|
|
while (variable) {
|
|
log_v(
|
|
"Read attribute response: status(%d), cluster(0x%x), attribute(0x%x), type(0x%x), value(%d)", variable->status, message->info.cluster,
|
|
variable->attribute.id, variable->attribute.data.type, variable->attribute.data.value ? *(uint8_t *)variable->attribute.data.value : 0
|
|
);
|
|
if (variable->status == ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_BASIC) {
|
|
(*it)->zbReadBasicCluster(&variable->attribute); //method zbReadBasicCluster implemented in the common EP class
|
|
} else if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_TIME) {
|
|
(*it)->zbReadTimeCluster(&variable->attribute); //method zbReadTimeCluster implemented in the common EP class
|
|
} else {
|
|
(*it)->zbAttributeRead(
|
|
message->info.cluster, &variable->attribute, message->info.src_endpoint, message->info.src_address
|
|
); //method zbAttributeRead must be implemented in specific EP class
|
|
}
|
|
}
|
|
variable = variable->next;
|
|
}
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_cmd_write_attr_resp_handler(const esp_zb_zcl_cmd_write_attr_resp_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
log_v(
|
|
"Write attribute response: from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->info.src_address.u.short_addr,
|
|
message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster
|
|
);
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
if (message->info.dst_endpoint == (*it)->getEndpoint()) {
|
|
esp_zb_zcl_write_attr_resp_variable_t *variable = message->variables;
|
|
while (variable) {
|
|
log_v("Write attribute response: status(%d), cluster(0x%x), attribute(0x%x)", variable->status, message->info.cluster, variable->attribute_id);
|
|
if (variable->status == ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
(*it)->zbWriteAttributeResponse(
|
|
message->info.cluster, variable->attribute_id, variable->status, message->info.src_endpoint, message->info.src_address
|
|
);
|
|
}
|
|
variable = variable->next;
|
|
}
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
esp_zb_zcl_config_report_resp_variable_t *variable = message->variables;
|
|
while (variable) {
|
|
log_v(
|
|
"Configure report response: status(%d), cluster(0x%x), direction(0x%x), attribute(0x%x)", variable->status, message->info.cluster, variable->direction,
|
|
variable->attribute_id
|
|
);
|
|
variable = variable->next;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_cmd_ias_zone_status_change_handler(const esp_zb_zcl_ias_zone_status_change_notification_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
log_v(
|
|
"IAS Zone Status Notification: from address(0x%x) src endpoint(%d) to dst endpoint(%d) cluster(0x%x)", message->info.src_address.u.short_addr,
|
|
message->info.src_endpoint, message->info.dst_endpoint, message->info.cluster
|
|
);
|
|
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
if (message->info.dst_endpoint == (*it)->getEndpoint()) {
|
|
(*it)->zbIASZoneStatusChangeNotification(message);
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_cmd_ias_zone_enroll_response_handler(const esp_zb_zcl_ias_zone_enroll_response_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
log_v("IAS Zone Enroll Response received");
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
if (message->info.dst_endpoint == (*it)->getEndpoint()) {
|
|
(*it)->zbIASZoneEnrollResponse(message);
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_window_covering_movement_resp_handler(const esp_zb_zcl_window_covering_movement_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
}
|
|
|
|
log_v(
|
|
"Received message: endpoint(%d), cluster(0x%x), command(0x%x), payload(%d)", message->info.dst_endpoint, message->info.cluster, message->command,
|
|
message->payload
|
|
);
|
|
|
|
// 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)->zbWindowCoveringMovementCmd(message); //method zbWindowCoveringMovementCmd must be implemented in specific EP class
|
|
}
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t esp_element_ota_data(uint32_t total_size, const void *payload, uint16_t payload_size, void **outbuf, uint16_t *outlen) {
|
|
static uint16_t tagid = 0;
|
|
void *data_buf = NULL;
|
|
uint16_t data_len;
|
|
|
|
if (!s_tagid_received) {
|
|
uint32_t length = 0;
|
|
if (!payload || payload_size <= OTA_ELEMENT_HEADER_LEN) {
|
|
log_e("Invalid element format");
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
const uint8_t *payload_ptr = (const uint8_t *)payload;
|
|
tagid = *(const uint16_t *)payload_ptr;
|
|
length = *(const uint32_t *)(payload_ptr + sizeof(tagid));
|
|
if ((length + OTA_ELEMENT_HEADER_LEN) != total_size) {
|
|
log_e("Invalid element length [%ld/%ld]", length, total_size);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
s_tagid_received = true;
|
|
|
|
data_buf = (void *)(payload_ptr + OTA_ELEMENT_HEADER_LEN);
|
|
data_len = payload_size - OTA_ELEMENT_HEADER_LEN;
|
|
} else {
|
|
data_buf = (void *)payload;
|
|
data_len = payload_size;
|
|
}
|
|
|
|
switch (tagid) {
|
|
case UPGRADE_IMAGE:
|
|
*outbuf = data_buf;
|
|
*outlen = data_len;
|
|
break;
|
|
default:
|
|
log_e("Unsupported element tag identifier %d", tagid);
|
|
return ESP_ERR_INVALID_ARG;
|
|
break;
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_ota_upgrade_status_handler(const esp_zb_zcl_ota_upgrade_value_message_t *message) {
|
|
static uint32_t total_size = 0;
|
|
static uint32_t offset = 0;
|
|
[[maybe_unused]]
|
|
static int64_t start_time = 0;
|
|
esp_err_t ret = ESP_OK;
|
|
|
|
if (message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
switch (message->upgrade_status) {
|
|
case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_START:
|
|
log_i("Zigbee - OTA upgrade start");
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
(*it)->zbOTAState(true); // Notify that OTA is active
|
|
}
|
|
start_time = esp_timer_get_time();
|
|
s_ota_partition = esp_ota_get_next_update_partition(NULL);
|
|
assert(s_ota_partition);
|
|
#if CONFIG_ZB_DELTA_OTA
|
|
ret = esp_delta_ota_begin(s_ota_partition, 0, &s_ota_handle);
|
|
#else
|
|
ret = esp_ota_begin(s_ota_partition, 0, &s_ota_handle);
|
|
#endif
|
|
if (ret != ESP_OK) {
|
|
log_e("Zigbee - Failed to begin OTA partition, status: %s", esp_err_to_name(ret));
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
(*it)->zbOTAState(false); // Notify that OTA is no longer active
|
|
}
|
|
return ret;
|
|
}
|
|
break;
|
|
case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_RECEIVE:
|
|
total_size = message->ota_header.image_size;
|
|
offset += message->payload_size;
|
|
log_i("Zigbee - OTA Client receives data: progress [%ld/%ld]", offset, total_size);
|
|
if (message->payload_size && message->payload) {
|
|
uint16_t payload_size = 0;
|
|
void *payload = NULL;
|
|
ret = esp_element_ota_data(total_size, message->payload, message->payload_size, &payload, &payload_size);
|
|
if (ret != ESP_OK) {
|
|
log_e("Zigbee - Failed to element OTA data, status: %s", esp_err_to_name(ret));
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
(*it)->zbOTAState(false); // Notify that OTA is no longer active
|
|
}
|
|
return ret;
|
|
}
|
|
#if CONFIG_ZB_DELTA_OTA
|
|
ret = esp_delta_ota_write(s_ota_handle, payload, payload_size);
|
|
#else
|
|
ret = esp_ota_write(s_ota_handle, (const void *)payload, payload_size);
|
|
#endif
|
|
if (ret != ESP_OK) {
|
|
log_e("Zigbee - Failed to write OTA data to partition, status: %s", esp_err_to_name(ret));
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
(*it)->zbOTAState(false); // Notify that OTA is no longer active
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
break;
|
|
case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_APPLY: log_i("Zigbee - OTA upgrade apply"); break;
|
|
case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_CHECK:
|
|
ret = offset == total_size ? ESP_OK : ESP_FAIL;
|
|
offset = 0;
|
|
total_size = 0;
|
|
s_tagid_received = false;
|
|
log_i("Zigbee - OTA upgrade check status: %s", esp_err_to_name(ret));
|
|
break;
|
|
case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_FINISH:
|
|
log_i("Zigbee - OTA Finish");
|
|
log_i(
|
|
"Zigbee - OTA Information: version: 0x%lx, manufacturer code: 0x%x, image type: 0x%x, total size: %ld bytes, cost time: %lld ms,",
|
|
message->ota_header.file_version, message->ota_header.manufacturer_code, message->ota_header.image_type, message->ota_header.image_size,
|
|
(esp_timer_get_time() - start_time) / 1000
|
|
);
|
|
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
|
|
(*it)->zbOTAState(false); // Notify that OTA is no longer active
|
|
}
|
|
#if CONFIG_ZB_DELTA_OTA
|
|
ret = esp_delta_ota_end(s_ota_handle);
|
|
#else
|
|
ret = esp_ota_end(s_ota_handle);
|
|
#endif
|
|
if (ret != ESP_OK) {
|
|
log_e("Zigbee - Failed to end OTA partition, status: %s", esp_err_to_name(ret));
|
|
return ret;
|
|
}
|
|
ret = esp_ota_set_boot_partition(s_ota_partition);
|
|
if (ret != ESP_OK) {
|
|
log_e("Zigbee - Failed to set OTA boot partition, status: %s", esp_err_to_name(ret));
|
|
return ret;
|
|
}
|
|
log_w("Zigbee - Prepare to restart system");
|
|
esp_restart();
|
|
break;
|
|
default: log_i("Zigbee - OTA status: %d", message->upgrade_status); break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static esp_err_t zb_ota_upgrade_query_image_resp_handler(const esp_zb_zcl_ota_upgrade_query_image_resp_message_t *message) {
|
|
if (message->info.status == ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_i("Zigbee - Queried OTA image from address: 0x%04hx, endpoint: %d", message->server_addr.u.short_addr, message->server_endpoint);
|
|
log_i("Zigbee - Image version: 0x%lx, manufacturer code: 0x%x, image size: %ld", message->file_version, message->manufacturer_code, message->image_size);
|
|
if (message->image_size == 0) {
|
|
log_i("Zigbee - Rejecting OTA image upgrade, image size is 0");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->file_version == 0) {
|
|
log_i("Zigbee - Rejecting OTA image upgrade, file version is 0");
|
|
return ESP_FAIL;
|
|
}
|
|
log_i("Zigbee - Approving OTA image upgrade");
|
|
} else {
|
|
log_i("Zigbee - OTA image upgrade response status: 0x%x", message->info.status);
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_message_t *message) {
|
|
if (!message) {
|
|
log_e("Empty message");
|
|
return ESP_FAIL;
|
|
}
|
|
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
|
log_e("Received message: error status(%d)", message->info.status);
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
log_v(
|
|
"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
|
|
);
|
|
|
|
// Call global callback if set
|
|
Zigbee.callDefaultResponseCallback((zb_cmd_type_t)message->resp_to_cmd, message->status_code, message->info.dst_endpoint, message->info.cluster);
|
|
|
|
// 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;
|
|
}
|
|
|
|
#endif // CONFIG_ZB_ENABLED
|