How to Send Images from an ESP32-S3 Camera to Telegram

How to Send Images from an ESP32-S3 Camera to Telegram Building an IoT camera that can send photos directly to your phone is a great way to learn how embedded devices, Wi-Fi, cameras, and cloud APIs work together. In this project, we will use an ESP32-S3 camera to capture a JPEG image and send it directly to a Telegram bot. The entire process happens over Wi-Fi, so you don't need a computer, ngrok, or a separate web server. The final result is simple: ESP32-S3 Camera │ │ Wi-Fi ▼ Telegram Bot API │ ▼ Telegram App │ ▼ 📷 Photo Let's build it step by step. What We Are Building The ESP32-S3 will: Connect to a Wi-Fi network. Initialize the camera. Capture a JPEG image. Connect securely to Telegram. Upload the image to a Telegram bot. Send the photo to our Telegram chat. Once everything is working, we can later extend the project to capture images when motion is detected, when a button is pressed, or at regular intervals. Components Required For this project, you need: ESP32-S3 camera board Camera module USB cable Wi-Fi network Telegram account Telegram mobile app Arduino IDE I'm using an ESP32-S3 camera with the ESP32S3_EYE camera configuration. Creating the Telegram Bot The first step is to create a Telegram bot. Open Telegram and search for BotFather. Start a conversation with BotFather and send: /newbot BotFather will ask you for a name. For example: ESP32 Camera Next, it will ask for a username. For example: Imagesp32cam_bot The username must end with bot. After creating the bot, BotFather will provide an HTTP API token. It will look similar to: 123456789:AAxxxxxxxxxxxxxxxxxxxxxxxx Keep this token private. Anyone who has the token can control your bot. Getting the Telegram Chat ID Next, we need to tell Telegram where the ESP32 should send the photo. Open your newly created bot and press Start. Send it a message: hello Now we can use the Telegram Bot API to find the chat ID. Open a browser and enter: https://api.telegram.org/botYOUR_BOT_TOKEN/getUpdates Replace YOUR_BOT_TOKEN with your actual token. The response will contain information similar to: { "ok": true, "result": [ { "message": { "chat": { "id": 123456789 } } } ] } The value of: chat.id is your Telegram Chat ID. For example: 123456789 Keep this number for the ESP32 program. Setting Up the ESP32-S3 Open Arduino IDE and make sure the ESP32 board package is installed. Select your ESP32-S3 board from: Tools → Board For the camera configuration, select: #define CAMERA_MODEL_ESP32S3_EYE and include the corresponding camera pin definitions: #include "camera_pins.h" Using the correct camera model is extremely important. If the camera pin configuration doesn't match your hardware, the camera may fail to initialize or the ESP32 may continuously reboot. Required Libraries One advantage of this project is that we don't need a special Telegram library. The program uses: #include "esp_camera.h" #include #include These are provided by the ESP32 Arduino environment. esp_camera.h handles the camera, WiFi.h handles the network connection, and WiFiClientSecure.h allows us to communicate with Telegram over HTTPS. Configuring Wi-Fi and Telegram Add your Wi-Fi credentials: const char* WIFI_SSID = "YourWiFi"; const char* WIFI_PASSWORD = "YourPassword"; Then add your Telegram bot token: const char* BOT_TOKEN = "YOUR_BOT_TOKEN"; And your Chat ID: const char* CHAT_ID = "123456789"; For security, don't publish your real bot token in source code repositories or blog posts. Initializing the Camera The ESP32 camera library uses a camera_config_t structure to configure the camera. For example: config.pixel_format = PIXFORMAT_JPEG; config.frame_size = FRAMESIZE_QVGA; config.jpeg_quality = 12; We're starting with QVGA: 320 × 240 This is a good starting point because it produces relatively small JPEG files and reduces memory usage. If your ESP32-S3 has PSRAM, you can later increase the resolution. Capturing an Image Once the camera is initialized, capturing an image is very simple: camera_fb_t* fb = esp_camera_fb_get(); The returned frame buffer contains the JPEG image. The image data is available through: fb->buf and the image size is: fb->len For example: Serial.printf("Image size: %u bytes\n", fb->len); After we're finished with the image, we must return the buffer: esp_camera_fb_return(fb); This is important because the camera needs the buffer for future captures. Sending the Image to Telegram Telegram provides a Bot API method called sendPhoto. The ESP32 sends an HTTPS POST request to: https://api.telegram.org/bot/sendPhoto The request contains two important fields: chat_id photo The image is uploaded as multipart/form-data. The ESP32 therefore doesn't need to upload the image to another server first. The process is: Camera ↓ JPEG buffer ↓ HTTPS POST ↓ Telegram Bot API ↓ Telegram chat Complete ESP32-S3 Code Here is the complete example: #include "esp_camera.h" #include #include #define CAMERA_MODEL_ESP32S3_EYE #include "camera_pins.h" // Wi-Fi const char* WIFI_SSID = "YOUR_WIFI"; const char* WIFI_PASSWORD = "YOUR_PASSWORD"; // Telegram const char* BOT_TOKEN = "YOUR_BOT_TOKEN"; const char* CHAT_ID = "YOUR_CHAT_ID"; bool sendPhotoToTelegram(camera_fb_t* fb) { if (fb == NULL) { Serial.println("Image buffer is NULL"); return false; } WiFiClientSecure client; // For initial testing client.setInsecure(); Serial.println("Connecting to Telegram..."); if (!client.connect("api.telegram.org", 443)) { Serial.println("Telegram connection failed"); return false; } String boundary = "----ESP32CameraBoundary"; String head = "--" + boundary + "\r\n" "Content-Disposition: form-data; " "name=\"chat_id\"\r\n\r\n" + String(CHAT_ID) + "\r\n" "--" + boundary + "\r\n" "Content-Disposition: form-data; " "name=\"photo\"; filename=\"esp32.jpg\"\r\n" "Content-Type: image/jpeg\r\n\r\n"; String tail = "\r\n--" + boundary + "--\r\n"; size_t contentLength = head.length() + fb->len + tail.length(); String request = "POST /bot" + String(BOT_TOKEN) + "/sendPhoto HTTP/1.1\r\n" "Host: api.telegram.org\r\n" "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n" "Content-Length: " + String(contentLength) + "\r\n" "Connection: close\r\n\r\n"; client.print(request); client.print(head); client.write(fb->buf, fb->len); client.print(tail); Serial.println("Image uploaded."); unsigned long timeout = millis(); while (client.connected() && millis() - timeout < 10000) { while (client.available()) { String line = client.readStringUntil('\n'); Serial.println(line); timeout = millis(); } } client.stop(); return true; } bool initCamera() { 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_sccb_sda = SIOD_GPIO_NUM; config.pin_sccb_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_QVGA; config.jpeg_quality = 12; if (psramFound()) { Serial.println("PSRAM found"); config.fb_location = CAMERA_FB_IN_PSRAM; config.fb_count = 2; config.grab_mode = CAMERA_GRAB_LATEST; } else { Serial.println("PSRAM not found"); config.fb_location = CAMERA_FB_IN_DRAM; config.fb_count = 1; config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; } esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf( "Camera initialization failed: 0x%x\n", err ); return false; } sensor_t* sensor = esp_camera_sensor_get(); if (sensor == NULL) { return false; } sensor->set_framesize( sensor, FRAMESIZE_QVGA ); sensor->set_vflip( sensor, 1 ); return true; } void setup() { Serial.begin(115200); delay(2000); Serial.println(); Serial.println("=============================="); Serial.println("ESP32-S3 TELEGRAM CAMERA"); Serial.println("=============================="); WiFi.mode(WIFI_STA); WiFi.begin( WIFI_SSID, WIFI_PASSWORD ); Serial.print("Connecting to Wi-Fi"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("Wi-Fi connected"); Serial.print("ESP32 IP: "); Serial.println(WiFi.localIP()); if (!initCamera()) { Serial.println( "Camera initialization failed" ); while (true) { delay(1000); } } Serial.println("Camera ready"); camera_fb_t* fb = esp_camera_fb_get(); if (fb == NULL) { Serial.println( "Camera capture failed" ); return; } Serial.printf( "Captured image: %u bytes\n", fb->len ); sendPhotoToTelegram(fb); esp_camera_fb_return(fb); Serial.println("Photo sent!"); } void loop() { } Uploading the Code Before uploading, replace: YOUR_WIFI with your Wi-Fi name. Replace: YOUR_PASSWORD with your Wi-Fi password. Replace: YOUR_BOT_TOKEN with the token from BotFather. Finally, replace: YOUR_CHAT_ID with your Telegram Chat ID. Upload the sketch to your ESP32-S3 and open the Serial Monitor at: 115200 baud Expected Serial Output If everything is working, you should see something similar to: ============================== ESP32-S3 TELEGRAM CAMERA ============================== Connecting to Wi-Fi...... Wi-Fi connected ESP32 IP: 192.168.31.193 PSRAM found Camera ready Captured image: 18342 bytes Connecting to Telegram... Image uploaded. Photo sent! You should then receive the image in your Telegram chat. Sending Images Automatically The current example sends one image when the ESP32 starts. We can easily change this to send an image every 30 seconds: void loop() { camera_fb_t* fb = esp_camera_fb_get(); if (fb != NULL) { Serial.printf( "Captured: %u bytes\n", fb->len ); sendPhotoToTelegram(fb); esp_camera_fb_return(fb); } delay(30000); } Now the ESP32 behaves like a simple remote camera: Capture ↓ Send to Telegram ↓ Wait 30 seconds ↓ Capture again ↓ Send again What's Next? Once the basic system is working, there are many ways to improve it. Motion Detection Connect a PIR sensor: Motion detected ↓ ESP32-S3 ↓ Capture photo ↓ Telegram ↓ 📷 Motion detected Button-Controlled Camera Add a push button: Button pressed ↓ Capture image ↓ Send to Telegram This could be used as a simple Wi-Fi doorbell. Security Camera We can also combine the camera with motion detection and send a Telegram notification whenever someone enters the camera's field of view. Conclusion In this project, we built a simple IoT camera using an ESP32-S3 and Telegram. The ESP32 captures a JPEG image and communicates directly with Telegram's Bot API over Wi-Fi. Because the image is sent directly to Telegram, there is no need for ngrok, port forwarding, or a separate computer running a server. The complete architecture is: ┌──────────────┐ │ ESP32-S3 │ │ Camera │ └──────┬───────┘ │ │ Wi-Fi ▼ ┌──────────────┐ │ Telegram │ │ Bot API │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ Telegram │ │ App │ └──────────────┘ │ ▼ 📷 Image This provides a solid foundation for more advanced ESP32 camera projects such as motion alerts, smart doorbells, remote monitoring, and security cameras.

Post a Comment

My Instagram

Made with by Pi-girl | Copyright © 2020 Pi-girl