Rehberler · 15 dk okuma

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.

HC-SR501 PIR hareket sensörü
HC-SR501 PIR hareket sensörü, alarm sisteminin iç mekân bölgesidir: beyaz Fresnel lensi görüş alanını onlarca küçük bölgeye ayırır, yanındaki iki potla algılama mesafesi ve çıkış süresi ayarlanır.

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ölgeSensörBölge tipiKurulu iken tetiklenirse
Giriş kapısıReed kontak (MC-38)Gecikmeli20 sn giriş süresi başlar; şifre girilmezse alarm
Salon, iç mekânPIR (HC-SR501)İç bölge (takipçi)Anında alarm; giriş süresi işliyorsa bekler; evde modunda kapalı
PencereTitreşim (SW-420)Anlık3 sn içinde 3 darbe gelirse anında alarm
Koridor, merdivenLazer + LDR (KY-008)İç bölge (takipçi)Anında alarm; giriş süresi işliyorsa bekler
Gaz, yangın, sabotajMQ-2, alev sensörü, kutu anahtarı24 saatSistem 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

MalzemeAdetGörevi
Arduino Uno (ya da Nano)1Sistemin 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)1Kapı ya da pencere açılınca devreyi açar
SW-420 titreşim sensörü modülü1Camdaki ve kasadaki darbeleri algılar
KY-008 lazer modülü + LDR + 10 kΩ direnç1 takımKoridoru kesen ışın bariyeri
4x4 membran keypad1Şifreyle kurma ve çözme
Aktif buzzer (5 V)1Tuş sesi, giriş-çıkış uyarısı, iç siren
1 kanallı 5 V röle modülü112 V sireni Arduino'dan yalıtarak çalıştırır
12 V siren (tercihen flaşörlü)1Asıl alarm sesi, genellikle 100–120 dB
Kırmızı ve yeşil LED + 2 adet 220 Ω direnç1 takımKurulu ve hazır göstergesi
12 V besleme, LM2596 modül, 12 V akü (isteğe bağlı)1 takımBesleme ve elektrik kesintisinde yedek
Breadboard, jumper kablo, 4 damarlı alarm kablosu-Bağlantılar ve uzaktaki sensörler
Arduino Uno
Arduino Uno
Reed
Reed
SW-420
SW-420
KY-008
KY-008
Keypad 4x4
Keypad 4x4
Buzzer
Buzzer
Relay 5 V
Relay 5 V

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.
KY-008, 3R sınıfı bir lazerdir; ışına doğrudan ya da bir ayna üzerinden bakmak gözüne zarar verebilir. Işını her zaman göz hizasının altında, örneğin yerden 20–40 cm yükseklikte tut. Bu yükseklik hem güvenlidir hem de içeri giren birinin ışını adım atarken kesmesini garanti eder.

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 UnoESP32Raspberry 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 / GND5V / D10 / GNDVIN (5V) / GPIO 27 / GNDVBUS / GP16 / GND
Reed kontak (2 kablo)D11 ve GNDGPIO 33 ve GNDGP15 ve GND
SW-420 VCC / DO / GND5V / D12 / GND3V3 / GPIO 32 / GND3V3(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)A1GPIO 25GP14
Röle modülü INA2GPIO 26GP13
Yeşil LED (220 Ω ile): hazırA3––
Kırmızı LED (220 Ω ile): kuruluD13GPIO 2 (dahili LED)Dahili LED
12 V sireni asla doğrudan Arduino pinine bağlama. Adaptörün artısı rölenin COM ucuna, rölenin NO ucu sirenin artısına, sirenin eksisi adaptörün eksisine gider; böylece siren akımı Arduino'dan hiç geçmez. ESP32 ve Pico'nun 3,3 V'luk pinleri bazı 5 V röle modüllerini tam bırakamaz ve röle sürekli çekili kalabilir; bu kartlarda 3,3 V uyumlu ya da yüksek seviye tetiklemeli bir modül veya NPN transistörlü bir sürücü kullan.

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

  1. 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.
  2. 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.
  3. 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.
  4. Reed kontağın iki kablosunu D11 ile GND'ye, SW-420'yi 5V, D12 ve GND'ye bağla.
  5. 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.
  6. 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.
  7. Önce aşağıdaki sensör testini yükle, Seri Monitör'ü 9600 baud'da aç ve her sensörü tek tek tetikle.
  8. 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.

