Rehberler · 8 dk okuma

ESP32-CAM Telegram: Hareket Algılayınca Fotoğraf Gönderme

ESP32-CAM ile Telegram'a fotoğraf gönder: PIR bağlantısı ve boş pin, /foto komutu, flaş kontrolü, deep sleep ile pil tasarrufu, gece çekimi ve tam kod.

ESP32-CAM ile Telegram botu kurduğunda kart, bir hareket algıladığı anda fotoğraf çeker ve birkaç saniye içinde telefonuna gönderir. Uygulama kurman, sunucu kiralaman ya da modeminde port açman gerekmez: kart fotoğrafı doğrudan Telegram'ın sunucusuna yükler, Telegram da sana anlık bildirim olarak iletir. Aynı bot üzerinden /foto yazarak istediğin an kapının önünü görebilir, flaşı açıp kapatabilir ve alarmı devre dışı bırakabilirsin.

Bu rehberde bir PIR sensörünü ESP32-CAM'in az sayıdaki boş pininden hangisine bağlaman gerektiğini, fotoğrafın Telegram'a nasıl yüklendiğini, komutlarla çalışan tam kodu ve flaşın doğru kullanımını adım adım göreceksin. Ardından kartı deep sleep ile pilde günlerce çalıştırmayı, IR aydınlatmayla gece çekimini ve bu düzenin bir güvenlik kamerası olarak nerede yetersiz kaldığını öğreneceksin. Kartın kurulumunu ve ilk kod yüklemeyi henüz yapmadıysan önce ESP32-CAM kullanımı yazısına göz at.

ESP32-CAM kamera modülü ile Telegram fotoğraf sistemi
ESP32-CAM: OV2640 kamera, flaş LED'i ve Wi-Fi tek kartta. Bir PIR sensörüyle hareket olunca fotoğrafı Telegram'a gönderebilir.

ESP32-CAM Telegram fotoğraf sistemi nasıl çalışır?

Zincir dört adımdan oluşur. PIR sensörü bir insanın vücut ısısındaki değişimi fark eder ve OUT pinini 3,3 V'a çeker. ESP32 bu yükselen kenarı görünce OV2640 kameradan bir JPEG kare ister; kare, karttaki 4 MB'lık PSRAM belleğe yazılır. Ardından ESP32, şifreli bir HTTPS bağlantısıyla Telegram Bot API'sinin sendPhoto adresine multipart/form-data biçiminde bir POST isteği gönderir; bu, tarayıcıda bir dosya yüklerken kullanılan yöntemle aynıdır. Telegram fotoğrafı alıp sohbetine ekler ve telefonun bildirim gösterir. Komutlar ters yönde çalışır: ESP32 her saniye getUpdates ile yeni mesaj olup olmadığını sorar, /foto gelmişse aynı yükleme işlemini senin isteğin için yapar.

ParçaÖzellikNot
ESP32-CAM (AI-Thinker)OV2640, 4 MB PSRAMPSRAM'li sürüm XGA fotoğrafı rahatça taşır
ESP32-CAM-MB ya da USB-TTL dönüştürücüCH340 / CP2102Kod yüklemek için; kartta USB yoktur
PIR sensörüHC-SR501 (5 V) ya da AM312 (3,3 V)OUT çıkışı 3,3 V, ESP32'ye doğrudan bağlanır
Besleme5 V, en az 2 AWi-Fi ve flaş aynı anda yüksek akım çeker
Elektrolitik kondansatör470–1000 µF5V ile GND arasına, karta yakın
İsteğe bağlı18650 pil + 5 V yükseltici, 850 nm IR aydınlatıcıPille çalışma ve gece çekimi için

PIR sensörü bağlantısı ve boş pin seçimi

ESP32-CAM'in kenarında 16 pin vardır ama kamera tek başına 15 GPIO kullanır, microSD yuvası da altı pini paylaşır. Geriye kalan pinlerin çoğu ya açılış (strapping) pinidir ya da seri port için gereklidir. Bu projede SD kart kullanmadığımız için SD hatları serbest kalır ve aralarından en güvenlisi GPIO 13'tür: açılış davranışını etkilemez, dahili pull-down direnci vardır ve bir RTC pini olduğu için kartı derin uykudan uyandırabilir. Aşağıdaki tablo diğer adayları da karşılaştırır.

PinSD kart yokkenDeep sleep'ten uyandırır mı?Not
GPIO 13SerbestEvet (ext0)PIR için en iyi seçim
GPIO 14SerbestEvetAçılışta kısa bir PWM sinyali görülebilir; giriş olarak sorunsuz
GPIO 15SerbestEvetAçılış pini; LOW tutulursa açılış mesajları kapanır
GPIO 2SerbestEvetAçılış pini; yükleme anında HIGH olmamalı
GPIO 12SerbestEvetAçılışta HIGH olursa kart açılmaz; kullanma
GPIO 4Flaş LED'iEvetFlaşa ayrılmış; başka iş için kullanma
GPIO 3 (U0R)Seri RXHayırYalnız seri port gerekmiyorsa
GPIO 16PSRAMHayırAsla kullanma
PIR piniESP32-CAM piniAçıklama
VCC5VHC-SR501 en az 4,5 V ister; AM312 kullanıyorsan 3V3
OUTGPIO 13Hareket varken 3,3 V, yokken 0 V
GNDGNDOrtak toprak
Kartın VCC etiketli pini bir giriş değil, 3,3 V regülatörünün çıkışıdır; PIR'yi ya da kartı beslemek için 5 V'u her zaman 5V pinine ver. PIR'yi asla GPIO 12'ye bağlama: sensör açılış anında HIGH verirse ESP32 flaş belleği yanlış gerilimle çalıştırmaya çalışır ve kart hiç açılmaz.

HC-SR501'in üzerindeki iki trimpottan süre (Tx) ayarını en kısa konuma (saat yönünün tersine sonuna kadar, yaklaşık 3 saniye) getir; bekleme süresini kod yönetecek. Tetikleme jumper'ını H (tekrarlı tetikleme) konumunda bırak, hassasiyeti ise 3–7 metre arasında ihtiyacına göre ayarla. Sensör açıldıktan sonra yaklaşık bir dakika boyunca kendini ortama alıştırır ve bu sürede rastgele tetiklenir; kod bu yüzden ilk 60 saniyeyi yok sayar. Sensörün çalışma mantığının ayrıntıları PIR hareket sensörü yazısında.

