Hi everyone,
I am trying to send images captured on the ESP32CAM over HTTP to my backend web server.
I am using the tinyGSM library.
Initially, I tried sending the image over by chunking the writes into chunks below 1500 (which is the max RX buffer for the SIM7600) however after sending a total of ~10,000 bytes it would fail and get an unhandled write. This was consistent and would always fail around ~10,000 bytes. I.e removing the authorisation write would make it fail at ~9,990 bytes into the image, but if I added it back it in it would fail 9940 bytes into the image. This suggests to me that the SIM7600 has an internal buffer ( altho I'm not 100% sure on this)
This was the code
HTTPResponse PostImage(const char *host, const char *resource, int port, const char *uuid, uint8_t *payload, size_t length)
{
if (!client.connected())
ConnectToAPI(host, port);
Serial.println(String("Img Length: ") + length);
String head = "----boundary\r\nContent-Disposition: form-data; name=\"image\"; filename=\"PotWatcherImage.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n----boundary--\r\n";
// Make a HTTP GET request:
Serial.println("Performing HTTP POST request...");
client.print(String("POST ") + resource + " HTTP/1.1\r\n");
client.print(String("Host: ") + host + "\r\n");
// client.print(String("Authorization: ") + uuid + "\r\n");
// client.println("Connection: Keep-Alive");
client.println("Content-Length: " + String(length + head.length() + tail.length()));
client.println("Content-Type: multipart/form-data;boundary=--boundary");
client.println();
client.print(head);
//"K;␚i@"
uint8_t *fbBuf = payload;
for (size_t n = 0; n < length; n = n + PACKET_SIZE)
{
if (n > 9900 && n < 10000)
{
Serial.println(n);
Serial.println();
Serial.println("====");
}
client.flush();
if (n + PACKET_SIZE < length)
{
client.write(fbBuf, PACKET_SIZE);
fbBuf += PACKET_SIZE;
}
else if (length % PACKET_SIZE > 0)
{
size_t remainder = length % PACKET_SIZE;
client.write(fbBuf, remainder);
}
}
client.flush();
client.print(tail);
HTTPResponse res;
for (int l = 0; client.connected(); l++)
{
// Reading headers line by line.
String line = client.readStringUntil('\n');
// Parse status and statusText from line 1.
if (l == 0)
{
// Serial.println(line);
res.status = line.substring(line.indexOf(" ")).substring(0, line.indexOf(" ")).toInt();
res.statusText = line.substring(line.indexOf(String(res.status)) + 4);
res.statusText.trim();
continue;
}
// If headers end, move on.
if (line == "\r")
break;
}
while (client.available())
{
res.body += client.readStringUntil('\n');
}
return res;
}
After this didn't work I looked into sending raw AT commands and using AT+HTTPSSEND
however that limits the length to 2048 byes.
I have now gone down the route of attempting to upload a file to the SIM7600 internal storage, then sending the image through "AT+CHTTPSSEND=1,"e:\image.jpg"" however the HTTTPSEND seems to return ERROR when this happens.
the latest code I am trying
// transfer file to EFS
Serial.println("Transferring file to EFS");
SerialAT.println(String("AT+CFTRANRX=\"e:\\image.jpg\",") + length);
delay(10);
// wait until > is present
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('>'));
Serial.println("Uploading file data");
// upload over serial
uint8_t *fbBuf = payload;
for (size_t n = 0; n < length; n = n + PACKET_SIZE)
{
if (n + PACKET_SIZE < length)
{
SerialAT.write(fbBuf, PACKET_SIZE);
fbBuf += PACKET_SIZE;
}
else if (length % PACKET_SIZE > 0)
{
size_t remainder = length % PACKET_SIZE;
SerialAT.write(fbBuf, remainder);
}
}
delay(10);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
// start https
Serial.println("starting HTTPS");
SerialAT.println("AT+CHTTPSSTART");
delay(500);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
// open https
Serial.println("Open HTTPS");
String openHttps = String("AT+CHTTPSOPSE=") + "\"" + host + "\"," + port + ",1";
SerialAT.println(openHttps);
delay(1000);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
// perform POST
Serial.println("Performing HTTP POST request...");
SerialAT.println("AT+CHTTPSSEND=1,\"e:\\image.jpg\"");
delay(1500);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
// check response
delay(1000);
SerialAT.println("AT+CHTTPSRECV=249");
delay(10);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
// close https
Serial.println("Close HTTPS session");
SerialAT.println("AT+CHTTPSCLSE");
delay(10);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
// end https
Serial.println("Stop HTTPS stack");
SerialAT.println("AT+CHTTPSSTOP");
delay(10);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
// delete file from EFS
Serial.println("Deleting file...");
SerialAT.println("AT+FSCD=e:/"); // select current dir
SerialAT.println("AT+FSDEL=image.jpg");
delay(10);
// wait until > is present
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('>\r\n'));
The issue here is that it gives an ERROR after trying to send the image, so I am not sure if its a server issue or microcontroller issue.
If I modify the above to just send a simple POST to send some dummy data (the payload is literally just "hello", so its not an actual file)
// perform POST
Serial.println("Performing HTTP POST request...");
String head = "----boundary\r\nContent-Disposition: form-data; name=\"image\"; filename=\"PotWatcherImage.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
String tail = "\r\n----boundary--\r\n";
String header = String("POST ") + resource + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Content-Length: " + String(length + head.length() + tail.length()) + "\r\n" + "Content-Type: multipart/form-data;boundary=--boundary\r\n\r\n";
SerialAT.println(String("AT+CHTTPSSEND=") + String(length + head.length() + tail.length() + header.length()));
delay(1500);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('>'));
SerialAT.print(header);
SerialAT.println(head);
uint8_t *fbBuf2 = payload;
for (size_t n = 0; n < length; n = n + PACKET_SIZE)
{
SerialAT.flush();
if (n + PACKET_SIZE < length)
{
SerialAT.write(fbBuf2, PACKET_SIZE);
fbBuf2 += PACKET_SIZE;
}
else if (length % PACKET_SIZE > 0)
{
size_t remainder = length % PACKET_SIZE;
SerialAT.write(fbBuf2, remainder);
}
}
SerialAT.flush();
SerialAT.print(tail);
delay(10);
while (SerialAT.available())
Serial.println(SerialAT.readStringUntil('\n'));
This works and I get a the payload on the server.