diff --git a/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino b/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino index 34ca17942..69ed71fe6 100644 --- a/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino +++ b/libraries/ESP8266httpUpdate/examples/httpUpdate/httpUpdate.ino @@ -43,6 +43,23 @@ void setup() { } +void update_started() { + USE_SERIAL.println("CALLBACK: HTTP update process started"); +} + +void update_finished() { + USE_SERIAL.println("CALLBACK: HTTP update process finished"); +} + +void update_progress(int cur, int total) { + USE_SERIAL.printf("CALLBACK: HTTP update process at %d of %d bytes...\n", cur, total); +} + +void update_error(int err) { + USE_SERIAL.printf("CALLBACK: HTTP update fatal error code %d\n", err); +} + + void loop() { // wait for WiFi connection if ((WiFiMulti.run() == WL_CONNECTED)) { @@ -57,6 +74,12 @@ void loop() { // value is used to put the LED on. If the LED is on with HIGH, that value should be passed ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW); + // Add optional callback notifiers + ESPhttpUpdate.onStart(update_started); + ESPhttpUpdate.onEnd(update_finished); + ESPhttpUpdate.onProgress(update_progress); + ESPhttpUpdate.onError(update_error); + t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://server/file.bin"); // Or: //t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin"); diff --git a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp index 30ccf2dbf..f73612065 100644 --- a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp +++ b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.cpp @@ -294,7 +294,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& if(code <= 0) { DEBUG_HTTP_UPDATE("[httpUpdate] HTTP error: %s\n", http.errorToString(code).c_str()); - _lastError = code; + _setLastError(code); http.end(); return HTTP_UPDATE_FAILED; } @@ -334,10 +334,14 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& } } - if(!startUpdate) { - _lastError = HTTP_UE_TOO_LESS_SPACE; + if (!startUpdate) { + _setLastError(HTTP_UE_TOO_LESS_SPACE); ret = HTTP_UPDATE_FAILED; } else { + // Warn main app we're starting up... + if (_cbStart) { + _cbStart(); + } WiFiClient * tcp = http.getStreamPtr(); @@ -360,7 +364,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& uint8_t buf[4]; if(tcp->peekBytes(&buf[0], 4) != 4) { DEBUG_HTTP_UPDATE("[httpUpdate] peekBytes magic header failed\n"); - _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + _setLastError(HTTP_UE_BIN_VERIFY_HEADER_FAILED); http.end(); return HTTP_UPDATE_FAILED; } @@ -368,7 +372,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& // check for valid first magic byte if(buf[0] != 0xE9) { DEBUG_HTTP_UPDATE("[httpUpdate] Magic header does not start with 0xE9\n"); - _lastError = HTTP_UE_BIN_VERIFY_HEADER_FAILED; + _setLastError(HTTP_UE_BIN_VERIFY_HEADER_FAILED); http.end(); return HTTP_UPDATE_FAILED; @@ -379,7 +383,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& // check if new bin fits to SPI flash if(bin_flash_size > ESP.getFlashChipRealSize()) { DEBUG_HTTP_UPDATE("[httpUpdate] New binary does not fit SPI Flash size\n"); - _lastError = HTTP_UE_BIN_FOR_WRONG_FLASH; + _setLastError(HTTP_UE_BIN_FOR_WRONG_FLASH); http.end(); return HTTP_UPDATE_FAILED; } @@ -388,6 +392,10 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& ret = HTTP_UPDATE_OK; DEBUG_HTTP_UPDATE("[httpUpdate] Update ok\n"); http.end(); + // Warn main app we're all done + if (_cbEnd) { + _cbEnd(); + } #ifdef ATOMIC_FS_UPDATE if(_rebootOnUpdate) { @@ -403,7 +411,7 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& } } } else { - _lastError = HTTP_UE_SERVER_NOT_REPORT_SIZE; + _setLastError(HTTP_UE_SERVER_NOT_REPORT_SIZE); ret = HTTP_UPDATE_FAILED; DEBUG_HTTP_UPDATE("[httpUpdate] Content-Length was 0 or wasn't set by Server?!\n"); } @@ -413,15 +421,15 @@ HTTPUpdateResult ESP8266HTTPUpdate::handleUpdate(HTTPClient& http, const String& ret = HTTP_UPDATE_NO_UPDATES; break; case HTTP_CODE_NOT_FOUND: - _lastError = HTTP_UE_SERVER_FILE_NOT_FOUND; + _setLastError(HTTP_UE_SERVER_FILE_NOT_FOUND); ret = HTTP_UPDATE_FAILED; break; case HTTP_CODE_FORBIDDEN: - _lastError = HTTP_UE_SERVER_FORBIDDEN; + _setLastError(HTTP_UE_SERVER_FORBIDDEN); ret = HTTP_UPDATE_FAILED; break; default: - _lastError = HTTP_UE_SERVER_WRONG_HTTP_CODE; + _setLastError(HTTP_UE_SERVER_WRONG_HTTP_CODE); ret = HTTP_UPDATE_FAILED; DEBUG_HTTP_UPDATE("[httpUpdate] HTTP Code is (%d)\n", code); //http.writeToStream(&Serial1); @@ -444,32 +452,44 @@ bool ESP8266HTTPUpdate::runUpdate(Stream& in, uint32_t size, const String& md5, StreamString error; + if (_cbProgress) { + Update.onProgress(_cbProgress); + } + if(!Update.begin(size, command, _ledPin, _ledOn)) { - _lastError = Update.getError(); + _setLastError(Update.getError()); Update.printError(error); error.trim(); // remove line ending DEBUG_HTTP_UPDATE("[httpUpdate] Update.begin failed! (%s)\n", error.c_str()); return false; } + if (_cbProgress) { + _cbProgress(0, size); + } + if(md5.length()) { if(!Update.setMD5(md5.c_str())) { - _lastError = HTTP_UE_SERVER_FAULTY_MD5; + _setLastError(HTTP_UE_SERVER_FAULTY_MD5); DEBUG_HTTP_UPDATE("[httpUpdate] Update.setMD5 failed! (%s)\n", md5.c_str()); return false; } } if(Update.writeStream(in) != size) { - _lastError = Update.getError(); + _setLastError(Update.getError()); Update.printError(error); error.trim(); // remove line ending DEBUG_HTTP_UPDATE("[httpUpdate] Update.writeStream failed! (%s)\n", error.c_str()); return false; } + if (_cbProgress) { + _cbProgress(size, size); + } + if(!Update.end()) { - _lastError = Update.getError(); + _setLastError(Update.getError()); Update.printError(error); error.trim(); // remove line ending DEBUG_HTTP_UPDATE("[httpUpdate] Update.end failed! (%s)\n", error.c_str()); diff --git a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h index 93d68f811..62fe280cd 100644 --- a/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h +++ b/libraries/ESP8266httpUpdate/src/ESP8266httpUpdate.h @@ -47,14 +47,15 @@ #endif /// note we use HTTP client errors too so we start at 100 -#define HTTP_UE_TOO_LESS_SPACE (-100) -#define HTTP_UE_SERVER_NOT_REPORT_SIZE (-101) -#define HTTP_UE_SERVER_FILE_NOT_FOUND (-102) -#define HTTP_UE_SERVER_FORBIDDEN (-103) -#define HTTP_UE_SERVER_WRONG_HTTP_CODE (-104) -#define HTTP_UE_SERVER_FAULTY_MD5 (-105) -#define HTTP_UE_BIN_VERIFY_HEADER_FAILED (-106) -#define HTTP_UE_BIN_FOR_WRONG_FLASH (-107) +//TODO - in v3.0.0 make this an enum +constexpr int HTTP_UE_TOO_LESS_SPACE = (-100); +constexpr int HTTP_UE_SERVER_NOT_REPORT_SIZE = (-101); +constexpr int HTTP_UE_SERVER_FILE_NOT_FOUND = (-102); +constexpr int HTTP_UE_SERVER_FORBIDDEN = (-103); +constexpr int HTTP_UE_SERVER_WRONG_HTTP_CODE = (-104); +constexpr int HTTP_UE_SERVER_FAULTY_MD5 = (-105); +constexpr int HTTP_UE_BIN_VERIFY_HEADER_FAILED = (-106); +constexpr int HTTP_UE_BIN_FOR_WRONG_FLASH = (-107); enum HTTPUpdateResult { HTTP_UPDATE_FAILED, @@ -64,6 +65,11 @@ enum HTTPUpdateResult { typedef HTTPUpdateResult t_httpUpdate_return; // backward compatibility +using HTTPUpdateStartCB = std::function; +using HTTPUpdateEndCB = std::function; +using HTTPUpdateErrorCB = std::function; +using HTTPUpdateProgressCB = std::function; + class ESP8266HTTPUpdate { public: @@ -124,6 +130,11 @@ public: #endif t_httpUpdate_return updateSpiffs(WiFiClient& client, const String& url, const String& currentVersion = ""); + // Notification callbacks + void onStart(HTTPUpdateStartCB cbOnStart) { _cbStart = cbOnStart; } + void onEnd(HTTPUpdateEndCB cbOnEnd) { _cbEnd = cbOnEnd; } + void onError(HTTPUpdateErrorCB cbOnError) { _cbError = cbOnError; } + void onProgress(HTTPUpdateProgressCB cbOnProgress) { _cbProgress = cbOnProgress; } int getLastError(void); String getLastErrorString(void); @@ -132,12 +143,25 @@ protected: t_httpUpdate_return handleUpdate(HTTPClient& http, const String& currentVersion, bool spiffs = false); bool runUpdate(Stream& in, uint32_t size, const String& md5, int command = U_FLASH); + // Set the error and potentially use a CB to notify the application + void _setLastError(int err) { + _lastError = err; + if (_cbError) { + _cbError(err); + } + } int _lastError; bool _rebootOnUpdate = true; private: int _httpClientTimeout; bool _followRedirects; + // Callbacks + HTTPUpdateStartCB _cbStart; + HTTPUpdateEndCB _cbEnd; + HTTPUpdateErrorCB _cbError; + HTTPUpdateProgressCB _cbProgress; + int _ledPin; uint8_t _ledOn; };