diff --git a/examples/Progress/Progress.ino b/examples/Progress/Progress.ino new file mode 100644 index 0000000..947800f --- /dev/null +++ b/examples/Progress/Progress.ino @@ -0,0 +1,51 @@ +const char* host = "ESP-OTA"; // Used for MDNS resolution +const char* ssid = "ssid"; +const char* password = "password"; + +#include + +#define LED_PIN 2 + +// the setup function runs once when you press reset or power the board +void setup() { + Serial.begin(115200); + + // initialize digital pin LED_PIN as an output. + pinMode(LED_PIN, OUTPUT); + + init_wifi(ssid, password, host); + + webota + .onStart([]() { + Serial.println("Start updating"); + }) + .onEnd([]() { + Serial.println("\nEnd"); + }) + // .onProgress([](unsigned int progress, unsigned int total) { + // Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + // }) + .onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) Serial.println("End Failed"); + }); + + // Defaults to 8080 and "/webota" + //webota.init(80, "/update"); +} + +// the loop function runs over and over again forever +void loop() { + int md = 1000; + + digitalWrite(LED_PIN, HIGH); + webota.delay(md); + digitalWrite(LED_PIN, LOW); + webota.delay(md); + + webota.handle(); +} diff --git a/src/WebOTA.cpp b/src/WebOTA.cpp index 8d97712..781d11c 100644 --- a/src/WebOTA.cpp +++ b/src/WebOTA.cpp @@ -290,25 +290,37 @@ int WebOTA::add_http_routes(WebServer *server, const char *path) { }, [server,this]() { HTTPUpload& upload = server->upload(); + if (upload.status == UPLOAD_FILE_START) { + if (_start_callback) { + _start_callback(); + } Serial.printf("Firmware update initiated: %s\r\n", upload.filename.c_str()); //uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; uint32_t maxSketchSpace = this->max_sketch_size(); if (!Update.begin(maxSketchSpace)) { //start with max available size + if (_error_callback) { + _error_callback(OTA_BEGIN_ERROR); + } Update.printError(Serial); } } else if (upload.status == UPLOAD_FILE_WRITE) { /* flashing firmware to ESP*/ if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { + if (_error_callback) { + _error_callback(OTA_END_ERROR); + } Update.printError(Serial); } // Store the next milestone to output uint16_t chunk_size = 51200; static uint32_t next = 51200; - + if(_progress_callback) { + _progress_callback(upload.totalSize, upload.currentSize); + } // Check if we need to output a milestone (100k 200k 300k) if (upload.totalSize >= next) { Serial.printf("%dk ", next / 1024); @@ -316,8 +328,14 @@ int WebOTA::add_http_routes(WebServer *server, const char *path) { } } else if (upload.status == UPLOAD_FILE_END) { if (Update.end(true)) { //true to set the size to the current progress + if (_end_callback) { + _end_callback(); + } Serial.printf("\r\nFirmware update successful: %u bytes\r\nRebooting...\r\n", upload.totalSize); } else { + if (_error_callback) { + _error_callback(OTA_END_ERROR); + } Update.printError(Serial); } } @@ -404,6 +422,26 @@ String WebOTA::human_time(uint32_t sec) { return ret; } +WebOTA& WebOTA::onStart(THandlerFunction fn) { + _start_callback = fn; + return *this; +} + +WebOTA& WebOTA::onEnd(THandlerFunction fn) { + _end_callback = fn; + return *this; +} + +WebOTA& WebOTA::onProgress(THandlerFunction_Progress fn) { + _progress_callback = fn; + return *this; +} + +WebOTA& WebOTA::onError(THandlerFunction_Error fn) { + _error_callback = fn; + return *this; +} + int init_wifi(const char *ssid, const char *password, const char *mdns_hostname) { WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); diff --git a/src/WebOTA.h b/src/WebOTA.h index 861ae41..1bda3a9 100644 --- a/src/WebOTA.h +++ b/src/WebOTA.h @@ -7,6 +7,14 @@ #include #endif +typedef enum { + OTA_AUTH_ERROR, + OTA_BEGIN_ERROR, + OTA_CONNECT_ERROR, + OTA_RECEIVE_ERROR, + OTA_END_ERROR +} ota_error_t; + class WebOTA { public: unsigned int port; @@ -29,6 +37,22 @@ class WebOTA { void set_custom_html(char const * const html); + typedef std::function THandlerFunction; + typedef std::function THandlerFunction_Error; + typedef std::function THandlerFunction_Progress; + + //This callback will be called when OTA connection has begun + WebOTA& onStart(THandlerFunction fn); + + //This callback will be called when OTA has finished + WebOTA& onEnd(THandlerFunction fn); + + //This callback will be called when OTA encountered Error + WebOTA& onError(THandlerFunction_Error fn); + + //This callback will be called when OTA is receiving data + WebOTA& onProgress(THandlerFunction_Progress fn); + private: bool init_has_run; char const * custom_html = NULL; @@ -36,6 +60,10 @@ class WebOTA { String human_time(uint32_t sec); String get_board_type(); long max_sketch_size(); + THandlerFunction _start_callback; + THandlerFunction _end_callback; + THandlerFunction_Error _error_callback; + THandlerFunction_Progress _progress_callback; }; int init_wifi(const char *ssid, const char *password, const char *mdns_hostname);