C++ (Arduino IDE)
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}
Lazer bariyerinin eşiğini bu testle bulursun: ışın LDR'ye vururken okunan değeri (ör. 950) ve elini ışının önüne koyduğunda okunan değeri (ör. 250) not al, alarm kodundaki LAZER_ESIK değerini bu ikisinin ortasına (600) yaz. İki değer arasındaki fark 300'den azsa borunun boyunu uzat ya da lazeri yeniden hizala.

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.

DurumNe zaman girilir?Ne yapar?Çıkış koşulu
ÇÖZÜLÜAçılışta ve doğru şifre + # ileSensö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ırSüre dolunca KURULU; şifre + # ile ÇÖZÜLÜ
KURULUÇıkış süresi doluncaBütün bölgeleri izler; kırmızı LED sürekli yanarKapı açılırsa GİRİŞ; anlık ya da iç bölgede ALARM
GİRİŞ GECİKMESİKurulu iken kapı açılınca20 sn boyunca buzzer kesik öter; PIR ve lazer bekletilirŞifre + # ile ÇÖZÜLÜ; süre dolarsa ALARM
ALARMBir bölge tetikleninceSiren ve buzzer çalar; siren 3 dk sonra susar, kırmızı LED hızlı yanıp sönerYalnızca şifre + # ile ÇÖZÜLÜ

Keypad ile kurma, çözme ve şifre

Tuşlarİşlev
2580 + ATam kurulum: dört bölge de aktif, 30 sn çıkış süresi
2580 + BEvde (gece) modu: PIR kapalı; kapı, pencere ve lazer aktif
2580 + #Sistemi çöz; alarm olduysa tetiklenen bölgeyi Seri Monitör'e yazar
* ya da CYanlış yazdığın kodu sil
DBölge testi: kapı, PIR ve lazer değerlerini Seri Monitör'e yazar
3 yanlış şifreTuş 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.

C++ (Arduino IDE)
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.

C++ (Arduino IDE)
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.

Wi-Fi her zaman güvenilir değildir: elektrik kesildiğinde modem de kapanır, bir hırsız da modemi fişten çekebilir. Modemi küçük bir UPS'e bağlamak ya da yedek kanal olarak bir SIM800L GSM modülüyle SMS göndermek bildirimin her koşulda ulaşmasını sağlar. Hareket algılandığında fotoğraf da istiyorsan ESP32-CAM ile Telegram'a fotoğraf gönderme yazısına bakabilirsin.

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.

MicroPython
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.
Sistemi gerçekten kullanmaya başlamadan önce bir yürüme testi yap: sireni rölenin COM ucundan ayır, alarmı kur ve evin içinde bir hırsızın izleyeceği yolu yürü. Hangi bölgenin ne zaman tetiklendiğini Seri Monitör'den izle, ardından birkaç gün yalnızca buzzer ile çalıştırıp kendiliğinden tetiklenme olup olmadığını gözle.

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.

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
Lazerli Güvenlik Sistemi
#23İleri
Premium

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

4.8(60)
77
Lazerli Uyarı Sistemi
#22Orta
Premium

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

4.8(64)
83
Reed Röle Kapı Sensörü
#38Başlangıç
Premium

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

4.7(34)
44
4x4 Keypad LCD Ekran Şifre Uygulaması
#64İleri
Premium

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ı

4.8(59)
75
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
Akıllı Elektronik Kasa
#92İleri
Premium

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

4.7(42)
63