espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.38k stars 7.22k forks source link

esp_http_client_write() - I haven’t been able to figure out how it works for a week now!!! (IDFGH-12857) #13822

Closed kotyara12 closed 3 months ago

kotyara12 commented 4 months ago

Answers checklist.

IDF version.

ramework-espidf @ 3.50102.240122 (5.1.2)

Espressif SoC revision.

ESP32-CAM AI Thinker

Operating System used.

Windows

How did you build your project?

VS Code IDE

If you are using Windows, please specify command line type.

None

Development Kit.

ESP32-CAM AI Thinker

Power Supply used.

USB

What is the expected behavior?

I've been trying to send a picture from my camera to Telegram for a week now. There are crooked examples everywhere for Arduino that do not work in ESP-IDF. Those examples that I finally dug up are NOT WORKING. The directory system didn't help me at all. I can't figure out why this doesn't work.

Here's my code:

extern const char api_telegram_org_pem_start[] asm(CONFIG_TELEGRAM_TLS_PEM_START);
extern const char api_telegram_org_pem_end[]   asm(CONFIG_TELEGRAM_TLS_PEM_END);  

#define API_TELEGRAM_BOUNDARY           "----7e83e29bb8f61021----"
#define API_TELEGRAM_CONTENT_TYPE       "multipart/form-data; boundary=" API_TELEGRAM_BOUNDARY "\r\n"
#define API_TELEGRAM_PHOTO_CHAT_ID      "--" API_TELEGRAM_BOUNDARY "\r\nContent-Disposition: form-data; name=\"chat_id\"\r\n\r\n%s\r\n"
#define API_TELEGRAM_PHOTO_CAPTION      "--" API_TELEGRAM_BOUNDARY "\r\nContent-Disposition: form-data; name=\"caption\"\r\n\r\n%s\r\n"
#define API_TELEGRAM_PHOTO_IMAGE        "--" API_TELEGRAM_BOUNDARY "\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"esp32-cam.jpg\"\r\n Content-Type: image/jpeg\r\n\r\n"
#define API_TELEGRAM_PHOTO_TAIL         "\r\n--" API_TELEGRAM_BOUNDARY "--\r\n\r\n"

void tgSendImage(camera_fb_t * fb, const char* chat_id, const char* caption) 
{
  rlog_i(logTAG, "Send photo to Telegram...");
  esp_log_level_set("HTTP_CLIENT", ESP_LOG_DEBUG);

  // Настраиваем параметры соединения
  esp_http_client_config_t config;
  memset(&config, 0, sizeof(config));
  config.host = "api.telegram.org";
  config.port = 443;
  config.path = "/bot" CONFIG_TELEGRAM_TOKEN "/sendPhoto";
  config.method = HTTP_METHOD_POST;
  config.transport_type = HTTP_TRANSPORT_OVER_SSL;
  config.cert_pem = api_telegram_org_pem_start;
  config.keep_alive_enable = true;
  config.is_async = false;

  char* chat_id_buf = nullptr;
  char* caption_buf = nullptr;
  if (chat_id) chat_id_buf = malloc_stringf(API_TELEGRAM_PHOTO_CHAT_ID, chat_id);
  if (caption) caption_buf = malloc_stringf(API_TELEGRAM_PHOTO_CAPTION, caption);

  size_t len_write = 0;
  size_t len_image = strlen(API_TELEGRAM_PHOTO_IMAGE) + fb->len + strlen(API_TELEGRAM_PHOTO_TAIL);
  if (chat_id_buf) len_image += strlen(chat_id_buf);
  if (caption_buf) len_image += strlen(caption_buf);

  esp_http_client_handle_t http_client = esp_http_client_init(&config);
  if (http_client) {
    esp_http_client_set_header(http_client, "Content-Type", API_TELEGRAM_CONTENT_TYPE);

    esp_err_t err = esp_http_client_open(http_client, len_image);
    if (err == ESP_OK) {
      if (chat_id_buf) {
        len_write += esp_http_client_write(http_client, chat_id_buf, strlen(chat_id_buf));
        rlog_i(logTAG, "Send chat id: %d", len_write);
        free(chat_id_buf);
      };

      if (caption_buf) {
        len_write += esp_http_client_write(http_client, caption_buf, strlen(caption_buf));
        rlog_i(logTAG, "Send caption: %d", len_write);
        free(caption_buf);
      };

      len_write += esp_http_client_write(http_client, API_TELEGRAM_PHOTO_IMAGE, strlen(API_TELEGRAM_PHOTO_IMAGE));
      rlog_i(logTAG, "Send image head: %d", len_write);
      len_write += esp_http_client_write(http_client, (const char*)fb->buf, fb->len);
      rlog_i(logTAG, "Send image data: %d", len_write);
      len_write += esp_http_client_write(http_client, API_TELEGRAM_PHOTO_TAIL, strlen(API_TELEGRAM_PHOTO_TAIL));
      rlog_i(logTAG, "Send image tail: %d", len_write);

      esp_http_client_fetch_headers(http_client);
      int ret_code = esp_http_client_get_status_code(http_client);
      rlog_i(logTAG, "Telegram API code: %d", ret_code);

      esp_http_client_close(http_client);
    } else {
      rlog_e(logTAG, "Failed to open HTTPS connection: %d (%s)", err, esp_err_to_name(err));
    };

    esp_http_client_cleanup(http_client);
    http_client = nullptr;

    esp_log_level_set("HTTP_CLIENT", ESP_LOG_NONE);
  };
}

