Sistem Alarm Arduino: Panduan PIR, Sensor Pintu, Keypad, dan Sirine
Buat sistem alarm Arduino dengan PIR, sensor pintu reed, zona getaran dan laser, kode keypad, jeda masuk dan keluar, relay sirine, serta notifikasi Telegram ESP32.
Sistem alarm Arduino adalah perangkat keamanan yang bisa kamu rakit sendiri: alat ini membunyikan sirine ketika ada orang masuk ke rumah atau kamarmu tanpa izin, memberimu beberapa detik untuk mengetik kode ketika pintu dibuka, dan kalau kamu mau, langsung mengirim notifikasi ke ponselmu. Di panduan ini kamu akan merakit alarm empat zona dengan sensor gerak PIR, kontak reed di pintu, sensor getaran yang menangkap ketukan di kaca jendela, dan tripwire laser yang melintang di lorong. Kamu akan mengaktifkan dan menonaktifkannya dengan kode di keypad 4x4, menyalakan sirine 12 V lewat relay, dan menjalankan semuanya dari satu Arduino Uno.
Langkah demi langkah kita akan membuat versi kecil dari apa yang dikerjakan panel alarm komersial: jeda masuk dan jeda keluar, mode di rumah (mode malam), penguncian setelah kode salah, batas waktu sirine, dan memori alarm. Alih-alih blok if yang bersarang, kodenya kita tulis sebagai state machine, sehingga apa yang sedang dikerjakan alarm selalu jelas di setiap momen. Setelah itu kamu akan memindahkan logika yang sama ke ESP32 untuk mengaktifkan, menonaktifkan, dan menerima notifikasi alarm lewat Telegram, menulis versi MicroPython untuk Raspberry Pi Pico, dan belajar cara mengurangi masalah yang paling menyebalkan: alarm palsu.

Bagaimana cara kerja sistem alarm Arduino?
Setiap sistem alarm punya tiga bagian: input (sensor), otak yang mengambil keputusan (Arduino), dan output (sirine, buzzer, notifikasi). Setiap sensor menjaga satu zona. Panel profesional mengelompokkan zona berdasarkan perilakunya ketika terpicu, dan perbedaan inilah yang memisahkan alarm yang bagus dari gadget menyebalkan yang berbunyi setiap kali pintu dibuka. Sistem kita akan punya empat zona:
| Zona | Sensor | Jenis zona | Jika terpicu ketika aktif |
|---|---|---|---|
| Pintu depan | Kontak reed (MC-38) | Tertunda | Memulai jeda masuk 20 dtk; alarm jika kode tidak dimasukkan |
| Ruang tamu, interior | PIR (HC-SR501) | Interior (follower) | Alarm langsung; menunggu jika jeda masuk sedang berjalan; mati di mode di rumah |
| Jendela | Getaran (SW-420) | Langsung | Alarm langsung setelah 3 ketukan dalam 3 dtk |
| Lorong, tangga | Laser + LDR (KY-008) | Interior (follower) | Alarm langsung; menunggu jika jeda masuk sedang berjalan |
| Gas, api, tamper | MQ-2, sensor api, sakelar kotak | 24 jam | Alarm bahkan ketika nonaktif (ide pengembangan) |
Berkat zona tertunda, sirine tidak langsung berbunyi begitu kamu pulang: pintu terbuka, buzzer berbunyi bip untuk mengingatkanmu, dan kamu punya 20 detik untuk mengetik kode. Zona interior follower (pengikut) bersabar selama jeda masuk berjalan, jadi melewati PIR dalam perjalanan dari pintu ke keypad tidak memicu alarm. Tapi kalau seseorang masuk tanpa membuka pintu, misalnya lewat jendela, lalu melangkah di depan PIR, jeda masuk tidak pernah dimulai dan alarm langsung berbunyi. Zona langsung selalu terpicu seketika; tidak ada gunanya memberi 20 detik kepada orang yang sedang membobol jendela. Ketika keluar, cara kerjanya mirip: begitu kamu mengaktifkan sistem, jeda keluar 30 detik dimulai, dan keluar lewat pintu selama waktu itu tidak memicu apa pun.
Daftar komponen sistem alarm Arduino
| Komponen | Jml | Fungsi |
|---|---|---|
| Arduino Uno (atau Nano) | 1 | Otak sistem; pin di panduan ini sama di Uno dan Nano |
| Sensor gerak PIR HC-SR501 | 1 | Deteksi gerakan di dalam ruangan, 3–7 m, sekitar 110° |
| Kontak pintu reed MC-38 (atau reed switch + magnet) | 1 | Memutus rangkaian ketika pintu atau jendela terbuka |
| Modul sensor getaran SW-420 | 1 | Mendeteksi ketukan di kaca atau kusen |
| Modul laser KY-008 + LDR + resistor 10 kΩ | 1 set | Penghalang cahaya yang melintang di lorong |
| Keypad membran 4x4 | 1 | Mengaktifkan dan menonaktifkan dengan kode |
| Buzzer aktif (5 V) | 1 | Bunyi klik tombol, peringatan masuk dan keluar, sirine dalam ruangan |
| Modul relay 5 V 1 kanal | 1 | Menghidupmatikan sirine 12 V, terisolasi dari Arduino |
| Sirine 12 V (idealnya dengan lampu strobo) | 1 | Suara alarm utama, biasanya 100–120 dB |
| LED merah dan hijau + 2 × resistor 220 Ω | 1 set | Indikator aktif dan siap |
| Catu daya 12 V, modul LM2596, aki 12 V (opsional) | 1 set | Daya dan cadangan ketika listrik padam |
| Breadboard, kabel jumper, kabel alarm 4 inti | - | Sambungan dan sensor jarak jauh |