Telegram botunu hazırlamak: token ve chat ID

  1. Telegram'da @BotFather hesabını aç, /newbot yaz, botuna bir ad ve sonu bot ile biten bir kullanıcı adı ver.
  2. BotFather'ın verdiği 1234567890:AAE... biçimindeki token'ı kopyala; koddaki BOT_TOKEN satırına bu gelecek.
  3. Kendi kullanıcı numaranı öğrenmek için @userinfobot hesabına /start yaz; dönen Id değeri CHAT_ID olacak.
  4. Kendi botunu açıp bir kez /start yaz; Telegram, botların daha önce konuşmadığı birine mesaj atmasına izin vermez.
  5. Arduino IDE'de Kütüphane Yöneticisi'nden UniversalTelegramBot (Brian Lough) ve ArduinoJson kütüphanelerini kur.
  6. Araçlar > Kart menüsünden AI Thinker ESP32-CAM kartını seç, Partition Scheme'in Huge APP (3MB No OTA/1MB SPIFFS) olduğundan emin ol.
Token, botunun şifresidir: kodu paylaşırken ya da bir yere yüklerken o satırı mutlaka sil. Token'ın sızdığını düşünürsen BotFather'da /revoke komutuyla yenisini al. Bot oluşturma, chat ID ve sertifika ayrıntılarını ESP32 Telegram bot yazısında daha geniş anlattık.

Telegram'a fotoğraf gönderme: sendPhotoByBinary nasıl çalışır?

UniversalTelegramBot kütüphanesindeki sendPhotoByBinary() fonksiyonu, fotoğrafı bir dosya gibi yükler. Fonksiyon önce isteğin başlığını ve chat ID alanını gönderir, sonra veriyi senin verdiğin üç küçük fonksiyondan ister: veriVarMi() gönderilecek parça kalıp kalmadığını, sonrakiTampon() verinin bellekteki adresini, tamponBoyu() da kaç bayt olduğunu söyler. Kameranın kare tamponu zaten tek parça bir JPEG olduğu için kod bütün fotoğrafı tek seferde verir ve bayrağı indirir. 1024×768 çözünürlükte 12 kalitesindeki bir fotoğraf sahneye göre 50–120 KB tutar ve iyi bir Wi-Fi bağlantısında 1–2 saniyede yüklenir. Telegram fotoğraflar için 10 MB'a kadar izin verdiği için boyut sınırına hiç yaklaşmazsın; asıl sınır yükleme süresidir.