What is the actual behavior?

20:46:13 [I] CAMERA :: Telegram API code: 400

Steps to reproduce.

  1. Step
  2. Step
  3. Step ...

Debug Logs.

20:46:11 [I] CAMERA :: Create snapshot...
20:46:11 [I] CAMERA :: Send photo to Telegram...
D (62461) HTTP_CLIENT: Begin connect to: https://api.telegram.org:443
D (63331) HTTP_CLIENT: Write header[4]: POST /bot......................................................................................./sendPhoto HTTP/1.1
User-Agent: ESP32 HTTP Client/1.0
Host: api.telegram.org
Content-Type: multipart/form-data; boundary=----7e83e29bb8f61021----
Content-Length: 4935

20:46:12 [I] CAMERA :: Send chat id: 94
20:46:12 [I] CAMERA :: Send image head: 223
20:46:12 [I] CAMERA :: Send image data: 4901
20:46:12 [I] CAMERA :: Send image tail: 4935
D (63851) HTTP_CLIENT: on_message_begin
D (63851) HTTP_CLIENT: HEADER=Server:nginx/1.18.0
D (63851) HTTP_CLIENT: HEADER=Date:Mon, 20 May 2024 17:46:13 GMT
D (63851) HTTP_CLIENT: HEADER=Content-Length:0
D (63851) HTTP_CLIENT: HEADER=Connection:keep-alive
D (63861) HTTP_CLIENT: HEADER=Strict-Transport-Security:max-age=31536000; includeSubDomains; preload
D (63871) HTTP_CLIENT: HEADER=Access-Control-Allow-Origin:*
D (63871) HTTP_CLIENT: HEADER=Access-Control-Expose-Headers:Content-Length,Content-Type,Date,Server,Connection
D (63881) HTTP_CLIENT: http_on_headers_complete, status=400, offset=318, nread=318
D (63891) HTTP_CLIENT: http_on_message_complete, parser=0x3ffcef80
D (63901) HTTP_CLIENT: content_length = 0
20:46:13 [I] CAMERA :: Telegram API code: 400
20:46:16 [I] PING :: Internet access is checked...
20:46:16 [D] PING :: Ping statistics for [yandex.ru : 5.255.255.70]: 5 packets transmitted, 5 received, 0.0% packet loss, average time 21 ms
20:46:16 [D] PING :: Ping statistics for [google.com : 216.58.209.206]: 5 packets transmitted, 5 received, 0.0% packet loss, average time 46 ms
20:46:16 [I] PING :: Internet access is available (66 ms)
20:46:16 [I] MQTT :: Publish to topic "cameras/camera0001/ping": {"internet":{"state":0,"duration":{"min":21,"max":46,"total":66},"loss":{"min":0.0,"max":0.0,"total":0.0},"display":"📶\nt: 66 ms\nl: 0%"},"host1":{"hostname":"yandex.ru","state":0,"packets":{"transmitted":5,"received":5,"ttl":53},"duration":21,"loss":0.0},"host2":{"hostname":"google.com","state":0,"packets":{"transmitted":5,"received":5,"ttl":58},"duration":46,"loss":0.0}}
20:47:00 [I] MQTT :: Publish to topic "cameras/camera0001/time": {"time":"20:47","date":"20.05.24","weekday":"пн","timeday":"20:47 пн","datetime1":"20:47\n20.05.24","datetime2":"20:47 пн\n20.05.24","year":2024,"month":4,"day":20,"hour":20,"min":47,"wday":1,"yday":140,"worktime":{"days":0,"hours":0,"minutes":3}}
20:47:00 [D] SCHD :: Restart schedule timer for 59979884 microseconds (sec=0, usec=20117)
20:47:13 [I] CAMERA :: Create snapshot...
20:47:13 [I] CAMERA :: Send photo to Telegram...
D (124111) HTTP_CLIENT: Begin connect to: https://api.telegram.org:443
D (124981) HTTP_CLIENT: Write header[4]: POST /bot,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,/sendPhoto HTTP/1.1
User-Agent: ESP32 HTTP Client/1.0
Host: api.telegram.org
Content-Type: multipart/form-data; boundary=----7e83e29bb8f61021----
Content-Length: 3264

