نظام إنذار ذكي باستخدام ESP32 | إرسال تنبيه إلى الهاتف عبر WiFi وntfy




في الحلقة التاسعة من سلسلة ESP32 من الصفر سنطوّر مشروع حاجز الليزر الذي صنعناه في الحلقة السابقة. كان النظام يكتشف انقطاع شعاع الليزر ويشغّل جرس الإنذار محليًا، لكن ماذا يحدث إذا لم نكن بالقرب من الجهاز؟ هذه المرة سنجعل ESP32 يرسل تنبيهًا إلى الهاتف عبر WiFi فور اكتشاف محاولة التسلل، باستخدام خدمة ntfy.

لن نغيّر توصيل حساس الضوء أو الترانزستور أو الجرس؛ سنضيف إلى البرنامج إمكانية الاتصال بالإنترنت وإرسال طلب HTTP POST، مع الحفاظ على خاصية تشغيل الإنذار حتى إعادة تشغيل اللوحة.

فيديو المشروع

فكرة المشروع: كيف يصل التنبيه إلى الهاتف؟

تعتمد خدمة ntfy على ما يسمى الموضوع Topic. يشترك الهاتف في موضوع محدد، ويرسل ESP32 رسالة إلى العنوان المرتبط بالموضوع عبر الإنترنت. تتولى الخدمة بعد ذلك إيصال إشعار إلى الهاتف.

مسار التنبيه: حاجز الليزر ← حساس LDR ← ESP32 ← شبكة WiFi ← خدمة ntfy ← الهاتف.

في هذا التطبيق لا نحتاج إلى إنشاء حساب أو إنشاء الموضوع مسبقًا عند استخدام الخادم العام ntfy.sh؛ يكفي اختيار اسم موضوع مناسب واستعماله نفسه في تطبيق الهاتف وفي برنامج ESP32.

تنبيه خصوصية: الموضوعات على الخادم العام ntfy.sh ليست خاصة تلقائيًا. اختر اسمًا طويلًا وعشوائيًا يصعب تخمينه، ولا تضع في الرسائل معلومات شخصية أو حساسة. وللاستخدام الحقيقي أو الحساس، استخدم خادمًا خاصًا أو إعدادات مصادقة مناسبة.

المكونات المطلوبة

المكوّنالعدد / القيمةالوظيفة
لوحة ESP321قراءة الحساس والاتصال بالإنترنت
مقاومة ضوئية LDR1استقبال شعاع الليزر
مقاومة 10kΩ1إنشاء مقسم جهد مع LDR
وحدة ليزر منخفض القدرة1توجيه الشعاع نحو الحساس
جرس Buzzer مناسب لجهد 3.3V1إنذار صوتي
ترانزستور NPN1تشغيل الجرس كمفتاح إلكتروني
مقاومة 1kΩ1التحكم في قاعدة الترانزستور
Breadboard وأسلاكحسب الحاجةتركيب الدارة
هاتف متصل بالإنترنت1استقبال إشعارات ntfy

مخطط التوصيل: نفس دائرة الحلقة الثامنة

سنحتفظ بالتوصيلات نفسها التي استخدمناها في الحلقة 8: حاجز ليزر لكشف التسلل. نقرأ مقسم الجهد المتكوّن من LDR ومقاومة 10kΩ عبر GPIO34، ونتحكم في قاعدة ترانزستور NPN عبر مقاومة 1kΩ متصلة بالمنفذ GPIO23. يغذّى الجرس من خط 3.3V عبر دائرة الترانزستور، مع توحيد الأرضي.

العنصرالمنفذ / التوصيل
نقطة المنتصف في مقسم جهد LDRGPIO34
التحكم في قاعدة NPNGPIO23 عبر مقاومة 1kΩ
تغذية الجرس3.3V عبر الترانزستور حسب المخطط
حالة GPIO23 LOWالجرس متوقف
حالة GPIO23 HIGHالجرس يعمل

سلامة الليزر: استخدم ليزرًا منخفض القدرة ومثبتًا باتجاه الحساس. لا توجّه الشعاع نحو العين أو الأشخاص أو الأسطح العاكسة. هذا المشروع نموذج تعليمي وليس نظام حماية معتمدًا.

الخطوة الأولى: إعداد تطبيق ntfy على الهاتف

  1. ثبّت تطبيق ntfy على الهاتف.
  2. اسمح للتطبيق بعرض الإشعارات.
  3. اختر اسم موضوع طويلًا وغير متوقع، مثل naadi-laser-7q4m2x9b6p (مثال فقط؛ أنشئ اسمًا مختلفًا).
  4. اشترك في الموضوع داخل التطبيق.
  5. احتفظ بالاسم نفسه لاستعماله في كود 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 عند بدء التشغيل، لذلك لن يبدأ المراقبة إذا تعذر الاتصال. يمكن تحسين ذلك بإضافة مهلة اتصال وآلية لإعادة المحاولة.

تجربة النظام كاملًا

  1. تأكد من أن الليزر موجّه إلى LDR ومن أن قيمة العتبة صحيحة.
  2. اشترك في الموضوع نفسه عبر تطبيق ntfy على الهاتف.
  3. ضع اسم شبكة WiFi وكلمة المرور واسم الموضوع وشهادة الجذر المناسبة في الكود.
  4. ارفع البرنامج إلى ESP32 وافتح Serial Monitor.
  5. تأكد من نجاح الاتصال بالشبكة وظهور عنوان IP.
  6. اقطع شعاع الليزر: يجب أن يعمل الجرس مباشرة.
  7. تحقق من وصول التنبيه إلى الهاتف ومن رمز الاستجابة على Serial Monitor.
  8. أعد الشعاع: سيظل الجرس مشتغلًا ولن يحاول البرنامج إرسال رسالة جديدة.
  9. اضغط زر 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.

موضوعات ذات صلة