Error sending URL with large image via POST HTTPClient

I'm taking pictures with ESP32-CAM and sending them through a temporary free trial API. When I set the camera to QQVGA it works. Photos are being sent.

Any resolution above this, for example QVGA, gives an error and does not send.

Searching on google I came to this post:

In the middle of the page the colleague Mikkel made a change in the cpp file, I changed my cpp file here according to Mikkel's example. But it was no use. I'm using HTTPClient.h version 1.2.

The snippet of my code that deals with this is this below.

Everything works perfectly if the camera resolution is QQVGA.

I'm trying to put a delay to give the URL time to be created due to the large size of the image (base64) in formats larger than QQVGA.

It looks like there is a debug tool to see what exactly the error is, but I've never used it.

Any help is always welcome.

My question is if anyone has a code snippet using the HTTPClient that sends large files and if they could post it here for me to use as an example.

If you don't want to help, please don't disturb those who would like to help.

char *input = (char *)fb->buf;
    char output[base64_enc_len(3)];
    String imageFile = "";
    for (int i=0;i<fb->len;i++) {
      base64_encode(output, (input++), 3);
      if (i%3==0) imageFile += urlencode(String(output));
    }
        
    delay(1000);  
    
    int httpCode;
    HTTPClient http;           
    http.begin(url);           
    httpCode = http.POST(url);  
  
    if (httpCode == 200) {
       Serial.println("OK");
       } else {Serial.println("ERROR");}
    http.end();

Your code doesn't do the same. The code in the link posts some large data, your code just sends the URL again.

What error? If the error came from the remote site that is the most important information.

What is the remote site? Does it implement all of today's standards? Then a hunked upload may be a solution. How large is your upload payload actually?
URL-encoding makes it bigger, so the overhead of a multipart upload may be justified, given the remote site supports that.

I'll contact API support and get back here with info.

I copied and pasted the entire URL (with the picture in base64) in the google chrome bar and also in another site that sends URLs in the POST method. Both gave the error URI too long.

This maybe means it's some limitation in the API.

Thanks

I need you,

Everything works fine in the code below. Base64 encoding is done with any ESP-32CAM camera resolution.

I know this because I copy and paste the code generated in Serial.println(imageFile) into a decoder site and see the picture.

The problem is that if the photo is QQVGA or HQVGA resolution, OK. It is sent to a test API and it works.

But just put the camera in QVGA onwards and it won't work, it gives a sending error, a 400 error in the HTTPclient or it shows too long URI.

Even if I copy and paste the URL in chrome it gives an error of too long URI.

How to resolve this? send up to at least VGA ?

Thanks

#include <WiFi.h>
#include <HTTPClient.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "Base64.h"
#include "esp_camera.h"

int naoconectouwifi;
String url,imageFile;

const char* ssid     = "xxxxxxx";
const char* password = "xxxxxxx";

#define LED 4

#define CAMERA_MODEL_AI_THINKER
#if defined(CAMERA_MODEL_AI_THINKER)
  #define PWDN_GPIO_NUM     32
  #define RESET_GPIO_NUM    -1
  #define XCLK_GPIO_NUM      0
  #define SIOD_GPIO_NUM     26
  #define SIOC_GPIO_NUM     27

  #define Y9_GPIO_NUM       35
  #define Y8_GPIO_NUM       34
  #define Y7_GPIO_NUM       39
  #define Y6_GPIO_NUM       36
  #define Y5_GPIO_NUM       21
  #define Y4_GPIO_NUM       19
  #define Y3_GPIO_NUM       18
  #define Y2_GPIO_NUM        5
  #define VSYNC_GPIO_NUM    25
  #define HREF_GPIO_NUM     23
  #define PCLK_GPIO_NUM     22
 #else
  #error "Camera model not selected"
 #endif

void setup()
{
  pinMode(LED, OUTPUT);
  
  WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
  
  Serial.begin(115200);
  delay(10);
  
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);              //ingressa com as credenciais na rede wifi (linhas 214 e 215)
  WiFi.setSleep(false);                    //desabilita o modo sleep do wifi, por precaução. Problema é que

  Serial.println("Connecting ao WiFi");
  while (WiFi.status() != WL_CONNECTED) {  //aguarda a conexão wifi ser estabelecida
      delay(1000);
      naoconectouwifi++;
      Serial.println(naoconectouwifi);
       if(naoconectouwifi > 5) {
           ESP.restart();                              
       }
  }

  Serial.println(WiFi.localIP());
  Serial.println(WiFi.RSSI());     
  
  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_HQVGA;  // UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
  config.jpeg_quality = 10;
  config.fb_count = 1;

