diff --git a/src/Config.h b/src/Config.h index 3bd746c..70cfcf7 100644 --- a/src/Config.h +++ b/src/Config.h @@ -4,7 +4,7 @@ #define NUKI_HUB_VERSION "9.01" #define NUKI_HUB_BUILD "unknownbuildnr" -#define NUKI_HUB_DATE "2024-08-26" +#define NUKI_HUB_DATE "2024-08-27" #define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest" #define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json" diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp index a6dc65d..86f62e3 100644 --- a/src/WebCfgServer.cpp +++ b/src/WebCfgServer.cpp @@ -149,6 +149,7 @@ void WebCfgServer::initialize() _network->reconfigureDevice(); return res; } + return(ESP_OK); }); #endif _psychicServer->on("/unpairlock", HTTP_POST, [&](PsychicRequest *request){ @@ -225,16 +226,38 @@ void WebCfgServer::initialize() #endif }); - /* - _psychicServer->on("/uploadota", HTTP_POST, - [&](PsychicRequest *request) {}, - [&](PsychicRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) - { - if(strlen(_credUser) > 0 && strlen(_credPassword) > 0) if(!request->authenticate(_credUser, _credPassword)) return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); - return handleOtaUpload(request, filename, index, data, len, final); - } + PsychicUploadHandler *updateHandler = new PsychicUploadHandler(); + updateHandler->onUpload([&](PsychicRequest *request, const String& filename, uint64_t index, uint8_t *data, size_t len, bool final) + { + if(strlen(_credUser) > 0 && strlen(_credPassword) > 0) if(!request->authenticate(_credUser, _credPassword)) return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + return handleOtaUpload(request, filename, index, data, len, final); + } ); - */ + + updateHandler->onRequest([&](PsychicRequest *request) { + if(strlen(_credUser) > 0 && strlen(_credPassword) > 0) if(!request->authenticate(_credUser, _credPassword)) return request->requestAuthentication(BASIC_AUTH, "Nuki Hub", "You must log in."); + + String result; + if (!Update.hasError()) + { + Log->print("Update code or data OK Update.errorString() "); + Log->println(Update.errorString()); + result = "Update OK."; + esp_err_t res = request->reply(200,"text/html",result.c_str()); + restartEsp(RestartReason::OTACompleted); + return res; + } + else { + result = " Update.errorString() " + String(Update.errorString()); + Log->print("ERROR : error "); + Log->println(result.c_str()); + esp_err_t res = request->reply(500, "text/html", result.c_str()); + restartEsp(RestartReason::OTAAborted); + return res; + } + }); + + _psychicServer->on("/uploadota", HTTP_POST, updateHandler); //Update.onProgress(printProgress); } @@ -295,27 +318,27 @@ esp_err_t WebCfgServer::buildOtaHtml(PsychicRequest *request, bool debug) bool manifestSuccess = false; JsonDocument doc; - NetworkClientSecure *client = new NetworkClientSecure; - if (client) { - client->setCACertBundle(x509_crt_imported_bundle_bin_start, x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start); + NetworkClientSecure *clientOTAUpdate = new NetworkClientSecure; + if (clientOTAUpdate) { + clientOTAUpdate->setCACertBundle(x509_crt_imported_bundle_bin_start, x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start); { - HTTPClient https; - https.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); - https.setTimeout(2500); - https.useHTTP10(true); + HTTPClient httpsOTAClient; + httpsOTAClient.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); + httpsOTAClient.setTimeout(2500); + httpsOTAClient.useHTTP10(true); - if (https.begin(*client, GITHUB_OTA_MANIFEST_URL)) { - int http_responseCode = https.GET(); + if (httpsOTAClient.begin(*clientOTAUpdate, GITHUB_OTA_MANIFEST_URL)) { + int httpResponseCodeOTA = httpsOTAClient.GET(); - if (http_responseCode == HTTP_CODE_OK || http_responseCode == HTTP_CODE_MOVED_PERMANENTLY) + if (httpResponseCodeOTA == HTTP_CODE_OK || httpResponseCodeOTA == HTTP_CODE_MOVED_PERMANENTLY) { - DeserializationError jsonError = deserializeJson(doc, https.getStream()); + DeserializationError jsonError = deserializeJson(doc, httpsOTAClient.getStream()); if (!jsonError) { manifestSuccess = true; } } - https.end(); + httpsOTAClient.end(); } } - delete client; + delete clientOTAUpdate; } if(!manifestSuccess) @@ -469,88 +492,108 @@ void WebCfgServer::printProgress(size_t prg, size_t sz) { Log->printf("Progress: %d%%\n", (prg*100)/_otaContentLen); } -void WebCfgServer::handleOtaUpload(PsychicRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) +esp_err_t WebCfgServer::handleOtaUpload(PsychicRequest *request, const String& filename, uint64_t index, uint8_t *data, size_t len, bool final) { - if(!request->url().endsWith("/uploadota")) return; + if(!request->url().endsWith("/uploadota")) return(ESP_FAIL); if(filename == "") { Log->println("Invalid file for OTA upload"); - return; + return(ESP_FAIL); } - if (!index) + if (!Update.hasError()) { + if (!index){ + Update.clearError(); + + Log->println("Starting manual OTA update"); + _otaContentLen = request->contentLength(); + + if(_partitionType == 1 && _otaContentLen > 1600000) + { + Log->println("Uploaded OTA file too large, are you trying to upload a Nuki Hub binary instead of a Nuki Hub updater binary?"); + return(ESP_FAIL); + } + else if(_partitionType == 2 && _otaContentLen < 1600000) + { + Log->println("Uploaded OTA file is too small, are you trying to upload a Nuki Hub updater binary instead of a Nuki Hub binary?"); + return(ESP_FAIL); + } + + _otaStartTs = esp_timer_get_time() / 1000; + esp_task_wdt_config_t twdt_config = { + .timeout_ms = 30000, + .idle_core_mask = 0, + .trigger_panic = false, + }; + esp_task_wdt_reconfigure(&twdt_config); + + #ifndef NUKI_HUB_UPDATER + _network->disableAutoRestarts(); + _network->disableMqtt(); + if(_nuki != nullptr) + { + _nuki->disableWatchdog(); + } + if(_nukiOpener != nullptr) + { + _nukiOpener->disableWatchdog(); + } + #endif + Log->print("handleFileUpload Name: "); + Log->println(filename); + + if (!Update.begin(UPDATE_SIZE_UNKNOWN, U_FLASH)) { + if (!Update.hasError()) + { + Update.abort(); + } + Log->print("ERROR : update.begin error Update.errorString() "); + Log->println(Update.errorString()); + return(ESP_FAIL); + } + } + + if ((len) && (!Update.hasError())) { + if (Update.write(data, len) != len) { + if (!Update.hasError()) + { + Update.abort(); + } + Log->print("ERROR : update.write error Update.errorString() "); + Log->println(Update.errorString()); + return(ESP_FAIL); + } + } + + if ((final) && (!Update.hasError())) { + if (Update.end(true)) { + Log->print("Update Success: "); + Log->print(index+len); + Log->println(" written"); + } + else { + if (!Update.hasError()) + { + Update.abort(); + } + Log->print("ERROR : update end error Update.errorString() "); + Log->println(Update.errorString()); + return(ESP_FAIL); + } + } + Log->print(F("Progress: 100%")); + Log->println(); + Log->print("handleFileUpload Total Size: "); + Log->println(index+len); + Log->println("Update complete"); + Log->flush(); + return(ESP_OK); + } + else { - Log->println("Starting manual OTA update"); - _otaContentLen = request->contentLength(); - - if(_partitionType == 1 && _otaContentLen > 1600000) - { - Log->println("Uploaded OTA file too large, are you trying to upload a Nuki Hub binary instead of a Nuki Hub updater binary?"); - return; - } - else if(_partitionType == 2 && _otaContentLen < 1600000) - { - Log->println("Uploaded OTA file is too small, are you trying to upload a Nuki Hub updater binary instead of a Nuki Hub binary?"); - return; - } - - int cmd = U_FLASH; - if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) { - Update.printError(Serial); - } - - _otaStartTs = esp_timer_get_time() / 1000; - esp_task_wdt_config_t twdt_config = { - .timeout_ms = 30000, - .idle_core_mask = 0, - .trigger_panic = false, - }; - esp_task_wdt_reconfigure(&twdt_config); - - #ifndef NUKI_HUB_UPDATER - _network->disableAutoRestarts(); - _network->disableMqtt(); - if(_nuki != nullptr) - { - _nuki->disableWatchdog(); - } - if(_nukiOpener != nullptr) - { - _nukiOpener->disableWatchdog(); - } - #endif - Log->print("handleFileUpload Name: "); - Log->println(filename); + return(ESP_FAIL); } - - if (_otaContentLen == 0) return; - - if (Update.write(data, len) != len) { - Update.printError(Serial); - restartEsp(RestartReason::OTAAborted); - } - - /* - if (final) { - AsyncWebServerResponse *response = request->beginResponse(302, "text/plain", "Please wait while the device reboots"); - response->addHeader("Refresh", "20"); - response->addHeader("Location", "/"); - request->send(response); - if (!Update.end(true)){ - Update.printError(Serial); - restartEsp(RestartReason::OTAAborted); - } else { - Log->print(F("Progress: 100%")); - Log->println(); - Log->print("handleFileUpload Total Size: "); - Log->println(index+len); - Log->println("Update complete"); - Log->flush(); - restartEsp(RestartReason::OTACompleted); - } - } - */ } esp_err_t WebCfgServer::buildConfirmHtml(PsychicRequest *request, const String &message, uint32_t redirectDelay, bool redirect) @@ -2557,7 +2600,7 @@ esp_err_t WebCfgServer::buildHtml(PsychicRequest *request) { response.print("
REBOOT REQUIRED TO APPLY SETTINGS
"); } - if(_preferences->getBool(preference_webserial_enabled, false)) + if(_preferences->getBool(preference_webserial_enabled, false)) { response.print("
WEBSERIAL IS ENABLED, ONLY ENABLE WHEN DEBUGGING AND DISABLE ASAP
"); } @@ -2593,7 +2636,7 @@ esp_err_t WebCfgServer::buildHtml(PsychicRequest *request) NukiOpener::lockstateToString(_nukiOpener->keyTurnerState().lockState, openerStateArr); printParameter(&response, "Nuki Opener paired", _nukiOpener->isPaired() ? ("Yes (BLE Address " + _nukiOpener->getBleAddress().toString() + ")").c_str() : "No", "", "openerPaired"); - if(_nukiOpener->keyTurnerState().nukiState == NukiOpener::State::ContinuousMode) + if(_nukiOpener->keyTurnerState().nukiState == NukiOpener::State::ContinuousMode) { printParameter(&response, "Nuki Opener state", "Open (Continuous Mode)", "", "openerState"); } @@ -2608,7 +2651,7 @@ esp_err_t WebCfgServer::buildHtml(PsychicRequest *request) } } printParameter(&response, "Firmware", NUKI_HUB_VERSION, "/info", "firmware"); - if(_preferences->getBool(preference_check_updates)) + if(_preferences->getBool(preference_check_updates)) { printParameter(&response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota", "ota"); } @@ -3911,7 +3954,7 @@ esp_err_t WebCfgServer::processFactoryReset(PsychicRequest *request) return res; } -void WebCfgServer::printInputField(PsychicStreamResponse *response, +void WebCfgServer::printInputField(PsychicStreamResponse *response, const char *token, const char *description, const char *value, @@ -3955,7 +3998,7 @@ void WebCfgServer::printInputField(PsychicStreamResponse *response, response->print(""); } -void WebCfgServer::printInputField(PsychicStreamResponse *response, +void WebCfgServer::printInputField(PsychicStreamResponse *response, const char *token, const char *description, const int value, @@ -3989,7 +4032,7 @@ void WebCfgServer::printCheckBox(PsychicStreamResponse *response, const char *to response->print("/>"); } -void WebCfgServer::printTextarea(PsychicStreamResponse *response, +void WebCfgServer::printTextarea(PsychicStreamResponse *response, const char *token, const char *description, const char *value, diff --git a/src/WebCfgServer.h b/src/WebCfgServer.h index 4eb30a8..f9fe598 100644 --- a/src/WebCfgServer.h +++ b/src/WebCfgServer.h @@ -104,7 +104,7 @@ private: esp_err_t sendFavicon(PsychicRequest *request); void buildHtmlHeader(PsychicStreamResponse *response, String additionalHeader = ""); void waitAndProcess(const bool blocking, const uint32_t duration); - void handleOtaUpload(PsychicRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); + esp_err_t handleOtaUpload(PsychicRequest *request, const String& filename, uint64_t index, uint8_t *data, size_t len, bool final); void printProgress(size_t prg, size_t sz); PsychicHttpServer* _psychicServer = nullptr; diff --git a/src/main.cpp b/src/main.cpp index 2cd32ca..ee565d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -19,10 +19,12 @@ #include "Logger.h" #include "PreferencesKeys.h" #include "RestartReason.h" +/* #ifdef DEBUG_NUKIHUB #include #include #endif +*/ char log_print_buffer[1024]; @@ -490,6 +492,9 @@ void setup() if(!doOta) { psychicServer = new PsychicHttpServer; + psychicServer->config.max_uri_handlers = 40; + psychicServer->config.stack_size = 8192; + psychicServer->listen(80); if(forceEnableWebServer || preferences->getBool(preference_webserver_enabled, true)) { @@ -497,18 +502,18 @@ void setup() webCfgServer->initialize(); psychicServer->onNotFound([](PsychicRequest* request) { return request->redirect("/"); }); } + /* #ifdef DEBUG_NUKIHUB else psychicServer->onNotFound([](PsychicRequest* request) { return request->redirect("/webserial"); }); if(preferences->getBool(preference_webserial_enabled, false)) { - //WebSerial.setAuthentication(preferences->getString(preference_cred_user), preferences->getString(preference_cred_password)); - //WebSerial.begin(asyncServer); - //WebSerial.setBuffer(1024); + WebSerial.setAuthentication(preferences->getString(preference_cred_user), preferences->getString(preference_cred_password)); + WebSerial.begin(asyncServer); + WebSerial.setBuffer(1024); } #endif - - psychicServer->listen(80); + */ } } #endif