Tam kod: /foto komutu, flaş kontrolü ve hareket alarmı

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5#include <time.h>
6#include "esp_camera.h"
7
8const char* WIFI_SSID = "AgAdi";          // Wi-Fi adın (yalnız 2,4 GHz) / your Wi-Fi name (2.4 GHz only)
9const char* WIFI_PASS = "Sifre123";       // Wi-Fi şifren / your Wi-Fi password
10#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"   // BotFather'ın verdiği token / token from BotFather
11#define CHAT_ID   "123456789"             // yalnız bu ID'ye yanıt verilir / only this ID gets answers
12
13// AI-Thinker ESP32-CAM kamera pinleri / AI-Thinker ESP32-CAM camera pins
14#define PWDN_GPIO_NUM     32
15#define RESET_GPIO_NUM    -1
16#define XCLK_GPIO_NUM      0
17#define SIOD_GPIO_NUM     26
18#define SIOC_GPIO_NUM     27
19#define Y9_GPIO_NUM       35
20#define Y8_GPIO_NUM       34
21#define Y7_GPIO_NUM       39
22#define Y6_GPIO_NUM       36
23#define Y5_GPIO_NUM       21
24#define Y4_GPIO_NUM       19
25#define Y3_GPIO_NUM       18
26#define Y2_GPIO_NUM        5
27#define VSYNC_GPIO_NUM    25
28#define HREF_GPIO_NUM     23
29#define PCLK_GPIO_NUM     22
30
31#define FLAS_LED   4                          // beyaz flaş LED'i / white flash LED
32#define PIR_PIN   13                          // PIR OUT (SD kart kullanılmıyor) / PIR OUT (no SD card)
33
34const unsigned long PIR_ISINMA = 60000;       // PIR ilk 60 sn dengelenir / the PIR settles in the first 60 s
35const unsigned long BEKLEME = 30000;          // iki hareket fotoğrafı arası en az 30 sn / at least 30 s between motion photos
36const unsigned long KONTROL_ARALIGI = 1000;   // Telegram'a saniyede bir sor / poll Telegram once per second
37
38WiFiClientSecure client;
39UniversalTelegramBot bot(BOT_TOKEN, client);
40
41camera_fb_t *fb = nullptr;                    // gönderilecek kare / the frame being sent
42bool veriBekliyor = false;                    // kütüphanenin geri çağırma bayrağı / flag for the library callbacks
43bool alarmKurulu = true;                      // hareket alarmı açık mı / is the motion alarm armed
44bool flasAcik = false;                        // fotoğrafta flaş kullanılsın mı / use the flash for photos
45bool pirOnceki = false;
46unsigned long sonFoto = 0;
47unsigned long sonKontrol = 0;
48
49bool kameraBaslat() {
50  camera_config_t config = {};
51  config.ledc_channel = LEDC_CHANNEL_0;
52  config.ledc_timer   = LEDC_TIMER_0;
53  config.pin_d0 = Y2_GPIO_NUM;
54  config.pin_d1 = Y3_GPIO_NUM;
55  config.pin_d2 = Y4_GPIO_NUM;
56  config.pin_d3 = Y5_GPIO_NUM;
57  config.pin_d4 = Y6_GPIO_NUM;
58  config.pin_d5 = Y7_GPIO_NUM;
59  config.pin_d6 = Y8_GPIO_NUM;
60  config.pin_d7 = Y9_GPIO_NUM;
61  config.pin_xclk     = XCLK_GPIO_NUM;
62  config.pin_pclk     = PCLK_GPIO_NUM;
63  config.pin_vsync    = VSYNC_GPIO_NUM;
64  config.pin_href     = HREF_GPIO_NUM;
65  config.pin_sccb_sda = SIOD_GPIO_NUM;
66  config.pin_sccb_scl = SIOC_GPIO_NUM;
67  config.pin_pwdn     = PWDN_GPIO_NUM;
68  config.pin_reset    = RESET_GPIO_NUM;
69  config.xclk_freq_hz = 20000000;             // 20 MHz kamera saati / 20 MHz camera clock
70  config.pixel_format = PIXFORMAT_JPEG;
71
72  if (psramFound()) {
73    config.frame_size   = FRAMESIZE_XGA;      // 1024x768: net ve hızlı gönderilir / sharp and quick to send
74    config.jpeg_quality = 12;                 // küçük = daha kaliteli / lower = better quality
75    config.fb_count     = 2;
76    config.fb_location  = CAMERA_FB_IN_PSRAM;
77    config.grab_mode    = CAMERA_GRAB_LATEST;
78  } else {
79    config.frame_size   = FRAMESIZE_SVGA;     // PSRAM yoksa 800x600 / 800x600 without PSRAM
80    config.jpeg_quality = 12;
81    config.fb_count     = 1;
82    config.fb_location  = CAMERA_FB_IN_DRAM;
83    config.grab_mode    = CAMERA_GRAB_WHEN_EMPTY;
84  }
85  return esp_camera_init(&config) == ESP_OK;
86}
87
88// sendPhotoByBinary için üç geri çağırma: kareyi tek parça verir
89// Three callbacks for sendPhotoByBinary: they hand over the frame in one piece
90bool veriVarMi() {
91  if (veriBekliyor) {
92    veriBekliyor = false;
93    return true;
94  }
95  return false;
96}
97byte *sonrakiTampon() { return fb ? fb->buf : nullptr; }
98int tamponBoyu() { return fb ? fb->len : 0; }
99
100String saat() {                               // "14:05:31" biçiminde saat / time as "14:05:31"
101  struct tm t;
102  if (!getLocalTime(&t, 100)) return "--:--:--";
103  char buf[9];
104  strftime(buf, sizeof(buf), "%H:%M:%S", &t);
105  return String(buf);
106}
107
108bool fotoGonder(const String& chatId, const String& yazi) {
109  if (flasAcik) {
110    digitalWrite(FLAS_LED, HIGH);             // flaşı yak / flash on
111    delay(150);                               // pozlama yeni ışığa uysun / let exposure adapt
112  }
113  fb = esp_camera_fb_get();                   // tampondaki eski kareyi at / discard the stale frame
114  if (fb) esp_camera_fb_return(fb);
115  fb = esp_camera_fb_get();                   // asıl fotoğraf / the real photo
116  digitalWrite(FLAS_LED, LOW);                // flaşı söndür / flash off
117
118  if (!fb) {
119    bot.sendMessage(chatId, "Kamera hatası / camera error");
120    return false;
121  }
122  bot.sendMessage(chatId, yazi);              // önce kısa bildirim / a quick notification first
123  veriBekliyor = true;
124  String cevap = bot.sendPhotoByBinary(chatId, "image/jpeg", fb->len,
125                                       veriVarMi, nullptr, sonrakiTampon, tamponBoyu);
126  Serial.printf("Foto / photo: %u bayt / bytes\n", fb->len);
127  esp_camera_fb_return(fb);                   // kareyi sürücüye geri ver / give the frame back
128  fb = nullptr;
129  return cevap.indexOf("\"ok\":true") >= 0;  // Telegram başarıyı böyle bildirir / how Telegram reports success
130}
131
132void mesajlariIsle(int adet) {
133  for (int i = 0; i < adet; i++) {
134    String chatId = bot.messages[i].chat_id;
135    String metin  = bot.messages[i].text;
136    if (chatId != CHAT_ID) continue;          // yabancılara yanıt yok / never answer strangers
137
138    int at = metin.indexOf('@');              // gruptaki "/foto@bot_adi" -> "/foto" / "/foto@bot_name" -> "/foto"
139    if (at > 0) metin = metin.substring(0, at);
140
141    if (metin == "/start") {
142      String yardim = "/foto - fotoğraf çek / take a photo\n";
143      yardim += "/flas - flaşı aç ya da kapat / toggle the flash\n";
144      yardim += "/alarm - hareket alarmını aç ya da kapat / arm or disarm\n";
145      yardim += "/durum - son durum / status";
146      bot.sendMessage(chatId, yardim);
147    } else if (metin == "/foto") {
148      if (!fotoGonder(chatId, "Fotoğraf / photo " + saat())) {
149        bot.sendMessage(chatId, "Gönderilemedi / send failed");
150      }
151    } else if (metin == "/flas") {
152      flasAcik = !flasAcik;
153      bot.sendMessage(chatId, flasAcik ? "Flaş AÇIK / flash ON" : "Flaş KAPALI / flash OFF");
154    } else if (metin == "/alarm") {
155      alarmKurulu = !alarmKurulu;
156      bot.sendMessage(chatId, alarmKurulu ? "Alarm KURULU / ARMED" : "Alarm KAPALI / DISARMED");
157    } else if (metin == "/durum") {
158      String s = "Alarm: " + String(alarmKurulu ? "KURULU / ARMED" : "KAPALI / DISARMED");
159      s += "\nFlaş / flash: " + String(flasAcik ? "AÇIK / ON" : "KAPALI / OFF");
160      s += "\nWi-Fi: " + String(WiFi.RSSI()) + " dBm";
161      bot.sendMessage(chatId, s);
162    }
163  }
164}
165
166void setup() {
167  Serial.begin(115200);
168  pinMode(FLAS_LED, OUTPUT);
169  digitalWrite(FLAS_LED, LOW);
170  pinMode(PIR_PIN, INPUT_PULLDOWN);           // PIR bağlı değilken pin boşta kalmasın / keep the pin defined without a PIR
171
172  if (!kameraBaslat()) {
173    Serial.println("Kamera baslatilamadi / camera init failed");
174    delay(3000);
175    ESP.restart();
176  }
177
178  WiFi.mode(WIFI_STA);
179  WiFi.begin(WIFI_SSID, WIFI_PASS);
180  while (WiFi.status() != WL_CONNECTED) delay(500);
181  Serial.println(WiFi.localIP());
182
183  configTzTime("<+03>-3", "pool.ntp.org");    // Türkiye saati (UTC+3) / Turkey time (UTC+3)
184  client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // api.telegram.org kök sertifikası / root certificate
185  bot.sendMessage(CHAT_ID, "Kamera hazır, /start yaz / camera ready, send /start");
186}
187
188void loop() {
189  bool pir = digitalRead(PIR_PIN);
190  // Yalnız yükselen kenarda, ısınmadan sonra ve bekleme süresi dolunca
191  // Only on a rising edge, after warm-up and once the cooldown has passed
192  if (pir && !pirOnceki && alarmKurulu && millis() > PIR_ISINMA && millis() - sonFoto > BEKLEME) {
193    sonFoto = millis();
194    fotoGonder(CHAT_ID, "Hareket algılandı! / Motion detected! " + saat());
195  }
196  pirOnceki = pir;
197
198  if (millis() - sonKontrol > KONTROL_ARALIGI) {
199    int adet = bot.getUpdates(bot.last_message_received + 1);
200    while (adet) {
201      mesajlariIsle(adet);
202      adet = bot.getUpdates(bot.last_message_received + 1);
203    }
204    sonKontrol = millis();
205  }
206}
BölümNe yapar?
kameraBaslat()PSRAM varsa XGA (1024×768) ve iki kare tamponu, yoksa SVGA (800×600) ile kamerayı başlatır
fotoGonder()İsteğe göre flaşı yakar, eski kareyi atıp yeni kare çeker, önce kısa bir mesaj sonra fotoğrafı gönderir
mesajlariIsle()Yalnız CHAT_ID'den gelen /start, /foto, /flas, /alarm ve /durum komutlarına yanıt verir
loop() PIR bölümüYükselen kenarı, 60 sn ısınmayı ve 30 sn bekleme süresini kontrol eder
loop() Telegram bölümüSaniyede bir yeni mesajları sorar; birikmiş mesaj varsa hepsini sırayla işler