Sensor: apa yang ditangkap setiap zona?
- PIR (HC-SR501): Mendeteksi perubahan radiasi inframerah yang dipancarkan tubuh manusia dan melihat gerakan pada jarak 3–7 meter dengan sudut sekitar 110 derajat. Output-nya 3,3 V, tapi butuh catu daya 5 V. Selama 30–60 detik setelah dinyalakan, sensor ini mempelajari ruangan dan bisa terpicu sendiri, karena itulah kode mengabaikan 60 detik pertama. Detailnya ada di artikel sensor gerak PIR.
- Kontak pintu reed (MC-38): Dua rumah plastik, satu disekrup ke kusen dan satu ke daun pintu. Ketika pintu tertutup, magnetnya dekat dan kontaknya tertutup; begitu pintu terbuka lebih dari 15–25 mm, kontaknya terbuka. Dibaca dengan satu pin dan pull-up internal; isinya sudah kita bahas di artikel reed switch.
- Sensor getaran (SW-420): Sakelar normally closed dengan batang logam yang dikelilingi pegas. Ketika kaca atau kusen terkena ketukan, kontaknya terbuka sekejap dan komparator LM393 di board mengubahnya menjadi pulsa digital. Pada kebanyakan modul, output-nya LOW ketika diam dan sebentar menjadi HIGH ketika ada ketukan; cek modulmu sendiri dengan tes sensor. Sensitivitasnya diatur dengan trimpot di board; detailnya di artikel sensor getaran SW-420.
- Tripwire laser (KY-008 + LDR): Laser 650 nm sekitar 5 mW menyinari terus-menerus sebuah LDR di sisi lain lorong. Ketika sinarnya terputus, hambatan LDR melonjak dari beberapa ratus ohm menjadi puluhan kiloohm dan pembacaan analognya turun tajam. Tips pemasangan dan penyelarasan ada di artikel modul laser KY-008.
- Keypad 4x4: Matriks 16 tombol yang terdiri dari 4 jalur baris dan 4 jalur kolom; memakai 8 pin dan dibaca dalam satu baris kode dengan library Keypad. Cara kerja pemindaian baris-kolom bisa kamu temukan di panduan keypad.
- Sirine dan buzzer: Buzzer aktif punya osilator sendiri, jadi langsung berbunyi bip begitu pin-nya kamu jadikan HIGH; cocok untuk bunyi klik tombol serta peringatan masuk dan keluar. Suara yang benar-benar menakutkan pencuri datang dari sirine 12 V, yang kamu hidupmatikan lewat modul relay. Untuk perbedaan buzzer aktif dan pasif, lihat apa itu buzzer.
Diagram pengkabelan dan tabel pin
Tabel di bawah memberikan pengkabelan untuk ketiga board. Versi Arduino Uno memakai keempat zona dan keypad. Karena versi ESP32 diaktifkan dan dinonaktifkan dengan perintah Telegram, bukan keypad, dan versi Pico dibuat ringkas, tripwire laser hanya ada di Uno. Untuk melihat nomor pin board-mu sendiri, pakai alat Pinout, dan untuk menghitung resistor LED, pakai kalkulator resistor LED.
| Sambungan | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| Keypad R1–R4 (baris) | D9, D8, D7, D6 | – (Telegram) | GP2, GP3, GP4, GP5 |
| Keypad C1–C4 (kolom) | D5, D4, D3, D2 | – (Telegram) | GP6, GP7, GP8, GP9 |
| PIR VCC / OUT / GND | 5V / D10 / GND | VIN (5V) / GPIO 27 / GND | VBUS / GP16 / GND |
| Kontak reed (2 kabel) | D11 dan GND | GPIO 33 dan GND | GP15 dan GND |
| SW-420 VCC / DO / GND | 5V / D12 / GND | 3V3 / GPIO 32 / GND | 3V3(OUT) / GP17 / GND |
| KY-008 S / − (laser selalu menyala) | 5V / GND | – | – |
| LDR antara 5V dan A0, 10 kΩ antara A0 dan GND | A0 | – | – |
| Buzzer aktif + (− ke GND) | A1 | GPIO 25 | GP14 |
| IN modul relay | A2 | GPIO 26 | GP13 |
| LED hijau (dengan 220 Ω): siap | A3 | – | – |
| LED merah (dengan 220 Ω): aktif | D13 | GPIO 2 (LED bawaan) | LED bawaan |
Alarm paling dibutuhkan justru ketika listrik padam, jadi pikirkan catu dayanya sejak awal. Susunan yang praktis: persis seperti panel profesional, catu daya alarm 13,8 V dengan sambungan aki memberi daya ke sirine dan, setelah diturunkan ke 5 V dengan buck converter LM2596, ke pin 5V Arduino. Ketika listrik PLN padam, aki kering (sealed lead-acid) 12 V 7 Ah mengambil alih. Hitungannya sederhana: Uno, PIR, laser, LED, dan SW-420 menarik sekitar 100 mA pada 5 V dalam keadaan standby; itu 0,5 W, yang dengan konverter berefisiensi 85% kira-kira 50 mA di sisi aki. Meskipun kamu hanya memakai 80% kapasitasnya, aki 7 Ah membuat sistem tetap jalan selama 4–5 hari; arus 0,2–0,5 A yang ditarik sirine ketika berbunyi sedikit memperpendeknya. Coba angkamu sendiri dengan kalkulator umur baterai, dan lihat Cara Memberi Daya ke Arduino untuk pilihan catu daya.
Merakit langkah demi langkah
- Di Arduino IDE, buka Library Manager, ketik Keypad, lalu instal library buatan Mark Stanley dan Alexander Brevig. Tanpa library ini kamu akan mendapat error Keypad.h: No such file or directory ketika mengompilasi.
- Pegang keypad dengan tombol menghadap ke arahmu; sambungkan empat kabel pertama dari kiri (R1–R4) ke D9, D8, D7, D6 dan empat berikutnya (C1–C4) ke D5, D4, D3, D2.
- Sambungkan PIR ke 5V, D10, dan GND; putar kedua trimpot penuh berlawanan arah jarum jam dan pasang jumper trigger di posisi H.
- Sambungkan dua kabel kontak reed ke D11 dan GND, dan SW-420 ke 5V, D12, dan GND.
- Pasang LDR antara 5V dan A0 dan resistor 10 kΩ antara A0 dan GND; letakkan LDR di dasar tabung hitam dan arahkan laser ke tengah tabung.
- Sambungkan buzzer ke A1, IN modul relay ke A2, serta VCC dan GND-nya ke 5V dan GND Arduino; sambungkan LED ke A3 dan D13 lewat resistor 220 Ω.
- Upload dulu tes sensor di bawah, buka Serial Monitor di 9600 baud, lalu picu setiap sensor satu per satu.
- Setelah itu upload sketch alarm lengkap, ganti kodenya, dan uji sistem hanya dengan buzzer selama beberapa hari sebelum menyambungkan sirine.
Tes pertama: melihat setiap sensor di Serial Monitor
Sebelum beralih ke kode alarm, pastikan setiap sensor berperilaku sesuai harapanmu. Sketch kecil ini mencetak status PIR, apakah pintu terbuka atau tertutup, jumlah pulsa getaran dalam setengah detik terakhir, dan nilai analog LDR dua kali per detik. Pin getaran dibaca terus-menerus karena pulsa SW-420 bisa hanya berlangsung beberapa milidetik, dan kode yang memakai delay() di sela-selanya akan melewatkannya.
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}State machine: otak alarm
Kalau kamu mencoba menulis alarm dengan blok if dan delay(), kodenya cepat berubah jadi kusut: keypad tidak dibaca selama jeda masuk menunggu, dan kamu tidak bisa mengetik kode ketika sirine berbunyi. Solusinya adalah state machine, di mana sistem berada tepat di satu state pada setiap momen dan berpindah antar-state karena kejadian tertentu. Di kode, state didefinisikan dengan enum, loop() hanya menerapkan aturan state yang sedang berlaku di setiap putaran, dan waktu tunggu diukur dengan millis(), bukan delay(). Dengan begitu loop berjalan ribuan kali per detik dan tidak ada tekanan tombol atau kejadian sensor yang terlewat.
| State | Dimasuki ketika | Apa yang dilakukan | Ditinggalkan ketika |
|---|---|---|---|
| DISARMED (nonaktif) | Ketika dinyalakan dan setelah kode + # | Memantau sensor tapi tidak pernah membunyikan alarm; LED hijau menyala ketika semuanya siap | Kode + A atau kode + B |
| EXIT DELAY (jeda keluar) | Kode + A (pergi) atau B (di rumah) | Menghitung mundur 30 dtk; buzzer berbunyi bip sekali per detik dan makin cepat di 10 dtk terakhir | ARMED ketika waktunya habis; DISARMED dengan kode + # |
| ARMED (aktif) | Ketika jeda keluar berakhir | Memantau semua zona; LED merah tetap menyala | ENTRY jika pintu terbuka; ALARM pada zona langsung atau interior |
| ENTRY DELAY (jeda masuk) | Pintu terbuka ketika aktif | Buzzer berbunyi bip selama 20 dtk; PIR dan laser ditahan | DISARMED dengan kode + #; ALARM ketika waktunya habis |
| ALARM | Sebuah zona terpicu | Sirine dan buzzer berbunyi; sirine berhenti setelah 3 mnt, LED merah berkedip cepat | DISARMED hanya dengan kode + # |
Mengaktifkan, menonaktifkan, dan kode di keypad
| Tombol | Fungsi |
|---|---|
| 2580 + A | Mode pergi: keempat zona aktif, jeda keluar 30 dtk |
| 2580 + B | Mode di rumah (malam): PIR mati; pintu, jendela, dan laser aktif |
| 2580 + # | Menonaktifkan; jika tadi ada alarm, mencetak zona pemicunya ke Serial Monitor |
| * atau C | Menghapus kode yang salah ketik |
| D | Tes zona: mencetak nilai pintu, PIR, dan laser ke Serial Monitor |
| 3 kode salah | Keypad terkunci selama 60 dtk; selama itu kode yang benar pun ditolak |
Meminta kode ketika mengaktifkan juga mencegah anak-anak atau tamu mengaktifkan sistem secara tidak sengaja. Kodenya juga melakukan pengecekan belum siap (not ready): kalau kamu mencoba mengaktifkan ketika pintu terbuka atau sinar laser terputus, kamu mendengar bunyi bip panjang dan sistem tidak aktif, persis seperti di panel komersial. Jangan biarkan kode tetap di bawaan 2580, dan hindari kode yang mudah ditebak seperti 1234, 0000, atau tahun lahirmu. Kalau kamu ingin mengganti kode tanpa meng-upload ulang sketch, simpan kodenya di EEPROM dan tambahkan menu untuk memasukkan kode baru dari keypad. Tambahkan layar LCD I2C di sebelah keypad, dan kamu juga bisa melihat hitung mundur dan pesan status di layar; karena itulah pin A4 dan A5 dibiarkan kosong.
Kode sistem alarm Arduino
Kode di bawah adalah inti panduan ini. Di bagian pengaturan paling atas kamu bisa mengganti kode, jeda, lama sirine, ambang laser, dan jenis relay; sisanya tidak perlu disentuh. Di Arduino Uno, kode ini memakai sekitar 6 KB memori program dan 620 byte RAM, jadi masih banyak ruang untuk LCD atau pembaca RFID.
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}Tulang punggung kode ini adalah fungsi suz() (dari bahasa Turki “saring”). Setiap kali nilai mentah sebuah input berubah, cap waktu dicatat, dan status stabilnya tidak berubah sampai nilainya tetap sama selama waktu tertentu (50 ms untuk pintu, 200 ms untuk PIR, 30 ms untuk laser). Filter sederhana ini mencegah gangguan singkat di kabel panjang dan pantulan kontak memicu alarm. Membaca pin pintu dengan INPUT_PULLUP juga pilihan yang disengaja: ketika pintu tertutup, reed menghubungkan pin ke GND dan terbaca LOW; ketika pintu terbuka atau seseorang memotong kabelnya, pin menjadi HIGH. Logika loop tertutup (closed-loop) yang dipakai di sistem alarm sungguhan ini memperlakukan kabel yang terpotong persis seperti pintu yang terbuka.
Getaran ditangani dengan cara berbeda. Satu ketukan saja membuat SW-420 memantul beberapa kali dalam beberapa milidetik; titresimVar() (“ada getaran”) pertama-tama menghitung pantulan dalam 150 ms sebagai satu kejadian, lalu menyimpan waktu tiga kejadian terakhir. Kalau tiga kejadian muat dalam 3 detik, itu dihitung sebagai upaya nyata membobol jendela; angin yang menggetarkan pintu atau satu bola yang mengenai kaca tidak akan memicunya. Sirine berhenti sendiri setelah 3 menit, tapi sistem tetap di state ALARM dan LED merah berkedip cepat untuk memberi tahu siapa pun yang pulang bahwa tadi ada alarm. Ketika kamu memasukkan kode yang benar, nama zona yang disimpan di variabel tetikleyen (“pemicu”) dicetak ke Serial Monitor; ini versi kecil dari memori alarm yang ada di panel komersial.
Cara mengatur jeda masuk dan jeda keluar
Kalau jedanya terlalu pendek, kamu akan memicu alarmmu sendiri; kalau terlalu panjang, kamu memberi waktu kepada pencuri. Buat jeda keluar dua kali waktu yang kamu butuhkan untuk berjalan dari keypad ke pintu lalu menguncinya, dan jeda masuk kira-kira dua kali waktu untuk membuka pintu, berjalan ke keypad, dan mengetik kode. Panel komersial biasanya memakai 30–60 detik untuk keluar dan 15–30 detik untuk masuk. Memasang keypad tepat di sebelah pintu, tapi tidak terlihat dari luar, membuat jeda masuk bisa tetap pendek. Perilaku buzzer juga penting: ketika keluar, bunyi bip pendek setiap detik makin cepat di 10 detik terakhir supaya kamu merasa waktunya hampir habis; ketika masuk, bunyi bip nyala-mati 200 ms mengingatkanmu untuk mengetik kode.
Pengkabelan sirine dan relay
Di rangkaian sirine, Arduino hanya menggerakkan kumparan relay; arus sirine 12 V mengalir lewat kontak relay. Kebanyakan modul relay bersifat aktif LOW, artinya menyala ketika pin IN bernilai LOW; karena itulah kode punya konstanta ROLE_AKTIF_LOW. Kode menulis level mati sebelum menjadikan pin sebagai output, sehingga relay tidak sempat klik sekejap dan membuat sirine berbunyi singkat ketika Arduino booting. Ketika memilih sirine, cek arusnya: sirine kecil 12 V 110 dB biasanya menarik 0,1–0,3 A, beban yang sangat kecil bagi kontak relay 10 A. Sirine luar ruangan dengan lampu strobo menakut-nakuti dengan suara sekaligus cahaya dan menunjukkan kepada tetangga dari mana alarm berbunyi. Panel profesional biasanya mematikan sirine setelah 3 menit, dan beberapa negara bahkan menetapkan batas hukum untuk ini, jadi atur SIREN_SURE (lama sirine) dengan wajar. Kalau kamu lebih suka sakelar solid-state daripada relay, kamu bisa memakai MOSFET logic-level dan, untuk sirine berbasis kumparan (elektromagnetik), menambahkan dioda terbalik di antara terminalnya.
Notifikasi Telegram dengan ESP32
Sirine yang tidak didengar siapa pun tidak ada gunanya; cara termudah untuk tahu bahwa alarmmu berbunyi ketika kamu sedang pergi adalah ESP32 dan Telegram. ESP32 terhubung ke Wi-Fi-mu dan mengirim pesan ke server Telegram lewat koneksi terenkripsi, dan kamu juga bisa mengirim perintah kepadanya. Cara membuat bot dengan BotFather, mendapatkan token dan chat ID-mu, serta menginstal library UniversalTelegramBot dan ArduinoJson sudah kami jelaskan langkah demi langkah di artikel bot Telegram ESP32. Versi ini tidak punya keypad; kamu mengendalikan sistem dari ponsel dengan perintah /kur (pergi; bahasa Turki untuk “aktifkan”), /evde (mode di rumah; “di rumah”), /coz (menonaktifkan; “lepaskan”), dan /durum (status). Bot hanya menjawab chat ID-mu dan diam-diam mengabaikan perintah dari orang lain.
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}Kode ESP32 berbeda dalam tiga hal penting. Pertama, mengirim pesan ke Telegram atau mengecek perintah baru bisa makan waktu 1–2 detik, dan selama itu loop() menunggu. Pintu yang tetap terbuka dan PIR yang tetap HIGH setidaknya beberapa detik tidak terpengaruh, tapi pulsa SW-420 yang hanya beberapa milidetik bisa terlewat, jadi getaran ditangkap dengan interrupt (attachInterrupt). Kedua, alarmVer() menyalakan sirine dulu lalu mengirim pesan sesudahnya, jadi selambat apa pun internetnya, sirine tidak pernah tertunda. Notifikasi yang gagal dimasukkan ke antrean dan dicoba lagi setiap 15 detik. Ketiga, library Preferences menyimpan status aktif-tidaknya sistem di memori flash: kalau listrik padam lalu kembali ketika sistem aktif, ESP32 menyala dalam keadaan aktif dan memberi tahu bahwa listrik sudah kembali. Kalau relay dan sirine berbagi catu daya lemah yang sama dengan ESP32, board bisa restart dengan error Brownout detector was triggered; solusinya ada di artikel ESP32 terus restart.
Alarm dengan Raspberry Pi Pico dan MicroPython
State machine yang sama bisa kamu buat di Raspberry Pi Pico dalam program MicroPython yang pendek. Keypad dibaca dengan fungsi pemindaian baris-kolom dari panduan keypad; baris ada di GP2–GP5 dan kolom di GP6–GP9 dengan pull-up internal. Beri daya PIR dari VBUS (5 V); output-nya sudah 3,3 V, jadi bisa langsung disambung ke GP16. Selalu beri daya SW-420 dari pin 3V3(OUT), karena output modul yang diberi 5 V bisa merusak input Pico. Pulsa getaran ditangkap dengan Pin.irq dan waktunya disimpan di sebuah list, sementara state dilacak sebagai string sederhana. Waktu diukur dengan time.ticks_diff(), karena fungsi ini memberi selisih yang benar bahkan ketika timer berputar kembali ke nol.
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)Cara mengurangi alarm palsu
Musuh terbesar sistem alarm bukan pencuri, melainkan alarm palsu: setelah sirine berbunyi tanpa alasan tiga kali, kamu maupun tetanggamu tidak akan menganggapnya serius lagi. Sebagian langkah di bawah sudah ada di kode; sisanya soal pemasangan dan pengkabelan:
- Tunggu pemanasan: PIR bisa terpicu sendiri di 30–60 detik pertama setelah dinyalakan; kode mengabaikan 60 detik pertama.
- Pakai filter: Menunggu setiap input tetap stabil selama waktu tertentu (debounce) menyaring gangguan singkat di kabel.
- Hitung ketukan: Mencari 3 ketukan dalam 3 detik, bukan satu ketukan saja, menyaring angin, truk yang lewat, dan pintu yang terbanting. Kalau perlu, naikkan hitungannya ke 4–5 atau turunkan sensitivitas dengan trimpot di board.
- Pasang PIR dengan cermat: Jangan arahkan ke pemanas ruangan, AC, jendela yang kena matahari, atau gorden; sensor ini mendeteksi paling baik ketika gerakan melintasi bidang pandangnya dari sisi ke sisi. Kalau kamu punya hewan peliharaan, pasang sensor di tempat tinggi, miringkan sedikit ke bawah, dan turunkan sensitivitasnya.
- Wajibkan dua sensor: Di area kritis, mensyaratkan PIR dan laser, atau PIR dan pintu, terpicu dalam selang beberapa detik (cross-zoning) mencegah satu sensor rusak menyebabkan alarm.
- Bersihkan catu daya: Penurunan tegangan ketika relay menyala bisa memicu PIR. Pasang kapasitor 100 µF dan 100 nF di antara VCC dan GND setiap sensor, dan pisahkan jalur kabel relay dan sirine dari kabel sensor.
- Pakai pull-up eksternal di kabel panjang: Pull-up internal Arduino bernilai 20–50 kΩ dan menangkap derau di kabel 10 meter; resistor eksternal 4,7 kΩ ditambah kapasitor 100 nF di pin membuat jalurnya jauh lebih tangguh.
- Lindungi laser dari cahaya sekitar: Masukkan LDR ke dalam tabung hitam dan uji ambangnya secara terpisah di siang hari dan malam hari.
Kesalahan umum dan solusinya
- Alarm berbunyi begitu diaktifkan: PIR masih dalam pemanasan atau kontak pintu salah sambung. Di tes sensor, pintu seharusnya terbaca LOW ketika tertutup; kalau terbaca HIGH, magnetnya terlalu jauh atau ada kabel yang putus.
- Keypad tidak merespons atau membaca tombol yang salah: Kabel baris dan kolom tertukar. Alih-alih menyambung ulang, ubah urutan array satirPinleri (pin baris) dan sutunPinleri (pin kolom) di kode.
- Kamu mendengar bip panjang ketika mencoba mengaktifkan: Itu bukan kerusakan, melainkan peringatan belum siap: pintu terbuka atau sinar laser tidak sampai ke LDR. Tekan D untuk mengecek zona.
- Relay klik sebentar ketika dinyalakan: Level mati tidak ditulis sebelum pin dijadikan output, atau ROLE_AKTIF_LOW dibiarkan true pada relay aktif HIGH.
- Arduino reset ketika sirine berbunyi: Sirine dan Arduino berbagi adaptor yang lemah dan penurunan tegangannya me-reboot board. Pakai adaptor yang lebih kuat, konverter terpisah, dan kabel yang lebih tebal; detailnya di Arduino terus reset.
- Sensor getaran tidak pernah terpicu atau terpicu terus: Putar trimpot di board pelan-pelan untuk mengatur ambang, lalu tempelkan sensor dengan kuat ke kaca atau kusen; sensor yang longgar tidak meneruskan ketukannya.
- ESP32 tidak mengirim pesan: Token atau chat ID salah, jaringannya 5 GHz, atau kamu belum pernah memulai bot di Telegram. Bot tidak bisa mengirimimu pesan sampai kamu mengirim /start kepadanya sekali.
- Laser berfungsi baik di siang hari tapi memberi alarm palsu di malam hari (atau sebaliknya): Ambangnya terlalu dekat dengan tingkat cahaya sekitar. Ukur nilai dengan sinar dan tanpa sinar di kedua kondisi, lalu pilih LAZER_ESIK baru di tengahnya.
Ide untuk mengembangkan sistem alarmmu
- Aktifkan dan nonaktifkan dengan kartu: Tambahkan pembaca RFID RC522 di sebelah keypad dan nonaktifkan alarm dengan gantungan kunci RFID.
- Zona 24 jam: Tambahkan sensor gas MQ-2 atau sensor api untuk membuat zona gas dan kebakaran yang membunyikan alarm bahkan ketika sistem nonaktif.
- Sensor pintu nirkabel: Buat kontak pintu bertenaga baterai untuk jendela yang jauh dengan modul RF 433 MHz.
- Panel dengan layar: Tampilkan hitung mundur, status, dan memori alarm di LCD I2C.
- Integrasi rumah pintar: Hubungkan ESP32 ke MQTT dan Home Assistant dan kelola alarm bersama lampu dan kameramu.
- Kontak tamper: Pasang micro switch di tutup kotak sehingga buzzer berbunyi ketika kotaknya dibuka, bahkan ketika sistem nonaktif.
- Proyek maket rumah: Gabungkan semua zona ini di maket rumah sebagai lapisan keamanan proyek rumah pintar.
Karena menggabungkan pembacaan sensor, pengaturan waktu, state machine, dan desain catu daya dalam satu proyek, sistem alarm Arduino juga cara belajar yang sangat bagus. Jalankan tes sensor dulu, lalu coba alarmnya hanya dengan buzzer selama beberapa hari, dan sambungkan sirine paling akhir. Di aplikasi BlueGrays kamu akan menemukan proyek seperti Sensor Pintu dengan Sakelar Reed, Sistem Keamanan Laser, Kunci Sandi dengan Keypad 4x4 dan LCD, serta Sistem Alarm Gerakan ESP32 dengan notifikasi Telegram, masing-masing dengan skema rangkaian dan kode langkah demi langkah.
Pertanyaan umum
Bagaimana cara membuat sistem alarm dengan Arduino?
Kamu menyambungkan sensor gerak PIR, kontak reed untuk pintu, keypad, buzzer aktif, dan modul relay yang menggerakkan sirine ke Arduino Uno. Kodenya ditulis sebagai state machine yang memindahkan sistem antara state nonaktif, jeda keluar, aktif, jeda masuk, dan alarm. Kamu mengaktifkan dan menonaktifkannya dengan kode di keypad, dan kalau ada sensor yang terpicu ketika sistem aktif, sirine berbunyi.
Sensor apa saja yang dipakai di sistem alarm Arduino?
Yang paling umum adalah sensor gerak PIR (HC-SR501) untuk area dalam ruangan, kontak reed (MC-38) untuk pintu dan jendela, sensor getaran SW-420 untuk ketukan di kaca, dan tripwire laser untuk lorong. Kamu bisa menambahkan MQ-2 untuk gas dan sensor api untuk kebakaran. Setiap sensor didefinisikan sebagai zona terpisah dengan perilakunya sendiri.
Apakah alarm Arduino tetap bekerja ketika listrik padam?
Tidak, kalau hanya diberi daya dari adaptor. Dengan catu daya alarm 13,8 V yang mengisi aki 12 V 7 Ah, sistem Uno yang menarik sekitar 100 mA bisa jalan selama 4–5 hari. Di versi ESP32, status aktif disimpan di flash, jadi sistem kembali dalam keadaan aktif ketika listrik menyala lagi; router juga butuh UPS supaya notifikasi bisa terkirim.
Bisakah alarm Arduino mengirim notifikasi ke ponselku?
Arduino Uno tidak bisa melakukannya sendiri, tapi ESP32 bisa mengirim pesan Telegram secara instan lewat Wi-Fi dan menerima perintah seperti /kur dan /coz dari ponselmu. Di tempat tanpa internet, modul GSM SIM800L bisa mengirim SMS atau menelepon. Memakai kedua cara sekaligus adalah pilihan yang paling andal.
Kenapa sensor PIR-ku memberi alarm palsu?
Penyebab yang biasa adalah pemanasan 30–60 detik setelah dinyalakan, sumber panas seperti pemanas ruangan dan AC, gorden yang bergoyang di bawah sinar matahari yang hangat, dan derau catu daya ketika relay menyala. Mengabaikan masa pemanasan di kode, menjauhkan sensor dari sumber panas, dan menambahkan kapasitor di antara VCC dan GND menyelesaikan sebagian besar masalah ini.
Bisakah sistem alarm Arduino dipakai di rumah sungguhan?
Sistem ini bagus untuk belajar dan untuk memantau kamar, garasi, atau gudang, tapi tidak menggantikan sistem alarm bersertifikat. Sistem komersial diuji sesuai standar seperti EN 50131 untuk perlindungan tamper, daya cadangan, koneksi nirkabel terenkripsi, dan sambungan ke pusat pemantauan. Kalau kamu memakai sistem Arduino di rumah, kami sarankan menambahkan aki cadangan, kontak tamper, dan jalur notifikasi kedua.
Proyek untuk dibuat setelah membaca ini
Lihat semua proyek
Sistem Alarm Gerakan ESP32 (PIR + Buzzer + LED + Telegram)
Sistem alarm keamanan pintar yang menyalakan buzzer dan LED ketika sensor PIR mendeteksi gerakan, sekaligus mengirim notifikasi instan ke pemilik lewat Telegram. Cooldown 30 detik membatasi seberapa sering alarm berulang; mekanisme ini tidak memvalidasi deteksi PIR atau menghilangkan pemicu palsu. Cocok untuk rumah, garasi, gudang, atau ruang kerja. Dengan ESP32-CAM bisa ditambahkan notifikasi berfoto; dengan ESP32 DevKit V1 klasik, notifikasinya berupa teks.

