سنتعلّمُ في هذا المقال كيفيَّة استخدام بروتوكول ESP-NOW لتبادل البيانات بين ألواح ESP32 المبرمجة باستخدامِ بيئة أردوينو البرمجيّة Arduino IDE.
ESP-NOW هو بروتوكول اتّصال غير مهيّأ مطور من قِبل شركة Espressif ويتميَّز بنقلِ الحزم القصيرة، يسمحُ هذا البروتوكول للعديدِ من الأجهزة بالتَّواصلِ مع بعضها البعض بطريقةٍ سلسةٍ.
بيئة أردوينو البرمجيّة
سنبرمجُ لوحةَ التَّطوير ESP32 باستخدامِ بيئة أردوينو البرمجيَّة، لذلك يجب تحميل إضافة ESP32 في بيئة أردوينو البرمجيَّة، اتبع الرَّابط الآتي لتحميلهِ (يصلح لأنظمة Windows وMac OS X وLINUX)
Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, Linux)
مقدّمة عن بروتوكول ESP-NOW
طوَّرت شركة Espressif بروتوكول ESP-NOW والذي يَسمح باتصال عدَّة أجهزة مع بعضها دون استخدام Wi-Fi، ويشابه هذا البروتوكول الاتّصالَ اللاسلكيَّ المنخفض استهلاك الطَّاقة بتردّد 2.4 GHz.
يجب أن يَحدُثَ الاقتران بين الأجهزةِ قبل عمليَّة الاتّصال، وبعد إتمامِ التَّوصيل نَحصُل على اتصال نَظير لنظير آمن بِبساطة.
أي بعد توصيل الأجهزة مع بَعضِها يكون الاتّصالُ مستمرّاً، وبمعنى آخر إذا فَقَدَت إحدى اللَّوحات مصدرَ الطَّاقةِ أو أُعيدَ ضَبطهَا عندما تبدأُ بالعملِ مجدَّداً ستتصل بشكلٍ تلقائيّ بنظيرِها لاستكمالِ الاتصال مُجدَّداً.
تدعَم ESP-NOW المَيّزات الآتية:
- الاتّصالَ الأحاديَّ المشفّر وغير المشفّر
- الأجهزةَ النَّظيرةَ المشفّرة وغير المشفّرة معاً
- يمكن نقل حمولة تصِل إلى 250 بايت
- إرسالَ توابع إعادةِ الاتّصال مرَّة أُخرى والتي يمكن ضَبطها لإعلامِ طبقة التَّطبيقات بنجاحِ أو فشلِ النَّقل.
لبروتوكول ESP-NOW القيود الآتية:
- عددٌ محدودٌ من النَّظائرِ المُشفَّرة، وهو 10 نظائِرَ مشفّرةٍ مدعّمةٍ في وضعِ المحطَّة station، وتكون 6 على الأكثر في وضع SoftAP، أو SoftAP مع وضع المحطَّة station
- تدعم هذه التّقنية النَّظائر المشفّرة المُتعددة ولكن يجب أن يَقِلَّ عددها عن 20 متضمّنةً النَّظائر المشفّرة.
- أقصى حدّ للحمولةِ هو 250 بايت.
بمعنى آخر ESP-NOW هو بروتوكول اتّصالٍ سريعٍ يمكن استخدامه لتبادلِ الرَّسائلِ القصيرة (حتى 250 بايت) بين لوحاتِ ESP32، وهذا البروتوكول متعدّدُ الاستعمالاتِ يمكن استخدامهُ للاتّصالِ باتّجاهٍ وحيدٍ أو باتّجاهَين من خلال ضَبط إعداداتٍ مختلفةٍ.
اتّصال ESP-NOW باتّجاهٍ واحدٍ
تستخدمُ طريقة الاتّصال باتّجاهٍ واحدٍ في الحالاتِ الآتية على سبيلِ المِثال:
-
لوح ESP32 يرسلُ بياناتٍ إلى لوحِ ESP32 آخر
والنّظامُ هُنا سهلٌ جداً ومناسبٌ لإرسالِ البياناتِ من لوحٍ لآخر مِثل إرسال قراءاتِ حسَّاس أو أوامر التَّشغيلِ والإيقافِ للتَّحكُّمِ ب GPIOs (أطراف الدَّخل/الخرج للأغراضِ العامةِ).
-
لوح ESP32 رئيسيٌّ يرسلُ بياناتٍ لعددٍ من ألواحِ ESP32 تمثّلُ توابعاً له
يرسل اللَّوح الرَّئيسيُّ الأوامِر ذاتَها أو أوامِر مختلفة للألواحِ التوابعِ، والبنيةُ هُنا مِثاليةٌ لبناءِ شيءٍ ما مثل جِهاز تَحكُّمٍ عن بُعد، فبإمكانِك تَركيب ألواحِ ESP32 عِدَّة حول المنزلِ والتَّحكم بِها من خلالِ لوح ESP32 رئيسيّ.
-
لوحُ ESP32 تابِع يتلقَّى البياناتِ من العديدِ من الألواحِ الرَّئيسيّةِ
وهذا النّظامُ مِثاليٌّ في حالِ أَردنا جمعَ البياناتِ من عقد استشعارٍ عدَّة في لوحِ ESP32 وحيد، على سَبيل المِثال يمكن ضَبطُ هذهِ الحالةِ كمخدّم ويب لإظهارِ البياناتِ من كلّ الألواحِ الأُخرى.
اتّصال ESP-NOW باتّجاهَين
عِندَ استخدامِ بروتوكول ESP-NOW فإنَّ كلَّ لوح يمكن أن يَكون مرسل ومستقبل في الوقتِ نفسِهِ، وبذلكَ يمكن تحقيقُ الاتّصال باتّجاهَين بينَ الألواحِ، ويوضّحُ الشَّكل مِثالاً على لَوحَينِ متّصلَين ببعضِهما البعض.
بإمكانكَ إضافة المزيد من الألواحِ في هذهِ الحالةِ للحصولِ على شبكةٍ (أي ألواحِ ESP32 عدَّة ٍمتصلةٍ ببعضِها البعض).
ملاحظة:
إنَّ بروتوكول ESP-NOW مِثاليٌّ لبناءِ شبكةٍ مكوّنةٍ من ألواحِ ESP32 تتبادلُ البياناتِ مع بعضِها البعض.
الحُصول على عنوانِ MAC للوحِ ESP32
للاتّصالِ من خلال بروتوكول ESP-NOW نحتاج لمعرفةِ عنوانِ MAC للوحِ ESP32 المستقبل وبذلك نَعلمُ لأيّ جهازٍ سنرسل البياناتِ، حيثُ لكلّ لوحِ ESP32 عنوان MAC فريد خاصّ به وبذلك نعرّف كلَّ لوحٍ لإرسالِ البياناتِ إليهِ باستخدامِ ESP-NOW، ولمعرفة كيفيَّة الحصول على العنوان وتغييره انقر هنا
ولتحصلِ على عنوانِ MAC للوحٍ معيَّنٍ حَمِّل الكود الآتي:
بعدَ تحميل الكود افتح شاشةَ العرضِ التَّسلسُليّ Serial monitor على معدّل سرعةِ تَدفُّق بياناتٍ baud يساوي 115200، ثم اضغط على زرّ RST/EN في لوحِ ESP32 وسيظهرُ عنوانُ MAC كما في الشَّكلِ الآتي:
نحفظُ عنوان MAC لأنَّنا سنحتاجُه لإرسالِ البياناتِ إلى اللّوحِ الصَّحيحِ عبرَ ESP-NOW.
اتّصال ESP-NOW نقطة إلى نقطة باتّجاهٍ واحدٍ
لكي ننشئ اتصالاً لاسلكيّاً عن طريقِ ESP-NOW سنبني مشروعاً بسيطاً يظهر كيفيَّةَ إرسالِ رسالةٍ من لوحِ ESP32 لآخر، يمثّل اللَّوحُ الأوّلُ المرسل واللَّوحُ الثَّاني المستقبل.
سنرسلُ تركيباً structure يحوي متغيراتٍ من النّوعِ المِحرَفي char والأعدادِ الصَّحيحةِ int والفواصِلِ العِشريّةِ float والمتغيّر المنطقيّ Boolean، ومن ثمّ نعدّل التَّركيب ليرسل أي نوع من المتغيرات الذي يناسب المشروع (مثل قراءة الحسَّاساتِ أو المتغيّرات المنطقيَّة لتشغيلِ وإيقافِ تشغيلِ شيءٍ ما)
ولتبسيطِ الأمورِ سنسمّي اللّوح 1ESP32 # المرسل واللَّوح الآخر ESP32 #2 بالمستقبل.
يجب أن يحقّقَ برنامجُ المرسل العناصر الآتية:
– تَهيئة بروتوكول ESP-NOW.
– ندخل تابعَ استدعاء بعدَ إرسالِ البياناتِ وهو التَّابع OnDataSent والذي ينفّذ عندما ترسل الرّسالة، وهذا يعلمُنا بنجاحِ أو فشلِ تسليمِ الرّسالةِ.
– نضيف جهازاً نظيراً (المستقبل)، ويجب أن نَعرفَ عنوان MAC الخاصّ به.
– نرسلُ رسالةً للجهازِ النَّظيرِ.
ويحقّقُ برنامجُ المستقبل مايلي:
– تهيئة ESP-NOW.
– نَكتبُ تابعَ الاستدعاءِ للمُستقبلِ وهو (OnDataRecv) والذي ينفّذ عندما تصِل الرّسالة.
– وفي تابعِ الاستدعاءِ نَحفظُ الرّسالة في مُتغيّرٍ لإنجازِ أيّ مهمَّةٍ تَتعلَّقُ بتلكَ المعلومةِ،
فبروتوكول ESP-NOW يعملُ مع توابعِ الاستدعاءِ المستخدمةِ عندما تستَلم أو تُرسَل رِسالةً للجهازِ (حيثُ ستعلم إذا تمَّ التَّسليم أم فشِل)
توابع ESP-NOW المفيدة:
وهنا لدينا مُلخَّص للتَّوابعِ الأساسيّةِ المُستخدمةِ في هذا البروتوكول:
وصف التابع | التابع |
يهيئ هذا التَّابعُ ESP-NOW، ويجب تهيئة Wi-Fi قبله. | ()esp_now_init |
يستدعى هذا التَّابع للاقترانِ بجهازٍ وتمرير عنوان MAC النَّظير. | ()esp_now_add_peer |
إرسالُ البيانات بوساطة ESP-NOW. | ()esp_now_send |
إدخالُ تابع استدعاء محفّز من خلال البياناتِ المُرسلةِ، فعندما ترسل الرّسالة يستدعى التَّابع، وهذا التَّابع يعيدُ قيمةً سواء نجحَ التَّسليم أم فشلَ. | ()esp_now_register_send_cb |
إدخالُ تابع استدعاء محفّز من خلال استقبالِ البيانات، فعندما تصلُ البياناتُ من خلال بروتوكول ESP-NOW يستدعى هذا التابع. | ()esp_now_register_rcv_cb |
ولمزيدٍ من المعلوماتِ عن هذه التَّوابع انقر هنا
برنامج مرسِل ESP32 في بروتوكول ESP-NOW
وهنا كودُ لوح ESP32 المرسِل، انسخ الكودَ إلى بيئةِ أردوينو البرمجيَّةِ ولكن لا تُحمّله، عليكَ إجراء بعض التَّعديلاتِ لكي يعمل عندك.
لتحميل الكود البرمجي، اضغط هنا.
كيف يعمل الكود؟
أولاً: ضمِّن كلّاً من المكتبتين esp_now.h و WiFi.h
#include <esp_now.h>
#include <WiFi.h>
في السَّطرِ الآتي عليكَ إضافة عِنوان MAC لمُستقبلِ ESP32
uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};
في هذه الحالةِ العنوانُ لدينا 30:AE:A4:07:0D:64 ولكن استبدلهُ بعنوانِ MAC الخاصّ بك.
أنشئ التَّركيبَ الذي يحوي نوعَ البياناتِ الذي تريدُ إرسالَه، نسمّي التَّركيبَ هُنا struct_message، وهو يحوي أربعَ أنواعَ متغيّراتٍ مُختلفةٍ بإمكانك تغييرُها لإرسالِ أنواعٍ أخرى من المُتغيّرات.
لتحميل الكود البرمجي، اضغط هنا.
ثم أنشئ متغيّراً جديداً من نوعِ struct_message يُدعى myData لتخزينِ قيم المُتغيّرات.
struct_message myData;
أنشئ مُتغيّراً من نوعِ esp_now_peer_info لتخزينِ المعلوماتِ عن النَّظير.
esp_now_peer_info_t peerInfo;
ثمَّ عرّف التَّابع OnDataSent() وهو تابعُ استدعاءٍ يُنفَّذُ عندَ إرسالِ الرّسالةِ، في هذه الحالةِ التَّابع سيُظهرُ ببساطةٍ إذا سُلّمتِ الرسالة أم لا.
لتحميل الكود البرمجي، اضغط هنا.
في تابع setup() يجب تهيئةَ شاشة العرض التَّسلسليّ من أجلِ اكتشافِ الأخطاءِ وتعديلِها:
Serial.begin(115200);
عيّنْ الجهاز كمحطةِ Wi-Fi
WiFi.mode(WIFI_STA);
تهيئةُ ESP-NOW:
if (esp_now_init() != ESP_OK) {
Serial.println(“Error initializing ESP-NOW”);
return;
}
بعدَ نجاحِ تهيئةِ ESP-NOW أدخل تابعَ الاستدعاءِ الذي يستدعى عندما تُرسَل الرّسالة، وفي هذه الحالة نُدخل تابع OnDataSent() المُنشَأ سابقاً.
esp_now_register_send_cb(OnDataSent);
والآن نريدُ أن نربطَ ESP-NOW مع جهازٍ آخرٍ لإرسالِ المعلوماتِ وهذا ما سنفعلُه في الأسطر الآتية:
لتحميل الكود البرمجي، اضغط هنا.
في تابع loop() سنرسلُ رسالةً عبرَ ESP-NOW كلَّ ثانيتينِ (بإمكانكَ تعديل زمنِ التأخير)
أولاً: نضبطُ قيمَ المتغيراتِ كما يلي:
strcpy(myData.a, “THIS IS A CHAR”);
myData.b = random(1,20);
myData.c = 1.2;
myData.d = false;
تذكَّر أنَّ myData هو تركيبٌ، هنا نسند القيمَ التي نودُّ إرسالها ضمن التَّركيب، فعلى سبيل المثال السَّطر الأوَّل يسند لمِحرف char والسَّطر الثَّاني لعددٍ صحيح ٍ int ورقم بفواصلِ عشرية ٍ float ومتغيّرٍ منطقيّ boolean.
لقد أنشأنا هذا النَّوع من التراكيبِ لنظهر كيفيَّةَ إرسالِ أنواعِ المتغيراتِ الشَّائِعة وبإمكانكَ تغيير هذه التَّراكيب لإرسالِ بياناتٍ من أنواعٍ مختلفةٍ.
أخيراً أرسِل الرّسالة كما في السَّطر الآتي:
لتحميل الكود البرمجي، اضغط هنا.
تحقَّق من نجاحِ إرسالِ الرّسالةِ:
if (result == ESP_OK) {
Serial.println(“Sent with success”);
}
else {
Serial.println(“Error sending the data”);
}
ينفّذ تابع loop() كلَّ 2000 ميلي ثانية (ثانيتين)
delay(2000);
برنامج مُستقبل ESP32 في بروتوكول ESP-NOW
حَمِّل الكودَ الآتي للوحِ ESP32 المستقبل.
لتحميل الكود البرمجي، اضغط هنا.
كيف يعمل هذا الكود؟
يشابه هذا الكود كودَ المُرسل فيبدأُ بتضمينِ المكتباتِ:
#include <esp_now.h>
#include <WiFi.h>
أنشئ تركيباً لاستقبالِ البياناتِ وهذا التَّركيب يجبُ أن يكونَ التَّركيبُ نفسُه المعرّف في برنامجِ المرسل.
typedef struct struct_message {
char a[32];
int b;
float c;
bool d;
} struct_message;
أنشئ متغيّراً struct_message وسَمِّه myData
struct_message myData;
أنشئ تابعَ استدعاءٍ والذي سيستخدمُ عندما تصلُ البيانات للمستقبلِ عبر ESP-NOW ويسمّى هذا التَّابع ()onDataRecv، ويجب أن يقبلَ بارامتراتٍ عِدَّة كما هو موضَّح في السَّطرِ الآتي:
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
ننسخُ محتوى بياناتِ المتغيّر incomingData إلى المتغيّرِ myData
memcpy(&myData, incomingData, sizeof(myData));
يحوي التَّركيبُ myData متغيراتٍ عِدَّة متضمّنةً القيم المرسلة بوساطةِ مرسل ESP32، وللوصولِ إلى متغيّرٍ a على سبيلِ المثال فعليكَ استدعاءِ myData.a
وهنا ببساطةٍ سنطبعُ البياناتِ المستلمة، ولكن في التَّطبيقِ العَمليّ بإمكانكَ على سبيلِ المثال طباعة البياناتِ على شاشةِ عرضٍ.
لتحميل الكود البرمجي، اضعط هنا.
في تابع ()setup يجبُ تهيئةَ شاشة العرضِ التَّسلسليّ:
Serial.begin(115200);
عيّن الجهاز كمحطةِ Wi-Fi:
WiFi.mode(WIFI_STA);
تهيئةُ ESP-NOW:
if (esp_now_init() != ESP_OK) {
Serial.println(“Error initializing ESP-NOW”);
return;
}
أدخل تابعَ استدعاءٍ يستدعى عندما تستلم البيانات وفي هذه الحالة ندخل التَّابع OnDataRecv() المنشأ سابقاً.
esp_now_register_recv_cb(OnDataRecv);
اختبار اتصال ESP-NOW
حمِّل كلّاً من برنامجِ لوحِ ESP32 المرسل وبرنامجِ لوح ESP32 المستقبل. والآن افتح نافذتين في بيئةِ أردوينو البرمجيّة واحدة للمستقبل والأخرى للمرسل، و افتح شاشةَ العرضِ التَّسلسليّ لكلّ لوحة ويجب أن يختلفَ منفذُ COM لِكلّ لَوحة مِنهما.
هذا ما ستحصلُ عليهِ من جهةِ المرسل:
وهذا ما ستتلقَّاهُ من جهةِ المستقبلِ، لاحظ أنَّ المتغير الصَّحيح int يتغيَّرُ بين كلّ قراءة مستلمة (وذلك لأنَّنا وضعنا رقماً عشوائيّاً في جهةِ المرسل).
وعندَ اختبار التَّغطية بينَ اللَّوحينِ فبإمكانِنا الحصول على اتّصالٍ مستقرّ لمسافةٍ تصِلُ إلى 220 متراً (حوالي 722 قدم) في مجالٍ مفتوحٍ، وفي هذهِ التَّجربةِ كلٌّ من هوائيَيّ اللَّوحينِ موجّهٌ نحوَ الآخر.
ملخّص
لقد حاولنا أن نبسطَ أمثلَتنا قدر الإمكانِ لتستطيعَ فهمَ كيفَ يَعملُ كلّ شيءٍ، وهناكَ العديدُ من توابعِ ESP-NOW المرتبطة والتي قد تكونُ مفيدةً في مشاريعكَ مثل: إدارةُ النَّظائِرِ، وحذفُ النَّظائر، والبحث عن الأجهزةِ التَّابعةِ… الخ وللحصولِ على مثالٍ متكاملٍ اختر أحدَ الأمثلةِ في بيئة أردوينو البرمجيَّة وذلك بالضَّغطِ على الخياراتِ:
File > Examples > ESP32 > ESPNow.
نتمنَّى أن تكونوا قد حَظيتم بمقدّمةٍ مفيدةٍ عن ESP-NOW وكمثالٍ بسيطٍ للبدءِ باستخدامِه أظهرنَا كيفيَّة إرسالِ البياناتِ كتركيب من لوحِ ESP32 إلى آخر، ويمكن تطوير الفكرة بتبديلِ قيمِ التركيبِ مثلاً بقراءةِ حسَّاسٍ ما أو بحالاتِ GPIO.
إضافة لذلك كلّ لوح يَستخدمُ بروتوكول ESP-NOW بإمكانِه أن يكونَ مرسل ومستقبل بالوقتِ نفسهِ، حيثُ يمكن أن يرسلَ لوحٌ وحيدٌ بياناتٍ لألواحٍ متعددةٍ وأيضاً أن يستقبلَ البياناتِ من ألواحٍ متعددةٍ.
المصدر هنا
ترجمة: سها أديب، مراجعة:يارا قاضون، تدقيق لغوي: علي يونس، تصميم: علي العلي، تحرير: نور شريفة.