Kod PIR'nin seviyesine değil yükselen kenarına bakar: sensör 3 saniye boyunca HIGH kalsa bile yalnız bir fotoğraf çekilir. 30 saniyelik bekleme süresi, odada dolaşan biri yüzünden telefonuna dakikada onlarca fotoğraf yağmasını ve Telegram'ın aynı sohbete saniyede birden fazla mesajı yavaşlatmasını önler. Her yoklama ayrı bir HTTPS isteği olduğundan getUpdates çağrısı loop'u yarım saniye kadar bekletebilir; HC-SR501'in çıkışı en az 3 saniye HIGH kaldığı için bu sırada hareket kaçmaz. Hareketle fotoğrafın telefona düşmesi arasında, kart sürekli açıkken genellikle 2–4 saniye geçer.

Flaş kontrolü: ne zaman yakmalı?

Ön yüzdeki beyaz LED, GPIO 4'e bağlı bir transistörle sürülür ve tam parlaklıkta besleme hattından 100 mA'den fazla akım çeker. Kod flaşı yalnızca fotoğraf anında yakar ve yaklaşık 150 ms bekler; kameranın otomatik pozlaması yeni ışığa ancak birkaç karede uyum sağladığı için tampondaki ilk kare de atılır. Flaş 1–2 metreye kadar etkilidir; daha uzaktaki bir kapı ya da bahçe aydınlanmaz. Cam arkasından çekiyorsan flaşı kapat, aksi hâlde fotoğrafta yalnızca camdaki parlak yansımayı görürsün. Flaşı daha sönük kullanmak istersen GPIO 4'e PWM uygulayabilirsin; CameraWebServer örneğindeki LED Intensity kaydırıcısı tam olarak bunu yapar. Unutma ki gece patlayan beyaz bir flaş, kameranın yerini de belli eder; gizli izleme için aşağıdaki IR bölümü daha uygundur.

Deep sleep ile pil tasarrufu

Wi-Fi'si açık bir ESP32-CAM sürekli 150–200 mA çeker; bu, 2600 mAh'lik bir 18650 pili yarım günde bitirir. Pille çalışacaksan kart zamanının neredeyse tamamını derin uykuda geçirmeli ve yalnız PIR tetiklendiğinde uyanmalıdır. Aşağıdaki kodda GPIO 13, ext0 uyandırma kaynağıdır: PIR çıkışı HIGH olunca kart sıfırdan açılır, önce fotoğrafı çeker, sonra Wi-Fi'ye bağlanıp fotoğrafı gönderir ve yeniden uyur. Sıralama önemlidir: Wi-Fi bağlantısı birkaç saniye sürer, fotoğrafı bağlantıdan önce çekmek hareketin tam anını yakalar.

