hoeken / PsychicHttp

Simple + Robust HTTP/S server with websockets for ESP32 based on ESP-IDF http server.
MIT License
118 stars 27 forks source link

OTA update example for PsychicHttp #90

Closed 06GitHub closed 1 month ago

06GitHub commented 4 months ago

OTA update example for PsychicHttp For those interested, an example of OTA (Over The Air) update implementation for PsychicHttp is provided below, using Arduino IDE.

Requirements Requirements for my project are :

Implementation OTA update relies on handler PsychicUploadHandler.

Screenshots and Code are provided below.

Credits https://github.com/hoeken/PsychicHttp/blob/master/src/PsychicUploadHandler.cpp

https://github.com/hoeken/PsychicHttp/issues/30

Configuration Arduino IDE 1.8.19 arduino-32 v2.0.15 ESP32S3

Files Structure

psychichttp_ota
     data
          | update.html
     psychichttp_ota.ino

SCREENSHOTS Update code (firmware) otaupdate1

otaupdate2 ESP-ROM:esp32s3-20210327 Build:Mar 27 2021 rst:0x1 (POWERON),boot:0x9 (SPI_FAST_FLASH_BOOT) SPIWP:0xee mode:DIO, clock div:1 load:0x3fce3808,len:0x4bc load:0x403c9700,len:0xbd8 load:0x403cc700,len:0x2a0c entry 0x403c98d0 [ 267][I][psychichttp_ota.ino:57] connectToWifi(): [OTA] [WiFi] WiFi is disconnected [ 775][I][psychichttp_ota.ino:60] connectToWifi(): [OTA] [WiFi] WiFi is connected, IP address 192.168.1.50 [ 9208][I][PsychicHttpServer.cpp:236] openCallback(): [psychic] New client connected 51 [ 9218][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 867274 [ 9230][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 861984 [ 9242][I][psychichttp_ota.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0 [ 9252][I][psychichttp_ota.ino:133] operator()(): [OTA] update begin, filename code.bin [ 9395][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 856240 [ 9407][I][psychichttp_ota.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0 [ 9435][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 850496 [ 9447][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 844752 [ 9459][I][psychichttp_ota.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0 [ 9488][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 839008 [ 9500][I][psychichttp_ota.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0 [ 9528][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 833264 [ 9540][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 827520 [ 9551][I][psychichttp_ota.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0 [snip] [ 15625][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 13308 [ 15637][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 7564 [ 15647][I][psychichttp_ota.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0 [ 15790][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 1820 [ 15800][I][psychichttp_ota.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 1 [ 15951][I][psychichttp_ota.ino:165] operator()(): [OTA] Update Success: 867040 written [ 15959][I][psychichttp_ota.ino:184] operator()(): [OTA] Update code or data OK Update.errorString() No Error [ 15972][I][PsychicHttpServer.cpp:236] openCallback(): [psychic] New client connected 52 [ 15980][I][PsychicHttpServer.cpp:262] closeCallback(): [psychic] Client disconnected 52

Update data (littlefs) otaupdate3

Restart otaupdate4

otaupdate5 [ 19616][I][psychichttp_ota.ino:205] operator()(): [OTA] Restarting ... [ 20808][W][WiFiGeneric.cpp:1062] _eventCallback(): Reason: 8 - ASSOC_LEAVE [ 20810][I][PsychicHttpServer.cpp:262] closeCallback(): [psychic] Client disconnected 51 ESP-ROM:esp32s3-20210327 Build:Mar 27 2021 rst:0xc (RTC_SW_CPU_RST),boot:0xa (SPI_FAST_FLASH_BOOT) Saved PC:0x420984ae SPIWP:0xee mode:DIO, clock div:1 load:0x3fce3808,len:0x4bc load:0x403c9700,len:0xbd8 load:0x403cc700,len:0x2a0c entry 0x403c98d0 [ 273][I][psychichttp_ota.ino:57] connectToWifi(): [OTA] [WiFi] WiFi is disconnected [ 781][I][psychichttp_ota.ino:60] connectToWifi(): [OTA] [WiFi] WiFi is connected, IP address 192.168.1.50

CODE psychichttp_ota.ino

/*
  Over The Air (OTA) update example for PsychicHttp web server

  This example code is in the Public Domain (or CC0 licensed, at your option.)

  Unless required by applicable law or agreed to in writing, this
  software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  CONDITIONS OF ANY KIND, either express or implied.

*/
char *TAG = "OTA"; // ESP_LOG tag

// PsychicHttp
#include <Arduino.h>
#include <WiFi.h>
#include <LittleFS.h>
#include <ESPmDNS.h>
#include <PsychicHttp.h>
PsychicHttpServer server; // main server object
const char *local_hostname = "psychichttp"; // hostname for mdns

// OTA
#include <Update.h> 
bool esprestart=false; // true if/when ESP should be restarted, after OTA update

// Wifi
const char *ssid = "myssid"; // SSID
const char *password = "mypassword"; // PASSWORD

bool connectToWifi() { // Wifi
  //client in STA mode
  WiFi.mode(WIFI_AP_STA);
  WiFi.begin(ssid,password);

  WiFi.begin(ssid, password);
  // Will try for about 10 seconds (20x 500ms)
  int tryDelay = 500;
  int numberOfTries = 20;

  // Wait for the WiFi event
  while (true) {
    switch (WiFi.status()) {
      case WL_NO_SSID_AVAIL:
        ESP_LOGE(TAG,"[WiFi] SSID not found");
        break;
      case WL_CONNECT_FAILED:
        ESP_LOGI(TAG,"[WiFi] Failed - WiFi not connected! Reason: ");
        return false;
        break;
      case WL_CONNECTION_LOST:
        ESP_LOGI(TAG,"[WiFi] Connection was lost");
        break;
      case WL_SCAN_COMPLETED:
        ESP_LOGI(TAG,"[WiFi] Scan is completed");
        break;
      case WL_DISCONNECTED:
        ESP_LOGI(TAG,"[WiFi] WiFi is disconnected");
        break;
      case WL_CONNECTED:
        ESP_LOGI(TAG,"[WiFi] WiFi is connected, IP address %s",WiFi.localIP().toString().c_str());
        return true;
        break;
      default:
        ESP_LOGI(TAG,"[WiFi] WiFi Status: %d",WiFi.status());
        break;
    }
    delay(tryDelay);

    if (numberOfTries <= 0) {
      ESP_LOGI(TAG,"[WiFi] Failed to connect to WiFi!");
      // Use disconnect function to force stop trying to connect
      WiFi.disconnect();
      return false;
    }
    else numberOfTries--;
  }
  return false;
}

// =======================================================================
// setup
// =======================================================================
void setup()
{ Serial.begin(115200);
  delay(10);

  // Wifi
  if (connectToWifi()) {  //set up our esp32 to listen on the local_hostname.local domain
    if (!MDNS.begin(local_hostname)) {
      ESP_LOGE(TAG,"Error starting mDNS");
      return;
    }
    MDNS.addService("http", "tcp", 80);

    if(!LittleFS.begin()) {
      ESP_LOGI(TAG,"ERROR : LittleFS Mount Failed.");
      return;
    }

    //setup server config stuff here
    server.config.max_uri_handlers = 20;     //maximum number of uri handlers (.on() calls) 
    server.listen(80);

    DefaultHeaders::Instance().addHeader("Server", "PsychicHttp");

    //server.maxRequestBodySize=2*1024*1024;   // 2Mb, change default value if needed
    //server.maxUploadSize=64*1024*1024;       // 64Mb, change default value if needed 

    //you can set up a custom 404 handler.
    // curl -i http://psychic.local/404
    server.onNotFound([](PsychicRequest *request) {
      return request->reply(404, "text/html", "Custom 404 Handler");
    });

    // OTA
    PsychicUploadHandler *updateHandler = new PsychicUploadHandler(); // create handler for OTA update
    updateHandler->onUpload([](PsychicRequest *request, const String& filename, uint64_t index, uint8_t *data, size_t len, bool last) { // onUpload
      /* callback to upload code (firmware) or data (littlefs)
       * callback is triggered for each file chunk, from first chunk (index is 0) to last chunk (last is true)
       * callback is triggered by handler in handleRequest(), after _multipartUploadHandler() * 
       * filename : name of file to upload, with naming convention below 
       * "*code.bin" for code (firmware) update, eg "v1_code.bin"
       * "*littlefs.bin" for data (little fs) update, eg "v1_littlefs.bin"     * 
       */

    int command;   //command : firmware and filesystem update type, ie code (U_FLASH 0) or data (U_SPIFFS 100)       
    ESP_LOGI(TAG,"updateHandler->onUpload _error %d Update.hasError() %d last %d", Update.getError(), Update.hasError(), last);

    // Update.abort() replaces 1st error (eg "UPDATE_ERROR_ERASE") with abort error ("UPDATE_ERROR_ABORT") so root cause is lost
    if (!Update.hasError()) { // no error encountered so far during update, process current chunk
      if (!index){ // index is 0, begin update (first chunk)
        ESP_LOGI(TAG,"update begin, filename %s", filename.c_str());
        Update.clearError();         // first chunk, clear Update error if any
        // check if update file is code, data or sd card one
        if (!filename.endsWith("code.bin") && !filename.endsWith("littlefs.bin")) { //  incorrect file name         
            ESP_LOGE(TAG,"ERROR : filename %s format is incorrect", filename.c_str());
            if (!Update.hasError()) Update.abort();
            return(ESP_FAIL);
        } // end incorrect file name
        else { // file name is correct
              // check update type : code or data
              if (filename.endsWith("code.bin")) command=U_FLASH;       // update code
              else command=U_SPIFFS;                                    // update data
              if (!Update.begin(UPDATE_SIZE_UNKNOWN, command)) {        // start update with max available size           
                // error, begin is KO        
                if (!Update.hasError()) Update.abort();                 // abort
                ESP_LOGE(TAG,"ERROR : update.begin error Update.errorString() %s",Update.errorString());                   
                return(ESP_FAIL);
              }
        } // end file name is correct          
      } // end begin update

      if ((len) && (!Update.hasError())) { // ongoing update if no error encountered
        if (Update.write(data, len) != len) {  
          // error, write is KO
          if (!Update.hasError()) Update.abort();
          ESP_LOGE(TAG,"ERROR : update.write len %d Update.errorString() %s",len, Update.errorString()) ;           
          return(ESP_FAIL);
        }   
      } // end ongoing update

      if ((last) && (!Update.hasError())) { // last update if no error encountered
        if (Update.end(true)) { // update end is OKTEST
          ESP_LOGI(TAG, "Update Success: %u written", index+len);          
        }
        else { // update end is KO                  
          if (!Update.hasError()) Update.abort(); // abort             
          ESP_LOGE(TAG,"ERROR : update end error Update.errorString() %s", Update.errorString());            
          return(ESP_FAIL);
        }
      } // last update if no error encountered
      return(ESP_OK);
    } // end no error encountered so far during update, process current chunk
    else { // error encountered so far during update
      return(ESP_FAIL);
    }
    });  // end onUpload

    updateHandler->onRequest([](PsychicRequest *request) {  // triggered when update is completed (either OK or KO) and returns request's response (important)
      String result; // request result
      // code below is executed when update is finished
      if (!Update.hasError()) { // update is OK
        ESP_LOGI(TAG,"Update code or data OK Update.errorString() %s", Update.errorString());
        result = "<b style='color:green'>Update done for file.</b>";
        return request->reply(200,"text/html",result.c_str());
        // ESP.restart();                                              // restart ESP if needed
      } // end update is OK
      else { // update is KO, send request with pretty print error
        result = " Update.errorString() " + String(Update.errorString()); 
        ESP_LOGE(TAG,"ERROR : error %s",result.c_str());    
        return request->reply(500, "text/html", result.c_str());
      } // end update is KO
    });

    server.on("/update", HTTP_GET, [](PsychicRequest*request){
      PsychicFileResponse response(request, LittleFS, "/update.html");
      return response.send();      
    });

    server.on("/update", HTTP_POST, updateHandler);

    server.on("/restart", HTTP_POST, [](PsychicRequest *request) {
      String output = "Restarting ...";
      ESP_LOGI(TAG,"%s",output.c_str());      
      esprestart=true;
      return request->reply(output.c_str());      
    });    
 } // end onRequest

} // end setup

// =======================================================================
// loop
// =======================================================================
void loop() {
  delay(2000);
  if (esprestart) ESP.restart(); // restart ESP
} // end loop

update.html

<html>
    <head>
        <title>PSYCHICHTTP</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <style>
            input[type=file]::file-selector-button {
            margin-right: 20px;
            border: none;
            background: #3498db; /* blue */
            padding: 10px 20px;
            border-radius: 30px;
            color: #fff;
            cursor: pointer;
            transition: background .2s ease-in-out;
            }

            input[type=file]::file-selector-button:hover {
            background: green ;       
            }

            .drop-container {
            position: relative;
            display: flex;
            gap: 10px;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 150px;
            padding: 20px;
            border-radius: 10px;
            border: 2px dashed #555;
            color: #444;
            cursor: pointer;
            transition: background .2s ease-in-out, border .2s ease-in-out;
            }

            .drop-container:hover {
            background: #eee;
            border-color: #111;
            }

            .drop-container:hover .drop-title {
            color: #222;
            }

            .drop-title {
            color: #444;
            font-size: 20px;
            font-weight: bold;
            text-align: center;
            transition: color .2s ease-in-out;
            }

            .drop-container.drag-active {
            background: #eee;
            border-color: #111;
            }

            .drop-container.drag-active .drop-title {
            color: #222;
            }

            .restart-button {
            margin-right: 20px;
            border: none;
            background: #3498db; /* blue */
            padding: 10px 20px;
            border-radius: 30px;
            color: #fff;
            cursor: pointer;
            transition: background .2s ease-in-out;
            }

            .restart-button:hover {
            background: green ;       
            }

        </style>

    </head>

    <body>  

        <div class="row">
            <h1>PsychicHttp OTA Update</h1>
        </div>

        <div><p style="text-align: left">This page allows to test OTA update with PsychicHttp, and file naming convention below :
            <ul>
                <li><b>"*code.bin"</b> for code (firmware) update, eg "v1_code.bin"</li>
                <li><b>"*littlefs.bin"</b> for data (littlefs) update, eg "v1_littlefs.bin" </li>
            </ul>
        </div>  

        <div>
            <form id="upload_form" enctype="multipart/form-data" method="post">
                <label for="images" class="drop-container" id="dropcontainer">
                    <input type="file" class="inputfile" name="updatefile" id="updatefile" value="updatefile" accept=".bin" onchange="uploadFile()" required>                   
                    <span class="drop-title">Or drop file here</span>
                    <progress id="progressBar" value="0" max="100" style="width:300px;"></progress>
                    <font color='black' id="status"></font>
                    <p id="loaded_n_total"></p>                 
                </label>            
            </form>
        </div>

        <div>
            <p style="text-align: left">Update must be done for each of the files provided (code, littlefs). Once updates are made, the ESP32 can be restarted.     
                <button class="restart-button" onclick="esprestartButton()">Restart</button>                        
            </p>
        </div>      

        </body>
        <script>

            function uploadFile() {
            var urltocall = "/update";  
            var xhr = new XMLHttpRequest();
            xhr.upload.addEventListener("progress", progressHandler, false);
            xhr.addEventListener("error", errorHandler, false);         
            var fileupdate = document.getElementById('updatefile'); // get file structure in DOM
            var file = fileupdate.files[0]; // get file element
            //alert(file.name+" | "+file.size+" | "+file.type);
            xhr.onreadystatechange = function() {
                if (this.readyState == 4 && this.status == 200) {
                    document.getElementById("status").innerHTML = xhr.responseText; // success, show response on page 
                }
                else {
                    document.getElementById("status").innerHTML = xhr.responseText; // error, show response on page
                }
            };
            var formdata = new FormData();
            formdata.append("file", file);
            xhr.open("POST", urltocall); // trigger upload request with file parameter
            xhr.send(formdata);
        }

        function progressHandler(event) {   
            // document.getElementById("loaded_n_total").innerHTML = "Chargé " + event.loaded + " octets"; // do not display bytes loaded
            var percent = (event.loaded / event.total) * 100;
            document.getElementById("progressBar").value = Math.round(percent);     
            document.getElementById("status").innerHTML = Math.round(percent) + "% uploaded...";
            if (percent >= 100) {
                document.getElementById("status").innerHTML = "Writing file ...";
            }
        }

        function errorHandler(event) {
            document.getElementById("status").innerHTML = "<b style='color:red'>Error event catched by errorHandler !</b>";         
        }

        function esprestartButton() {
            /* restart ESP */
            var urltocall = "/restart";
            xhr=new XMLHttpRequest();
            xhr.onreadystatechange = function() {
                if (this.readyState == 4) document.getElementById("status").innerHTML = xhr.responseText;
            };
            xhr.open("POST", urltocall, false); // trigger restart request with file parameter
            xhr.send(); 
        }

    </script>
</html>
hitecSmartHome commented 3 months ago

I always got some weird crash on like 70-80% on upload. Doesn't matter if i upload the firmware or the littlefs.bin

Decoding stack results
0x4008381e: panic_abort at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_system\panic.c line 408
0x401c6b45: esp_system_abort at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_system\esp_system.c line 137
0x4008fbf6: abort at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\newlib\abort.c line 46
0x401c6c27: task_wdt_isr at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_system\task_wdt.c line 176
0x4008a157: vPortExitCritical at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\freertos\port\xtensa\include/freertos/portmacro.h line 571
0x40081a13: esp_intr_noniram_enable at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\freertos\port\xtensa\include/freertos/portmacro.h line 605
0x40084e7b: spi_flash_enable_interrupts_caches_and_other_cpu at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\spi_flash\cache_utils.c line 208
0x40085c89: cache_enable at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\spi_flash\spi_flash_os_func_app.c line 68
0x40085cc7: spi1_end at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\spi_flash\spi_flash_os_func_app.c line 131
0x400887a9: spiflash_end_default at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\spi_flash\esp_flash_api.c line 154
0x400853de: flash_end_flush_cache at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\spi_flash\esp_flash_api.c line 192
0x40085812: esp_flash_erase_region at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\spi_flash\esp_flash_api.c line 658
0x401e73cf: esp_partition_erase_range at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\spi_flash\partition.c line 540
0x401b83c1: EspClass::partitionEraseRange(esp_partition_t const*, unsigned int, unsigned int) at C:/Users/Pc/.platformio/packages/framework-arduinoespressif32/cores/esp32/Esp.cpp line 436
0x4019e5f7: UpdateClass::_writeBuffer() at C:/Users/Pc/.platformio/packages/framework-arduinoespressif32/libraries/Update/src/Updater.cpp line 237
0x4019e731: UpdateClass::write(unsigned char*, unsigned int) at C:/Users/Pc/.platformio/packages/framework-arduinoespressif32/libraries/Update/src/Updater.cpp line 329
0x4017d470: std::_Function_handler   >::_M_invoke(const std::_Any_data &, PsychicRequest *&&, const String &, unsigned long long &&, unsigned char *&&, unsigned int &&, bool &&) at src/Server/httpUpdater.cpp line 40
0x401a3ae1: std::function ::operator()(PsychicRequest*, String const&, unsigned long long, unsigned char*, unsigned int, bool) const at c:\users\pc\.platformio\packages\toolchain-xtensa-esp32@8.4.0+2021r2-patch5\xtensa-esp32-elf\include\c++\8.4.0\bits/std_function.h line 260
0x401a3bd6: PsychicUploadHandler::_handleUploadByte(unsigned char, bool) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 212
0x401a3c95: PsychicUploadHandler::_parseMultipartPostByte(unsigned char, bool) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 243
0x401a45da: PsychicUploadHandler::_multipartUploadHandler(PsychicRequest*) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 189
0x401a465b: PsychicUploadHandler::handleRequest(PsychicRequest*) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 58
0x401a4e7e: PsychicEndpoint::requestCallback(httpd_req*) at lib/PsychicHttp/src/PsychicEndpoint.cpp line 72
0x401c3906: httpd_uri at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_uri.c line 329
0x401c28ec: httpd_req_new at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_parse.c line 659
0x401c3006: httpd_sess_process at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_sess.c line 419
0x401c2088: httpd_process_session at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_main.c line 178
0x402601b2: httpd_sess_enum at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_sess.c line 53
0x401c2170: httpd_thread at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_main.c line 228
hitecSmartHome commented 3 months ago

On regular firmware

Decoding stack results
0x4008381e: panic_abort at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_system\panic.c line 408
0x401c6b45: esp_system_abort at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_system\esp_system.c line 137
0x4008fbf6: abort at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\newlib\abort.c line 46
0x401c6c27: task_wdt_isr at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_system\task_wdt.c line 176
0x401a3b9e: PsychicUploadHandler::_handleUploadByte(unsigned char, bool) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 207
0x401a3c95: PsychicUploadHandler::_parseMultipartPostByte(unsigned char, bool) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 243
0x401a45da: PsychicUploadHandler::_multipartUploadHandler(PsychicRequest*) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 189
0x401a465b: PsychicUploadHandler::handleRequest(PsychicRequest*) at lib/PsychicHttp/src/PsychicUploadHandler.cpp line 58
0x401a4e7e: PsychicEndpoint::requestCallback(httpd_req*) at lib/PsychicHttp/src/PsychicEndpoint.cpp line 72
0x401c3906: httpd_uri at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_uri.c line 329
0x401c28ec: httpd_req_new at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_parse.c line 659
0x401c3006: httpd_sess_process at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_sess.c line 419
0x401c2088: httpd_process_session at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_main.c line 178
0x402601b2: httpd_sess_enum at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_sess.c line 53
0x401c2170: httpd_thread at C:\Users\Pc\.platformio\packages\framework-espidf@3.40407.0\components\esp_http_server\src\httpd_main.c line 228
06GitHub commented 3 months ago

Are you using Arduino IDE or ESP-IDF ? If ESP-IDF, is version ESP-IDF v4.4.7 ?

This OTA example has been developed on top of Arduino IDE 1.8.19 and arduino-esp32 v2.0.15. Arduino-esp32 release v2.0.15 is based on ESP-IDF v4.4.7 https://github.com/espressif/arduino-esp32/releases/tag/2.0.15

PsychichHttp version is v1.1.0. ESP is ESP-S3.

So maybe crash is due to some differences between this version and version you are using ?

Note that example described in this issue has been submitted as a PR https://github.com/hoeken/PsychicHttp/pull/94

hitecSmartHome commented 3 months ago

I'm using ESP-Wrover-E with PSram. Arduino is 2.0.17 IDF version is 4.4.7

I'm using Arduino as a component of IDF in PlatformIO

06GitHub commented 3 months ago

I have done a new test today with (almost) same configuration as yours :

The only difference is that I am using Arduino IDE 1.8.19, which is built on top of IDF 4.4.7, and you are using ESP-IDF 4.4.7. So both IDEs use same version IDF 4.4.7.

Test is ok : both code and firmware can be updated using OTA, see for instance below output for code update.

Which partition are you using ? Is partition size large enough for OTA, and contains otadata, app0 and app1 ? Maybe there is a glitch in partition you are using, which could prevent ota process to complete ?

I am using default partition called "Default 4Mb with SPIFFS" on Arduino IDE : Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x9000, 0x5000, otadata, data, ota, 0xe000, 0x2000, app0, app, ota_0, 0x10000, 0x140000, app1, app, ota_1, 0x150000,0x140000, spiffs, data, spiffs, 0x290000,0x160000, coredump, data, coredump,0x3F0000,0x10000,

output for code update

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
[   451][I][esp32-hal-psram.c:96] psramInit(): PSRAM enabled
[   586][I][psychichttp_ota_issue90.ino:57] connectToWifi(): [OTA] [WiFi] WiFi is disconnected
[  1094][I][psychichttp_ota_issue90.ino:60] connectToWifi(): [OTA] [WiFi] WiFi is connected, IP address 192.168.1.31
[ 13175][I][PsychicHttpServer.cpp:236] openCallback(): [psychic] New client connected 51
[ 13186][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 936264
[ 13200][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 930973
[ 13212][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13223][I][psychichttp_ota_issue90.ino:133] operator()(): [OTA] update begin, filename code.bin
[ 13371][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 925229
[ 13385][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13414][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 919485
[ 13428][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 913741
[ 13439][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13474][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 907997
[ 13487][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13517][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 902253
[ 13530][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 896509
[ 13553][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13583][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 895073
[ 13596][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 889329
[ 13608][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13639][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 883585
[ 13652][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13682][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 877841
[ 13696][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 872097
[ 13708][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 13739][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 866353
[snip]
[ 20500][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 20531][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 21985
[ 20544][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 20574][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 16241
[ 20587][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 10497
[ 20598][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 20809][I][PsychicUploadHandler.cpp:164] _multipartUploadHandler(): [psychic] Remaining size : 4753
[ 20820][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 0
[ 20851][I][psychichttp_ota_issue90.ino:128] operator()(): [OTA] updateHandler->onUpload _error 0 Update.hasError() 0 last 1
[ 21131][I][psychichttp_ota_issue90.ino:165] operator()(): [OTA] Update Success: 936032 written
[ 21140][I][psychichttp_ota_issue90.ino:184] operator()(): [OTA] Update code or data OK Update.errorString() No Error
[ 21154][I][PsychicHttpServer.cpp:236] openCallback(): [psychic] New client connected 52
[ 21163][I][PsychicHttpServer.cpp:262] closeCallback(): [psychic] Client disconnected 52
hitecSmartHome commented 3 months ago

I have a custom partition table with several partitions, including app0 and app1. The firmware goes on a regular route to either app0 or app1 which freeRTOS decides. The file system goes to a "system" partition. I'm sure it is enough, the firmware download works with OTA and with http requests too. I wanted to implement this as a third option but I get crashes on 90% of the time.

Interestingly, the firmware succeeds sometimes and everything goes well 4 out of 10 times. The file system can not make it a single time. Usually it halts at 80-90% upload. The freeRTOS watchdog complains that the idle task has not enough time to switch tasks.

hoeken commented 1 month ago

seems fixed?