ازدادت شهرة شريحة NodeMCU خلال السنوات الماضية بين الشرائح المستعمَلة في التطبيقات المرتبطة بإنترنت الأشياء (IoT) أو بتقنية الواي فاي WIFI؛ كونها تتضمّن وحدة واي فاي رخيصة الثّمن، ويمكن بالعمل عليها وبرمجتها أن نُنشِئ مُخدِّم ويب (web server) مُستقلّاً بشكل كامل.

سنبدأ بتعريف مُخدِّم الويب وكيفيّة عملهِ: يُخزِّن مُخدِّم الويب ويعالج ويوصل صفحات الويب إلى الزبائن (clients)، وزبون الشبكة العنكبوتيّة ليس إلّا مستعرِضَ الويب (browser) في الحاسوب المحمول وأجهزة الهاتف الذكيّة، ويتمّ الاتصال بين الزبون والمخدِّم باستعمال بروتوكول خاصّ يُدعى بروتوكول نقل النصّ المتشعّب (HTTP).

مُخدِّم الويب
مُخدِّم الويب (مصدر الصورة: موقع lastminuteengineers )

يبدأ الزبون في هذا البروتوكول بالتواصل عبر إرسال طلب (request) لصفحة ويب ما باستعمال البرتوكول (HTTP)، فيردّ المخدِّم بمحتوى صفحة الويب أو برسالة خطأ إن لم يتمكّن من الوصول إليها كالخطأ الشهير 404  ، ومعظم الصفحات التي يقدّمها المخدِّم هي ملفّات (HTML).

أنماط عمل شريحة ESP8266

تتميّز شريحة ESP8266 بأنّها لا تتّصل بشبكة واي فاي متوافرة لتعمل كمخدّم ويب فحسب، وإنّما يمكنها بناء شبكة مستقلّة، وتسمح للأجهزة الأخرى أن تتّصل بها مباشرةً لتصل لصفحات الويب، وذلك لأنّ شريحة ESP8266 يمكن أن تعمل بثلاثة أنماط مختلفة: النمط (Station mode)، ونمط (Soft Access Point mode) و نمط ثالث تجمع فيه النمطَين السابقَين معاً، بالتالي تمنحنا إمكانيّة لبناء شبكات متداخلة (mesh networks).

النمط (Station mode ) اختصاراً (STA):

تتّصل شريحة ESP8266 بشبكة واي فاي متوفّرة مُسبقاً باستعمال الموجّه (router) اللاسلكي خاصّتك وتُدعى بالمحطة (Station)

النمط (Station mode )
النمط (Station mode ) (مصدر الصورة: موقع lastminuteengineers )

تتلقّى شريحة ESP8266 في نمط المحطّة (STA) عنوان الـ IP من الموجّه اللاسلكي المتّصل بها،  بعدها يمكن إنشاء مخدِّم ويب وإيصال صفحات الويب إلى جميع الأجهزة المتّصلة ضمن شبكة الواي فاي.

النمط الثاني (Soft Access Point mode) اختصاراً (AP):

تُدعى شريحة ESP8266 التي تُنشئ شبكة الواي فاي الخاصّة بها ، وتعمل كموزع (hub) (كموجّه شبكة الواي فاي) لواحدة أو أكثر من المحطّات بنقطة الوصول(AP)، وعلى خلاف موجّه الواي فاي هي لا تملك واجهة للتعامل مع الشبكة السلكيّة، ولهذا يُدعى هكذا نمط عمل بــ Soft Access Point (soft-AP)، ويصل عدد المحطّات المتّصلة معها إلى خمسة.

النمط الثاني (Soft Access Point mode)
النمط الثاني (Soft Access Point mode) (مصدر الصورة: موقع lastminuteengineers )

وفي نمط ال AP تُنشئ شريحة ESP8266 شبكة واي فاي جديدة ، وتحدّد اسماً للشبكة (SSID)، وعنوانIP خاصّاً بها، يمكن لجميع الأجهزة المتّصلة بشبكتها من خلال هذا العنوان الوصول لصفحات الويب.

توصيل LED مع شريحة الESP8266 NodeMCU:

وبعد أن استعرضنا أساسيات عمل مخدِّم الويب، وأيّ أنماط يمكننا من خلالها إنشاء مخدِّم سننتقل إلى التوصيل

بداية تقوم بوضع شريحة الـ  NodeMCUعلى لوح التجريب (breadboard) بحيث يوضع كلّ من جانبي الشريحة في مكان منفصل عن الجانب الآخر للوح، وبعدها نقوم بوصل الديودَين الباعثَين للضّوء (LED) إلى المَنفذ العام الرقميّ GPIO D6 و D7 عبر مقاومة قيمتُها 220 أوماً، وتحصل على مخطّط كما في الشكل الآتي:

توصيل LED مع شريحة الESP8266 NodeMCU
توصيل LED مع شريحة ال ESP8266 NodeMCU (مصدر الصورة: موقع lastminuteengineers )

مفهوم التحكّم بالأجهزة باستعمال مخدِّم ويب الشريحة 8266ESP :

عندما تكتب رابط URL في مستعرض الويب خاصّتك وتضغط زر Enter يُرسل المستعرِض طلب HTTP الذي يُعرف بطلب GET إلى مخدِّم الويب، يتعامل مخدِّم الويب مع هكذا طلب بتنفيذ أمرٍ ما. للتحكّم بأيّ جهاز علينا استعمال رابط ٍما ذي عنوان مخصَّص مثل http://192.168.1.1/ledon في مستعرض، ويُرسل المستعرِض طلب HTTP إلى شريحة ESP8266  للتعامل مع هذا الطلب، وعند قراءة الشريحة هذا الطلب تفسِّر رغبة المستخدم بإضاءة الليد وتضيْئُه، وترسل صفحة ويب ديناميكيّة إلى المستعرض مظهرةً حالة الليد المفعَّلة( LED status : ON) . وهذا المثال يوضّح كيفية تحويل الشريحة إلى نقطة وصول (AP)، وإيصال صفحات الويب لأيّ زبون متّصل.

للبدء بتنفيذ ذلك قُم بوصل شريحة ESP8266 NodeMCU إلى جهاز الحاسوب لديك ، ثمّ ضَع ِالشيفرة البرمجيّة الآتية:

الكود البرمجي : للتحميل انقر هنا


الوصول إلى مخدّم الويب في نمط AP

بعد تحميل البرنامج قم بفتح نافذة العرض التسلسليّة بمعدل بود 115200، واضغط زر إعادة التشغيل (RESET) الموجود على الشريحة، فتظهر رسالة  في نافذة العرض التسلسليّة (HTTP server started)

رسالة  في نافذة العرض التسلسليّة (HTTP server started)
رسالة  في نافذة العرض التسلسليّة (HTTP server started) (مصدر الصورة: موقع lastminuteengineers )

بعدها قم بإيجاد الجهاز الذي يمكنك من خلاله الاتّصال بشبكة واي فاي (لابتوب، هاتف..)  وابحث عن شبكة لها الاسم NodeMCU، وقم بالاتصال بها وكتابة كلمة السّرّ الآتية: 123456789

الاتّصال بشبكة واي فاي
الاتّصال بشبكة واي فاي (مصدر الصورة: موقع lastminuteengineers )

بعد الاتصال بشبكة AP الخاصّة بشريحة NodeMCU ، افتح مستعرض الويب واكتب العنوان 192.168.1.1  فتظهر صفحة  ويب مبيّنةً الحالة الحاليّة لليدات وأزرار التحكُّم، وبالنّظر إلى واجهة العرض التسلسليّة في ذات الوقت يمكنك مشاهدة حالة المنافذ العامّة لشريحة NodeMCU.

