سنوضّح في هذا المقال كيفيّة استخدام بروتوكول اتّصال ESP-NOW لإرسال البيانات من لوحة ESP32 واحدة إلى عدّة لوحات ESP32 أو ESP8266 (اتّصال من نوع: من واحد إلى متعدّد one-to-many)، وسنبرمج اللوحات باستخدام بيئة أردوينو البرمجيّة.
لاستخدام ESP-NOW مع ESP32 أو ESP8266، يمكنك الاطّلاع على المقالة التالية: هنا
نظرة عامّة على المشروع:
يوضّح هذا المقال كيفيّة إرسال البيانات من لوحة ESP32 واحدة إلى عدّة لوحات ESP32 أو ESP8266 باستخدام ESP-NOW (اتّصال من نوع: من واحد إلى متعدّد one-to-many).
- تعمل إحدى لوحات ESP32 كمرسل.
- تعمل لوحات ESP32، أو ESP8266 الأخرى، كمستقبل.
- تتلقّى لوحة ESP32 المُرسلة رسالة تأكيد توضّح فيما إذا سُلِّمت الرسالة بنجاح، أم لا.
- تحتاج إلى تحميل كود برمجيّ مختلف قليلاً إلى المستقبِل اعتماداً على ما إذا كنت تستخدم ESP32 أو ESP8266.
- ستتبادل اللوحات في هذا المثال قيماً عشوائيّة فيما بينها، ويمكن تعديل هذا المثال لإرسال أوامر أو قراءات حسّاس. للمزيد، تابع المقال هنا
-
سيغطّي هذا المقال حالتين:
- إرسال نفس الرسالة إلى جميع اللوحات.
- إرسال رسالة مختلفة إلى كلّ لوحة.
المتطلّبات:
سنبرمج لوحات ESP32/ESP8266 باستخدام بيئة أردوينو البرمجيّة، لذلك تأكّد من تثبيت هذه اللوحات لديك في بيئة أردوينو البرمجيّة قبل المتابعة في هذا المقال.
- Installing ESP32 Board in Arduino IDE (Windows, Mac OS X, and Linux)
- Installing ESP8266 Board in Arduino IDE (Windows, Mac OS X, Linux)
القطع المطلوبة:
تحتاج إلى عدّة لوحات ESP32، و/أو عدّة لوحات ESP8266.
الحصول على عنوان MAC الخاصّ باللوحات:
تحتاج إلى معرفة عنوان MAC للوحة المُستقبِلة لإرسال رسائل عبر ESP-NOW، حيث إنّ لكلّ لوحة عنوان MAC مميّز خاصّ بها (لمعرفة مزيد من هنا).
حمّل الكود التالي إلى كلّ لوحة مُستقبِلة للحصول على عنوان MAC الخاصّ بها.
لتحميل الكود البرمجي اضغط هنا.
اضغط على زرّ RST/EN بعد تحميل الكود. عندها، يجب أن يُعرض عنوان MAC على شاشة العرض التسلسليّ.
يمكنك كتابة عنوان MAC الخاصّ باللوحات على ملصقات لتحديد كلّ لوحة بوضوح.
الكود البرمجيّ للوحة ESP32 المُرسلة:
يرسل الكود البرمجيّ التالي البيانات إلى عدّة لوحات ESP (ثلاثة) عبر ESP-NOW، وعليك تعديل الكود باستخدام عنوان MAC الخاصّ بلوحات الاستقبال لديك، وكذلك إضافة أو حذف أسطر من التعليمات البرمجيّة اعتماداً على عدد لوحات الاستقبال.
لتحميل الكود البرمجي اضغط هنا.
كيفيّة عمل الكود البرمجيّ:
ضمّن مكتبتي WiFi.h وesp_now.h. كما يلي:
<include <esp_now.h#
<include <WiFi.h#
أدخِل عنوان ال MAC إلى لوحة الاستقبال. في مثالنا، نرسل البيانات إلى ثلاث لوحات.
;uint8_t broadcastAddress1[] = {0x3C, 0x71, 0xBF, 0xC3, 0xBF, 0xB0} ;uint8_t broadcastAddress2[] = {0x24, 0x0A, 0xC4, 0xAE, 0xAE, 0x44} ;uint8_t broadcastAddress3[] = {0x80, 0x7D, 0x3A, 0x58, 0xB4, 0xB0}
أنشئ تركيب (structure)يحتوي على البيانات التي تريد إرسالها باسم test_struct، وهو يحتوي على متغيّرين صحيحين، ويمكنك تغيير ما سبق لإرسال أيّ نوع من المتغيّرات.
}typedef struct test_struct ;int x ;int y { ;test_struct
أنشئ متغيّراً جديداً من النوع test_struct، وسمِّه test؛ لتخزين قيم المتغيّرات.
;test_struct test
أنشئ متغيّراً من النوع esp_now_peer_info_t لتخزين معلومات حول اللوح النظير.
;esp_now_peer_info_t peerInfo
تابع استدعاء ()OnDataSent:
عرّف التابع ()OnDataSent، وهو تابع استدعاء سينفّذ عند إرسال رسالة. يعرض هذا التابع رسالةً تأكيد في حال سُلّمت الرسالة بنجاح، أم لا، ولأيّ عنوان MAC سُلّمت، وبذلك ستعلم اللوحات التي تلقّت الرسالة، أو اللوحات التي لم تتلقّها.
لتحميل الكود البرمجي اضغط هنا.
()setup هيّئ شاشة العرض التسلسليّ في تابع setup() لاكتشاف الأخطاء وتعديلها :debbuging
;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 الأخرى لإرسال البيانات، وهذا ما نفعله في السطور التالية.
تسجيل الأقران:
لتحميل الكود البرمجي اضغط هنا.
إذا رغبت في إضافة المزيد من الأقران، يجب فقط تكرار هذه الأسطر، وتمرير عنوان MAC إلى الأقران:
;memcpy(peerInfo.peer_addr, broadcastAddress, 6)
}if (esp_now_add_peer(&peerInfo) != ESP_OK) ;Serial.println("Failed to add peer") ;return {
()loop
في ()loop، سنرسل رسالة عبر ESP-NOW كل ثانيتين (يمكنك تغيير وقت التأخير).
أسند قيمة لكلّ متغيّر.
;test.x = random(0,20) ;test.y = random(0,20)
تذكّر أنّ test عبارة عن تركيب، فهنا تُسنَد القيم المُراد إرسالها داخل التركيب. في هذا المثال، نُرسل قيم عشوائيّة فقط، ويمكن استبدال هذه القيم بأوامر، أو قراءات حسّاسات في التطبيقات العمليّة على سبيل المثال.
إرسال نفس البيانات إلى عدّة لوحات:
أرسل الرسالة كالتالي:
;esp_err_t result = esp_now_send(0, (uint8_t *) &test, sizeof(test_struct))
الوسيط الأول للتابع ()esp_now_send هو عنوان MAC للمستلم. إذا مرّرنا 0 كوسيط، ترسل نفس الرسالة إلى جميع الأقران المُسجّلة. أما إذا كنت ترغب في إرسال رسالة مختلفة إلى كلّ قرين، فاتّبع ما يلي:
تحقّق فيما إذا أُرسلت الرسالة بنجاح.
}if (result == ESP_OK) {;Serial.println("Sent with success") }else ;Serial.println("Error sending the data") }
تُنفَّذ ()loop كلّ 2000 مللي ثانية (2 ثانية).
;delay(2000)
إرسال بيانات مختلفة إلى كلّ لوحة:
يشبه الكود البرمجيّ لإرسال رسالة مختلفة إلى كلّ لوحة إلى حدٍّ كبير الكود السابق، لذا سنلقي نظرة على الاختلافات.
إذا أردت إرسال رسالة مختلفة إلى كلّ لوحة، فستحتاج إلى إنشاء تركيب لكلّ منها. على سبيل المثال:
;test_struct test ;test_struct test2 ;test_struct test3
في هذه الحالة، سنرسل تركيب من نفس النوع (test_struct). يمكنك إرسال نوع مختلف طالما أنّ الكود البرمجيّ للمستقبل مستعدّ لتلقّيه.
ثمّ أسنِد قيم مختلفة لمتغيّرات كلّ بنية. أسندنا في هذا المثال أرقام عشوائيّة.
;test.x = random(0,20) ;test.y = random(0,20) ;test2.x = random(0,20) ;test2.y = random(0,20) ;test3.x = random(0,20) ;test3.y = random(0,20)
يجب استدعاء التابع ()esp_now_send لكلّ جهاز استقبال.
على سبيل المثال، أرسل التركيب test إلى اللوحة ذات عنوان MAC التالي: broadcastAddress1.
;esp_err_t result1 = esp_now_send( broadcastAddress1, (uint8_t *) &test, sizeof(test_struct))
}if (result1 == ESP_OK) ;Serial.println("Sent with success") }else {Serial.println("Error sending the data")
كرِّر ما سبق مع اللوحات الأخرى. أرسل تركيب test2 إلى اللوحة الثانية.
;esp_err_t result2 = esp_now_send( broadcastAddress2, (uint8_t *) &test2, sizeof(test_struct))
}if (result2 == ESP_OK) ;Serial.println("Sent with success") { }else ;Serial.println("Error sending the data") {
أرسل تركيب test3 إلى اللوحة الثالثة.
;esp_err_t result3 = esp_now_send( broadcastAddress3, (uint8_t *) &test3, sizeof(test_struct))
}if (result3 == ESP_OK) ;Serial.println("Sent with success") } }else ;Serial.println("Error sending the data") {
فيما يلي الكود البرمجيّ الكامل الذي يرسل رسالة مختلفة إلى كلّ لوحة.
لتحميل الكود البرمجي، اضغط هنا.
الكود البرمجيّ للوحة ESP32 المُستقبلة (ESP-NOW):
حمّل الكود البرمجيّ التالي إلى لوحات الاستقبال (استخدمنا ثلاث لوحات استقبال في مثالنا):
لتحميل الكود البرمجي، اضغط هنا.
كيفيّة عمل الكود البرمجيّ:
كما في كود المُرسل، ابدأ بتضمين المكتبات:
<include <esp_now.h# <include <WiFi.h#
أنشئ تركيب لاستقبال البيانات المُرسلة، ويجب أن يكون هو ذاته التركيب المعرّف في برنامج المُرسل.
}typedef struct test_struct ;int x ;int y { ;test_struct
أنشئ متغيّراً جديداً من النوع test_struct، وسمِّه myData.
;test_struct myData
أنشئ تابع استدعاء يُستدعى عند استقبال لوحة ESP32 البيانات عبر ESP-NOW. سمِّ التابع ()onDataRecv، ويجب أن يقبل العديد من البارمترات، كما يلي:
}void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len)
انسخ محتوى متغيّر incomingData إلى متغيّر myData..
;memcpy(&myData, incomingData, sizeof(myData))
يحتوي تركيب myData على العديد من المتغيّرات، بالإضافة إلى القيم المرسلة من قبل لوحة ESP32 المرسلة. على سبيل المثال، نستطيع الوصول إلى المتغيّر x من خلال استدعاء myData.x..
في هذا المثال، نظهِر البيانات المستلمة على شاشة العرض التسلسليّ، ولكن يمكنك إظهار البيانات على شاشة OLED في تطبيق عمليّ على سبيل المثال.
;Serial.print("Bytes received: ") ;Serial.println(len) ;Serial.print("x: ") ;Serial.println(myData.x) ;Serial.print("y: ") ;Serial.println(myData.y) ;()Serial.println
هيّئ شاشة العرض التسلسليّ في ()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)
الكود البرمجيّ للوحة ESP8266 المُستقبلة:
لتحميل الكود البرمجي، اضغط هنا.
يشبه هذا الكود إلى حدٍّ كبيرٍ كود لوحة ESP32 المُستقبلة، بصرف النظر عن التفاصيل الصغيرة، لذلك لن نوضّح كيفيّة عمله. لمعرفة المزيد يمكنك قراءة هنا
توضيح:
افتح شاشة العرض التسلسليّ في بيئة أردوينو البرمجيّة لمنفذ COM الذي يتّصل به المرسل بعد تشغيل جميع لوحاتك.
يجب أن تظهر رسائل تأكيد نجاح التسليم “Delivery Success” مع عنوان MAC للمستقبِل على شاشة العرض التسلسليّ.
إذا قطعت التغذية عن إحدى اللوحات، ستتلقّى رسالة فشل التسليم “Delivery Fail” لهذه اللوحة، وبذلك يمكن تحديد اللوحة التي لم تتلقَّ الرسالة بسرعة.
إذا أردت التحقّق من استلام اللوحات للرسائل، يمكنك فتح شاشة العرض التسلسليّ لمنفذ COM المتّصل بها، أو يمكنك استخدام PuTTY لإنشاء اتّصال تسلسليّ مع لوحاتك.
إذا كنت تستخدم PuTTY، حدّد الاتّصال التسلسليّ “Serial communication” واكتب رقم منفذ COM و”baud rate” معدّل الباود (115200) كما هو موضَّح أدناه، ثمّ انقر فوق فتح.
(baud rate: معدّل نقل البيانات بوحدات البتات في الثانية (((bps
بعد ذلك، يجب أن ترى الرسائل المستقبلة.
ملخّص:
أوضحنا في هذا المقال كيفيّة إرسال بيانات من لوحة ESP32 واحدة إلى عدّة لوحات ESP32 أو ESP8266 باستخدام ESP-NOW (اتّصال من نوع: من واحد إلى متعدّد one-to-many).
المصدر: هنا.
ترجمة: غدير سليمان، مراجعة: يارا قاضون، تدقيق لغوي: سلام أحمد، تصميم: علي العلي، تحرير: محمد حنّان.