نظام إنذار ذكي باستخدام ESP32 | إرسال تنبيه إلى الهاتف عبر WiFi وntfy
في الحلقة التاسعة من سلسلة ESP32 من الصفر سنطوّر مشروع حاجز الليزر الذي صنعناه في الحلقة السابقة. كان النظام يكتشف انقطاع شعاع الليزر ويشغّل جرس الإنذار محليًا، لكن ماذا يحدث إذا لم نكن بالقرب من الجهاز؟ هذه المرة سنجعل ESP32 يرسل تنبيهًا إلى الهاتف عبر WiFi فور اكتشاف محاولة التسلل، باستخدام خدمة ntfy.
لن نغيّر توصيل حساس الضوء أو الترانزستور أو الجرس؛ سنضيف إلى البرنامج إمكانية الاتصال بالإنترنت وإرسال طلب HTTP POST، مع الحفاظ على خاصية تشغيل الإنذار حتى إعادة تشغيل اللوحة.
فيديو المشروع
فكرة المشروع: كيف يصل التنبيه إلى الهاتف؟
تعتمد خدمة ntfy على ما يسمى الموضوع Topic. يشترك الهاتف في موضوع محدد، ويرسل ESP32 رسالة إلى العنوان المرتبط بالموضوع عبر الإنترنت. تتولى الخدمة بعد ذلك إيصال إشعار إلى الهاتف.
مسار التنبيه: حاجز الليزر ← حساس LDR ← ESP32 ← شبكة WiFi ← خدمة ntfy ← الهاتف.
في هذا التطبيق لا نحتاج إلى إنشاء حساب أو إنشاء الموضوع مسبقًا عند استخدام الخادم العام ntfy.sh؛ يكفي اختيار اسم موضوع مناسب واستعماله نفسه في تطبيق الهاتف وفي برنامج ESP32.
تنبيه خصوصية: الموضوعات على الخادم العام ntfy.sh ليست خاصة تلقائيًا. اختر اسمًا طويلًا وعشوائيًا يصعب تخمينه، ولا تضع في الرسائل معلومات شخصية أو حساسة. وللاستخدام الحقيقي أو الحساس، استخدم خادمًا خاصًا أو إعدادات مصادقة مناسبة.
المكونات المطلوبة
| المكوّن | العدد / القيمة | الوظيفة |
|---|---|---|
| لوحة ESP32 | 1 | قراءة الحساس والاتصال بالإنترنت |
| مقاومة ضوئية LDR | 1 | استقبال شعاع الليزر |
| مقاومة 10kΩ | 1 | إنشاء مقسم جهد مع LDR |
| وحدة ليزر منخفض القدرة | 1 | توجيه الشعاع نحو الحساس |
| جرس Buzzer مناسب لجهد 3.3V | 1 | إنذار صوتي |
| ترانزستور NPN | 1 | تشغيل الجرس كمفتاح إلكتروني |
| مقاومة 1kΩ | 1 | التحكم في قاعدة الترانزستور |
| Breadboard وأسلاك | حسب الحاجة | تركيب الدارة |
| هاتف متصل بالإنترنت | 1 | استقبال إشعارات ntfy |
مخطط التوصيل: نفس دائرة الحلقة الثامنة

