Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web server hangs up #1425

Open
NicklasMatzulla opened this issue Jul 23, 2024 · 1 comment
Open

Web server hangs up #1425

NicklasMatzulla opened this issue Jul 23, 2024 · 1 comment

Comments

@NicklasMatzulla
Copy link

Hello everyone,
I have written a Rest API for an OTA update. Basically, this works great, but as soon as I execute the request#send method during the upload process (several times), the web server hangs and no new requests are accepted and existing ones. If I remove all request#send calls, nothing hangs anymore. How can I make the web server report the upload status to the client but not hang up? Unfortunately, I have not found an explanation for this in the sample code.

#include "RestApi.h"
#include <Update.h>
#include <ArduinoJson.h>

#define U_PART U_SPIFFS

const size_t MAX_FIRMWARE_SIZE = 1048576; // 1 MB (ota partition size)
const size_t MAX_SPIFFS_SIZE = 786432; // 0.78 mb (spiffs partition size)
AsyncWebServerRequest* updateRequest = nullptr;

bool endsWith(const String& str, const String& suffix) {
  if (str.length() >= suffix.length()) {
    return str.substring(str.length() - suffix.length()) == suffix;
  } else {
    return false;
  }
}

void handleFirmwareUpload(AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final, bool updateUi) {
  if (updateRequest == nullptr || updateRequest == request) {
    size_t firmwareSize = request->contentLength();
    size_t allowedFirmwareSize = updateUi ? MAX_SPIFFS_SIZE : MAX_FIRMWARE_SIZE;
    if (!endsWith(filename, ".bin") || firmwareSize > allowedFirmwareSize) {
      request->send(400, "application/json", "{\"message\":\"Invalid file or file size too large.\"}");
      return;
    }
    if (!index) {
      updateRequest = request;
      Serial.println("Processing firmware update...");
      size_t content_len = request->contentLength();
      int cmd = updateUi ? U_PART : U_FLASH;
      if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) {
        String errorMsg = "Update begin error: " + String(Update.errorString());
        Serial.println(errorMsg);
        request->send(500, "application/json", "{\"message\":\"" + errorMsg + "\"}");
        updateRequest = nullptr;
        Update.end();
        return;
      }
    }
    if (Update.write(data, len) != len) {
      String errorMsg = "Update write error: " + String(Update.errorString());
      Serial.println(errorMsg);
      request->send(500, "application/json", "{\"message\":\"" + errorMsg + "\"}");
      updateRequest = nullptr;
      Update.end();
      return;
    }
    if (final) {
      if (Update.end(true)) {
        Serial.println("Firmware update complete.");
        request->send(200, "application/json", "{\"message\":\"Firmware update complete.\"}");
      } else {
        String errorMsg = "Update end error: " + String(Update.errorString());
        Serial.println(errorMsg);
        request->send(500, "application/json", "{\"message\":\"" + errorMsg + "\"}");
      }
      updateRequest = nullptr;
    }
  } else {
    request->send(400, "application/json", "{\"message\":\"Another update is in progress.\"}");
  }
}

void setupRestApi(AsyncWebServer &server) {
  server.on("/api/v1/firmware/update", HTTP_POST, [](AsyncWebServerRequest *request) {},
  [](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
    handleFirmwareUpload(request, filename, index, data, len, final, false);
  });
  server.on("/api/v1/ui/update", HTTP_POST, [](AsyncWebServerRequest *request) {},
  [](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) {
    handleFirmwareUpload(request, filename, index, data, len, final, true);
  });
}
@butaikis
Copy link

Look at the Update class, there is an opportunity to put a callback on &onProgress(THandlerFunction_Progress fn); with it, you can track the file upload process and save data to the global area. Then use the web server to return the data to the user.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants