Arduino Alarm Sistemi Yapımı: PIR, Kapı Sensörü, Keypad ve Siren
Arduino alarm sistemi nasıl yapılır? PIR, reed kapı sensörü, titreşim ve lazer bölgeleri, keypad şifresi, giriş gecikmesi, siren rölesi ve ESP32 Telegram kodu.
Arduino alarm sistemi, evine ya da odana izinsiz girildiğinde sireni çalıştıran, kapı açıldığında şifreni girmen için sana birkaç saniye tanıyan ve istersen telefonuna anında bildirim gönderen, kendi elinle kurabileceğin bir güvenlik düzeneğidir. Bu rehberde bir PIR hareket sensörü, kapıya takılan bir reed kontak, pencere camındaki darbeleri yakalayan bir titreşim sensörü ve koridoru kesen bir lazer bariyeri ile dört bölgeli bir alarm kuracaksın. Sistemi 4x4 keypad ile şifreyle kurup çözecek, 12 V'luk bir sireni röle üzerinden çalıştıracak ve hepsini tek bir Arduino Uno ile yöneteceksin.
Ticari alarm panellerinin yaptığı işlerin küçük bir kopyasını adım adım yapacağız: giriş ve çıkış gecikmesi, evde modu (gece modu), yanlış şifre kilidi, siren süresi sınırı ve alarm hafızası. Kodu iç içe if bloklarıyla değil, bir durum makinesiyle yazacağız; böylece alarmın hangi anda ne yaptığı her zaman açık olacak. Ardından aynı mantığı ESP32'ye taşıyıp Telegram'dan kurma, çözme ve alarm bildirimi ekleyecek, Raspberry Pi Pico için MicroPython sürümünü yazacak ve en çok can sıkan sorun olan yanlış alarmları nasıl azaltacağını göreceksin.

Arduino alarm sistemi nasıl çalışır?
Her alarm sistemi üç parçadan oluşur: girişler (sensörler), karar veren beyin (Arduino) ve çıkışlar (siren, buzzer, bildirim). Sensörlerin her biri bir bölgeyi (zone) korur. Profesyonel panellerde bölgeler, tetiklendiklerinde nasıl davranacaklarına göre sınıflandırılır; iyi bir alarmı, her kapı açılışında öten can sıkıcı bir düzenekten ayıran şey bu ayrımdır. Bizim sistemimizde dört bölge olacak:
| Bölge | Sensör | Bölge tipi | Kurulu iken tetiklenirse |
|---|---|---|---|
| Giriş kapısı | Reed kontak (MC-38) | Gecikmeli | 20 sn giriş süresi başlar; şifre girilmezse alarm |
| Salon, iç mekân | PIR (HC-SR501) | İç bölge (takipçi) | Anında alarm; giriş süresi işliyorsa bekler; evde modunda kapalı |
| Pencere | Titreşim (SW-420) | Anlık | 3 sn içinde 3 darbe gelirse anında alarm |
| Koridor, merdiven | Lazer + LDR (KY-008) | İç bölge (takipçi) | Anında alarm; giriş süresi işliyorsa bekler |
| Gaz, yangın, sabotaj | MQ-2, alev sensörü, kutu anahtarı | 24 saat | Sistem kurulu olmasa bile alarm (geliştirme önerisi) |
Gecikmeli bölge sayesinde eve girdiğinde siren hemen çalmaz: kapı açılır, buzzer kesik kesik öterek seni uyarır ve şifreni girmen için 20 saniyen olur. Takipçi (follower) iç bölge ise giriş süresi işlerken sabırlı davranır; kapıdan girip keypad'e yürürken PIR'ın önünden geçmen alarmı çaldırmaz. Ama biri kapıyı hiç açmadan, örneğin pencereden içeri girip PIR'ın önüne çıkarsa giriş süresi başlamamış olduğu için alarm anında çalar. Anlık bölge her koşulda hemen alarm verir; pencereyi zorlayan birine 20 saniye tanımanın anlamı yoktur. Çıkışta da benzer bir mantık işler: sistemi kurduğunda 30 saniyelik çıkış gecikmesi başlar ve bu sürede kapıdan çıkman alarmı tetiklemez.
Arduino alarm sistemi malzeme listesi
| Malzeme | Adet | Görevi |
|---|---|---|
| Arduino Uno (ya da Nano) | 1 | Sistemin beyni; bu rehberdeki pinler Uno ve Nano'da aynıdır |
| HC-SR501 PIR hareket sensörü | 1 | İç mekânda hareket algılama, 3–7 m, yaklaşık 110° |
| MC-38 reed kapı kontağı (ya da reed + mıknatıs) | 1 | Kapı ya da pencere açılınca devreyi açar |
| SW-420 titreşim sensörü modülü | 1 | Camdaki ve kasadaki darbeleri algılar |
| KY-008 lazer modülü + LDR + 10 kΩ direnç | 1 takım | Koridoru kesen ışın bariyeri |
| 4x4 membran keypad | 1 | Şifreyle kurma ve çözme |
| Aktif buzzer (5 V) | 1 | Tuş sesi, giriş-çıkış uyarısı, iç siren |
| 1 kanallı 5 V röle modülü | 1 | 12 V sireni Arduino'dan yalıtarak çalıştırır |
| 12 V siren (tercihen flaşörlü) | 1 | Asıl alarm sesi, genellikle 100–120 dB |
| Kırmızı ve yeşil LED + 2 adet 220 Ω direnç | 1 takım | Kurulu ve hazır göstergesi |
| 12 V besleme, LM2596 modül, 12 V akü (isteğe bağlı) | 1 takım | Besleme ve elektrik kesintisinde yedek |
| Breadboard, jumper kablo, 4 damarlı alarm kablosu | - | Bağlantılar ve uzaktaki sensörler |







Sensörler: hangi bölge neyi yakalar?
- PIR (HC-SR501): İnsan vücudunun yaydığı kızılötesi ışınımdaki değişimi algılar; 3–7 metre mesafede ve yaklaşık 110 derecelik bir açıda hareketi görür. Çıkışı 3,3 V'tur, beslemesi ise 5 V olmalıdır. Açıldıktan sonra 30–60 saniye boyunca ortamı öğrenirken kendiliğinden tetiklenebilir; kod bu yüzden ilk 60 saniyeyi yok sayar. Ayrıntılar için PIR hareket sensörü yazısına bak.
- Reed kapı kontağı (MC-38): Biri kasaya, diğeri kapı kanadına vidalanan iki plastik gövdeden oluşur. Kapı kapalıyken mıknatıs yakındadır ve kontak kapalıdır; kapı 15–25 mm'den fazla açılınca kontak açılır. Tek bir pin ve dahili pull-up ile okunur; içinde neler olduğunu reed röle yazısında anlattık.
- Titreşim sensörü (SW-420): İçinde yayla çevrili bir metal çubuk bulunan, normalde kapalı bir anahtardır. Cam ya da çerçeve darbe aldığında kontak bir anlığına açılır, karttaki LM393 karşılaştırıcı bunu dijital bir darbeye çevirir. Çoğu modülde çıkış sakinken LOW olur, darbede kısa süre HIGH olur; kendi modülünü sensör testiyle doğrula. Hassasiyet karttaki potla ayarlanır; ayrıntılar SW-420 titreşim sensörü yazısında.
- Lazer bariyeri (KY-008 + LDR): 650 nm dalga boylu, yaklaşık 5 mW'lık lazer, koridorun karşısındaki bir LDR'ye sürekli vurur. Işın kesilince LDR'nin direnci yüzlerce ohmdan onlarca kiloohma çıkar ve analog okuma belirgin şekilde düşer. Kurulum ve hizalama ipuçları lazer modülü yazısında.
- 4x4 keypad: 16 tuşlu, 4 satır ve 4 sütun hattından oluşan bir matristir; 8 pin kullanır ve Keypad kütüphanesiyle tek satırda okunur. Satır-sütun taramasının mantığını keypad kullanımı yazısında bulabilirsin.
- Siren ve buzzer: Aktif buzzer kendi osilatörüne sahip olduğu için pine HIGH vermekle öter; tuş sesi ve giriş-çıkış uyarısı için idealdir. Asıl caydırıcı ses ise 12 V'luk sirenden gelir ve onu bir röle modülü üzerinden çalıştırırsın. Aktif ve pasif buzzer farkı için buzzer nedir yazısına bakabilirsin.
Bağlantı şeması ve pin tablosu
Aşağıdaki tablo üç kartın bağlantısını birlikte veriyor. Arduino Uno sürümü dört bölgeyi ve keypad'i birlikte kullanır. ESP32 sürümü keypad yerine Telegram komutlarıyla kurulup çözüldüğü, Pico sürümü de kısa tutulduğu için lazer bariyeri yalnızca Uno'da var. Pin numaralarını kendi kartında görmek için Pinout aracını, LED dirençlerini hesaplamak için LED direnci hesaplayıcıyı kullanabilirsin.
| Bağlantı | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| Keypad R1–R4 (satırlar) | D9, D8, D7, D6 | – (Telegram) | GP2, GP3, GP4, GP5 |
| Keypad C1–C4 (sütunlar) | D5, D4, D3, D2 | – (Telegram) | GP6, GP7, GP8, GP9 |
| PIR VCC / OUT / GND | 5V / D10 / GND | VIN (5V) / GPIO 27 / GND | VBUS / GP16 / GND |
| Reed kontak (2 kablo) | D11 ve GND | GPIO 33 ve GND | GP15 ve GND |
| SW-420 VCC / DO / GND | 5V / D12 / GND | 3V3 / GPIO 32 / GND | 3V3(OUT) / GP17 / GND |
| KY-008 S / − (lazer sürekli açık) | 5V / GND | – | – |
| LDR 5V–A0 arası, 10 kΩ A0–GND arası | A0 | – | – |
| Aktif buzzer + (− ucu GND) | A1 | GPIO 25 | GP14 |
| Röle modülü IN | A2 | GPIO 26 | GP13 |
| Yeşil LED (220 Ω ile): hazır | A3 | – | – |
| Kırmızı LED (220 Ω ile): kurulu | D13 | GPIO 2 (dahili LED) | Dahili LED |
Alarm en çok elektrik kesildiğinde işe yarar; bu yüzden beslemeyi baştan düşün. Pratik bir düzen şöyledir: profesyonel panellerdeki gibi 13,8 V çıkışlı, akü bağlantılı bir alarm güç kaynağı hem sireni besler hem de bir LM2596 voltaj düşürücüyle 5 V'a indirilerek Arduino'nun 5V pinine verilir. Böylece elektrik kesildiğinde 12 V 7 Ah'lik kuru akü devreye girer. Hesap basittir: Uno, PIR, lazer, LED'ler ve SW-420 beklemede 5 V'ta yaklaşık 100 mA çeker; bu 0,5 W eder ve %85 verimli bir düşürücüyle akü tarafında yaklaşık 50 mA'e karşılık gelir. 7 Ah'lik akü, kapasitesinin yalnızca %80'ini kullansan bile sistemi 4–5 gün ayakta tutar; siren çalarken çekilen 0,2–0,5 A bu süreyi biraz kısaltır. Kendi değerlerinle denemek için pil ömrü hesaplayıcıyı, besleme seçenekleri için Arduino nasıl beslenir yazısını kullanabilirsin.
Adım adım kurulum
- Arduino IDE'de Kütüphane Yöneticisi'ni aç, Keypad yaz ve Mark Stanley ile Alexander Brevig'in kütüphanesini kur. Kütüphane kurulu değilse derlerken Keypad.h: No such file or directory hatası alırsın.
- Keypad'i tuşlar sana bakacak şekilde tut; soldan ilk dört kabloyu (R1–R4) D9, D8, D7, D6'ya, sonraki dördünü (C1–C4) D5, D4, D3, D2'ye bağla.
- PIR'ı 5V, D10 ve GND'ye bağla; iki potu da saat yönünün tersine sonuna kadar çevir ve tetikleme jumper'ını H konumuna al.
- Reed kontağın iki kablosunu D11 ile GND'ye, SW-420'yi 5V, D12 ve GND'ye bağla.
- LDR'yi 5V ile A0 arasına, 10 kΩ direnci A0 ile GND arasına tak; LDR'yi siyah bir borunun dibine yerleştir ve lazeri borunun tam ortasına hizala.
- Buzzer'ı A1'e, röle modülünün IN ucunu A2'ye, VCC ve GND uçlarını Arduino'nun 5V ve GND pinlerine bağla; LED'leri 220 Ω dirençlerle A3 ve D13'e tak.
- Önce aşağıdaki sensör testini yükle, Seri Monitör'ü 9600 baud'da aç ve her sensörü tek tek tetikle.
- Ardından tam alarm kodunu yükle, şifreyi değiştir ve sireni bağlamadan önce sistemi birkaç gün yalnızca buzzer ile dene.
İlk test: bütün sensörleri Seri Monitör'de görmek
Alarm koduna geçmeden önce her sensörün beklediğin gibi davrandığından emin ol. Bu küçük program yarım saniyede bir PIR'ın durumunu, kapının açık mı kapalı mı olduğunu, son yarım saniyedeki titreşim darbesi sayısını ve LDR'nin analog değerini yazar. Titreşim pini sürekli okunur, çünkü SW-420'nin darbeleri birkaç milisaniye sürebilir ve arada delay() kullanan bir kod bunları kaçırır.
1// Alarm sensör testi: tüm girişleri saniyede iki kez yazdırır / Alarm sensor test: prints every input twice a second
2const int PIR_PIN = 10; // HC-SR501 OUT
3const int KAPI_PIN = 11; // reed kapı kontağı, diğer ucu GND / reed door contact, other leg to GND
4const int TITRESIM_PIN = 12; // SW-420 DO
5const int LAZER_PIN = A0; // LDR bölücünün orta noktası / LDR divider midpoint
6
7int titresimSayisi = 0; // yarım saniyedeki darbe sayısı / pulses in the last half second
8int oncekiTitresim = LOW;
9unsigned long sonYazma = 0;
10
11void setup() {
12 Serial.begin(9600);
13 pinMode(PIR_PIN, INPUT);
14 pinMode(KAPI_PIN, INPUT_PULLUP); // kapı kapalı = LOW, açık = HIGH / door closed = LOW, open = HIGH
15 pinMode(TITRESIM_PIN, INPUT);
16}
17
18void loop() {
19 int t = digitalRead(TITRESIM_PIN); // kısa darbeleri kaçırmamak için sürekli oku / read constantly so short pulses are not missed
20 if (t == HIGH && oncekiTitresim == LOW) titresimSayisi++;
21 oncekiTitresim = t;
22
23 if (millis() - sonYazma >= 500) {
24 sonYazma = millis();
25 Serial.print(F("PIR: "));
26 Serial.print(digitalRead(PIR_PIN));
27 Serial.print(F(" Kapi / door: "));
28 Serial.print(digitalRead(KAPI_PIN) == HIGH ? F("ACIK / open") : F("kapali / closed"));
29 Serial.print(F(" Titresim / vibration: "));
30 Serial.print(titresimSayisi);
31 Serial.print(F(" Lazer / laser: "));
32 Serial.println(analogRead(LAZER_PIN));
33 titresimSayisi = 0;
34 }
35}Durum makinesi: alarmın beyni
Bir alarmı if blokları ve delay() ile yazmaya kalkarsan kısa sürede içinden çıkılmaz bir koda dönüşür: giriş süresi beklenirken keypad okunmaz, siren çalarken şifre girilemez. Çözüm, sistemin her an yalnızca bir durumda bulunduğu ve durumlar arası geçişlerin belirli olaylarla gerçekleştiği bir durum makinesidir. Kodda bu durumlar bir enum ile tanımlanır, loop() her turda yalnızca o anki durumun kurallarını uygular ve beklemeler delay() yerine millis() ile ölçülür. Böylece döngü saniyede binlerce kez döner ve hiçbir tuş basışı ya da sensör olayı kaçmaz.
| Durum | Ne zaman girilir? | Ne yapar? | Çıkış koşulu |
|---|---|---|---|
| ÇÖZÜLÜ | Açılışta ve doğru şifre + # ile | Sensörleri izler ama alarm vermez; her şey hazırsa yeşil LED yanar | Şifre + A ya da şifre + B |
| ÇIKIŞ GECİKMESİ | Şifre + A (tam) ya da B (evde) | 30 sn geri sayar; buzzer saniyede bir öter, son 10 sn hızlanır | Süre dolunca KURULU; şifre + # ile ÇÖZÜLÜ |
| KURULU | Çıkış süresi dolunca | Bütün bölgeleri izler; kırmızı LED sürekli yanar | Kapı açılırsa GİRİŞ; anlık ya da iç bölgede ALARM |
| GİRİŞ GECİKMESİ | Kurulu iken kapı açılınca | 20 sn boyunca buzzer kesik öter; PIR ve lazer bekletilir | Şifre + # ile ÇÖZÜLÜ; süre dolarsa ALARM |
| ALARM | Bir bölge tetiklenince | Siren ve buzzer çalar; siren 3 dk sonra susar, kırmızı LED hızlı yanıp söner | Yalnızca şifre + # ile ÇÖZÜLÜ |
Keypad ile kurma, çözme ve şifre
| Tuşlar | İşlev |
|---|---|
| 2580 + A | Tam kurulum: dört bölge de aktif, 30 sn çıkış süresi |
| 2580 + B | Evde (gece) modu: PIR kapalı; kapı, pencere ve lazer aktif |
| 2580 + # | Sistemi çöz; alarm olduysa tetiklenen bölgeyi Seri Monitör'e yazar |
| * ya da C | Yanlış yazdığın kodu sil |
| D | Bölge testi: kapı, PIR ve lazer değerlerini Seri Monitör'e yazar |
| 3 yanlış şifre | Tuş takımı 60 sn kilitlenir; bu sürede doğru şifre de kabul edilmez |
Kurarken de şifre istenmesi, çocukların ya da misafirlerin sistemi yanlışlıkla kurmasını önler. Kod ayrıca bir hazır değil kontrolü yapar: kapı açıkken ya da lazer ışını kesikken kurmaya çalışırsan uzun bir bip duyarsın ve sistem kurulmaz, tıpkı ticari panellerdeki gibi. Şifreyi varsayılan 2580 olarak bırakma; 1234, 0000 ya da doğum yılın gibi tahmin edilebilir kodlardan kaçın. Şifreyi kodu yeniden yüklemeden değiştirmek istersen onu EEPROM'a kaydedip keypad'den yeni şifre girmeni sağlayan bir menü ekleyebilirsin. Keypad'in yanına bir I2C LCD ekran eklersen geri sayımı ve durum mesajlarını da ekranda görürsün; A4 ve A5 pinleri bu yüzden boş bırakıldı.
Arduino alarm sistemi kodu
Aşağıdaki kod bu rehberin merkezi. En üstteki ayarlar bölümünden şifreyi, gecikme sürelerini, siren süresini, lazer eşiğini ve röle tipini değiştirebilirsin; kodun geri kalanına dokunman gerekmez. Arduino Uno'da yaklaşık 6 KB program belleği ve 620 bayt RAM kullanır, yani LCD ya da RFID eklemek için bol yer kalır.
1// Arduino ev alarm sistemi: 4 bölge, keypad, giriş/çıkış gecikmesi, siren / Arduino home alarm: 4 zones, keypad, entry/exit delay, siren
2#include <Keypad.h>
3
4// ---- Ayarlar / Settings ----
5const char SIFRE[] = "2580"; // kendi şifreni yaz / set your own code
6const unsigned long CIKIS_SURE = 30000; // çıkış gecikmesi 30 sn / exit delay 30 s
7const unsigned long GIRIS_SURE = 20000; // giriş gecikmesi 20 sn / entry delay 20 s
8const unsigned long SIREN_SURE = 180000; // siren en fazla 3 dk çalar / siren sounds for at most 3 min
9const unsigned long PIR_ISINMA = 60000; // PIR ilk 60 sn yok sayılır / PIR is ignored for the first 60 s
10const unsigned long KILIT_SURE = 60000; // 3 yanlış şifrede 60 sn kilit / 60 s lockout after 3 wrong codes
11const int LAZER_ESIK = 600; // ışınlı ve ışınsız değerin ortası / midpoint of beam and no-beam readings
12const bool LAZER_VAR = true; // lazer bariyerin yoksa false yap / set to false without a laser barrier
13const bool ROLE_AKTIF_LOW = true; // çoğu röle modülü LOW'da çeker / most relay modules switch on with LOW
14
15// ---- Pinler / Pins ----
16const int PIR_PIN = 10; // HC-SR501 OUT
17const int KAPI_PIN = 11; // reed, diğer ucu GND / reed, other leg to GND
18const int TITRESIM_PIN = 12; // SW-420 DO
19const int LAZER_PIN = A0; // LDR bölücü / LDR divider
20const int BUZZER_PIN = A1; // aktif buzzer / active buzzer
21const int ROLE_PIN = A2; // siren rölesi / siren relay
22const int YESIL_LED = A3; // hazır / ready
23const int KIRMIZI_LED = 13; // kurulu / armed
24
25const byte SATIR = 4, SUTUN = 4;
26char tuslar[SATIR][SUTUN] = {
27 {'1', '2', '3', 'A'},
28 {'4', '5', '6', 'B'},
29 {'7', '8', '9', 'C'},
30 {'*', '0', '#', 'D'}
31};
32byte satirPinleri[SATIR] = {9, 8, 7, 6}; // R1–R4
33byte sutunPinleri[SUTUN] = {5, 4, 3, 2}; // C1–C4
34Keypad keypad = Keypad(makeKeymap(tuslar), satirPinleri, sutunPinleri, SATIR, SUTUN);
35
36enum Durum { COZULU, CIKIS_GECIKMESI, KURULU, GIRIS_GECIKMESI, ALARM };
37const char* const DURUM_ADI[] = { "COZULU / DISARMED", "CIKIS / EXIT DELAY", "KURULU / ARMED", "GIRIS / ENTRY DELAY", "ALARM" };
38
39struct Giris { // gürültü süzgeçli giriş / debounced input
40 bool ham;
41 bool kararli;
42 unsigned long degisim;
43};
44Giris gKapi = {false, false, 0};
45Giris gPir = {false, false, 0};
46Giris gLazer = {false, false, 0};
47
48Durum durum = COZULU;
49unsigned long durumZamani = 0; // duruma giriş anı / when the state began
50bool evdeModu = false; // true: PIR devre dışı / true: PIR bypassed
51bool sirenAcik = false;
52bool pirHazir = false;
53const char* tetikleyen = ""; // alarmı başlatan bölge / zone that caused the alarm
54char girilen[9] = ""; // girilen şifre, en fazla 8 hane / typed code, max 8 digits
55byte haneSayisi = 0;
56byte yanlisSayisi = 0;
57bool kilitli = false;
58unsigned long kilitZamani = 0;
59unsigned long bipZamani = 0, bipSuresi = 0;
60unsigned long darbe[3] = {0, 0, 0}; // son 3 titreşim olayı / last 3 vibration events
61int oncekiTitresim = LOW;
62
63// Okuma "sure" ms boyunca aynı kalırsa kabul edilir / a reading is accepted once it stays the same for "sure" ms
64bool suz(Giris &g, bool okuma, unsigned long sure) {
65 unsigned long simdi = millis();
66 if (okuma != g.ham) {
67 g.ham = okuma;
68 g.degisim = simdi;
69 }
70 if (simdi - g.degisim >= sure) g.kararli = g.ham;
71 return g.kararli;
72}
73
74// 3 sn içinde 3 ayrı darbe = zorlama; tek vuruş alarm vermez / 3 separate hits within 3 s = forcing; a single knock is ignored
75bool titresimVar(unsigned long simdi) {
76 int okuma = digitalRead(TITRESIM_PIN);
77 bool sonuc = false;
78 if (okuma == HIGH && oncekiTitresim == LOW && simdi - darbe[2] > 150) { // 150 ms içindeki sekmeler tek olay / bounces within 150 ms count once
79 darbe[0] = darbe[1];
80 darbe[1] = darbe[2];
81 darbe[2] = simdi;
82 if (darbe[0] != 0 && simdi - darbe[0] <= 3000) sonuc = true;
83 }
84 oncekiTitresim = okuma;
85 return sonuc;
86}
87
88void bip(unsigned long ms) { // kısa = tuş sesi, uzun = hata / short = key click, long = error
89 bipZamani = millis();
90 bipSuresi = ms;
91}
92
93void sirenYaz(bool acik) {
94 sirenAcik = acik;
95 if (ROLE_AKTIF_LOW) digitalWrite(ROLE_PIN, acik ? LOW : HIGH);
96 else digitalWrite(ROLE_PIN, acik ? HIGH : LOW);
97}
98
99void durumDegis(Durum yeni) {
100 durum = yeni;
101 durumZamani = millis();
102 Serial.print(F("Durum / state: "));
103 Serial.println(DURUM_ADI[yeni]);
104}
105
106void alarmVer(const char* bolge) {
107 tetikleyen = bolge;
108 sirenYaz(true);
109 durumDegis(ALARM);
110 Serial.print(F("ALARM! Bolge / zone: "));
111 Serial.println(bolge);
112}
113
114bool kurulabilirMi() { // açık kapı ya da kesik ışınla kurulmaz / never arm with an open door or a broken beam
115 if (gKapi.kararli) {
116 Serial.println(F("Kapi acik, kurulamaz / door open, cannot arm"));
117 return false;
118 }
119 if (LAZER_VAR && gLazer.kararli) {
120 Serial.println(F("Lazer kesik, kurulamaz / beam broken, cannot arm"));
121 return false;
122 }
123 return true;
124}
125
126void kur(bool evde) {
127 if (!kurulabilirMi()) {
128 bip(800);
129 return;
130 }
131 evdeModu = evde;
132 for (int i = 0; i < 3; i++) darbe[i] = 0;
133 tetikleyen = "";
134 durumDegis(CIKIS_GECIKMESI);
135 Serial.println(evde ? F("Evde modu: PIR devre disi / stay mode: PIR bypassed") : F("Tam kurulum / away mode"));
136}
137
138void coz() {
139 sirenYaz(false);
140 if (tetikleyen[0] != '\0') { // alarm hafızası / alarm memory
141 Serial.print(F("Alarm hafizasi / alarm memory: "));
142 Serial.println(tetikleyen);
143 }
144 durumDegis(COZULU);
145 bip(150);
146}
147
148void sensorRaporu() {
149 Serial.print(F("Kapi / door: "));
150 Serial.print(gKapi.kararli ? F("ACIK / open") : F("kapali / closed"));
151 Serial.print(F(" PIR: "));
152 Serial.print(digitalRead(PIR_PIN));
153 Serial.print(F(" Lazer / laser: "));
154 Serial.println(analogRead(LAZER_PIN));
155}
156
157void tusIsle(char t) {
158 if (t >= '0' && t <= '9') {
159 if (haneSayisi < 8) {
160 girilen[haneSayisi++] = t;
161 girilen[haneSayisi] = '\0';
162 }
163 bip(30);
164 return;
165 }
166 if (t == '*' || t == 'C') { // girilen kodu sil / clear the typed code
167 haneSayisi = 0;
168 girilen[0] = '\0';
169 bip(30);
170 return;
171 }
172 if (t == 'D') { // bölge testi / zone test
173 sensorRaporu();
174 return;
175 }
176
177 // A, B ve # önce şifre ister / A, B and # need the code first
178 bool dogru = strcmp(girilen, SIFRE) == 0;
179 haneSayisi = 0;
180 girilen[0] = '\0';
181 if (kilitli) {
182 Serial.println(F("Tus takimi kilitli / keypad locked"));
183 bip(800);
184 return;
185 }
186 if (!dogru) {
187 Serial.println(F("Yanlis sifre / wrong code"));
188 if (++yanlisSayisi >= 3) {
189 kilitli = true;
190 kilitZamani = millis();
191 yanlisSayisi = 0;
192 }
193 bip(800);
194 return;
195 }
196 yanlisSayisi = 0;
197 if (durum == COZULU && t == 'A') kur(false); // tam kurulum / away
198 else if (durum == COZULU && t == 'B') kur(true); // evde modu / stay
199 else if (durum != COZULU && t == '#') coz(); // çöz / disarm
200 else bip(800);
201}
202
203void cikislariGuncelle() {
204 unsigned long simdi = millis();
205 unsigned long gecen = simdi - durumZamani;
206 bool buzzer = simdi - bipZamani < bipSuresi; // tuş sesi / key click
207 bool kirmizi = false;
208
209 switch (durum) {
210 case CIKIS_GECIKMESI: {
211 unsigned long periyot = (gecen > CIKIS_SURE - 10000) ? 250 : 1000; // son 10 sn hızlanır / faster in the last 10 s
212 buzzer = buzzer || (gecen % periyot) < 60;
213 kirmizi = (gecen % 1000) < 500;
214 break;
215 }
216 case KURULU:
217 kirmizi = true;
218 break;
219 case GIRIS_GECIKMESI:
220 buzzer = buzzer || (gecen % 400) < 200; // "şifreni gir" uyarısı / "enter your code" warning
221 kirmizi = (gecen % 400) < 200;
222 break;
223 case ALARM:
224 buzzer = buzzer || sirenAcik;
225 kirmizi = (gecen % 200) < 100; // hızlı yanıp sönme = alarm hafızası / fast blink = alarm memory
226 break;
227 default:
228 break;
229 }
230 bool hazir = !gKapi.kararli && !(LAZER_VAR && gLazer.kararli);
231 digitalWrite(BUZZER_PIN, buzzer ? HIGH : LOW);
232 digitalWrite(KIRMIZI_LED, kirmizi ? HIGH : LOW);
233 digitalWrite(YESIL_LED, (durum == COZULU && hazir) ? HIGH : LOW);
234}
235
236void setup() {
237 Serial.begin(9600);
238 sirenYaz(false); // pin çıkış olmadan önce "kapalı" yaz, açılışta röle çekmez / write "off" first so the relay doesn't click at boot
239 pinMode(ROLE_PIN, OUTPUT);
240 pinMode(BUZZER_PIN, OUTPUT);
241 pinMode(KIRMIZI_LED, OUTPUT);
242 pinMode(YESIL_LED, OUTPUT);
243 pinMode(PIR_PIN, INPUT);
244 pinMode(KAPI_PIN, INPUT_PULLUP); // kapı kapalı = LOW; kablo kesilirse HIGH / door closed = LOW; a cut wire reads HIGH
245 pinMode(TITRESIM_PIN, INPUT);
246 keypad.setDebounceTime(20);
247 durumDegis(COZULU);
248 Serial.println(F("PIR 60 sn isiniyor / PIR warming up for 60 s"));
249}
250
251void loop() {
252 char t = keypad.getKey();
253 if (t) tusIsle(t);
254
255 unsigned long simdi = millis();
256 if (kilitli && simdi - kilitZamani >= KILIT_SURE) kilitli = false;
257 if (!pirHazir && simdi >= PIR_ISINMA) pirHazir = true;
258
259 bool kapiAcik = suz(gKapi, digitalRead(KAPI_PIN) == HIGH, 50);
260 bool hareket = suz(gPir, digitalRead(PIR_PIN) == HIGH, 200) && pirHazir;
261 bool isinKesik = LAZER_VAR && suz(gLazer, analogRead(LAZER_PIN) < LAZER_ESIK, 30);
262 bool titresim = titresimVar(simdi);
263
264 switch (durum) {
265 case CIKIS_GECIKMESI:
266 if (simdi - durumZamani >= CIKIS_SURE) durumDegis(KURULU);
267 break;
268 case KURULU: // anlık bölgeler önce / instant zones first
269 if (titresim) alarmVer("Pencere (titresim) / window (vibration)");
270 else if (isinKesik) alarmVer("Lazer bariyeri / laser beam");
271 else if (hareket && !evdeModu) alarmVer("Ic mekan (PIR) / interior (PIR)");
272 else if (kapiAcik) durumDegis(GIRIS_GECIKMESI);
273 break;
274 case GIRIS_GECIKMESI: // PIR ve lazer giriş süresince bekler / PIR and laser wait during the entry delay
275 if (titresim) alarmVer("Pencere (titresim) / window (vibration)");
276 else if (simdi - durumZamani >= GIRIS_SURE) alarmVer("Giris kapisi / entry door");
277 break;
278 case ALARM:
279 if (sirenAcik && simdi - durumZamani >= SIREN_SURE) {
280 sirenYaz(false); // siren susar, hafıza kalır / siren stops, memory stays
281 Serial.println(F("Siren sustu, sifre bekleniyor / siren off, waiting for the code"));
282 }
283 break;
284 default:
285 break;
286 }
287 cikislariGuncelle();
288}Kodun belkemiği suz() fonksiyonudur. Her girişin ham değeri değiştiğinde bir zaman damgası alınır ve değer belirli bir süre (kapı için 50 ms, PIR için 200 ms, lazer için 30 ms) aynı kalmadıkça kararlı durum değişmez. Bu basit süzgeç, uzun kablolarda oluşan kısa parazitlerin ve kontak sıçramalarının alarm çaldırmasını engeller. Kapı pininin INPUT_PULLUP ile okunması da bilinçli bir seçimdir: kapı kapalıyken reed pini GND'ye bağlar ve LOW okunur; kapı açıldığında ya da biri kabloyu kestiğinde pin HIGH olur. Alarm sistemlerindeki bu kapalı devre mantığı, kablo kesmeyi kapı açmakla aynı sayar.
Titreşim için farklı bir yöntem kullanılır. SW-420 tek bir vuruşta bile birkaç milisaniye içinde defalarca seker; titresimVar() önce 150 ms içindeki sekmeleri tek olay sayar, sonra son üç olayın zamanını saklar. Üç olay 3 saniyenin içine sığarsa bu gerçek bir zorlama kabul edilir; kapıyı çarpan rüzgâr ya da cama çarpan tek bir top alarm vermez. Siren 3 dakika sonra kendiliğinden susar ama sistem ALARM durumunda kalır ve kırmızı LED hızlı yanıp sönerek eve dönen kişiye alarm olduğunu haber verir. Doğru şifreyi girdiğinde tetikleyen değişkeninde saklanan bölge adı Seri Monitör'e yazılır; bu, ticari panellerdeki alarm hafızasının küçük bir karşılığıdır.
Giriş ve çıkış gecikmesi nasıl ayarlanır?
Gecikmeler çok kısa olursa kendi evinde alarm çaldırırsın, çok uzun olursa hırsıza zaman tanırsın. Çıkış süresini keypad'den kapıya yürüyüp kapıyı kilitlemenin aldığı sürenin iki katı, giriş süresini de kapıyı açıp keypad'e yürüyerek şifreyi girmenin aldığı sürenin yaklaşık iki katı olarak seç. Ticari panellerde çıkış için 30–60 saniye, giriş için 15–30 saniye yaygındır. Keypad'i kapının hemen yanına, ama dışarıdan görünmeyecek bir yere koymak giriş süresini kısaltmanı sağlar. Buzzer'ın davranışı da önemlidir: çıkışta saniyede bir çalan kısa bip son 10 saniyede hızlanarak sürenin bittiğini hissettirir; girişte ise 200 ms'lik kesik ötüş sana şifre girmen gerektiğini hatırlatır.
Siren ve röle bağlantısı
Siren devresinde Arduino yalnızca rölenin bobinini sürer; 12 V'luk siren akımı rölenin kontaklarından geçer. Röle modüllerinin çoğu aktif LOW çalışır, yani IN pinine LOW verildiğinde çeker; kodda ROLE_AKTIF_LOW sabiti bu yüzden var. Kod, pini çıkış yapmadan önce kapalı seviyesini yazar; böylece Arduino açılırken röle bir anlığına çekip sireni öttürmez. Siren seçerken akım değerine bak: 110 dB'lik küçük 12 V sirenler genellikle 0,1–0,3 A çeker ve bu, 10 A'lik bir röle kontağı için çok küçük bir yüktür. Flaşörlü bir dış siren hem sesle hem ışıkla caydırır ve komşuların alarmın nereden geldiğini görmesini sağlar. Profesyonel paneller sireni çoğunlukla 3 dakika sonra susturur; bazı ülkelerde bunun için yasal bir üst sınır da vardır, bu yüzden SIREN_SURE değerini makul tut. Röle yerine yarı iletken bir anahtar tercih edersen lojik seviye bir MOSFET kullanabilir, bobinli (elektromanyetik) sirenlerde uçlara ters yönde bir diyot ekleyebilirsin.
ESP32 ile Telegram bildirimi
Kimsenin duymadığı bir siren işe yaramaz; evden uzaktayken alarmın çaldığını öğrenmenin en kolay yolu ESP32 ve Telegram'dır. ESP32, Wi-Fi'ye bağlanıp Telegram sunucusuna şifreli bir bağlantıyla mesaj gönderir; sen de ona komut yazabilirsin. BotFather ile bot oluşturmayı, token ve chat ID almayı, UniversalTelegramBot ile ArduinoJson kütüphanelerini kurmayı ESP32 Telegram bot yazısında adım adım anlattık. Bu sürümde keypad yok; sistem telefondan /kur (tam kurulum), /evde (evde modu), /coz (çöz) ve /durum komutlarıyla yönetilir. Bot yalnızca senin chat ID'ne yanıt verir, başka birinin yazdığı komutlar sessizce yok sayılır.
1// ESP32 alarm sistemi + Telegram: kurma/çözme komutları ve anlık bildirim / ESP32 alarm + Telegram: arm/disarm commands and instant alerts
2#include <WiFi.h>
3#include <WiFiClientSecure.h>
4#include <UniversalTelegramBot.h> // ArduinoJson kütüphanesi de gerekir / also needs ArduinoJson
5#include <Preferences.h> // kurulu durumu elektrik kesintisinde unutmamak için / remembers the armed state across power cuts
6
7const char* WIFI_SSID = "AgAdi"; // Wi-Fi adın (yalnız 2,4 GHz) / your Wi-Fi name (2.4 GHz only)
8const char* WIFI_PASS = "Sifre123"; // Wi-Fi şifren / your Wi-Fi password
9#define BOT_TOKEN "1234567890:AAExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" // BotFather'dan / from BotFather
10#define CHAT_ID "123456789" // yalnız bu ID komut verebilir / only this ID may send commands
11
12const int PIR_PIN = 27; // HC-SR501 OUT
13const int KAPI_PIN = 33; // reed, diğer ucu GND / reed, other leg to GND
14const int TITRESIM_PIN = 32; // SW-420 DO
15const int BUZZER_PIN = 25; // aktif buzzer / active buzzer
16const int ROLE_PIN = 26; // siren rölesi / siren relay
17const int LED_PIN = 2; // dahili LED: kurulu / onboard LED: armed
18const bool ROLE_AKTIF_LOW = true; // çoğu röle modülü LOW'da çeker / most relay modules switch on with LOW
19
20const unsigned long CIKIS_SURE = 30000; // çıkış gecikmesi / exit delay
21const unsigned long GIRIS_SURE = 20000; // giriş gecikmesi / entry delay
22const unsigned long SIREN_SURE = 180000; // siren en fazla 3 dk / siren for at most 3 min
23const unsigned long PIR_ISINMA = 60000; // PIR ısınma süresi / PIR warm-up time
24const unsigned long KONTROL_ARALIGI = 2000; // Telegram'a 2 sn'de bir sor / poll Telegram every 2 s
25
26WiFiClientSecure client;
27UniversalTelegramBot bot(BOT_TOKEN, client);
28Preferences ayar;
29
30enum Durum { COZULU, CIKIS_GECIKMESI, KURULU, GIRIS_GECIKMESI, ALARM };
31const char* const DURUM_ADI[] = { "ÇÖZÜLÜ / DISARMED", "ÇIKIŞ GECİKMESİ / EXIT DELAY", "KURULU / ARMED", "GİRİŞ GECİKMESİ / ENTRY DELAY", "ALARM" };
32
33struct Giris { // gürültü süzgeçli giriş / debounced input
34 bool ham;
35 bool kararli;
36 unsigned long degisim;
37};
38Giris gKapi = {false, false, 0};
39Giris gPir = {false, false, 0};
40
41Durum durum = COZULU;
42unsigned long durumZamani = 0;
43bool evdeModu = false;
44bool sirenAcik = false;
45bool pirHazir = false;
46String tetikleyen = "";
47String bekleyen = ""; // gönderilemeyen bildirimler / notifications not sent yet
48unsigned long sonDeneme = 0;
49unsigned long sonKontrol = 0;
50
51volatile unsigned long darbe[3] = {0, 0, 0}; // son 3 titreşim olayı / last 3 vibration events
52volatile bool zorlama = false; // 3 sn'de 3 darbe oldu / 3 hits within 3 s
53
54// Kesme: Telegram beklerken de kısa darbeler kaçmaz / interrupt: short pulses are caught even while Telegram blocks
55void IRAM_ATTR titresimKesmesi() {
56 unsigned long simdi = millis();
57 if (simdi - darbe[2] > 150) { // 150 ms içindeki sekmeler tek olay / bounces within 150 ms count once
58 darbe[0] = darbe[1];
59 darbe[1] = darbe[2];
60 darbe[2] = simdi;
61 if (darbe[0] != 0 && simdi - darbe[0] <= 3000) zorlama = true;
62 }
63}
64
65bool suz(Giris &g, bool okuma, unsigned long sure) {
66 unsigned long simdi = millis();
67 if (okuma != g.ham) {
68 g.ham = okuma;
69 g.degisim = simdi;
70 }
71 if (simdi - g.degisim >= sure) g.kararli = g.ham;
72 return g.kararli;
73}
74
75void sirenYaz(bool acik) {
76 sirenAcik = acik;
77 if (ROLE_AKTIF_LOW) digitalWrite(ROLE_PIN, acik ? LOW : HIGH);
78 else digitalWrite(ROLE_PIN, acik ? HIGH : LOW);
79}
80
81void bekleyeniGonder() {
82 sonDeneme = millis();
83 if (WiFi.status() != WL_CONNECTED) {
84 WiFi.reconnect(); // bağlantı koptuysa yeniden dene / reconnect if the link dropped
85 return;
86 }
87 if (bot.sendMessage(CHAT_ID, bekleyen, "")) bekleyen = "";
88}
89
90void bildir(const String& metin) { // gönderemezse 15 sn sonra yeniden dener / retries after 15 s if sending fails
91 Serial.println(metin);
92 bekleyen += metin + "\n";
93 if (bekleyen.length() > 1200) bekleyen = bekleyen.substring(bekleyen.length() - 1200);
94 bekleyeniGonder();
95}
96
97void durumDegis(Durum yeni) {
98 durum = yeni;
99 durumZamani = millis();
100 if (yeni == KURULU || yeni == COZULU) { // yalnız kurma ve çözmede yazılır / written only on arm and disarm
101 ayar.putBool("kurulu", yeni == KURULU);
102 ayar.putBool("evde", evdeModu);
103 }
104}
105
106void alarmVer(const String& bolge) {
107 tetikleyen = bolge;
108 sirenYaz(true); // önce siren, sonra mesaj / siren first, message second
109 durumDegis(ALARM);
110 bildir("ALARM! " + bolge);
111}
112
113void kur(bool evde) {
114 if (gKapi.kararli) {
115 bildir("Kapı açık, kurulamadı / door open, not armed");
116 return;
117 }
118 evdeModu = evde;
119 for (int i = 0; i < 3; i++) darbe[i] = 0;
120 zorlama = false;
121 tetikleyen = "";
122 durumDegis(CIKIS_GECIKMESI);
123 bildir(evde ? "Evde modu, 30 sn sonra kurulu (PIR kapalı) / stay mode, armed in 30 s (PIR off)"
124 : "Tam kurulum, 30 sn içinde çık / away mode, leave within 30 s");
125}
126
127void coz() {
128 sirenYaz(false);
129 String m = "Alarm çözüldü / disarmed";
130 if (tetikleyen.length()) m += "\nAlarm hafızası / memory: " + tetikleyen;
131 tetikleyen = "";
132 durumDegis(COZULU);
133 bildir(m);
134}
135
136String durumMetni() {
137 String s = String("Durum / state: ") + DURUM_ADI[durum];
138 if (evdeModu && durum != COZULU) s += " (evde / stay)";
139 s += "\nKapı / door: ";
140 s += gKapi.kararli ? "AÇIK / open" : "kapalı / closed";
141 s += "\nWi-Fi: " + String(WiFi.RSSI()) + " dBm";
142 return s;
143}
144
145void mesajlariIsle(int adet) {
146 for (int i = 0; i < adet; i++) {
147 String chatId = bot.messages[i].chat_id;
148 String metin = bot.messages[i].text;
149 if (chatId != CHAT_ID) continue; // yabancıya yanıt yok / strangers get no answer
150
151 int at = metin.indexOf('@'); // "/kur@bot_adi" -> "/kur"
152 if (at > 0) metin = metin.substring(0, at);
153
154 if (metin == "/kur" && durum == COZULU) kur(false);
155 else if (metin == "/evde" && durum == COZULU) kur(true);
156 else if (metin == "/coz" && durum != COZULU) coz();
157 else if (metin == "/durum") bildir(durumMetni());
158 else bot.sendMessage(chatId, "/kur /evde /coz /durum\n" + durumMetni(), "");
159 }
160}
161
162void setup() {
163 Serial.begin(115200);
164 pinMode(ROLE_PIN, OUTPUT);
165 sirenYaz(false); // açılışta siren kapalı / siren off at boot
166 pinMode(BUZZER_PIN, OUTPUT);
167 pinMode(LED_PIN, OUTPUT);
168 pinMode(PIR_PIN, INPUT);
169 pinMode(KAPI_PIN, INPUT_PULLUP); // kapı kapalı = LOW, açık ya da kablo kesik = HIGH / closed = LOW, open or cut = HIGH
170 pinMode(TITRESIM_PIN, INPUT);
171 attachInterrupt(digitalPinToInterrupt(TITRESIM_PIN), titresimKesmesi, RISING);
172
173 ayar.begin("alarm", false);
174 if (ayar.getBool("kurulu", false)) { // kesintiden önce kuruluysa kurulu başla / start armed if it was armed before the outage
175 evdeModu = ayar.getBool("evde", false);
176 durumDegis(KURULU);
177 }
178
179 WiFi.mode(WIFI_STA);
180 WiFi.begin(WIFI_SSID, WIFI_PASS);
181 unsigned long bas = millis();
182 while (WiFi.status() != WL_CONNECTED && millis() - bas < 20000) delay(500); // Wi-Fi yoksa alarm yine çalışır / the alarm works without Wi-Fi too
183 client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // api.telegram.org kök sertifikası / root certificate of api.telegram.org
184 if (WiFi.status() == WL_CONNECTED) {
185 while (bot.getUpdates(bot.last_message_received + 1)) { } // kapalıyken gelen eski komutları atla / skip commands sent while off
186 }
187 bildir(String("Sistem açıldı (elektrik geldi mi?) / system started (power restored?)\n") + durumMetni());
188}
189
190void loop() {
191 unsigned long simdi = millis();
192 if (!pirHazir && simdi >= PIR_ISINMA) pirHazir = true;
193 bool kapiAcik = suz(gKapi, digitalRead(KAPI_PIN) == HIGH, 50);
194 bool hareket = suz(gPir, digitalRead(PIR_PIN) == HIGH, 200) && pirHazir;
195 bool titresim = zorlama;
196 zorlama = false;
197
198 switch (durum) {
199 case CIKIS_GECIKMESI:
200 if (simdi - durumZamani >= CIKIS_SURE) {
201 durumDegis(KURULU);
202 bildir("Sistem kuruldu / system armed");
203 }
204 break;
205 case KURULU:
206 if (titresim) alarmVer("Pencere (titreşim) / window (vibration)");
207 else if (hareket && !evdeModu) alarmVer("İç mekân (PIR) / interior (PIR)");
208 else if (kapiAcik) {
209 durumDegis(GIRIS_GECIKMESI);
210 bildir("Kapı açıldı, 20 sn giriş süresi / door opened, 20 s entry delay");
211 }
212 break;
213 case GIRIS_GECIKMESI:
214 if (titresim) alarmVer("Pencere (titreşim) / window (vibration)");
215 else if (simdi - durumZamani >= GIRIS_SURE) alarmVer("Giriş kapısı / entry door");
216 break;
217 case ALARM:
218 if (sirenAcik && simdi - durumZamani >= SIREN_SURE) {
219 sirenYaz(false);
220 bildir("Siren sustu, alarm hafızada / siren stopped, alarm kept in memory");
221 }
222 break;
223 default:
224 break;
225 }
226
227 unsigned long gecen = millis() - durumZamani;
228 bool buzzer = false;
229 if (durum == CIKIS_GECIKMESI) buzzer = (gecen % 1000) < 60;
230 else if (durum == GIRIS_GECIKMESI) buzzer = (gecen % 400) < 200;
231 else if (durum == ALARM) buzzer = sirenAcik;
232 digitalWrite(BUZZER_PIN, buzzer ? HIGH : LOW);
233 digitalWrite(LED_PIN, (durum == KURULU || durum == ALARM) ? HIGH : LOW);
234
235 if (millis() - sonKontrol > KONTROL_ARALIGI && WiFi.status() == WL_CONNECTED) {
236 int adet = bot.getUpdates(bot.last_message_received + 1);
237 while (adet) {
238 mesajlariIsle(adet);
239 adet = bot.getUpdates(bot.last_message_received + 1);
240 }
241 sonKontrol = millis();
242 }
243 if (bekleyen.length() && millis() - sonDeneme > 15000) bekleyeniGonder();
244}ESP32 kodunda üç önemli fark var. Birincisi, Telegram'a mesaj göndermek ya da yeni komutları sormak 1–2 saniye sürebilir ve bu sırada loop() bekler. Açık kalan kapı ve en az birkaç saniye HIGH kalan PIR bu beklemeden etkilenmez, ama SW-420'nin milisaniyelik darbeleri kaçabilir; bu yüzden titreşim bir kesmeyle (attachInterrupt) yakalanır. İkincisi, alarmVer() önce sireni açar, sonra mesajı gönderir; internet ne kadar yavaş olursa olsun siren gecikmez. Gönderilemeyen bildirimler bir kuyruğa eklenir ve 15 saniyede bir yeniden denenir. Üçüncüsü, Preferences kütüphanesi kurulu olup olmadığını flash belleğe yazar: sistem kuruluyken elektrik kesilip geri gelirse ESP32 kurulu olarak açılır ve sana elektriğin geldiğini haber verir. Röle ve siren ESP32 ile aynı zayıf beslemeyi paylaşıyorsa kart Brownout detector was triggered hatasıyla yeniden başlayabilir; çözümünü ESP32 sürekli yeniden başlıyor yazısında bulabilirsin.
Raspberry Pi Pico ve MicroPython ile alarm
Aynı durum makinesini Raspberry Pi Pico'da MicroPython ile kısa bir programla kurabilirsin. Keypad, keypad yazısındaki satır-sütun tarama fonksiyonuyla okunur; satırlar GP2–GP5'te, sütunlar dahili pull-up ile GP6–GP9'dadır. PIR'ı VBUS'tan (5 V) besle; çıkışı zaten 3,3 V olduğu için GP16'ya doğrudan bağlanır. SW-420'yi ise mutlaka 3V3(OUT) pininden besle, çünkü 5 V ile beslenen modülün çıkışı Pico'nun girişine zarar verebilir. Titreşim darbeleri Pin.irq ile yakalanıp zamanları bir listede tutulur, durumlar ise basit metinlerle izlenir. Süre hesapları time.ticks_diff() ile yapılır, çünkü bu fonksiyon zamanlayıcı başa döndüğünde bile doğru farkı verir.
1# Raspberry Pi Pico alarm: keypad + PIR + kapı + titreşim, durum makinesi / Pico alarm: keypad + PIR + door + vibration, state machine
2from machine import Pin
3import time
4
5SIFRE = "2580" # kendi şifreni yaz / set your own code
6CIKIS_MS, GIRIS_MS, SIREN_MS = 30000, 20000, 180000
7
8KEYS = ["123A", "456B", "789C", "*0#D"]
9rows = [Pin(n, Pin.OUT, value=1) for n in (2, 3, 4, 5)] # R1–R4
10cols = [Pin(n, Pin.IN, Pin.PULL_UP) for n in (6, 7, 8, 9)] # C1–C4
11pir = Pin(16, Pin.IN) # HC-SR501 OUT (3,3 V)
12kapi = Pin(15, Pin.IN, Pin.PULL_UP) # reed, diğer ucu GND / reed, other leg to GND
13titresim = Pin(17, Pin.IN) # SW-420 DO, modül 3V3'ten / module powered from 3V3
14buzzer = Pin(14, Pin.OUT, value=0) # aktif buzzer / active buzzer
15role = Pin(13, Pin.OUT, value=1) # aktif LOW röle: 1 = kapalı / active-LOW relay: 1 = off
16led = Pin("LED", Pin.OUT) # dahili LED: kurulu / onboard LED: armed
17
18darbeler = [] # son titreşim zamanları / recent vibration times
19son_darbe = 0
20
21
22def titresim_irq(p):
23 global son_darbe
24 simdi = time.ticks_ms()
25 if time.ticks_diff(simdi, son_darbe) > 150: # sekmeler tek olay / bounces count once
26 son_darbe = simdi
27 darbeler.append(simdi)
28
29
30titresim.irq(trigger=Pin.IRQ_RISING, handler=titresim_irq)
31
32
33def tus_oku():
34 for r, row in enumerate(rows):
35 row.value(0) # bu satırı etkinleştir / activate this row
36 for c, col in enumerate(cols):
37 if col.value() == 0:
38 row.value(1)
39 return KEYS[r][c]
40 row.value(1)
41 return None
42
43
44durum = "COZULU"
45zaman = time.ticks_ms()
46acilis = time.ticks_ms()
47pir_hazir = False
48evde = False
49girilen = ""
50son_tus = None
51
52
53def degis(yeni):
54 global durum, zaman
55 durum, zaman = yeni, time.ticks_ms()
56 print("Durum / state:", yeni)
57
58
59def alarm(bolge):
60 role.value(0) # siren açık / siren on
61 degis("ALARM")
62 print("ALARM! Bolge / zone:", bolge)
63
64
65while True:
66 tus = tus_oku()
67 if tus != son_tus: # değişimi 20 ms sonra doğrula / confirm the change after 20 ms
68 time.sleep_ms(20)
69 if tus_oku() != tus:
70 tus = son_tus # sekme, yok say / contact bounce, ignore it
71 if tus and tus != son_tus: # her basış bir kez / each press once
72 if tus in "0123456789":
73 girilen = (girilen + tus)[-8:]
74 elif tus in "*C":
75 girilen = ""
76 else:
77 dogru = girilen == SIFRE
78 girilen = ""
79 if not dogru:
80 print("Yanlis sifre / wrong code")
81 elif durum == "COZULU" and tus in "AB":
82 if kapi.value():
83 print("Kapi acik, kurulamaz / door open, cannot arm")
84 else:
85 evde = tus == "B" # B = evde modu, PIR kapalı / B = stay mode, PIR off
86 darbeler.clear()
87 degis("CIKIS")
88 elif durum != "COZULU" and tus == "#":
89 role.value(1)
90 degis("COZULU")
91 son_tus = tus
92
93 simdi = time.ticks_ms()
94 gecen = time.ticks_diff(simdi, zaman)
95 if not pir_hazir and time.ticks_diff(simdi, acilis) > 60000:
96 pir_hazir = True # PIR ısındı / PIR warmed up
97 kapi_acik = kapi.value() == 1
98 hareket = pir_hazir and pir.value() == 1 and not evde
99 darbeler[:] = [t for t in darbeler if time.ticks_diff(simdi, t) < 3000]
100 zorlama = len(darbeler) >= 3 # 3 sn'de 3 darbe / 3 hits in 3 s
101
102 if durum == "CIKIS" and gecen >= CIKIS_MS:
103 degis("KURULU")
104 elif durum == "KURULU":
105 if zorlama:
106 alarm("Pencere / window")
107 elif hareket:
108 alarm("PIR")
109 elif kapi_acik:
110 degis("GIRIS")
111 elif durum == "GIRIS":
112 if zorlama:
113 alarm("Pencere / window")
114 elif gecen >= GIRIS_MS:
115 alarm("Kapi / door")
116 elif durum == "ALARM" and role.value() == 0 and gecen >= SIREN_MS:
117 role.value(1) # siren susar, hafıza kalır / siren stops, memory stays
118
119 gecen = time.ticks_diff(time.ticks_ms(), zaman)
120 if durum == "CIKIS":
121 buzzer.value(1 if gecen % 1000 < 60 else 0)
122 elif durum == "GIRIS":
123 buzzer.value(1 if gecen % 400 < 200 else 0)
124 else:
125 buzzer.value(1 if durum == "ALARM" and role.value() == 0 else 0)
126 led.value(1 if durum in ("KURULU", "ALARM") else 0)
127 time.sleep_ms(10)Yanlış alarmı azaltmanın yolları
Bir alarm sisteminin en büyük düşmanı hırsız değil, yanlış alarmdır: üç kez boşuna çalan bir sireni ne sen ne de komşuların ciddiye alır. Aşağıdaki önlemlerin bir kısmı kodda zaten var, kalanı montaj ve kablolamayla ilgili:
- Isınma süresini bekle: PIR açılıştan sonraki 30–60 saniye içinde kendiliğinden tetiklenebilir; kod ilk 60 saniyeyi yok sayar.
- Süzgeç kullan: Her girişin belirli bir süre kararlı kalmasını beklemek (debounce), kablolardaki kısa parazitleri ayıklar.
- Darbe say: Titreşimde tek vuruş yerine 3 saniyede 3 darbe aramak rüzgârı, geçen kamyonu ve kapı çarpmasını eler. Gerekirse sayıyı 4–5'e çıkar ya da karttaki potla hassasiyeti düşür.
- PIR'ı doğru yere koy: Kalorifere, klimaya, güneş alan pencereye ve perdeye doğrultma; en iyi algılama, hareket görüş alanını yandan yana kestiğinde olur. Evcil hayvanın varsa sensörü yükseğe takıp hafif aşağı baktır ve hassasiyeti düşür.
- İki sensör birden iste: Kritik bölgelerde PIR ile lazerin ya da PIR ile kapının birkaç saniye arayla tetiklenmesini şart koşmak (çapraz bölge), tek bir sensörün hatasının alarma dönüşmesini önler.
- Beslemeyi temizle: Röle çektiğinde beslemede oluşan çöküntü PIR'ı tetikleyebilir. Sensörlerin VCC ile GND uçları arasına 100 µF ve 100 nF kondansatör koy, röle ve siren kablolarını sensör kablolarından ayrı götür.
- Uzun kablolarda harici pull-up kullan: Arduino'nun dahili pull-up direnci 20–50 kΩ'dur ve 10 metrelik bir kabloda parazite açıktır; 4,7 kΩ'luk harici direnç ve pine eklenen 100 nF kondansatör hattı sağlamlaştırır.
- Lazeri ortam ışığından koru: LDR'yi siyah bir borunun içine yerleştir ve eşiği hem gün ışığında hem gece ayrı ayrı test et.
Sık yapılan hatalar ve çözümleri
- Sistem kurulur kurulmaz alarm veriyor: PIR hâlâ ısınıyor ya da kapı kontağı yanlış bağlanmış. Sensör testinde kapı kapalıyken LOW okunmalı; HIGH okunuyorsa mıknatıs uzakta ya da kablolardan biri kopuk.
- Keypad tepki vermiyor ya da yanlış tuşu okuyor: Satır ve sütun kabloları yer değiştirmiş. Kabloları sökmek yerine koddaki satirPinleri ve sutunPinleri dizilerinin sırasını değiştir.
- Kurmaya çalışınca uzun bip duyuluyor: Bu bir arıza değil, hazır değil uyarısıdır: kapı açık ya da lazer ışını LDR'ye ulaşmıyor. D tuşuyla bölgelerin durumuna bak.
- Röle açılışta bir anlığına çekiyor: Pin çıkış yapılmadan önce kapalı seviyesi yazılmamış ya da röle aktif HIGH olduğu hâlde ROLE_AKTIF_LOW true bırakılmış.
- Siren çalınca Arduino resetleniyor: Siren ve Arduino aynı zayıf adaptörü paylaşıyor ve gerilim düşümü kartı yeniden başlatıyor. Daha güçlü bir adaptör, ayrı bir düşürücü ve kalın kablo kullan; ayrıntılar Arduino kendi kendine resetleniyor yazısında.
- Titreşim sensörü hiç tetiklenmiyor ya da sürekli tetikleniyor: Karttaki potu yavaşça çevirerek eşiği ayarla ve sensörü cama ya da çerçeveye sıkıca yapıştır; gevşek duran bir sensör darbeyi iletmez.
- ESP32 mesaj göndermiyor: Token ya da chat ID yanlış, ağ 5 GHz ya da botu Telegram'da hiç başlatmamışsın. Bota bir kez /start yazmadan bot sana mesaj gönderemez.
- Lazer gündüz sorunsuz, gece yanlış alarm veriyor (ya da tersi): Eşik, ortam ışığının değerine çok yakın. İki ortamda da ışınlı ve ışınsız değeri ölç, LAZER_ESIK'i ortaya göre yeniden seç.
Alarm sistemini geliştirmek için fikirler
- Kartla kurma ve çözme: Keypad'in yanına bir RFID RC522 okuyucu ekleyip sistemi anahtarlıkla çöz.
- 24 saat bölgeleri: Bir MQ-2 gaz sensörü ya da alev sensörü ekleyip sistem çözülü olsa bile alarm veren bir gaz ve yangın bölgesi oluştur.
- Kablosuz kapı sensörleri: Uzaktaki pencereler için 433 MHz RF modüllerle pilli kapı kontakları yap.
- Ekranlı panel: I2C LCD'de geri sayımı, durumu ve alarm hafızasını göster.
- Akıllı ev entegrasyonu: ESP32'yi MQTT ve Home Assistant ile bağlayıp alarmı ışıklar ve kameralarla birlikte yönet.
- Sabotaj (tamper) kontağı: Kutunun kapağına bir mikro anahtar koy; kutu açılınca sistem çözülü olsa bile buzzer ötsün.
- Maket ev projesi: Bütün bu bölgeleri bir maket evde toplayıp akıllı ev projesinin güvenlik katmanı yap.
Arduino alarm sistemi; sensör okumayı, zamanlamayı, durum makinesini ve güç tasarımını tek bir projede birleştirdiği için öğrenmek açısından da çok değerlidir. Önce sensör testini çalıştır, ardından alarmı birkaç gün yalnızca buzzer ile dene ve sireni en son bağla. BlueGrays uygulamasında Reed Röle Kapı Sensörü, Lazerli Güvenlik Sistemi, 4x4 Keypad LCD Ekran Şifre Uygulaması ve Telegram bildirimli ESP32 Hareket Alarm Sistemi gibi projeleri adım adım devre şemaları ve kodlarıyla bulabilirsin.
Sıkça sorulan sorular
Arduino ile alarm sistemi nasıl yapılır?
Bir Arduino Uno'ya PIR hareket sensörü, kapı için reed kontak, keypad, aktif buzzer ve sireni süren bir röle modülü bağlarsın. Kod; sistemi çözülü, çıkış gecikmesi, kurulu, giriş gecikmesi ve alarm durumları arasında geçiren bir durum makinesiyle yazılır. Sistem keypad'den şifreyle kurulup çözülür, kuruluyken bir sensör tetiklenirse siren çalar.
Arduino alarm sistemi için hangi sensörler kullanılır?
En yaygın sensörler iç mekân için PIR hareket sensörü (HC-SR501), kapı ve pencereler için reed kontak (MC-38), cam darbeleri için SW-420 titreşim sensörü ve koridorlar için lazer bariyeridir. Bunlara gaz için MQ-2, yangın için alev sensörü eklenebilir. Her sensör ayrı bir bölge olarak tanımlanır ve kendine özgü bir davranışı olur.
Elektrik kesilince Arduino alarmı çalışır mı?
Yalnızca adaptörle besleniyorsa çalışmaz. 13,8 V çıkışlı, akü bağlantılı bir alarm güç kaynağı ve 12 V 7 Ah akü kullanırsan, yaklaşık 100 mA çeken bir Uno sistemi 4–5 gün çalışır. ESP32 sürümünde kurulu durum flash belleğe yazıldığı için elektrik gelince sistem kurulu olarak açılır; bildirimlerin gitmesi için modemin de UPS'e bağlı olması gerekir.
Arduino alarmı telefona bildirim gönderebilir mi?
Arduino Uno tek başına gönderemez, ama ESP32 Wi-Fi üzerinden Telegram'a anında mesaj gönderebilir ve telefondan /kur, /coz gibi komutlar alabilir. İnternetin olmadığı yerlerde SIM800L GSM modülüyle SMS gönderilebilir ya da arama yapılabilir. İki yöntemi birlikte kullanmak en güvenilir çözümdür.
PIR sensör neden yanlış alarm veriyor?
En sık nedenler açılıştaki 30–60 saniyelik ısınma süresi, kalorifer ve klima gibi ısı kaynakları, güneşte ısınıp sallanan perdeler ve röle çektiğinde beslemede oluşan gürültüdür. Isınma süresini kodda yok saymak, sensörü ısı kaynaklarından uzak tutmak ve VCC ile GND arasına kondansatör koymak sorunların çoğunu çözer.
Arduino alarm sistemi gerçek bir evde kullanılabilir mi?
Öğrenmek, bir odayı, garajı ya da depoyu izlemek için iyi çalışır, ama sertifikalı bir alarm sisteminin yerini tutmaz. Ticari sistemler EN 50131 gibi standartlara göre sabotaj koruması, yedek besleme, şifreli kablosuz haberleşme ve izleme merkezi bağlantısıyla test edilir. Arduino sistemini evde kullanacaksan yedek akü, sabotaj kontağı ve ikinci bir bildirim kanalı eklemeni öneririz.
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

Lazerli Güvenlik Sistemi
Filmlerdeki lazerli soygun sahneleri gibi: lazer ışını bir ışık sensörüne vurur, biri araya girip ışını kestiği an kırmızı LED yanar ve buzzer ötmeye başlar. Alarm kendiliğinden susmaz; butona basarak

Lazerli Uyarı Sistemi
Filmlerdeki gibi görünmez bir ışın çiti kuruyorsun. Lazer ışığı karşıdaki ışık sensörüne düşer; biri önünden geçip ışını kestiği an LED yanar ve buzzer öter, ışın geri gelince ikisi de susar. Kapı ya

Reed Röle Kapı Sensörü
Kapın açık mı kapalı mı, bir ışığa bakarak anla. Kapıya küçük bir mıknatıs, kasaya da mıknatısı hisseden bir anahtar takarsın; kapı kapalıyken ikisi yan yana durur ve yeşil LED yanar, kapı açılıp mıkn

4x4 Keypad LCD Ekran Şifre Uygulaması
Doğru şifreyi bilmeyenin giremediği küçük bir elektronik kapı kilidi. Kare tuşuna basıp şifreyi tuş takımından girersin; şifre doğruysa ekranda giriş izni yazar, yeşil LED yanar ve servo motor kapıyı

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

Akıllı Elektronik Kasa
Değerli eşyalarını saklayabileceğin, şifreyle açılan küçük bir kasa. Tuş takımından dört haneli şifreni girersin; doğruysa servo motor kilidi açar, yeşil ışık yanar ve ekran kasanın durumunu yazar, he
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ç