صفحة  ويب مبيّنةً الحالة الحاليّة لليدات وأزرار التحكُّم
صفحة  ويب مبيّنةً الحالة الحاليّة لليدات وأزرار التحكُّم (مصدر الصورة: موقع lastminuteengineers )

الآن نضغط على الزر لتشغيل الليد1 ونراقب عنوان الـURL، فعند الضغط على الزرّ تتلقّى شريحة ESP8266 طلباّ برابط بنهايته   /led1on لتشغيل الليد، يُضيء الليد، وتتحدّث حالة الليد على صفحة الويب، وتظهر حالة المنافذ العامّة على الواجهة التسلسليّة.

عنوان الـ URL لتشغيل الليد
عنوان الـ URL لتشغيل الليد (مصدر الصورة: موقع lastminuteengineers )

يمكنك الآن اختبار زرّ الليد الثاني والتحقّق من عمله بالطريقة ذاتها. والآن سنتعمّق في فهم الكود البرمجيّ وكيفيّة عمله ليكون بإمكاننا التعديل عليه حسب رغبتنا.

شرح الكود البرمجيّ

يبدأ الكود بتضمين مكتبة ESP8266WiFi.h التي تؤمّن توابع (Methods) نستدعيها للاتصال بالشبكة، بعد ذلك نُضمّن مكتبة ESP8266WebServer.h التي تحتوي بعض التوابع التي تساعد بإعداد مخدِّم ، وتتعامل مع طلبات HTTP دون الحاجة للقلق من تفاصيل التنفيذ .

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

وبينما نقوم بضبط شريحةNodeMCU  إلى نمط نقطة الوصول (AP) ستنشأ شبكة واي فاي؛ لذا نحتاج لإدخال اسم الشبكة(SSID)، وكلمة السرّ(Password)، وعنوان الIP لقناع الشبكة(IP subnet mask)،و عنوان البوابة (IP gateway)،

/* Put your SSID & Password */
const char* ssid = "NodeMCU";  // Enter SSID here
const char* password = "12345678";  //Enter Password here

/* Put IP Address details */
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddress subnet(255,255,255,0);

بعدها نعرَف كائن (object) من مكتبة  ESP8266WebServer حتى يمكننا الوصول لتوابعها، والتابع الباني للكائن يأخذ منفذ port (حيث يتنصّت المخدّم فيها ) كمعامل، وبما أنّ “80” هو رقم منفذ بروتوكول HTTP الافتراضي سنستعمل هذه القيمة، ويمكنك الوصول إلى لمخدّم دون الحاجة لتحديد المنفذ في الـرابط

// declare an object of ESP8266WebServer library
ESP8266WebServer server(80);

بعدها نصرّح بالمنافذ العامّة للـ NodeMCU التي تتّصل معها الليدات ونعطي لها قِيماً ابتدائيّة:

uint8_t LED1pin = D7;
bool LED1status = LOW;

uint8_t LED2pin = D6;
bool LED2status = LOW;

شرح ما ضمن تابع Setup()

نقوم بإعداد مخدّم HTTP قبل تشغيله، أولاً ننشئ اتّصالاً تسلسليّاً بهدف تحديد الأخطاء وتصحيحها، وضبط المنافذ العامّة كخرج.

Serial.begin(115200);
pinMode(LED1pin, OUTPUT);
pinMode(LED2pin, OUTPUT);

بعد ذلك نُنشئ نقطة وصول برمجية لإنشاء شبكة واي فاي بكتابة اسم الشبكة، وكلمة السّرّ، وعنوان الIP لقناع الشبكة، وعنوان البوابة.

WiFi.softAP(ssid, password);
WiFi.softAPConfig(local_ip, gateway, subnet);
delay(100);

وبغرض التعامل مع طلبات  HTTP القادمة نحتاج أن نحدّد الشيفرة الواجب تنفيذها مع كل رابط، لذلك نستعمل تابعاً فرعيّاً on، الذي يأخذ مُعامِلَين: الأوّل هو الرابط ، والثاني هو اسم التابع الذي نرغب بتنفيذه عند نقر الرابط.