20:47:14 [I] CAMERA :: Send chat id: 94
20:47:14 [I] CAMERA :: Send image head: 223
20:47:14 [I] CAMERA :: Send image data: 3230
20:47:14 [I] CAMERA :: Send image tail: 3264
D (125391) HTTP_CLIENT: on_message_begin
D (125391) HTTP_CLIENT: HEADER=Server:nginx/1.18.0
D (125391) HTTP_CLIENT: HEADER=Date:Mon, 20 May 2024 17:47:14 GMT
D (125391) HTTP_CLIENT: HEADER=Content-Length:0
D (125401) HTTP_CLIENT: HEADER=Connection:keep-alive
D (125401) HTTP_CLIENT: HEADER=Strict-Transport-Security:max-age=31536000; includeSubDomains; preload
D (125411) HTTP_CLIENT: HEADER=Access-Control-Allow-Origin:*
D (125421) HTTP_CLIENT: HEADER=Access-Control-Expose-Headers:Content-Length,Content-Type,Date,Server,Connection
D (125431) HTTP_CLIENT: http_on_headers_complete, status=400, offset=318, nread=318
D (125431) HTTP_CLIENT: http_on_message_complete, parser=0x3ffd49a8
D (125441) HTTP_CLIENT: content_length = 0
20:47:14 [I] CAMERA :: Telegram API code: 400

More Information.

No response

nopnop2002 commented 4 months ago

I used this when sending JPGE data as a multipart. I'm using vanilla socket API instead of esp_http_client.

Content-Type: application/octet-stream

https://github.com/nopnop2002/esp-idf-multipart-upload/blob/main/main/multipart-upload.c#L129C20-L129C58

hmalpani commented 3 months ago

Hello @kotyara12 Can you please refer to https://esp32.com/viewtopic.php?t=36627. I think it might help solve your problem. Please let me know if you need more assistance.

kotyara12 commented 3 months ago

It wasn't the bobbin, it was the wires.... In general, the code above is absolutely working, almost. The problem I spent a week fixing was one small thing. API_TELEGRAM_BOUNDARY cannot contain "--". And it's all!