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 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 | Özellik | Not |
|---|---|---|
| ESP32-CAM (AI-Thinker) | OV2640, 4 MB PSRAM | PSRAM'li sürüm XGA fotoğrafı rahatça taşır |
| ESP32-CAM-MB ya da USB-TTL dönüştürücü | CH340 / CP2102 | Kod 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 |
| Besleme | 5 V, en az 2 A | Wi-Fi ve flaş aynı anda yüksek akım çeker |
| Elektrolitik kondansatör | 470–1000 µF | 5V 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.
| Pin | SD kart yokken | Deep sleep'ten uyandırır mı? | Not |
|---|---|---|---|
| GPIO 13 | Serbest | Evet (ext0) | PIR için en iyi seçim |
| GPIO 14 | Serbest | Evet | Açılışta kısa bir PWM sinyali görülebilir; giriş olarak sorunsuz |
| GPIO 15 | Serbest | Evet | Açılış pini; LOW tutulursa açılış mesajları kapanır |
| GPIO 2 | Serbest | Evet | Açılış pini; yükleme anında HIGH olmamalı |
| GPIO 12 | Serbest | Evet | Açılışta HIGH olursa kart açılmaz; kullanma |
| GPIO 4 | Flaş LED'i | Evet | Flaşa ayrılmış; başka iş için kullanma |
| GPIO 3 (U0R) | Seri RX | Hayır | Yalnız seri port gerekmiyorsa |
| GPIO 16 | PSRAM | Hayır | Asla kullanma |
| PIR pini | ESP32-CAM pini | Açıklama |
|---|---|---|
| VCC | 5V | HC-SR501 en az 4,5 V ister; AM312 kullanıyorsan 3V3 |
| OUT | GPIO 13 | Hareket varken 3,3 V, yokken 0 V |
| GND | GND | Ortak toprak |
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
- Telegram'da @BotFather hesabını aç, /newbot yaz, botuna bir ad ve sonu bot ile biten bir kullanıcı adı ver.
- BotFather'ın verdiği 1234567890:AAE... biçimindeki token'ı kopyala; koddaki BOT_TOKEN satırına bu gelecek.
- Kendi kullanıcı numaranı öğrenmek için @userinfobot hesabına /start yaz; dönen Id değeri CHAT_ID olacak.
- Kendi botunu açıp bir kez /start yaz; Telegram, botların daha önce konuşmadığı birine mesaj atmasına izin vermez.
- Arduino IDE'de Kütüphane Yöneticisi'nden UniversalTelegramBot (Brian Lough) ve ArduinoJson kütüphanelerini kur.
- 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.
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ı
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üm | Ne 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.
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.
| Senaryo | Ortalama 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.
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
| Belirti | Olası sebep | Çözüm |
|---|---|---|
| Mesaj geliyor, fotoğraf gelmiyor | Kare çok büyük, PSRAM kapalı ya da yükleme yarıda kesildi | AI Thinker ESP32-CAM kartını seç, çözünürlüğü SVGA'ya indir, Wi-Fi sinyalini güçlendir |
| Bot hiçbir komuta yanıt vermiyor | Token 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ı geliyor | PIR, Wi-Fi anteninin yaydığı sinyalden ya da ısı kaynağından etkileniyor | PIR'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ıyor | Uyurken PIR çıkışı hâlâ HIGH | Uyumadan önce pinin LOW'a dönmesini bekle, HC-SR501'in süre trimpotunu en kısaya al |
| Uykudayken flaş hafifçe yanıyor | GPIO 4 boşta kalıyor | Uyumadan önce LOW yaz ve rtc_gpio_hold_en(GPIO_NUM_4) çağır |
| Fotoğraf karanlık ya da yeşilimsi | Kamera açıldıktan hemen sonraki ilk kareler | Asıl fotoğraftan önce 2–3 kare çekip at |
| Fotoğraf gönderirken kart yeniden başlıyor | Brownout: besleme Wi-Fi ve flaş akımını karşılayamıyor | 5 V / 2 A adaptör, kısa kablolar ve 5V-GND arasına 470–1000 µF kondansatör kullan |
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.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
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

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.

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

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

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.

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

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
Diğer yazılar
BlueGrays uygulaması
Bu devreyi telefonunda adım adım kur
Devre şeması, kod ve parça listesi tek ekranda. 200'den fazla Arduino, ESP32 ve Pico projesi seni bekliyor.
Telefonunla tara
Kamerayı koda tut; telefonunun uygulama mağazası açılır.
ya da mağazada aç