وكمثال: يشير السطر الأوّل من المقطع البرمجيّ أدناه أنّه عندما يتلقّى المخدّمِ طلب HTTP ذي إشارة (/)، فيستجيب التابع ()handle_OnConnect

وبالمثل فإنّنا نحتاج لأربعة روابط للتعامل مع حالتي ليدات.

server.on("/", handle_OnConnect);
server.on("/led1on", handle_led1on);
server.on("/led1off", handle_led1off);
server.on("/led2on", handle_led2on);
server.on("/led2off", handle_led2off);

لم نحدّد ما ينبغي للمخدّم عمله إذا كانت طلبات الزبون هي أيّ رابط مغاير عن المحدّد بـ server.on()، إذ ينبغي أن يستجيب بـ الرمز 404 (غير متوفر)، لذا نستعمل تابع  server.onNotFound()  الذي يحدد ما يجب تنفيذه عندما نتلقى طلباً لرابط لم يكن محدّداً بـserver.on

server.onNotFound(handle_NotFound);

والآن نشغل المخدّم خاصّتنا باستدعاء التابع begin.

server.begin();
Serial.println("HTTP server started");

تابع Loop()

للتعامل مع طلبات HTTP القادمة علينا استدعاء تابع فرعيّ handleClient()، وعلينا تغيير أيضاً حالة الليد بحسب الأمر

void loop() {
  server.handleClient();
  if(LED1status)
  {digitalWrite(LED1pin, HIGH);}
  else
  {digitalWrite(LED1pin, LOW);}
  
  if(LED2status)
  {digitalWrite(LED2pin, HIGH);}
  else
  {digitalWrite(LED2pin, LOW);}
}

بعد ذلك نحتاج إلى كتابة تابع خاصّ بورود رابط ينتهي بهذا الرمز (/) والذي سيكون كمعامل في التابع server.on  ، وببدايته نضبط حالة الليدات (الحالة الابتدائيّة لليدات) ، ونعرض القِيم في نافذة العرض التسلسليّة، نستخدم تابعاً فرعيّاً send للإجابة  على طلب HTTP، وعلى الرغم من أنّ التابع فرعيٌّ يمكن أن يُستدعى بعدد مختلف من البارامترات إلّا أنّ أبسطها يتألّف من رمز استجابة HTTP ونمط المحتوى والمحتوى.

في حالتنا نرسل رمز 200 (أحد رموز حالة الHTTP) الذي يستجيب بـ OK، بعدها نحدّد نمط المحتوى ب“text/html“

وأخيراً نستدعي ()SendHTML الدالة المخصصّة التي تُنشئ صفحة HTML ديناميكيّة تحتوي حالة الليدات.

الكود البرمجي: للتحميل انقر هنا

عرض صفحة ويب الHTML

يتولى التابع ()SendHTML مسؤوليّة إنشاء صفحة ويب في أيّ وقت يتلقّى فيه مخدّم ويب الشريحة  ESP8266 طلباً من زبون، تجمّع   HTMLبشكل سلسلة ضخمة يتّخذ التابع حالة الليدات كمعامل للتوليد الديناميكيّ لمحتوى HTML.

ينبغي إرسال أول رسالة بالشكل !DOCTYPE> declaration> وتشير أنّنا نرسل كود HTML