C++ (Arduino IDE)
1#include <WiFi.h>
2#include <WiFiClientSecure.h>
3#include <UniversalTelegramBot.h>
4#include <ArduinoJson.h>
5#include "esp_camera.h"
6#include "driver/rtc_io.h"
7
8const char* WIFI_SSID = "AgAdi";
9const char* WIFI_PASS = "Sifre123";
10#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
11#define CHAT_ID   "123456789"
12
13// AI-Thinker ESP32-CAM kamera pinleri / AI-Thinker ESP32-CAM camera pins
14#define PWDN_GPIO_NUM     32
15#define RESET_GPIO_NUM    -1
16#define XCLK_GPIO_NUM      0
17#define SIOD_GPIO_NUM     26
18#define SIOC_GPIO_NUM     27
19#define Y9_GPIO_NUM       35
20#define Y8_GPIO_NUM       34
21#define Y7_GPIO_NUM       39
22#define Y6_GPIO_NUM       36
23#define Y5_GPIO_NUM       21
24#define Y4_GPIO_NUM       19
25#define Y3_GPIO_NUM       18
26#define Y2_GPIO_NUM        5
27#define VSYNC_GPIO_NUM    25
28#define HREF_GPIO_NUM     23
29#define PCLK_GPIO_NUM     22
30
31#define FLAS_LED   4                          // flaş LED'i (RTC pini) / flash LED (RTC pin)
32#define PIR_PIN   13                          // PIR OUT, ext0 ile uyandırır / PIR OUT, wakes via ext0
33
34RTC_DATA_ATTR int hareketSayisi = 0;          // uykuda korunur / survives deep sleep
35
36WiFiClientSecure client;
37UniversalTelegramBot bot(BOT_TOKEN, client);
38camera_fb_t *fb = nullptr;
39bool veriBekliyor = false;
40
41bool veriVarMi() {
42  if (veriBekliyor) {
43    veriBekliyor = false;
44    return true;
45  }
46  return false;
47}
48byte *sonrakiTampon() { return fb ? fb->buf : nullptr; }
49int tamponBoyu() { return fb ? fb->len : 0; }
50
51bool kameraBaslat() {
52  camera_config_t config = {};
53  config.ledc_channel = LEDC_CHANNEL_0;
54  config.ledc_timer   = LEDC_TIMER_0;
55  config.pin_d0 = Y2_GPIO_NUM;
56  config.pin_d1 = Y3_GPIO_NUM;
57  config.pin_d2 = Y4_GPIO_NUM;
58  config.pin_d3 = Y5_GPIO_NUM;
59  config.pin_d4 = Y6_GPIO_NUM;
60  config.pin_d5 = Y7_GPIO_NUM;
61  config.pin_d6 = Y8_GPIO_NUM;
62  config.pin_d7 = Y9_GPIO_NUM;
63  config.pin_xclk     = XCLK_GPIO_NUM;
64  config.pin_pclk     = PCLK_GPIO_NUM;
65  config.pin_vsync    = VSYNC_GPIO_NUM;
66  config.pin_href     = HREF_GPIO_NUM;
67  config.pin_sccb_sda = SIOD_GPIO_NUM;
68  config.pin_sccb_scl = SIOC_GPIO_NUM;
69  config.pin_pwdn     = PWDN_GPIO_NUM;
70  config.pin_reset    = RESET_GPIO_NUM;
71  config.xclk_freq_hz = 20000000;
72  config.pixel_format = PIXFORMAT_JPEG;
73  config.frame_size   = psramFound() ? FRAMESIZE_XGA : FRAMESIZE_SVGA;
74  config.jpeg_quality = 12;
75  config.fb_count     = 1;                    // tek kare yeter / one frame is enough
76  config.fb_location  = psramFound() ? CAMERA_FB_IN_PSRAM : CAMERA_FB_IN_DRAM;
77  config.grab_mode    = CAMERA_GRAB_WHEN_EMPTY;
78  return esp_camera_init(&config) == ESP_OK;
79}
80
81void uyu() {
82  // PIR çıkışı LOW'a dönmeden uyursan kart hemen yeniden uyanır
83  // If you sleep while the PIR output is still HIGH, the board wakes straight away
84  unsigned long t = millis();
85  while (digitalRead(PIR_PIN) == HIGH && millis() - t < 30000) delay(100);
86
87  digitalWrite(FLAS_LED, LOW);
88  rtc_gpio_hold_en(GPIO_NUM_4);               // flaş uykuda sönük kalsın / keep the flash off while asleep
89  esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 1);   // GPIO 13 HIGH olunca uyan / wake when GPIO 13 goes HIGH
90  Serial.println("Uyku / sleep");
91  Serial.flush();
92  esp_deep_sleep_start();
93}
94
95void setup() {
96  Serial.begin(115200);
97  rtc_gpio_hold_dis(GPIO_NUM_4);              // flaş pinini serbest bırak / release the flash pin
98  rtc_gpio_deinit(GPIO_NUM_13);               // pini yeniden normal GPIO yap / make the pin a normal GPIO again
99  pinMode(FLAS_LED, OUTPUT);
100  digitalWrite(FLAS_LED, LOW);
101  pinMode(PIR_PIN, INPUT);
102
103  if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_EXT0) {
104    Serial.println("Ilk acilis: PIR 60 sn isiniyor / first boot: PIR warming up 60 s");
105    delay(60000);
106    uyu();
107  }
108  hareketSayisi++;
109
110  // 1) Fotoğrafı hemen çek, Wi-Fi'yi sonra aç: an kaçmasın
111  // 1) Take the photo at once and start Wi-Fi later, so the moment is not lost
112  if (kameraBaslat()) {
113    for (int i = 0; i < 3; i++) {             // ilk kareler karanlık ya da yeşil olur / first frames are dark or green
114      fb = esp_camera_fb_get();
115      if (fb) esp_camera_fb_return(fb);
116    }
117    fb = esp_camera_fb_get();
118  }
119
120  // 2) Wi-Fi'ye bağlan, en fazla 15 sn bekle / connect to Wi-Fi, wait at most 15 s
121  WiFi.mode(WIFI_STA);
122  WiFi.begin(WIFI_SSID, WIFI_PASS);
123  unsigned long t0 = millis();
124  while (WiFi.status() != WL_CONNECTED && millis() - t0 < 15000) delay(100);
125
126  // 3) Gönder ve uyu / send and go back to sleep
127  if (WiFi.status() == WL_CONNECTED) {
128    client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
129    bot.sendMessage(CHAT_ID, "Hareket / motion #" + String(hareketSayisi));
130    if (fb) {
131      veriBekliyor = true;
132      bot.sendPhotoByBinary(CHAT_ID, "image/jpeg", fb->len,
133                            veriVarMi, nullptr, sonrakiTampon, tamponBoyu);
134    } else {
135      bot.sendMessage(CHAT_ID, "Kamera hatası / camera error");
136    }
137  }
138  if (fb) esp_camera_fb_return(fb);
139  Serial.printf("Uyanik kalma / awake: %lu ms\n", millis());
140  uyu();
141}
142
143void loop() {
144}

