Reputation: 11
I am trying to replace a Unity app with a React Native app, that communicates with a remote with an ESP32 board inside it. The app needs to send a binary file to a Web Server created by the ESP32 and successfully update its firmware. The binary file is 1.73MB.
This is the current Unity app code that works properly:
Here is the Unity plugin used to create the HttpClient: https://assetstore.unity.com/packages/tools/network/http-client-79343
void UploadRemote()
{
byte[] remote = File.ReadAllBytes(remoteFirmwarePath);
remoteUploadSize = remote.Length;
if (firmwareUploadClient != null)
{
firmwareUploadClient.Abort();
firmwareUploadClient = null;
}
firmwareUploadClient = new HttpClient();
ByteArrayContent remoteContent = new ByteArrayContent(remote, "multipart/form-data");
MultipartFormDataContent multipartFormDataContent = new MultipartFormDataContent();
multipartFormDataContent.Add(remoteContent, remoteFileName, remoteFileName);
firmwareUploadClient.Cache = null;
firmwareUploadClient.Cookies = null;
firmwareUploadClient.Post(new Uri("http://192.168.1.3/update"), multipartFormDataContent, HttpCompletionOption.AllResponseContent, CallBackRemote);
}
And here is the code that is running on the ESP32:
It uses the standard WebServer and Update libraries from the arduino-esp32 repo, provided by espressif:
The Webserver code is pretty much directly lifted from the example with a few minor changes to send UDP signals:
https://github.com/espressif/arduino-esp32/blob/master/libraries/WebServer/examples/WebUpdate/WebUpdate.ino
server.on("/update", HTTP_POST, []()
{
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
if (SelfOTA)
{
sendUDP("OTA_Done,");
delay(1000);
ESP.restart();
}
},
[]()
{
//udp.stop();
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
showUpdating = true;
Keep_Screen_On = true;
webServerStartFlag = true;
////serial.println("web updated started now");
////serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
//Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
////serial.println(String(upload.totalSize));
////serial.println(xPortGetCoreID());
sendUDP("R" + String(upload.totalSize));
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
//Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
////serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
webServerStartFlag = false;
BluetoothFlag = false;
} else {
//Update.printError(Serial);
webServerStartFlag = false;
}
}
});
After much research this is the code that I am running on the React Native app. For testing purposes, I have put the Binary file into the assets folder in the Android bundle and am copying it over to the Documents directory before sending it over POST:
const expoAssetsUri = FileSystem.bundleDirectory;
const expoDocumentUri = FileSystem.documentDirectory;
const initialUpdateFilePath =
expoAssetsUri + "updates/Firmware_Beta.ino.pico32.bin";
const finalUpdateFilePath =
expoDocumentUri + "Firmware_Beta.ino.pico32.bin";
try {
await FileSystem.copyAsync({
from: initialUpdateFilePath,
to: finalUpdateFilePath,
});
setIsSendingData(true);
const formData = new FormData();
formData.append("Firmware_Beta.ino.pico32.bin", {
uri: finalUpdateFilePath,
name: "Firmware_Beta.ino.pico32.bin",
type: "application/octet-stream",
} as any);
const response = await axios.post(ESP32_UPDATE_URL, {
headers: {
"Content-Type": "multipart/form-data",
},
body: formData,
});
The issue is that I get the 200,OK response from the server but the firmware doesn't update, as the callback function handling the file upload on the ESP32 side is never called. (I do not get the corresponding upload.status UDP signals, only the one after hitting the endpoint ["OTA_Done,"], before the ESP32 restarts)
I'm not really sure how I can correctly send over the file. Do I need to manually chunk it? Convert the binary into a buffer array? From what I've read the FormData object and the POST method with Content-Type: multipart/form-data should do this automatically.
Does anyone have any experience with this? Any help would be appreciated.
Upvotes: 1
Views: 60