//  if(psramFound()){
//    config.frame_size = FRAMESIZE_SVGA;
//    config.jpeg_quality = 10;  //0-63 lower number means higher quality
//    config.fb_count = 2;
//  } else {
//    config.frame_size = FRAMESIZE_CIF;
//    config.jpeg_quality = 12;  //0-63 lower number means higher quality
//    config.fb_count = 1;
//  }
  
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    delay(1000);
    ESP.restart();
  }

  takefoto(); 

}//end void setup

// **************************************************************************************************

void loop() {
}

// *************************************************************************************************

void takefoto() {
    
    camera_fb_t * fb = NULL;
      digitalWrite(LED, HIGH);
    fb = esp_camera_fb_get();
      digitalWrite(LED, LOW);
    
    if(!fb) {
      Serial.println("Camera capture failed");
      delay(1000);
      ESP.restart();
      return;
    }
  
    char *input = (char *)fb->buf;
    char output[base64_enc_len(3)];
    imageFile = "";
    for (int i=0;i<fb->len;i++) {
      base64_encode(output, (input++), 3);
      if (i%3==0) imageFile += urlencode(String(output));
    }
        
    esp_camera_fb_return(fb);

//    Serial.println(imageFile);

    sendfoto();

}//end void takefoto

// ************************************************************************************************

void sendfoto() {    
  
    url = "http://api.textmyhost.com/send.php?recipient=+55XXXXXXXXXX&apikey=J6AsF7htBH2V&text=This%20is%20a%20test" + "&file=" + imageFile;

    int httpCode;
    HTTPClient http;           
    http.begin(url);           
    httpCode = http.POST(url);   

    if(httpCode == 200) {  
      String response = http.getString(); //get the response to the request
      Serial.println(response);           //request answer
      Serial.println(httpCode);           //return code
      imageFile = "";
    } else {
      String response = http.getString();
      Serial.println(response);
      Serial.println(httpCode);
      imageFile = "";
      }
  
    http.end();
  
}//fim void sendfoto

// **************************************************************************************************

//https://github.com/zenmanenergy/ESP8266-Arduino-Examples/
String urlencode(String str)
{
    String encodedString="";
    char c;
    char code0;
    char code1;
    char code2;
    for (int i =0; i < str.length(); i++){
      c=str.charAt(i);
      if (c == ' '){
        encodedString+= '+';
      } else if (isalnum(c)){
        encodedString+=c;
      } else{
        code1=(c & 0xf)+'0';
        if ((c & 0xf) >9){
            code1=(c & 0xf) - 10 + 'A';
        }
        c=(c>>4)&0xf;
        code0=c+'0';
        if (c > 9){
            code0=c - 10 + 'A';
        }
        code2='\0';
        encodedString+='%';
        encodedString+=code0;
        encodedString+=code1;
        //encodedString+=code2;
      }
      yield();
    }
    return encodedString;
}

I was wondering if it would work to divide the String imageFile already converted into base64 into two parts

Does anyone know how to do this ?

Since you are using http POST, why do you try to put the entire image in the url? A typical POST has the contents in the body of the post

I researched a lot, and also this link. But the image I am uploading is the photo that the esp32 cam takes. This photo is converted to base64, then added to the URL.

I mean, this is the problem. When I increase the quality of the photo, the URL is so long that it gives the error URI too long and does not send.

I cannot send the photo to a website, web server, telegram, etc. It has to be like this, take the picture, encrypt base64 and send it along with the URL.

But you don't say why that is so. Perhaps you can post a link to the documentation that specifies it?

Try this:

void sendfoto() {    
    url = "http://api.textmyhost.com/send.php";

    // Data to send with HTTP POST
    String httpRequestData = "recipient=+55XXXXXXXXXX&apikey=J6AsF7htBH2V&text=This%20is%20a%20test&file=" + imageFile;

    HTTPClient http;           
    http.begin(url);           

    http.addHeader("Content-Type", "application/x-www-form-urlencoded");

      // Send HTTP POST request
      int httpCode = http.POST(httpRequestData);
      
    if(httpCode == 200) {  
      String response = http.getString(); //get the response to the request
      Serial.println(response);           //request answer
      Serial.println(httpCode);           //return code
      imageFile = "";
    } else {
      String response = http.getString();
      Serial.println(response);
      Serial.println(httpCode);
      imageFile = "";
      }
  
    http.end();
  
}//fim void sendfoto