Kodda gözden kaçabilecek dört ayrıntı var. Birincisi, kart uyumadan önce PIR çıkışının LOW'a dönmesini bekler; sinyal hâlâ HIGH iken uyursan kart hemen yeniden uyanır ve döngüye girer. İkincisi, rtc_gpio_hold_en() flaş pinini uyku boyunca LOW'a kilitler; bu satır olmadan GPIO 4 boşta kalır ve flaş uykuda hafifçe yanarak hem pili bitirir hem dikkat çeker. Üçüncüsü, uyandıktan sonra rtc_gpio_deinit() GPIO 13'ü normal giriş hâline getirir, yoksa digitalRead() yanlış okuyabilir. Dördüncüsü, RTC_DATA_ATTR ile işaretli sayaç uyku boyunca korunur, böylece her mesajda kaçıncı hareket olduğunu görürsün. Uyku modlarının ve uyandırma kaynaklarının tamamı ESP32 deep sleep yazısında.

SenaryoOrtalama akım (pil tarafı)2600 mAh 18650 ile
Sürekli açık, Wi-Fi bağlı (ilk kod)≈ 290 mA≈ 9 saat
Deep sleep + günde 20 hareket≈ 11 mA≈ 10 gün
Güç kilitleme devresi (kart tamamen kapalı) + günde 20 hareket≈ 0,7 mA≈ 4–5 ay (teorik)

Tablodaki değerler 5 V yükselticinin %85 verimle çalıştığı varsayımıyla hesaplanmıştır. Derin uykudaki ESP32 yongası yalnızca 10 µA civarında harcasa da ESP32-CAM kartı üzerindeki regülatör, PSRAM ve kamera yüzünden uykuda bile yaklaşık 6 mA çeker; pil süresini asıl bu belirler. Her uyanma ise 6–10 saniye sürer: açılış, kamera, Wi-Fi bağlantısı ve iki HTTPS isteği. Aylarca çalışma istiyorsan kartın beslemesini bir MOSFET'le tamamen kesen, PIR tetiklenince kartı açan ve iş bitince kartın kendini kapattığı bir güç kilitleme (power latch) devresi gerekir. Kendi senaryonu Pil Ömrü Hesaplama aracıyla hesaplayabilir, sık yeniden başlama sorunları için ESP32 brownout yazısına bakabilirsin.

Gece çekimi: flaş, IR LED ve kamera ayarları

Standart ESP32-CAM merceklerinin içinde, kızılötesi ışığı engelleyen sabit bir IR-cut filtresi bulunur; bu yüzden gündüz renkler doğal görünür ama IR ışıkla aydınlatılmış bir sahne karanlık kalır. Karanlıkta görmek için iki yol var: beyaz flaş ya da filtresiz bir mercekle IR aydınlatma. Piyasada night vision ya da 850 nm olarak satılan OV2640 modüllerinde bu filtre yoktur; gündüz renkler pembeye kayar ama 850 nm IR LED'lerle aydınlatılan sahneyi siyah-beyaz olarak net görürsün. 940 nm LED'ler tamamen görünmezdir, ancak OV2640'ın bu dalga boyundaki duyarlılığı çok daha düşük olduğu için görüntü belirgin şekilde karanlıklaşır. IR aydınlatıcıyı ayrı bir 5 V ya da 12 V kaynaktan besle; üzerinde ışık sensörü olan hazır modüller hava kararınca kendiliğinden yanar. GPIO'dan kontrol etmek istersen bir MOSFET kullan, LED'leri asla doğrudan pine bağlama.

C++ (Arduino IDE)
1#include "esp_camera.h"
2void setup() {
3// esp_camera_init() başarılı olduktan sonra / after esp_camera_init() succeeds
4sensor_t *s = esp_camera_sensor_get();
5s->set_gainceiling(s, GAINCEILING_32X);   // karanlıkta daha yüksek kazanç / more gain in the dark
6s->set_aec2(s, 1);                        // DSP pozlaması: gece modu / DSP exposure: night mode
7s->set_ae_level(s, 2);                    // pozlamayı artır (-2..2) / raise exposure (-2..2)
8s->set_whitebal(s, 1);                    // otomatik beyaz dengesi / auto white balance
9s->set_special_effect(s, 2);              // 2 = siyah-beyaz: IR'de renk zaten bozulur / 2 = grayscale: IR spoils colour anyway
10}
11void loop() {}

Bu ayarlar sensörün kazanç tavanını ve pozlama süresini artırır. Bedeli şudur: karanlıkta kare hızı düşer, hareket eden biri bulanık çıkar ve yüksek kazanç görüntüye kumlanma ekler. Gece fotoğrafını iyileştirmenin en etkili yolu yine ışıktır; zayıf bir IR aydınlatıcı bile kazancı artırmaktan daha net sonuç verir. Kodu kameraBaslat() çağrısından hemen sonra ekleyebilir, istersen bir LDR ile ortam ışığını ölçüp gece ve gündüz ayarları arasında otomatik geçiş yapabilirsin.

Güvenlik kamerası olarak sınırları

  • Video kaydetmez: Bu sistem yalnızca anlık fotoğraf gönderir. Sürekli kayıt ya da geriye dönük izleme için hazır bir güvenlik kamerası gerekir.
  • Gecikme vardır: Kart açıkken 2–4 saniye, derin uykudan uyanınca 6–10 saniye geçer; hızlı geçen biri fotoğrafta kadrajdan çıkmış olabilir.
  • PIR camın arkasını görmez: Cam, kızılötesi ısı ışınımını geçirmez. Pencere arkasına koyduğun sensör dışarıdaki hareketi algılamaz, ama güneş ve kalorifer onu yanlış tetikleyebilir.
  • İnternete bağımlıdır: Wi-Fi ya da internet kesilirse fotoğraf gitmez. Kritik bir kullanımda fotoğrafı ayrıca SD karta kaydetmek bir yedek sağlar.
  • Fiziksel korumasızdır: Kart kolayca sökülebilir, kapatılabilir ve dış ortamda nem ile güneşten etkilenir; dışarıda kullanacaksan kapalı bir kutu ve sıcaklığa dayanıklı bir besleme şart.
  • Görüntü kalitesi sınırlıdır: 2 MP'lik OV2640, birkaç metreden yüz tanımaya ya da plaka okumaya yetmez; geniş açılı mercekler kadrajı büyütür ama ayrıntıyı azaltır.
  • Gizlilik kuralları: Kamerayı kendi alanına yönelt; komşunun bahçesini, ortak alanları ya da sokağı kaydetmeden önce bulunduğun yerin yasal kurallarını kontrol et.