String SendHTML(uint8_t led1stat,uint8_t led2stat){
String ptr = "<!DOCTYPE html> <html>\n";

بعدها يجعل  meta> viewport element> صفحة الويب تستجيب في أي مستعرض ويب، بينما يحدّد الوسم title عنوان الصفحة.

ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>LED Control</title>\n";

تصميم صفحة الويب

بعدها لدينا العديد من الخيارات في لغة (CSS) لتصميم الأزرار ومظهر صفحة الويب، ونختار خط هيلفيتكا (Helvetica font)، ونحدّد المحتوى ليُوضع كصندوق داخليّ ومتوضِّع في منتصف الصفحة.

ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";

ويَضبط الكود الآتي الألوان والخط والهوامش حول جسم الصفحة وحجوم العناوين والفقرات H1 وH3 وp

ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
ptr +="p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";

ويطبّق بعض التعديلات على شكل الأزرار والخصائص كاللون والحجم والهامش وغيرها، ولزرّ التشغيل والإطفاء لون خلفيّة مختلفٌ، بينما الخاصيّة (active selector) للأزرار تؤكّد عمل الزرّ لدى نقره.

ptr +=".button {display: block;width: 80px;background-color: #1abc9c;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
ptr +=".button-on {background-color: #1abc9c;}\n";
ptr +=".button-on:active {background-color: #16a085;}\n";
ptr +=".button-off {background-color: #34495e;}\n";
ptr +=".button-off:active {background-color: #2c3e50;}\n";

ضبط ترويسة صفحة الويب:

بعد ذلك تكون ترويسة صفحة الويب جاهزة ويمكن تغيير هذا النص لأيّ نصّ يلائم تطبيقك.

ptr +="<h1>ESP8266 Web Server</h1>\n";
ptr +="<h3>Using Access Point(AP) Mode</h3>\n";

عرض الأزرار وحالتها الموافقة

نستخدم الشرط if للتوليد الديناميكي للأزرار وحالة الليد، لذا بالاعتماد على حالة المنافذ العامّة يتمّ عرض أزرار ON/OFF

if(led1stat)
  {ptr +="<p>LED1 Status: ON</p><a class=\"button button-off\" href=\"/led1off\">OFF</a>\n";}
else
  {ptr +="<p>LED1 Status: OFF</p><a class=\"button button-on\" href=\"/led1on\">ON</a>\n";}

if(led2stat)
  {ptr +="<p>LED2 Status: ON</p><a class=\"button button-off\" href=\"/led2off\">OFF</a>\n";}
else
  {ptr +="<p>LED2 Status: OFF</p><a class=\"button button-on\" href=\"/led2on\">ON</a>\n";}

شريحةESP8266كمخدّم باستعمال نمط (STA)

لننتقل لمثالنا الذي نوضّح فيه كيفيّة تحويل شريحة ESP8266 إلى نمط (STA) وتقديم صفحات الويب لأي زبون متّصل إلى شبكة موجودة.

قبل أن تتطرّق لتحميل الكود البرمجيّ، تحتاج لتعديله بما يناسبك حيث تحتاج لتعديل المتغيّرين التاليَين من معلومات الوثوقيّة لشبكتك  لتستطيع الشريحة من تأسيس اّتّصال بالشبكة المتواجدة.

تعديل المتغيّرين التاليَين من معلومات الوثوقيّة
تعديل المتغيّرين التاليَين من معلومات الوثوقيّة لشبكتك (مصدر الصورة: موقع lastminuteengineers )

بمجرّد انتهائك جرب الكود البرمجيّ

الكود البرمجيّ: للتحميل انقر هنا

الوصول لمخدّم الويب في نمط STA

بعد تحميل الكود البرمجيّ نقوم بفتح الواجهة التسلسليّة بمعدل بود 115200، ونضغط زرّ إعادة التشغيل الموجود على شريحة ESP8266، وإن جرى كل ّشيء على ما يرام سيكون الخَرْج عنوانIP ديناميكيّ يُحصل عليه من جهاز الراوتر وتظهر رسالة (HTTP server started )

الخَرْج عنوانIP ديناميكيّ يُحصل عليه من جهاز الراوتر
الخَرْج عنوانIP ديناميكيّ يُحصل عليه من جهاز الراوتر (مصدر الصورة: موقع lastminuteengineers )

بعد ذلك نقوم بفتح مستعرض ونكتب مكان العنوان عنوان IP الذي يظهر على الواجهة التسلسليّة، وينبغي على الشريحة أن ترسل صفحة ويب مُظهرِة حالة الليدات والزرين للتحكّم بهم، وبالنظر للواجهة التسلسليّة في ذات الوقت يمكنك رؤية حالة المنافذ العامّة للـ NodeMCU

نكتب مكان العنوان عنوان IP الذي يظهر على الواجهة التسلسليّة
نكتب مكان العنوان عنوان IP الذي يظهر على الواجهة التسلسليّة (مصدر الصورة: موقع lastminuteengineers )

الآن بالضغط على الزرّ يعمل الليد1 بينما نستمرّ بمراقبة الرابط، وحالما يُضغط الزرّ تتلقّى الشريحة طلباً لرابط/led1on، عندها يعمل الليد ويفتح صفحة ويب بحالة الليد المحدَّثة، ويطيع حالة المنفذ العام ّعلى الواجهة التسلسليّة.

يمكنك اختبار زرّ الليد2 والتحقّق من عمله بطريقة مماثلة.

شرح الكود البرمجيّ:

بتفحص هذا الكود والكود السابق، نجد الاختلاف الوحيد يكمن بعدم إنشاء نقطة وصول ، وبدلاً من ذلك نضيف شبكة موجودة باستعمال التابع ()WiFi.begin

//connect to your local wi-fi network
  WiFi.begin(ssid, password);

بينما تحاول الشريحة الاتصال بالشبكة، يمكن التحقّق من الحالة باستعمال التابع ()WiFi.status

//check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.print(".");
  }