Oops, how are you? I was rooting for you to show up, lol.

I apologize if I didn't reveal the site/api, but this is it.

I'm just testing.

This link goes straight to the documentation that uploads images.

With this information you might want to modify something in the code of your previous topic (#6)

But I copied and pasted the entire URL both in the chrome bar browser and in a site that sends the URL through the POST method and both gave the error URI too long.

Doesn't this prove to be an API limitation ?

See my post #7

The URL that API support sent me via chat and that sends images is this one below

It really works. And it is through her that I have been sending photos from the esp32-cam.

However, only in very low quality.

Any photo equal to or larger than QVGA does not send. Gives URI too long error

https://api.ultramsg.com/instance27986/messages/image?token=xxxxxxxxxxxxx&to=552197700304&image=%2F9j%2F4AAQSkZJRgABAQEASABIAAD%2F4gIoSUNDX1BST0ZJTEUAAQEAAAIYAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAAABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAAAChnVFJDAAABoAAAAChiVFJDAAABoAAAACh3dHB0AAAByAAAABRjcHJ0AAAB3AAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFgAAAAcAHMAUgBHAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA%2BEAAC2z3BhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLW1sdWMAAAAAAAAAAQAAAAxlblVTAAAAIAAAABwARwBvAG8AZwBsAGUAIABJAG4AYwAuACAAMgAwADEANv%2FbAEMACgcHCAcGCggICAsKCgsOGBAODQ0OHRUWERgjHyUkIh8iISYrNy8mKTQpISIwQTE0OTs%2BPj4lLkRJQzxINz0%2BO%2F%2FbAEMBCgsLDg0OHBAQHDsoIig7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O%2F%2FAABEIAAEAAQMBIgACEQEDEQH%2FxAAVAAEBAAAAAAAAAAAAAAAAAAAABv%2FEABQQAQAAAAAAAAAAAAAAAAAAAAD%2FxAAVAQEBAAAAAAAAAAAAAAAAAAAGB%2F%2FEABQRAQAAAAAAAAAAAAAAAAAAAAD%2F2gAMAwEAAhEDEQA%2FAJUAdWZ%2F%2F9k%3D

See if my thinking is correct:

If the API support in sent the format of a URL for images, and it really works for small images. If I just change the base64 code of the photo for a slightly larger photo and it gives an error when I try to send it through this site:

This means that it is the API that is not able to receive large URLs and not the arduino IDE code.

That is, while you are giving this error using the website described above. It will be a waste of time to make any attempt to correct the code in the arduino IDE.

Is that right ?

Are you trying to encode and send whole image as URL?
HTTP POST method used data section rather than URL, please see the examples to the HttpClient library

As per the information I provided above. I received from API support a URL (it's in the posts above) containing the necessary fields including the image code in base64 format. It works. But when I change the base64 code to one of a larger picture, it gives the error 414 URI too long

So do not put the image to the URL...

const char * url ="https://api.ultramsg.com/instance27986/messages/image";
http.begin(client, url);

// If you need Node-RED/server authentication, insert user and password below
//http.setAuthorization("REPLACE_WITH_SERVER_USERNAME", "REPLACE_WITH_SERVER_PASSWORD");
      
      // Specify content-type header
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
      // Data to send with HTTP POST
String httpRequestData = "api_key=tPmAT5Ab3j7F9&sensor=BME280&value1=24.25&value2=49.54&value3=1005.14";           
      // Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);

I already saw it, I tried to adapt it, I'll try it again now because if that solves the problem I must have done something wrong. I will be back in a moment.

I just don't understand why I did it as the chat support told me and it works with small images.

I will try this in my code. I will be back in a moment.

I have no idea if this will work with your server, but the fact that the length of the url has limitations and you can’t put a whole big image into it is obvious.

I did it like this:

url = "https://api.ultramsg.com/instance27187/messages/image";

 int httpCode;                                                        
 HTTPClient http;                                                     
//    http.begin(client, url); 
 http.begin(url);                                                     
 http.addHeader("Content-Type", "application/x-www-form-urlencoded");
 String httpRequestData = "?token=dmvrgguolmn4hfdg5&to=552197720304&image=https://file-example.s3-accelerate.amazonaws.com/images/test.jpg";
 httpCode = http.POST(url);                                              

   
    String response = http.getString();
    Serial.print("response é: ");Serial.println(response);

It returns with this error:

response é: {"error":"Wrong token. Please provide token as a GET parameter."}