ESP32-CAM Telegram proje fikirleri

  • Kapı zili kamerası: Zil butonu GPIO 13'e bağlansın, butona basılınca kapının önünü çekip sana göndersin; butonun bağlantısı için buton bağlama yazısına bak.
  • Posta kutusu bildirimi: Kapağa bir reed röle yerleştir, kapak açılınca kart uyanıp içerinin fotoğrafını göndersin.
  • Kuş yuvası ya da evcil hayvan kamerası: Hareket olunca fotoğraf çeksin, gün içinde /foto ile kontrol et.
  • Alarm sistemine göz: Bir Arduino alarm sistemi tetiklendiğinde ESP32-CAM'e sinyal versin ve olay yerini çeksin.
  • Bitki ve sera takibi: Zamanlayıcıyla saatte bir uyanıp fotoğraf göndersin, ölçümleri MQTT ile Home Assistant ekranına da aktar.
  • Aile grubu: Botu bir Telegram grubuna ekle ve grubun ID'sini kullan; fotoğraf herkese aynı anda gitsin.

Sık hatalar ve çözümleri

BelirtiOlası sebepÇözüm
Mesaj geliyor, fotoğraf gelmiyorKare çok büyük, PSRAM kapalı ya da yükleme yarıda kesildiAI Thinker ESP32-CAM kartını seç, çözünürlüğü SVGA'ya indir, Wi-Fi sinyalini güçlendir
Bot hiçbir komuta yanıt vermiyorToken ya da CHAT_ID yanlış, botla hiç /start yazışılmadıToken'ı yeniden kopyala, @userinfobot ile ID'ni kontrol et, botuna /start yaz
Durup dururken hareket fotoğrafı geliyorPIR, Wi-Fi anteninin yaydığı sinyalden ya da ısı kaynağından etkileniyorPIR'yi karttan 10–20 cm uzaklaştır, VCC-GND arasına 100 nF ekle, sensörü güneşe ve kaloriferlere çevirme
Kart uykudan hemen tekrar uyanıyorUyurken PIR çıkışı hâlâ HIGHUyumadan önce pinin LOW'a dönmesini bekle, HC-SR501'in süre trimpotunu en kısaya al
Uykudayken flaş hafifçe yanıyorGPIO 4 boşta kalıyorUyumadan önce LOW yaz ve rtc_gpio_hold_en(GPIO_NUM_4) çağır
Fotoğraf karanlık ya da yeşilimsiKamera açıldıktan hemen sonraki ilk karelerAsıl fotoğraftan önce 2–3 kare çekip at
Fotoğraf gönderirken kart yeniden başlıyorBrownout: besleme Wi-Fi ve flaş akımını karşılayamıyor5 V / 2 A adaptör, kısa kablolar ve 5V-GND arasına 470–1000 µF kondansatör kullan
Gruba fotoğraf gönderirken grup ID'si eksi işaretiyle başlar (ör. -1001234567890); CHAT_ID satırına işaretiyle birlikte yaz. Botun grup mesajlarını okuyabilmesi için BotFather'da /setprivacy ayarını kapatman ya da komutları /foto@bot_adi biçiminde göndermen gerekebilir; kod bu ekleri zaten temizler.

ESP32-CAM, Telegram ile birleşince birkaç yüz liralık bir kartı telefonuna fotoğraf gönderen akıllı bir göze dönüştürür. Önce sürekli açık kodla sistemi kur ve PIR'yi ayarla, sonra ihtiyacın varsa deep sleep sürümüne geç. BlueGrays uygulamasında PIR, buzzer ve LED'li Telegram hareket alarmı, ESP32 deep sleep ve PIR ile otomatik aydınlatma projelerini devre şemaları ve hazır kodlarıyla adım adım bulabilirsin.

Sıkça sorulan sorular

ESP32-CAM ile Telegram'a fotoğraf nasıl gönderilir?

BotFather'dan bir bot oluşturup token alırsın, UniversalTelegramBot kütüphanesini kurarsın ve kameranın kare tamponunu sendPhotoByBinary() fonksiyonuyla Telegram'ın sendPhoto adresine yüklersin. Kütüphane fotoğrafı tarayıcıdaki dosya yükleme gibi multipart biçiminde HTTPS üzerinden gönderir. Kodda yalnızca Wi-Fi bilgilerini, token'ı ve kendi chat ID'ni değiştirmen yeterlidir.

ESP32-CAM'e PIR sensörü hangi pine bağlanır?

SD kart kullanmıyorsan en güvenli seçim GPIO 13'tür: açılışı etkilemez ve bir RTC pini olduğu için kartı deep sleep'ten uyandırabilir. PIR'nin VCC'sini 5V pinine, GND'sini GND'ye, OUT'unu GPIO 13'e bağla. GPIO 12'yi kullanma; açılışta HIGH olursa kart açılmaz.

ESP32-CAM pille ne kadar çalışır?

Wi-Fi sürekli açıkken 2600 mAh'lik bir 18650 pil yaklaşık 9 saat dayanır. Deep sleep kullanıp yalnız hareket olunca uyanırsan bu süre 10 gün civarına çıkar; kart uykuda bile regülatör ve PSRAM yüzünden yaklaşık 6 mA çeker. Aylarca çalışma için kartın beslemesini tamamen kesen bir güç kilitleme devresi gerekir.

ESP32-CAM gece görebilir mi?

Standart modüllerdeki IR-cut filtresi kızılötesi ışığı engellediği için karanlıkta yalnız beyaz flaşla 1–2 metreye kadar görüntü alırsın. Filtresiz (night vision) bir OV2640 modülü ve 850 nm IR aydınlatıcıyla karanlıkta siyah-beyaz ama net fotoğraf çekebilirsin. Kamera ayarlarında kazanç tavanını yükseltmek de yardımcı olur, ancak görüntüye kumlanma ekler.

ESP32-CAM Telegram'a video gönderebilir mi?

Pratikte hayır. ESP32-CAM tek tek JPEG kareleri üretir; bunları bir MP4 videoya dönüştürecek işlem gücü ve bellek yoktur. Birkaç fotoğrafı arka arkaya göndermek ya da canlı görüntüyü ev ağında CameraWebServer ile izlemek daha gerçekçi çözümlerdir.