سنحتفظ بالتوصيلات نفسها التي استخدمناها في الحلقة 8: حاجز ليزر لكشف التسلل. نقرأ مقسم الجهد المتكوّن من LDR ومقاومة 10kΩ عبر GPIO34، ونتحكم في قاعدة ترانزستور NPN عبر مقاومة 1kΩ متصلة بالمنفذ GPIO23. يغذّى الجرس من خط 3.3V عبر دائرة الترانزستور، مع توحيد الأرضي.
| العنصر | المنفذ / التوصيل |
|---|---|
| نقطة المنتصف في مقسم جهد LDR | GPIO34 |
| التحكم في قاعدة NPN | GPIO23 عبر مقاومة 1kΩ |
| تغذية الجرس | 3.3V عبر الترانزستور حسب المخطط |
حالة GPIO23 LOW | الجرس متوقف |
حالة GPIO23 HIGH | الجرس يعمل |
سلامة الليزر: استخدم ليزرًا منخفض القدرة ومثبتًا باتجاه الحساس. لا توجّه الشعاع نحو العين أو الأشخاص أو الأسطح العاكسة. هذا المشروع نموذج تعليمي وليس نظام حماية معتمدًا.
الخطوة الأولى: إعداد تطبيق ntfy على الهاتف
- ثبّت تطبيق ntfy على الهاتف.
- اسمح للتطبيق بعرض الإشعارات.
- اختر اسم موضوع طويلًا وغير متوقع، مثل
naadi-laser-7q4m2x9b6p(مثال فقط؛ أنشئ اسمًا مختلفًا). - اشترك في الموضوع داخل التطبيق.
- احتفظ بالاسم نفسه لاستعماله في كود ESP32.
يمكنك التعرف على الخدمة من موقعها الرسمي: ntfy.sh.
الخطوة الثانية: اختبار إرسال إشعار من ESP32
قبل دمج الإشعارات مع حاجز الليزر، سنجري تجربة مستقلة. يتصل ESP32 بشبكة WiFi، ثم يرسل رسالة قصيرة إلى عنوان الموضوع باستخدام طلب POST. إذا وصلت الرسالة إلى الهاتف، فهذا يعني أن الاتصال بالخدمة يعمل.
في المثال التالي نستخدم اتصال HTTPS. يجب ضبط التحقق من شهادة الخادم باستعمال شهادة جذر موثوقة ومحدّثة تناسب ntfy.sh، بدل تعطيل التحقق الأمني. ستجد موضع إعداد الشهادة داخل الكود.
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";
const char* ntfyURL = "https://ntfy.sh/naaditech-alarm-X7K29";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("Wi-Fi connected");
HTTPClient http;
http.begin(ntfyURL);
http.addHeader(
"Content-Type",
"text/plain; charset=utf-8"
);
http.POST("اختبار ناجح من ESP32");
http.end();
}
void loop() {
}
ملاحظة تقنية: الكود أعلاه قالب يحتاج إلى إضافة شهادة جذر صالحة فعلًا قبل تشغيل HTTPS. لا تستعمل النص PASTE_VALID_ROOT_CA_CERTIFICATE_HERE كما هو. كما أن نجاح طلب HTTP لا يضمن وحده ظهور الإشعار إذا كانت إشعارات الهاتف معطلة أو لا يوجد اتصال بالإنترنت.
الخطوة الثالثة: دمج التنبيه مع نظام الإنذار
بعد التأكد من وصول رسالة الاختبار، نعود إلى برنامج الحلقة السابقة. نضيف مكتبات WiFi.h وWiFiClientSecure.h وHTTPClient.h، وبيانات شبكة WiFi، وعنوان الموضوع، ودالة لإرسال التنبيه.
عندما تنخفض قراءة GPIO34 عن العتبة التي حددناها أثناء المعايرة، نشغّل الجرس فورًا عبر GPIO23، ثم نحاول إرسال إشعار إلى ntfy، وبعد ذلك ندخل في حلقة مستمرة لإبقاء الإنذار مشتغلًا ومنع إرسال الرسالة مرات متعددة.
الكود الكامل للمشروع
القيمة 3200 أدناه مثال توضيحي وليست القيمة المقاسة في الفيديو. استبدلها بعتبة الكشف التي حددتها باستخدام قراءات LDR على دائرتك.
#include <WiFi.h>
#include <HTTPClient.h>
#include <WiFiClientSecure.h>
// =========================
// Wi-Fi
// =========================
const char* ssid = "WIFI_NAME";
const char* password = "WIFI_PASSWORD";
// =========================
// ntfy
// =========================
// Topic utilisé uniquement pour la démonstration
const char* ntfyURL =
"https://ntfy.sh/naaditech-alarm-X7K29";
// =========================
// Pins
// =========================
const int ldrPin = 34;
const int buzzerPin = 23;
// =========================
// Seuil de détection
// =========================
// À remplacer par la valeur déterminée
// lors de la calibration de la vidéo #8
const int seuil = 3200;
// =========================
// Fonction notification
// =========================
void envoyerNotification() {
// Vérifier la connexion Wi-Fi
if (WiFi.status() == WL_CONNECTED) {
WiFiClientSecure client;
HTTPClient http;
// Pour cette démonstration
client.setInsecure();
// Connexion à ntfy
http.begin(client, ntfyURL);
// Message en UTF-8
http.addHeader(
"Content-Type",
"text/plain; charset=utf-8"
);
// Titre de la notification
http.addHeader(
"Title",
"ESP32 Laser Alarm"
);
// Priorité élevée
http.addHeader(
"Priority",
"high"
);
// Envoyer la notification
int httpResponseCode =
http.POST("🚨 إنذار! تم اكتشاف محاولة تسلل");
// Afficher le résultat dans le Serial Monitor
Serial.print("ntfy HTTP code: ");
Serial.println(httpResponseCode);
// Fermer la connexion
http.end();
}
else {
Serial.println("Wi-Fi disconnected");
}
}
// =========================
// SETUP
// =========================
void setup() {
Serial.begin(115200);
// Configuration du buzzer
pinMode(buzzerPin, OUTPUT);
// Alarme OFF au démarrage
digitalWrite(buzzerPin, LOW);
// =========================
// Connexion Wi-Fi
// =========================
Serial.print("Connecting to Wi-Fi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("Wi-Fi connected");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
Serial.println("System armed");
}
// =========================
// LOOP
// =========================
void loop() {
// Lire le capteur LDR
int valeurLDR = analogRead(ldrPin);
Serial.print("LDR: ");
Serial.println(valeurLDR);
// =========================
// Détection intrusion
// =========================
if (valeurLDR < seuil) {
Serial.println("INTRUSION DETECTED!");
// 1 - Activer l'alarme
digitalWrite(buzzerPin, HIGH);
// 2 - Envoyer la notification
envoyerNotification();
// 3 - Verrouiller l'alarme
while (true) {
// L'alarme reste active
// jusqu'au redémarrage de l'ESP32
// avec le bouton EN
delay(100);
}
}
delay(50);
}
شرح الإضافات الجديدة في البرنامج
1. الاتصال بشبكة WiFi
نضع اسم الشبكة وكلمة المرور داخل المتغيرين ssid وpassword. في setup() يبدأ ESP32 الاتصال وينتظر نجاحه، ثم يعرض عنوان IP على شاشة Serial Monitor.
2. عنوان موضوع ntfy
المتغير ntfyUrl يحتوي على العنوان الكامل للموضوع، مثل https://ntfy.sh/YOUR_UNIQUE_TOPIC. يجب أن يكون اسم الموضوع مطابقًا تمامًا للاسم المشترك فيه على الهاتف.
3. دالة إرسال التنبيه
تتحقق الدالة sendAlert() أولًا من حالة WiFi، ثم تفتح اتصال HTTPS وترسل طلب POST. نحدد نوع المحتوى text/plain; charset=utf-8 لدعم النص العربي، ونضيف عنوانًا وأولوية مرتفعة للرسالة. بعد الإرسال نطبع رمز استجابة HTTP في الشاشة التسلسلية ونغلق الاتصال.
4. تشغيل الجرس أولًا ثم إرسال الرسالة
عند اكتشاف قطع الشعاع نرسل HIGH إلى GPIO23 لتشغيل الجرس فورًا. بعد ذلك نستدعي sendAlert(). هكذا يستمر الإنذار المحلي حتى إذا تعذّر إرسال الرسالة بسبب مشكلة في WiFi أو الإنترنت.
5. منع تكرار الإشعارات
بعد محاولة إرسال التنبيه ندخل في while (true). وبما أن البرنامج لا يعود إلى بداية loop() فلن يعيد إرسال التنبيه بسبب استمرار انقطاع الشعاع أو عودته. لإعادة التسليح نضغط زر EN لإعادة تشغيل ESP32.
ملاحظة مهمة: البرنامج يحاول إرسال طلب تنبيه واحد لكل حدث، لكنه لا يضمن وصول إشعار واحد بالضبط إلى الهاتف في جميع الظروف؛ فقد يفشل الاتصال أو تتأخر الإشعارات أو تتأثر بإعدادات الهاتف. كما أن البرنامج ينتظر اتصال WiFi عند بدء التشغيل، لذلك لن يبدأ المراقبة إذا تعذر الاتصال. يمكن تحسين ذلك بإضافة مهلة اتصال وآلية لإعادة المحاولة.
تجربة النظام كاملًا
- تأكد من أن الليزر موجّه إلى LDR ومن أن قيمة العتبة صحيحة.
- اشترك في الموضوع نفسه عبر تطبيق ntfy على الهاتف.
- ضع اسم شبكة WiFi وكلمة المرور واسم الموضوع وشهادة الجذر المناسبة في الكود.
- ارفع البرنامج إلى ESP32 وافتح Serial Monitor.
- تأكد من نجاح الاتصال بالشبكة وظهور عنوان IP.
- اقطع شعاع الليزر: يجب أن يعمل الجرس مباشرة.
- تحقق من وصول التنبيه إلى الهاتف ومن رمز الاستجابة على Serial Monitor.
- أعد الشعاع: سيظل الجرس مشتغلًا ولن يحاول البرنامج إرسال رسالة جديدة.
- اضغط زر EN لإعادة تشغيل ESP32 والعودة إلى المراقبة.
مشاكل شائعة وحلولها
| المشكلة | السبب المحتمل والحل |
|---|---|
| الهاتف لا يستقبل إشعارًا | تحقق من اشتراك الهاتف في الموضوع نفسه، وصلاحيات الإشعارات والإنترنت، ورمز HTTP الظاهر في Serial Monitor. |
| ESP32 لا يتصل بـ WiFi | تحقق من بيانات الشبكة وقوة الإشارة؛ تحتاج أغلب لوحات ESP32 التقليدية إلى شبكة 2.4GHz. |
| خطأ عند إرسال HTTPS | تحقق من شهادة الجذر الصحيحة وسلسلة شهادات الخادم وإعدادات الوقت اللازمة للتحقق من الشهادة. |
| الجرس يعمل لكن الإشعار لا يصل | راجع اتصال WiFi والإنترنت واسم الموضوع؛ الإنذار المحلي يعمل بصورة مستقلة عن نجاح الطلب. |
| الإنذار يعمل فور التشغيل | أعد معايرة LDR وتحقق من اتجاه مقسم الجهد وعتبة الكشف. |
| الجرس لا يتوقف عند عودة الليزر | هذا هو السلوك المقصود؛ اضغط EN لإعادة التسليح. |
ماذا تعلمنا؟
- تطوير حاجز الليزر من إنذار محلي إلى مشروع متصل بالإنترنت.
- الاشتراك في موضوع ntfy على الهاتف وإرسال رسائل إليه.
- استخدام WiFi مع ESP32 للاتصال بخدمة خارجية.
- إرسال طلب
HTTP POSTباستخدام اتصال HTTPS. - إرسال نص عربي بترميز
UTF-8. - تشغيل الجرس محليًا وإرسال محاولة تنبيه واحدة عند اكتشاف التسلل.
- الحفاظ على حالة الإنذار حتى إعادة تشغيل ESP32 بزر EN.
أفكار لتطوير المشروع
يمكن لاحقًا إضافة زر مستقل لإعادة التسليح، أو شاشة لعرض حالة النظام، أو مهلة اتصال WiFi تسمح باستمرار المراقبة دون إنترنت، أو آلية لإعادة محاولة إرسال الإشعارات مع تجنّب التكرار، أو استضافة خادم ntfy خاص لحماية التنبيهات.
بهذا نكون قد حوّلنا مشروع حاجز الليزر إلى تجربة عملية تجمع بين ESP32 والحساسات والاتصال اللاسلكي وخدمات الإنترنت، وهي خطوة مهمة في تعلم تطبيقات إنترنت الأشياء IoT.
