diff --git a/libraries/Zigbee/examples/Zigbee_OTA_Client/Zigbee_OTA_Client.ino b/libraries/Zigbee/examples/Zigbee_OTA_Client/Zigbee_OTA_Client.ino index 29d114014b4..6ea2329a459 100644 --- a/libraries/Zigbee/examples/Zigbee_OTA_Client/Zigbee_OTA_Client.ino +++ b/libraries/Zigbee/examples/Zigbee_OTA_Client/Zigbee_OTA_Client.ino @@ -44,6 +44,18 @@ uint8_t button = BOOT_PIN; ZigbeeLight zbLight = ZigbeeLight(ZIGBEE_LIGHT_ENDPOINT); +volatile bool otaRunning = false; + +/********************* Callbacks *************************/ +void otaActiveCallback(bool otaActive) { + otaRunning = otaActive; + if (otaActive) { + Serial.println("OTA started"); + } else { + Serial.println("OTA finished"); + } +} + /********************* RGB LED functions **************************/ void setLED(bool value) { digitalWrite(led, value); @@ -69,6 +81,9 @@ void setup() { // Add OTA client to the light bulb zbLight.addOTAClient(OTA_UPGRADE_RUNNING_FILE_VERSION, OTA_UPGRADE_DOWNLOADED_FILE_VERSION, OTA_UPGRADE_HW_VERSION); + // Optional: Register callback for OTA state change + zbLight.onOTAStateChange(otaActiveCallback); + // Add endpoint to Zigbee Core Serial.println("Adding ZigbeeLight endpoint to Zigbee Core"); Zigbee.addEndpoint(&zbLight); @@ -99,6 +114,10 @@ void loop() { while (digitalRead(button) == LOW) { delay(50); if ((millis() - startTime) > 3000) { + if (otaRunning) { + Serial.println("OTA in progress, cannot reset now"); + break; + } // If key pressed for more than 3secs, factory reset Zigbee and reboot Serial.println("Resetting Zigbee to factory and rebooting in 1s."); delay(1000); diff --git a/libraries/Zigbee/src/ZigbeeEP.cpp b/libraries/Zigbee/src/ZigbeeEP.cpp index 5e4d9a38545..b857eb5e7a5 100644 --- a/libraries/Zigbee/src/ZigbeeEP.cpp +++ b/libraries/Zigbee/src/ZigbeeEP.cpp @@ -28,6 +28,7 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) { _ep_config.endpoint = 0; _cluster_list = nullptr; _on_identify = nullptr; + _on_ota_state_change = nullptr; _read_model = NULL; _read_manufacturer = NULL; _time_status = 0; @@ -318,6 +319,12 @@ void ZigbeeEP::zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message) { } } +void ZigbeeEP::zbOTAState(bool otaActive) { + if (_on_ota_state_change != NULL) { + _on_ota_state_change(otaActive); + } +} + bool ZigbeeEP::addTimeCluster(tm time, int32_t gmt_offset) { time_t utc_time = 0; // Check if time is set diff --git a/libraries/Zigbee/src/ZigbeeEP.h b/libraries/Zigbee/src/ZigbeeEP.h index a873205808f..3a7dea19a41 100644 --- a/libraries/Zigbee/src/ZigbeeEP.h +++ b/libraries/Zigbee/src/ZigbeeEP.h @@ -153,6 +153,7 @@ class ZigbeeEP { 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) {}; virtual void zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented virtual void zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message); + virtual void zbOTAState(bool otaActive); virtual void zbWindowCoveringMovementCmd(const esp_zb_zcl_window_covering_movement_message_t *message) {}; 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) {}; @@ -176,6 +177,10 @@ class ZigbeeEP { _on_identify = callback; } + void onOTAStateChange(void (*callback)(bool state)) { + _on_ota_state_change = callback; + } + void onDefaultResponse(void (*callback)(zb_cmd_type_t resp_to_cmd, esp_zb_zcl_status_t status)) { _on_default_response = callback; } @@ -186,6 +191,7 @@ class ZigbeeEP { char *_read_manufacturer; char *_read_model; void (*_on_identify)(uint16_t time); + void (*_on_ota_state_change)(bool state); 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; diff --git a/libraries/Zigbee/src/ZigbeeHandlers.cpp b/libraries/Zigbee/src/ZigbeeHandlers.cpp index 29c4e670f66..9b574ea7422 100644 --- a/libraries/Zigbee/src/ZigbeeHandlers.cpp +++ b/libraries/Zigbee/src/ZigbeeHandlers.cpp @@ -338,6 +338,9 @@ static esp_err_t zb_ota_upgrade_status_handler(const esp_zb_zcl_ota_upgrade_valu switch (message->upgrade_status) { case ESP_ZB_ZCL_OTA_UPGRADE_STATUS_START: log_i("Zigbee - OTA upgrade start"); + for (std::list::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); @@ -348,6 +351,9 @@ static esp_err_t zb_ota_upgrade_status_handler(const esp_zb_zcl_ota_upgrade_valu #endif if (ret != ESP_OK) { log_e("Zigbee - Failed to begin OTA partition, status: %s", esp_err_to_name(ret)); + for (std::list::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; @@ -361,6 +367,9 @@ static esp_err_t zb_ota_upgrade_status_handler(const esp_zb_zcl_ota_upgrade_valu 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::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 @@ -370,6 +379,9 @@ static esp_err_t zb_ota_upgrade_status_handler(const esp_zb_zcl_ota_upgrade_valu #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::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) { + (*it)->zbOTAState(false); // Notify that OTA is no longer active + } return ret; } } @@ -389,6 +401,9 @@ static esp_err_t zb_ota_upgrade_status_handler(const esp_zb_zcl_ota_upgrade_valu 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::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