Fotoğraf birden fazla kişiye gönderilebilir mi?

Evet. Botu bir Telegram grubuna ekleyip grubun eksi işaretiyle başlayan ID'sini CHAT_ID olarak kullanırsan fotoğraf gruptaki herkese aynı anda gider. Alternatif olarak kodda birkaç chat ID'yi bir diziye koyup fotoğrafı sırayla her birine gönderebilirsin; her gönderim ayrı bir yükleme olduğu için süre uzar.

Tüm projeleri gör
ESP32 Hareket Alarm Sistemi (PIR + Buzzer + LED + Telegram)
#145İleri
Premium

ESP32 Hareket Alarm Sistemi (PIR + Buzzer + LED + Telegram)

PIR sensörü hareket algıladığında buzzer ve LED'i aktif eden, aynı anda Telegram üzerinden sahibine anlık bildirim gönderen akıllı bir güvenlik alarm sistemidir. Tekrarlayan alarmların sıklığını sınırlamak için 30 saniyelik cooldown (bekleme süresi) mekanizması vardır; bu mekanizma PIR sensörünün yanlış algılamalarını doğrulamaz veya ortadan kaldırmaz. Ev güvenliği, garaj izleme, depo veya çalışma odası gibi alanlarda kullanılabilir. Telegram entegrasyonu sayesinde nerede olursanız olun anında h

0.0(0)
9
ESP32 PIR Hareket Sensörü ile Otomatik Aydınlatma
#121Orta
Premium

ESP32 PIR Hareket Sensörü ile Otomatik Aydınlatma

Bu projede HC-SR501 PIR hareket sensörü ile odaya giren kişiyi algılayıp LED'i otomatik olarak yakacağız. LED'in açık kalma süresini millis() ile izleyeceğiz; sensör HIGH okundukça son hareket zamanı yenilenecek ve son HIGH okumasından en az 10 saniye sonra LED sönecek. Mevcut kod ayrıca her döngüde delay(50) ile 50 ms beklediğinden uygulama döngüsü tamamen bloklamayan bir yapıda değildir. Gerçek hayatta merdiven, koridor, banyo veya dolap içi aydınlatmalarda kullanılabilir.

4.4(24)
38
ESP32 Deep Sleep — Pil Tasarrufu (OLED + RTC RAM Sayaç)
#135İleri
Premium

ESP32 Deep Sleep — Pil Tasarrufu (OLED + RTC RAM Sayaç)

ESP32'nin Deep Sleep modu, CPU ve çoğu çevre birimini kapatarak akım tüketimini ~10µA seviyesine düşürür ve pille çalışan IoT cihazları için kritik öneme sahiptir. Bu projede üç farklı uyandırma kaynağını kullanıyoruz: zamanlayıcı (timer, 15sn), harici pin (EXT0 — buton GPIO 33) ve touch (T0/GPIO 4). RTC_DATA_ATTR ile işaretlenen değişkenler deep sleep boyunca korunur — boot sayacı, timer wake sayacı ve buton wake sayacı kalıcı olarak izlenir. SSD1306 OLED ekranda her uyanışta wake reason, say

4.3(10)
16
ESP32 Akıllı Aydınlatma (PIR + LDR + Röle + OLED)
#141İleri
Premium

ESP32 Akıllı Aydınlatma (PIR + LDR + Röle + OLED)

ESP32, PIR hareket sensörü, LDR ışık sensörü ve röle modülü ile evinin koridorunu, tuvaletini veya kilerini akıllı aydınlatmaya dönüştürüyoruz. Klasik "karanlıkta hareket algılanınca ışık yansın" senaryosunu inşa ediyoruz — ortam aydınlıksa hareket olsa bile ışık yanmaz, böylece gündüz gereksiz yere yanmaz ve enerji tasarrufu sağlanır. Işık 30 saniye yanık kalır; hareket devam ederse timer otomatik sıfırlanır ve süre uzar. SSD1306 OLED ekranda büyük fontlarla durum (AÇIK / GÜNDÜZ / BEKLE), geri

4.3(6)
11
ESP32 Wi-Fi STA Bağlantısı (LCD Ekranlı)
#127İleri

ESP32 Wi-Fi STA Bağlantısı (LCD Ekranlı)

Bu projede ESP32'yi Station (STA) modunda evdeki Wi-Fi ağına güvenli ve hata toleranslı şekilde bağlıyoruz. SSID/şifreyi secrets.h dosyasına ayırarak Git'e sızmasını önlüyor, otomatik yeniden bağlanma mekanizması kuruyor, RSSI sinyal seviyesini ve IP adresini I2C LCD ekranda gösteriyoruz. Dahili LED durum göstergesi olarak çalışır. Üretim seviyesi bir bağlantı yöneticisidir.

4.4(21)
34
ESP32 mDNS: bluegrays-esp.local ile Cihaza Erişim (LCD Ekranlı)
#131İleri
Premium

ESP32 mDNS: bluegrays-esp.local ile Cihaza Erişim (LCD Ekranlı)

Bu projede ESP32'ye mDNS (Multicast DNS) servisi ekleyerek IP adresi yerine bluegrays-esp.local gibi okunabilir bir host adıyla erişim sağlıyoruz. DHCP'nin verdiği IP değişse bile cihaza her zaman aynı isimle ulaşabilirsiniz. Üzerinde küçük bir web server da çalıştırarak tarayıcıdan http://bluegrays-esp.local/ adresiyle LED kontrolü gönderiyoruz. I2C LCD ekranda hostname, IP ve LED durumu hem Türkçe hem İngilizce gösterilir. iOS, macOS ve Linux mDNS'i doğal olarak destekler; Windows'ta Bonjo

4.8(14)
23
Hareket Sensörü İle Hareket Algılayıcı
#24Başlangıç
Premium

Hareket Sensörü İle Hareket Algılayıcı

Biri odaya girdiğinde haber veren basit bir bekçi. Hareket sensörü insan vücudunun yaydığı ısıyı fark eder; Arduino hareket olduğu sürece LED'i yakar, hareket bitince söndürür. Kapı önünde kendiliğind

4.6(47)
67