Pendahuluan
Pada tutorial kali ini, kita akan membahas cara menghubungkan ESP32 CAM dengan Telegram Bot untuk mengirimkan gambar secara otomatis. Proyek ini memanfaatkan ESP32 CAM, sebuah mikrokontroller dengan modul kamera dan kemampuan Wi-Fi, serta Telegram Bot API untuk mengirimkan gambar. Proyek ini menggunakan metode penyimpanan gambar di SPIFFS (Serial Peripheral Interface Flash File System) dan pengiriman gambar menggunakan metode HTTP requests.
Komponen Yang Digunakan
Berikut adalah daftar komponen yang digunakan dalam proyek ini beserta link pembelian di Golite Store:
- ESP32 CAM – Beli Disini
- USB To TTL FTDI – Beli Disini
- Kabel Jumper (Female to Female) – Beli Disini
- Kabel USB untuk FTDI – Beli Disini
Skema Sistem
Penjelasan Skema Sistem
Pada skema sistem ini, ESP32 CAM terhubung dengan USB To TTL FTDI untuk keperluan upload program dan sebagai power supply menggunakan kabel USB. ESP32 CAM akan mengambil gambar menggunakan kamera dan menyimpannya di SPIFFS. Gambar tersebut kemudian dikirimkan ke Telegram Bot melalui koneksi internet Wi-Fi.
Persiapan BOT Telegram
Hal pertama setelah proses perakitan yang harus kita lakukan yaitu lanjut ke proses pembuatan bot telegram dan mendapatkan chat id dari akun telegram kita
Buka aplikasi telegram dan buat bot dengan cara cari “botfather” kemudian pilih BotFather yang sudah centang biru seperti gambar di bawah ini
Setelah itu kirim pesan /start
Kemudian ikuti langkah langkah di bawah ini , untuk nama bot dan user name bot dapat di sesuaikan. Selanjutkan simpan Token (HTTP API) untuk selanjutkan kita masukan kedalam program di ESP32 Cam nya
Setelah itu kita perlu mendapatkan Chat Id Telegram kita dengan cari akun bot “idbot”
kemudian kirim pesan ke bot tersebut dengan perintah “/getid”, dan kita harus simpan id tersebut untuk kita masukan pada program utama kita
Program Arduino/ESP32
Program lengkap dapat di download pada Github Idrus Project , Klik disini
Hal yang harus di perhatikan sebelum upload program di bawah ini :
- Pastikan board ESP32 sudah terinstall pada Arduino IDE
- Pilih jenis board AI THINKER ESP32-CAM
- Pastikan Semua library sudah terinstal dengan baik sesuai dengan versi yang sudah tertulis pada program
- Untuk mempermudah proses upload bisa menggunakan module Downloader untuk ESP32 Cam
- Jika menggunakan USB To TTL / FTDI pastiakan board sudah masuk ke download mode dengan cara jumper IO0 ke GND dan klik tombol reset
#include <Arduino.h> #include <WiFi.h> #include <WiFiClientSecure.h> #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" #include "esp_camera.h" #include <UniversalTelegramBot.h> //1.3.0 #include <ArduinoJson.h> //6.15.2 #include "FS.h" #include "SPIFFS.h" #include <HTTPClient.h> //ESP32 CAM AI Thinker Camera Pinout #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 #define FLASH_LED_PIN 4 const char* ssid = "xxxxxxx"; const char* password = "xxxxxx"; String BOT_TOKEN = "xxxxxxx"; String CHAT_ID = "xxxxxxx"; WiFiClientSecure clientTCP; UniversalTelegramBot bot(BOT_TOKEN, clientTCP); unsigned long botRequestsMillis; bool sendPhoto, flashState = 0; void setup() { WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); Serial.begin(115200); cameraConfig(); wifiConfig(); if (!SPIFFS.begin(true)) { Serial.println("SPIFFS Mount Failed"); return; } pinMode(FLASH_LED_PIN, OUTPUT); digitalWrite(FLASH_LED_PIN, flashState); } void loop() { if (sendPhoto) { Serial.println("\nPreparing photo"); String response = sendPhotoTelegramSpiff(); response.trim(); if (response == "NOK") { sendPhoto = 1; } else { sendPhoto = 0; } } if (millis() > botRequestsMillis + 1000UL) { int numNewMessages = bot.getUpdates(bot.last_message_received + 1); while (numNewMessages) { Serial.println("\nGot Response"); handleNewMessages(numNewMessages); numNewMessages = bot.getUpdates(bot.last_message_received + 1); } botRequestsMillis = millis(); } }
void cameraConfig(){ 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.grab_mode = CAMERA_GRAB_LATEST; if(psramFound()){ config.frame_size = FRAMESIZE_UXGA; config.jpeg_quality = 16; //0-63 lower number means higher quality config.fb_count = 2; } else { config.frame_size = FRAMESIZE_SVGA; 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(); } } void wifiConfig(){ WiFi.mode(WIFI_STA); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); clientTCP.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org while (WiFi.status() != WL_CONNECTED) { Serial.print("."); delay(500); } Serial.println(); Serial.print("ESP32-CAM IP Address: "); Serial.println(WiFi.localIP()); } // Remove All Files in SPIFF void deleteAllFilesInSPIFFS() { File root = SPIFFS.open("/"); File file = root.openNextFile(); while (file) { Serial.print("Deleting file: "); Serial.println(file.name()); SPIFFS.remove(file.name()); file.close(); file = root.openNextFile(); } Serial.println("All files deleted in SPIFFS"); }
void handleNewMessages(int numNewMessages) { Serial.print("Handle New Messages: "); Serial.println(numNewMessages); for (int i = 0; i < numNewMessages; i++) { String chat_id = String(bot.messages[i].chat_id); if (chat_id != chat_id) { bot.sendMessage(chat_id, "Unauthorized user", ""); continue; } // Print the received message String text = bot.messages[i].text; Serial.println(text); String from_name = bot.messages[i].from_name; if (text == "/start") { String welcome = "Welcome , " + from_name + "\n"; welcome += "Berikut adalah perintah yang dapat digunakan : \n"; welcome += "/photo : Mengambil foto baru\n"; welcome += "/flash : Menyalakan dan mematikan lampu flash \n"; bot.sendMessage(CHAT_ID, welcome, ""); } else if (text == "/photo") { Serial.println("New photo request"); sendPhoto = 1; } else if (text == "/flash") { Serial.println("Change flash LED state"); flashState = !flashState; digitalWrite(FLASH_LED_PIN, flashState); }else if (text == "/remove"){ deleteAllFilesInSPIFFS(); } } }
void captureAndSavePhoto() { // Remove Previous Picture camera_fb_t *fb = esp_camera_fb_get(); esp_camera_fb_return(fb); // Get New Picture digitalWrite(FLASH_LED_PIN, 1); fb = esp_camera_fb_get(); delay(150); digitalWrite(FLASH_LED_PIN, 0); if (!fb) { Serial.println("Camera capture failed"); return; } // Save Picture To SPIFF File file = SPIFFS.open("/idrusproject.jpg", FILE_WRITE); if (!file) { Serial.println("Failed to open file for writing"); esp_camera_fb_return(fb); return; } file.write(fb->buf, fb->len); file.close(); esp_camera_fb_return(fb); Serial.println("Photo saved to SPIFFS"); } String sendPhotoTelegramSpiff() { String serverPath = "https://api.telegram.org/bot" + String(BOT_TOKEN) + "/sendPhoto"; captureAndSavePhoto(); if (WiFi.status() == WL_CONNECTED) { WiFiClientSecure client; HTTPClient http; client.setInsecure(); // SSL Not Verified Yet // Start Server Connection http.begin(client, serverPath); // Open Picture From SPIFFS File file = SPIFFS.open("/idrusproject.jpg", "r"); if (!file) { Serial.println("Failed to open file for reading"); return "Failed to open file for reading"; } // Cek ukuran file size_t fileSize = file.size(); if (fileSize == 0) { Serial.println("File is empty"); file.close(); return "NOK"; } // Siapkan body permintaan String boundary = "IdrusProject"; String bodyHead = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"chat_id\"\r\n\r\n" + String(CHAT_ID) + "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"photo\"; filename=\"photo.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n"; String bodyTail = "\r\n--" + boundary + "--\r\n"; int bodyLength = bodyHead.length() + bodyTail.length() + file.size(); uint8_t *body = (uint8_t *)malloc(bodyLength); if (body == NULL) { Serial.println("Failed to allocate memory for body"); file.close(); http.end(); return "Failed to allocate memory for body"; } // Copy head to body memcpy(body, bodyHead.c_str(), bodyHead.length()); // Copy file content to body file.readBytes((char *)body + bodyHead.length(), file.size()); // Copy tail to body memcpy(body + bodyHead.length() + file.size(), bodyTail.c_str(), bodyTail.length()); http.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary); int httpResponseCode = http.POST(body, bodyLength); Serial.print("HTTP Response code: "); if (httpResponseCode > 0) { String payload = http.getString(); Serial.println(httpResponseCode); Serial.println("Response payload: " + payload); free(body); http.end(); file.close(); return payload; }else { Serial.println(httpResponseCode); return "NOK"; } } else { Serial.println("WiFi Disconnected"); return "WiFi Disconnected"; } }
Penjelasan Program
- Memasukan Library Program menggunakan library
WiFi
,WiFiClientSecure
,UniversalTelegramBot
,ArduinoJson
, FS,SPIFFS
dan HTTPClient untuk mengakses dan mengendalikan berbagai fungsi ESP32 CAM dan Telegram Bot. - Variabel Global
ssid
,password
: Mengatur koneksi Wi-Fi.BOT_TOKEN
,CHAT_ID
: Token dan ID chat untuk Telegram Bot.
- Setup Function
- Inisialisasi Serial Monitor dan SPIFFS.
- Mengatur konfigurasi LED flash dan kamera.
- Menghubungkan ke Wi-Fi dan menginisialisasi koneksi Telegram.
- Loop Function
- Mengatur waktu tunggu dan pembacaan pesan baru dari Telegram.
- Menangani dan mengirim gambar ke Telegram jika diperlukan.
Pengujian
Selama pengujian, ESP32 CAM berhasil terhubung ke jaringan Wi-Fi dan Telegram Bot, serta berhasil mengirimkan gambar yang diambil ke chat Telegram yang dituju. Tampilan gambar dan status pengujian dapat dilihat pada gambar di atas.
Kesimpulan
Proyek ini berhasil menghubungkan ESP32 CAM dengan Telegram Bot untuk mengirimkan gambar. Dengan konfigurasi ini, Anda dapat memodifikasi dan memperluas proyek ini untuk aplikasi yang lebih kompleks, seperti sistem pemantauan dengan notifikasi berbasis gambar. Penggunaan SPIFFS memungkinkan penyimpanan gambar sementara sebelum dikirim, sehingga mengurangi beban pada memori utama.