Sistem Keamanan Laser
Persis seperti adegan perampokan dengan laser di film: sinar laser menyorot sensor cahaya, dan begitu ada orang masuk dan memutus sinarnya, LED merah menyala dan buzzer mulai berbunyi. Alarmnya tidak

Sistem Peringatan Laser
Kamu memasang pagar sinar tak terlihat, persis seperti di film. Laser menyorot sensor cahaya di sisi seberang; begitu ada orang lewat dan memutus sinarnya, LED menyala dan buzzer berbunyi, dan ketika

Sensor Pintu dengan Sakelar Reed
Ketahui apakah pintumu terbuka atau tertutup hanya dengan melihat lampu. Kamu menempelkan magnet kecil di pintu dan sakelar peka magnet di kusennya; ketika pintu tertutup keduanya bersebelahan dan LED

Kunci Sandi dengan Keypad 4x4 dan LCD
Kunci pintu elektronik kecil yang menahan siapa pun yang tidak tahu kodenya. Kamu menekan tombol pagar lalu mengetik kodenya di keypad; jika benar, layar menulis akses diberikan, LED hijau menyala, da

Pendeteksi Gerakan dengan Sensor Gerak
Penjaga sederhana yang memberi tahu ketika ada orang masuk ke ruangan. Sensor gerak menangkap panas yang dipancarkan tubuh manusia, dan Arduino menjaga LED tetap menyala selama ada gerakan lalu memati

Brankas Elektronik Pintar
Brankas kecil untuk barang berhargamu yang terbuka dengan kode. Kamu mengetik kode empat digitmu di keypad; jika benar, motor servo membuka kunci, lampu hijau menyala, dan layar menampilkan keadaan br
Artikel lainnya
Aplikasi BlueGrays
Rakit rangkaian ini langkah demi langkah di ponselmu
Skema pengkabelan, kode, dan daftar komponen dalam satu layar. 200+ proyek Arduino, ESP32, dan Pico siap dibuat.
Pindai dengan ponselmu
Arahkan kamera ke kode ini dan toko aplikasi di ponselmu akan terbuka.
atau buka toko aplikasi

