From 283646a69936d1c18f111c8e4b247056129034ba Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 02:47:05 +0700 Subject: [PATCH] Move OtaHandler to src OTA only valid for esp32 based monitor --- examples/OneOpenAir/OneOpenAir.ino | 35 +++-- examples/OneOpenAir/OtaHandler.h | 206 ----------------------------- src/OtaHandler.cpp | 164 +++++++++++++++++++++++ src/OtaHandler.h | 43 ++++++ 4 files changed, 223 insertions(+), 225 deletions(-) delete mode 100644 examples/OneOpenAir/OtaHandler.h create mode 100644 src/OtaHandler.cpp create mode 100644 src/OtaHandler.h diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 971a5c8..ee4b680 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -112,9 +112,8 @@ static void wdgFeedUpdate(void); static void ledBarEnabledUpdate(void); static bool sgp41Init(void); static void firmwareCheckForUpdate(void); -static void otaHandlerCallback(OtaState state, String mesasge); -static void displayExecuteOta(OtaState state, String msg, - int processing); +static void otaHandlerCallback(OtaHandler::OtaState state, String mesasge); +static void displayExecuteOta(OtaHandler::OtaState state, String msg, int processing); static int calculateMaxPeriod(int updateInterval); static void setMeasurementMaxPeriod(); @@ -519,29 +518,27 @@ static void firmwareCheckForUpdate(void) { Serial.println(); } -static void otaHandlerCallback(OtaState state, String mesasge) { - Serial.println("OTA message: " + mesasge); +static void otaHandlerCallback(OtaHandler::OtaState state, String message) { + Serial.println("OTA message: " + message); switch (state) { - case OtaState::OTA_STATE_BEGIN: + case OtaHandler::OTA_STATE_BEGIN: displayExecuteOta(state, fwNewVersion, 0); break; - case OtaState::OTA_STATE_FAIL: + case OtaHandler::OTA_STATE_FAIL: displayExecuteOta(state, "", 0); break; - case OtaState::OTA_STATE_PROCESSING: - displayExecuteOta(state, "", mesasge.toInt()); - break; - case OtaState::OTA_STATE_SUCCESS: - displayExecuteOta(state, "", mesasge.toInt()); + case OtaHandler::OTA_STATE_PROCESSING: + case OtaHandler::OTA_STATE_SUCCESS: + displayExecuteOta(state, "", message.toInt()); break; default: break; } } -static void displayExecuteOta(OtaState state, String msg, int processing) { +static void displayExecuteOta(OtaHandler::OtaState state, String msg, int processing) { switch (state) { - case OtaState::OTA_STATE_BEGIN: { + case OtaHandler::OTA_STATE_BEGIN: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateVersion(msg); } else { @@ -550,7 +547,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_FAIL: { + case OtaHandler::OTA_STATE_FAIL: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateFailed(); } else { @@ -560,7 +557,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_SKIP: { + case OtaHandler::OTA_STATE_SKIP: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateSkipped(); } else { @@ -570,7 +567,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_UP_TO_DATE: { + case OtaHandler::OTA_STATE_UP_TO_DATE: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateUpToDate(); } else { @@ -580,7 +577,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_PROCESSING: { + case OtaHandler::OTA_STATE_PROCESSING: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateProgress(processing); } else { @@ -589,7 +586,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { break; } - case OtaState::OTA_STATE_SUCCESS: { + case OtaHandler::OTA_STATE_SUCCESS: { int i = 6; while(i != 0) { i = i - 1; diff --git a/examples/OneOpenAir/OtaHandler.h b/examples/OneOpenAir/OtaHandler.h deleted file mode 100644 index a845f8b..0000000 --- a/examples/OneOpenAir/OtaHandler.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef _OTA_HANDLER_H_ -#define _OTA_HANDLER_H_ -#include -#include -#include -#include - -#define OTA_BUF_SIZE 1024 -#define URL_BUF_SIZE 256 - -enum OtaUpdateOutcome { - UPDATE_PERFORMED, - ALREADY_UP_TO_DATE, - UPDATE_FAILED, - UDPATE_SKIPPED -}; - -enum OtaState { - OTA_STATE_BEGIN, - OTA_STATE_FAIL, - OTA_STATE_SKIP, - OTA_STATE_UP_TO_DATE, - OTA_STATE_PROCESSING, - OTA_STATE_SUCCESS -}; - -typedef void(*OtaHandlerCallback_t)(OtaState state, - String message); - -class OtaHandler { -public: - void updateFirmwareIfOutdated(String deviceId) { - String url = "http://hw.airgradient.com/sensors/airgradient:" + deviceId + - "/generic/os/firmware.bin"; - url += "?current_firmware="; - url += GIT_VERSION; - char urlAsChar[URL_BUF_SIZE]; - url.toCharArray(urlAsChar, URL_BUF_SIZE); - Serial.printf("checking for new OTA update @ %s\n", urlAsChar); - - esp_http_client_config_t config = {}; - config.url = urlAsChar; - OtaUpdateOutcome ret = attemptToPerformOta(&config); - Serial.println(ret); - if (this->callback) { - switch (ret) { - case OtaUpdateOutcome::UPDATE_PERFORMED: - this->callback(OtaState::OTA_STATE_SUCCESS, ""); - break; - case OtaUpdateOutcome::UDPATE_SKIPPED: - this->callback(OtaState::OTA_STATE_SKIP, ""); - break; - case OtaUpdateOutcome::ALREADY_UP_TO_DATE: - this->callback(OtaState::OTA_STATE_UP_TO_DATE, ""); - break; - case OtaUpdateOutcome::UPDATE_FAILED: - this->callback(OtaState::OTA_STATE_FAIL, ""); - break; - default: - break; - } - } - } - - void setHandlerCallback(OtaHandlerCallback_t callback) { - this->callback = callback; - } - -private: - OtaHandlerCallback_t callback; - - OtaUpdateOutcome attemptToPerformOta(const esp_http_client_config_t *config) { - esp_http_client_handle_t client = esp_http_client_init(config); - if (client == NULL) { - Serial.println("Failed to initialize HTTP connection"); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - esp_err_t err = esp_http_client_open(client, 0); - if (err != ESP_OK) { - esp_http_client_cleanup(client); - Serial.printf("Failed to open HTTP connection: %s\n", - esp_err_to_name(err)); - return OtaUpdateOutcome::UPDATE_FAILED; - } - esp_http_client_fetch_headers(client); - - int httpStatusCode = esp_http_client_get_status_code(client); - if (httpStatusCode == 304) { - Serial.println("Firmware is already up to date"); - cleanupHttp(client); - return OtaUpdateOutcome::ALREADY_UP_TO_DATE; - } else if (httpStatusCode != 200) { - Serial.printf("Firmware update skipped, the server returned %d\n", - httpStatusCode); - cleanupHttp(client); - return OtaUpdateOutcome::UDPATE_SKIPPED; - } - - esp_ota_handle_t update_handle = 0; - const esp_partition_t *update_partition = NULL; - Serial.println("Starting OTA update ..."); - update_partition = esp_ota_get_next_update_partition(NULL); - if (update_partition == NULL) { - Serial.println("Passive OTA partition not found"); - cleanupHttp(client); - return OtaUpdateOutcome::UPDATE_FAILED; - } - Serial.printf("Writing to partition subtype %d at offset 0x%x\n", - update_partition->subtype, update_partition->address); - - err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); - if (err != ESP_OK) { - Serial.printf("esp_ota_begin failed, error=%d\n", err); - cleanupHttp(client); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - esp_err_t ota_write_err = ESP_OK; - char *upgrade_data_buf = (char *)malloc(OTA_BUF_SIZE); - if (!upgrade_data_buf) { - Serial.println("Couldn't allocate memory for data buffer"); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - int binary_file_len = 0; - int totalSize = esp_http_client_get_content_length(client); - Serial.println("File size: " + String(totalSize) + String(" bytes")); - - // Show display start update new firmware. - if (this->callback) { - this->callback(OtaState::OTA_STATE_BEGIN, ""); - } - - // Download file and write new firmware to OTA partition - uint32_t lastUpdate = millis(); - while (1) { - int data_read = - esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE); - if (data_read == 0) { - if (this->callback) { - this->callback(OtaState::OTA_STATE_PROCESSING, String(100)); - } - Serial.println("Connection closed, all data received"); - break; - } - if (data_read < 0) { - Serial.println("Data read error"); - if (this->callback) { - this->callback(OtaState::OTA_STATE_FAIL, ""); - } - break; - } - if (data_read > 0) { - ota_write_err = esp_ota_write( - update_handle, (const void *)upgrade_data_buf, data_read); - if (ota_write_err != ESP_OK) { - if (this->callback) { - this->callback(OtaState::OTA_STATE_FAIL, ""); - } - break; - } - binary_file_len += data_read; - - int percent = (binary_file_len * 100) / totalSize; - uint32_t ms = (uint32_t)(millis() - lastUpdate); - if (ms >= 250) { - // sm.executeOTA(StateMachine::OtaState::OTA_STATE_PROCESSING, "", - // percent); - if (this->callback) { - this->callback(OtaState::OTA_STATE_PROCESSING, - String(percent)); - } - lastUpdate = millis(); - } - } - } - free(upgrade_data_buf); - cleanupHttp(client); - Serial.printf("# of bytes written: %d\n", binary_file_len); - - esp_err_t ota_end_err = esp_ota_end(update_handle); - if (ota_write_err != ESP_OK) { - Serial.printf("Error: esp_ota_write failed! err=0x%d\n", err); - return OtaUpdateOutcome::UPDATE_FAILED; - } else if (ota_end_err != ESP_OK) { - Serial.printf("Error: esp_ota_end failed! err=0x%d. Image is invalid", - ota_end_err); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - err = esp_ota_set_boot_partition(update_partition); - if (err != ESP_OK) { - Serial.printf("esp_ota_set_boot_partition failed! err=0x%d\n", err); - return OtaUpdateOutcome::UPDATE_FAILED; - } - return OtaUpdateOutcome::UPDATE_PERFORMED; - } - - void cleanupHttp(esp_http_client_handle_t client) { - esp_http_client_close(client); - esp_http_client_cleanup(client); - } -}; - -#endif diff --git a/src/OtaHandler.cpp b/src/OtaHandler.cpp new file mode 100644 index 0000000..1e2ec64 --- /dev/null +++ b/src/OtaHandler.cpp @@ -0,0 +1,164 @@ +#include "OtaHandler.h" + +void OtaHandler::setHandlerCallback(OtaHandlerCallback_t callback) { _callback = callback; } + +void OtaHandler::updateFirmwareIfOutdated(String deviceId) { + String url = + "http://hw.airgradient.com/sensors/airgradient:" + deviceId + "/generic/os/firmware.bin"; + url += "?current_firmware="; + url += GIT_VERSION; + char urlAsChar[URL_BUF_SIZE]; + url.toCharArray(urlAsChar, URL_BUF_SIZE); + Serial.printf("checking for new OTA update @ %s\n", urlAsChar); + + esp_http_client_config_t config = {}; + config.url = urlAsChar; + OtaUpdateOutcome ret = attemptToPerformOta(&config); + Serial.println(ret); + if (_callback) { + switch (ret) { + case OtaUpdateOutcome::UPDATE_PERFORMED: + _callback(OtaState::OTA_STATE_SUCCESS, ""); + break; + case OtaUpdateOutcome::UPDATE_SKIPPED: + _callback(OtaState::OTA_STATE_SKIP, ""); + break; + case OtaUpdateOutcome::ALREADY_UP_TO_DATE: + _callback(OtaState::OTA_STATE_UP_TO_DATE, ""); + break; + case OtaUpdateOutcome::UPDATE_FAILED: + _callback(OtaState::OTA_STATE_FAIL, ""); + break; + default: + break; + } + } +} + +OtaHandler::OtaUpdateOutcome +OtaHandler::attemptToPerformOta(const esp_http_client_config_t *config) { + esp_http_client_handle_t client = esp_http_client_init(config); + if (client == NULL) { + Serial.println("Failed to initialize HTTP connection"); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + esp_err_t err = esp_http_client_open(client, 0); + if (err != ESP_OK) { + esp_http_client_cleanup(client); + Serial.printf("Failed to open HTTP connection: %s\n", esp_err_to_name(err)); + return OtaUpdateOutcome::UPDATE_FAILED; + } + esp_http_client_fetch_headers(client); + + int httpStatusCode = esp_http_client_get_status_code(client); + if (httpStatusCode == 304) { + Serial.println("Firmware is already up to date"); + cleanupHttp(client); + return OtaUpdateOutcome::ALREADY_UP_TO_DATE; + } else if (httpStatusCode != 200) { + Serial.printf("Firmware update skipped, the server returned %d\n", httpStatusCode); + cleanupHttp(client); + return OtaUpdateOutcome::UPDATE_SKIPPED; + } + + esp_ota_handle_t update_handle = 0; + const esp_partition_t *update_partition = NULL; + Serial.println("Starting OTA update ..."); + update_partition = esp_ota_get_next_update_partition(NULL); + if (update_partition == NULL) { + Serial.println("Passive OTA partition not found"); + cleanupHttp(client); + return OtaUpdateOutcome::UPDATE_FAILED; + } + Serial.printf("Writing to partition subtype %d at offset 0x%x\n", update_partition->subtype, + update_partition->address); + + err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); + if (err != ESP_OK) { + Serial.printf("esp_ota_begin failed, error=%d\n", err); + cleanupHttp(client); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + esp_err_t ota_write_err = ESP_OK; + char *upgrade_data_buf = (char *)malloc(OTA_BUF_SIZE); + if (!upgrade_data_buf) { + Serial.println("Couldn't allocate memory for data buffer"); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + int binary_file_len = 0; + int totalSize = esp_http_client_get_content_length(client); + Serial.println("File size: " + String(totalSize) + String(" bytes")); + + // Show display start update new firmware. + if (_callback) { + _callback(OtaState::OTA_STATE_BEGIN, ""); + } + + // Download file and write new firmware to OTA partition + uint32_t lastUpdate = millis(); + while (1) { + int data_read = esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE); + if (data_read == 0) { + if (_callback) { + _callback(OtaState::OTA_STATE_PROCESSING, String(100)); + } + Serial.println("Connection closed, all data received"); + break; + } + if (data_read < 0) { + Serial.println("Data read error"); + if (_callback) { + _callback(OtaState::OTA_STATE_FAIL, ""); + } + break; + } + if (data_read > 0) { + ota_write_err = esp_ota_write(update_handle, (const void *)upgrade_data_buf, data_read); + if (ota_write_err != ESP_OK) { + if (_callback) { + _callback(OtaState::OTA_STATE_FAIL, ""); + } + break; + } + binary_file_len += data_read; + + int percent = (binary_file_len * 100) / totalSize; + uint32_t ms = (uint32_t)(millis() - lastUpdate); + if (ms >= 250) { + // sm.executeOTA(StateMachine::OtaState::OTA_STATE_PROCESSING, "", + // percent); + if (_callback) { + _callback(OtaState::OTA_STATE_PROCESSING, String(percent)); + } + lastUpdate = millis(); + } + } + } + free(upgrade_data_buf); + cleanupHttp(client); + Serial.printf("# of bytes written: %d\n", binary_file_len); + + esp_err_t ota_end_err = esp_ota_end(update_handle); + if (ota_write_err != ESP_OK) { + Serial.printf("Error: esp_ota_write failed! err=0x%d\n", err); + return OtaUpdateOutcome::UPDATE_FAILED; + } else if (ota_end_err != ESP_OK) { + Serial.printf("Error: esp_ota_end failed! err=0x%d. Image is invalid", ota_end_err); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + err = esp_ota_set_boot_partition(update_partition); + if (err != ESP_OK) { + Serial.printf("esp_ota_set_boot_partition failed! err=0x%d\n", err); + return OtaUpdateOutcome::UPDATE_FAILED; + } + return OtaUpdateOutcome::UPDATE_PERFORMED; +} + +void OtaHandler::cleanupHttp(esp_http_client_handle_t client) { + esp_http_client_close(client); + esp_http_client_cleanup(client); +} \ No newline at end of file diff --git a/src/OtaHandler.h b/src/OtaHandler.h new file mode 100644 index 0000000..8863f9e --- /dev/null +++ b/src/OtaHandler.h @@ -0,0 +1,43 @@ +#ifndef OTA_HANDLER_H +#define OTA_HANDLER_H +#ifndef ESP8266 // Only for esp32 based mcu + +#include +#include +#include +#include + +#define OTA_BUF_SIZE 1024 +#define URL_BUF_SIZE 256 + +class OtaHandler { +public: + enum OtaState { + OTA_STATE_BEGIN, + OTA_STATE_FAIL, + OTA_STATE_SKIP, + OTA_STATE_UP_TO_DATE, + OTA_STATE_PROCESSING, + OTA_STATE_SUCCESS + }; + + typedef void (*OtaHandlerCallback_t)(OtaState state, String message); + void setHandlerCallback(OtaHandlerCallback_t callback); + void updateFirmwareIfOutdated(String deviceId); + +private: + OtaHandlerCallback_t _callback; + + enum OtaUpdateOutcome { + UPDATE_PERFORMED = 0, + ALREADY_UP_TO_DATE, + UPDATE_FAILED, + UPDATE_SKIPPED + }; // Internal use + + OtaUpdateOutcome attemptToPerformOta(const esp_http_client_config_t *config); + void cleanupHttp(esp_http_client_handle_t client); +}; + +#endif // ESP8266 +#endif // OTA_HANDLER_H \ No newline at end of file