لنحيطك علماً أنّ هذا التابع يعيد الحالات الآتية:

●      WL_CONNECTED: تخصّص عند الاتصال بشبكة واي فاي

●      WL_NO_SHIELD: تخصّص عند عدم اتصال دارات ملحقة خاصّة بالواي فاي (Wi-Fi shield )

●      WL_IDLE_STATUS: هي حالة مؤقتة تخصّص عند استدعاء الدالّة ()WiFi.begin  وتبقى فعّالة حتى ينتهي عدد مرّات المحاولات(تنتج WL_CONNECT_FAILED) أو تأسيس الاتّصال(تنتج WL_CONNECTED )

●      WL_NO_SSID_AVAIL: تخصّص عند عدم توفّر أي اسم شبكة واي فاي

●      WL_SCAN_COMPLETED: تخصّص عند انتهاء البحث عن الشبكات

●      WL_CONNECT_FAILED: تخصّص عند فشل الاتصال لكلّ المحاولات

●      WL_CONNECTION_LOST: تخصّص عند فقدان الاتصال

●      WL_DISCONNECTED: تخصّص عند فصل الاتصال عن شبكة

ولدى اتصال شريحة الـ ESP8266 بالشبكة يطبع الكود البرمجيّ عنوان الIP المخصّص للشريحة بإظهار قيمة ()WiFi.localIP على الواجهة التسلسليّة.

Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: ");  Serial.println(WiFi.localIP());

الفرق الوحيد بين نمط AP & STA أنّ أحدهما يُنشئ الشبكة والأخر ينضمّ إلى شبكة موجودة، ولذا بقية الكود للتعامل مع طلبات HTTP وتقديم صفحة ويب بنمط STA هو نفسه كنمط AP الموضّح أعلاه، ويتضمّن:

●      تصريح المنافذ العامة للشريحة التي تتصل الليدات بها.

●      تحديد العديد من التوابع الفرعيّة ()server.on للتعامل مع طلبات HTTP.

●      تحديد تابع فرعيّ ()server.onNotFound للتعامل مع خطأ HTTP  404

●      إنشاء توابع مخصّصة للاستجابة  لرابط  URLمحدّد

●      إنشاء صفحة HTML

●      تصميم صفحة الويب

●      إنشاء أزرار وإظهار حالتها


المصدر: هنا

ترجمة: مي همدر, مراجعة: علي العلي, تدقيق لغوي: رنيم العلي, تصميم: علي العلي, تحرير: كرم ديوب.