عملکرد وب سوکت
ایجاد صفحه نمایش تحت وب (وب سرور) همواره یکی از نکات مهم در پروژههای مبتنی بر پردازندههای وای فای (ESP32 و ESP8266) است. با استفاده از کدهای وب در این صفحات، میتوان انواع مقادیر مرتبط با سخت افزار را نمایش داد. یا با کلیک کردن روی دکمههای نرمافزاری در صفحه وب، تغییرات وضعیتی را در سختافزار اعمال کرد. این کار از نظر کاربری بسیار جذاب و حرفهای به نظر میرسد. بزرگترین مشکل در این صفحات، بارگذاری مقادیر آنهاست. مثلا برای نمایش مقدار دما و رطوبت که توسط سنسور اندازهگیری شدهاند، مجبور به رفرش کردن صفحه هستید تا مقادیر جدید نمایش داده شوند. همچنین، با زدن هر کلید در صفحه وب تحت پروتکل GET یا POST نیز، مجبور به رفرش صفحه هستید. که ممکن است از جذابیت پروژه کاسته شود. (وب سرور بدون وب سوکت در وای فای های ESP32 یا ESP8266)
آموزش توابع آردوینو (توابع پایه)
پروژه وب سرور 10 کانال با NodeMCU
برای حل مشکلات نمایش داده های real-time، استفاده از وب سوکت به عنوان یک پروتکل دوطرفه، کاملا ایدهآل است که در طول زمان ارتباط دو طرفه بین مرورگر و سخت افزار وای فای ESP32 یا ESP8266 را برقرار می کند و قادر به ارسال و دریافت دادهها است. وب سوکت پیوسته تلاش می کند تا تأخیر در شبکه را کاهش دهد و باعث بهرهوری عالی شود. با استفاده از وب سوکت، می توان با سرور تعامل کرد و دادههای جدید را به مرورگر ارسال و درخواست آن ها را از مرورگر دریافت کرد.
پیکربندی کتابخانه آردوینو
در کامپایلر آردوینو، کتابخانههای متعددی برای اجرای وبسرور و وبسوکت برای پردازندههای وای فای (ESP32 و ESP8266) موجود است. که هر یک مزایا و معایبی در عملکرد و کد نویسی دارند. مهمترین موضوع در انتخاب کتابخانه مناسب، این است که حلقه اصلی برنامه باید درگیر عملکرد وبسرور نشود. برخی کتابخانهها با تابع update صفحات وب را به مرورگر ارسال میکنند. در پروژههای پیچیده، این میتواند باعث تاخیر در فراخوانی تابع بروزرسانی وبسرور شود، زیرا برنامه ممکن است برای مدتی در حلقهای بماند.
توصیه می شود که برای وب سرور از کتابخانه ESPAsyncWebServer استفاده کنید. این کتابخانه قادر است صفحات وب ایجاد شده را بدون نیاز به تابع بروزرسانی به مرورگر کاربر ارسال کند و به صورت موازی با برنامه اصلی کار خود را انجام دهد. یکی از مزیت های دیگر این کتابخانه، پشتیبانی از وب سوکت است. به عبارت دیگر، با استفاده از این کتابخانه، به تنهایی می توانید یک صفحه وب حرفهای تحت پروتکل وب سوکت ارائه دهید و نیازی به کتابخانه وب سوکت جانبی ندارید.
فراخوانی کتابخانه ESPAsyncWebServer و ایجاد شی های مورد نیاز از آن را به صورت زیر ایجاد کنید.
#if defined(ESP8266)
#include
#elif defined(ESP32)
#include
#endif
#include
//Specifying the Webserver instance to connect with HTTP Port: 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
تنظیمات در حلقه Setup
قبل از فراخوانی توابع تنظیمات وب سرور و وب سوکت، لازم است ابتدا اتصالات وای فای را پیکربندی کنید. برای این کار، ابتدا کتابخانه وای فای مرتبط با پردازندهی مورد نظر را فراخوانی کرده و تنظیمات مربوطه را در حلقهی setup وارد کنید.
پس از تنظیم اتصالات وای فای، ابتدا حلقهی وقفه وب سوکت و سپس تعریف وب سوکت به هندلر وب سرور را مانند کد زیر بنویسید.
ws.onEvent(onEvent);
server.addHandler(&ws);
سپس، صفحات وب سرور را پیکربندی کنید. برای صفحات ساده و با اندازه کم، میتوانید کدهای مربوط به آنها را در متغیرهای برنامه قرار دهید. اما برای صفحات با اندازه و پیچیدگی بیشتر، از حافظه سیستم فایل SPIFFS استفاده کنید.
پس از تعیین محل ذخیره کدهای صفحات وب، با استفاده از یکی از کدهای زیر، صفحات خود را پیکربندی کرده و آدرس آنها را مشخص کنید.
// Route for root / web page stored in internal variables (const char html_page[] PROGMEM)
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send_P(200, "text/html", html_page);
});
// Route for root / web page stored of the file in the SPIFFS file system (page.html)
server.serveStatic("/", SPIFFS, "/");
server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(SPIFFS, "/page.html", "text/html");
});
حذف درخواست های قدیمی (oldest client)
ارسال درخواست های متعدد از سمت مرورگر باعث پر شدن منابع وب سرور میشود و در نهایت باعث از کار افتادن سرور میشود. برای جلوگیری از این اتفاق، کلاس AsyncWebSocket یک روش کارآمد برای تمیز کردن منابع ارائه میدهد. با استفاده از فراخوانی دورهای تابع زیر در حلقه ()loop، تعداد کلاینتها را به حداکثر مقدار مجاز محدود میکند و در صورتی که بازه زمانی تعیین شده رسیده باشد، کلاینتهای قدیمیتر بسته میشوند.
void loop() {
/*
* Other program codes
*/
ws.cleanupClients();
}
برنامه JavaScript (جاوااسکریپت)
کد های جاوااسکریپت معمولا در فایل .js ذخیره می شود.
جهت اجرای پروتکل وبسوکت در جاوااسکریپت، از توابع مربوط به آن استفاده میکنیم. در کدهای جاوا، ابتدا اتصال وبسوکت را مشخص کرده و سپس توابع ارسال و دریافت دادهها را تعریف میکنیم. با استفاده از آدرسهای id موجود در بخش html صفحه، میتوانیم مقادیر موردنظر را به صفحهی نمایش منتقل کنیم و یا با دریافت دادههای جدید از سرور، در قالب صفحه (style) تغییراتی ایجاد کنیم. فرمت کلی توابع وبسوکت در جاوااسکریپت به صورت زیر است:
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
// ----------------------------------------------------------------------------
// Initialization
// ----------------------------------------------------------------------------
window.addEventListener('load', onLoad);
function onLoad(event) {
initWebSocket();
}
// ----------------------------------------------------------------------------
// WebSocket handling
// ----------------------------------------------------------------------------
function initWebSocket() {
websocket = new WebSocket(gateway);
websocket.onopen = onOpen;
websocket.onclose = onClose;
websocket.onmessage = onMessage;
}
function onOpen(event) {
console.log('Connection opened');
websocket.send("Page reloaded");
}
function onClose(event) {
console.log('Connection closed');
setTimeout(initWebSocket, 2000);
}
function onMessage(event) {
console.log(event.data);
var myObj = JSON.parse(event.data);
var keys = Object.keys(myObj);
for (var i = 0; i < keys.length; i++){
var key = keys[i];
console.log(keys[i]);
}
}
تابع وقفه دریافت اطلاعات از مرورگر
در قسمتهای پیشین، به فراخوانی تابع ws.onEvent(onEvent) اشاره شد. با استفاده از این دستور، تابع وقفهای که تنظیم شده است، فراخوانی میشود و اطلاعات دریافتی قابل پردازش و مشاهده است. تابع وقفه به فرمت زیر باید نوشته شود:
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
AwsFrameInfo *info = (AwsFrameInfo*)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
data[len] = 0;
String message = (char*)data;
Serial.println(message);
}
}
void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
switch (type) {
case WS_EVT_CONNECT:
Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
break;
case WS_EVT_DISCONNECT:
Serial.printf("WebSocket client #%u disconnected\n", client->id());
break;
case WS_EVT_DATA:
Serial.println("DATA");
handleWebSocketMessage(arg, data, len);
break;
case WS_EVT_PONG:
Serial.println("PONG");
case WS_EVT_ERROR:
Serial.println("ERROR");
break;
}
}
ارسال اطلاعات از سرور به مرورگر
برای ارسال اطلاعات از سرور به مرورگر تحت پروتکل وب سوکت با پردازندههای وای فای (ESP32 و ESP8266)، ابتدا باید مقادیر را در فرمت JSON ذخیره کرده و سپس آنها را ارسال کرد. برای سهولت در تبدیل و ذخیره اطلاعات به فرمت JSON میتوان از کتابخانه Arduino_JSON استفاده کرد. در نهایت، اطلاعات ذخیره شده در رشته String را با فرمت زیر به مرورگر ارسال کنید:
ws.textAll(myData); //String myData
پروژه عملی
یکی از بهترین روشها برای فهمیدن مفاهیم مرتبط با وب سوکت در پردازندههای وای فای (ESP32 و ESP8266)، اجرای یک پروژه عملی است. برای این منظور میتوان از بازی Circle Game که با استفاده از توابع کیبورد در زبان جاوا پیادهسازی شده است، بهره گرفت و با استفاده از ژیروسکوپ به جای کلیدهای بالا و پایین و … از تغییرات زاویه فیزیکی استفاده کرد. در سخت افزار، با تغییر زاویه و ارسال مقادیر آن در دو راستای X و Y، دایره قرمز درون بازی که در مرورگر مشاهده میشود، جابجا میشود.