آموزش ESP32آموزش اینترنت اشیا

آموزش ساخت وب سرور با وب سوکت با ESP32

فرض کنید قصد داریم پروژه‌ای طراحی کنیم که در آن از ماژول ESP32 برای کنترل یک لامپ از طریق اتصال WiFi استفاده شود. پیاده‌سازی این پروژه بسیار ساده است: ESP32 را در حالت Soft-AP یا STA تنظیم می‌کنیم تا یک صفحه وب ارائه دهد که وضعیت کلید روشن/خاموش لامپ را به صورت “on” یا “off” نمایش می‌دهد. زمانی که کاربر در مرورگر کلید را تغییر می‌دهد، ESP32 یک درخواست HTTP دریافت می‌کند، وضعیت لامپ را متناسب با آن تنظیم کرده و پاسخ را به مرورگر ارسال می‌کند. این دقیقاً همان روشی است که هنگام ساخت یک وب‌  سرور ساده با ESP32 استفاده کردیم و عملکرد بسیار خوبی دارد.

اما این روش یک مشکل کوچک دارد. وب یک سیستم چندکاربره است، به این معنا که افراد مختلف می‌توانند به یک وب‌سرور واحد متصل شوند. در واقع، سرور منبعی مشترک است. حال تصور کنید دو کاربر هم‌زمان بخواهند لامپ را روشن یا خاموش کنند؛ در این صورت رابط‌های کاربری دو مرورگر با یکدیگر همگام نخواهند بود و وضعیت واقعی لامپ به درستی نمایش داده نمی‌شود. به همین دلیل، این روش برای چنین سیستم‌هایی مناسب نیست.

برای رفع این مشکل، می‌توان از قابلیت ارتباط دوطرفه (bi-directional) در پروتکل WebSocket استفاده کرد تا سیستمی واکنش‌گرا ایجاد شود. در این روش، با هر بار کلیک روی کلید لامپ، پیام فوراً به سرور ارسال شده و سپس به همه مرورگرهای متصل پخش می‌شود تا وضعیت کلید در تمام مرورگرها همواره هماهنگ باقی بماند.

در این آموزش، دقیقاً یاد می‌گیرید چطور با استفاده از پروتکل WebSocket یک وب‌سرور با ESP32 بسازید. در مثال عملی، صفحه وبی طراحی می‌کنیم که LED روی برد ESP32 را کنترل می‌کند. وضعیت LED روی صفحه وب نمایش داده می‌شود و به محض اینکه یکی از کاربران کلید LED را تغییر دهد، وضعیت LED در تمام مرورگرهای متصل به سرور بلافاصله به‌روزرسانی می‌شود.

آماده‌اید؟ پس شروع کنیم! قبل از هر چیز، بیایید ببینیم:

WebSocket چیست؟

اگرچه در نگاه اول نام “WebSocket” ممکن است گیج‌کننده به نظر برسد، اما مفهوم آن بسیار ساده است و می‌توان به‌سرعت آن را درک کرد.

WebSocket یک پروتکل ارتباطی است که امکان برقراری ارتباط دوطرفه (full-duplex) بین کلاینت و وب‌سرور را فراهم می‌کند. به زبان ساده، WebSocket فناوری‌ای است که به دو سمت ارتباط (کلاینت و سرور) اجازه می‌دهد تا اتصال پایداری برقرار کرده و در هر لحظه بتوانند داده‌هایی را برای یکدیگر ارسال کنند.

این روش با اتصال‌های معمول HTTP تفاوت دارد. در ارتباط HTTP، کلاینت درخواست را ارسال کرده، سرور پاسخ می‌دهد و سپس اتصال قطع می‌شود. در مقابل، WebSocket یک پروتکل مستقل است که پس از برقراری ارتباط بین کلاینت و سرور، هر دو طرف می‌توانند داده‌ها را به‌طور هم‌زمان ارسال و دریافت کنند. به این ترتیب، همان‌طور که سرور منتظر دریافت پیام‌های جدید است، تمام کلاینت‌های متصل نیز در حال گوش دادن هستند. در نتیجه، سرور می‌تواند داده‌ها را به یک کلاینت خاص یا به‌صورت هم‌زمان به تمام کلاینت‌ها ارسال کند، بدون اینکه نیازی به ارسال درخواست از سمت کلاینت باشد. علاوه بر این، اتصال تا زمانی که یکی از طرفین آن را قطع نکند باز باقی می‌ماند و ارتباط پیوسته‌ای بین سرور و کلاینت برقرار است.

WebSocket چیست؟

در نتیجه، WebSocket روشی عالی برای پروژه‌هایی است که نیاز به ارسال داده در لحظه دارند. با این حال، نباید در همه پروژه‌ها از آن استفاده کرد، زیرا پیاده‌سازی WebSocket به‌ویژه در سمت سرور، می‌تواند پیچیدگی‌هایی ایجاد کند. اگر پروژه شما نیاز به پخش داده (data broadcasting) بین چندین کلاینت ندارد، استفاده از روش‌های ساده‌تر مانند polling ممکن است کافی باشد.

نمای کلی پروژه

در این بخش، قصد داریم یک پروژه ساده ایجاد کنیم که در آن با استفاده از ماژول ESP32، یک وب‌سرور WebSocket بسازیم تا بتوانیم LED روی برد ESP32 را از راه دور و از طریق اتصال WebSocket کنترل کنیم.

در این پروژه، یک صفحه وب طراحی می‌کنیم که شامل یک کلید سوئیچ (toggle switch) است و به کاربر اجازه می‌دهد وضعیت پایه GPIO2 (که LED داخلی به آن متصل است) را تغییر دهد. در همین صفحه وب، وضعیت فعلی LED نیز نمایش داده می‌شود تا کاربر بتواند به‌صورت زنده آن را مشاهده کند.

ماژول ESP32 به‌صورت فعال روی پورت 80 منتظر برقراری اتصال‌های WebSocket و دریافت پیام‌های جدید خواهد بود. زمانی که کاربر کلید LED را در صفحه وب تغییر دهد، یک پیام با محتوای "toggle" به ESP32 ارسال می‌شود. پس از دریافت این پیام، ESP32 وضعیت LED را تغییر داده و بلافاصله به تمام کلاینت‌های متصل (مرورگرها) پیام جدیدی ارسال می‌کند. این پیام می‌تواند "1" (برای روشن بودن LED) یا "0" (برای خاموش بودن LED) باشد. در نتیجه، تمام کاربران متصل وضعیت LED را در لحظه و بدون تأخیر روی صفحه وب خود مشاهده خواهند کرد.

برای درک بهتر عملکرد این پروژه، یک انیمیشن آموزشی در ادامه آورده شده که نحوه اتصال چندین مرورگر به ESP32 از طریق WebSocket و تبادل پیام‌ها بین آن‌ها را نمایش می‌دهد.

نمای کلی پروژه

اگر در مورد این مطلب سوالی دارید در قسمت نظرات بپرسید

با وجود سادگی، این پروژه می‌تواند پایه‌ای برای آزمایش‌ها و پروژه‌های پیشرفته‌تر باشد. به عنوان مثال، می‌توان از همین ساختار برای طراحی یک سیستم روشنایی هوشمند خانگی استفاده کرد.

راه‌اندازی Arduino IDE

در این پروژه از نرم‌افزار Arduino IDE برای برنامه‌نویسی ماژول ESP32 استفاده می‌کنیم. پیش از شروع، مطمئن شوید که برد ESP32 در Arduino IDE شما نصب شده است.

چندین پلتفرم توسعه برای برنامه‌نویسی ESP32 وجود دارد، از جمله Arduino IDE (برای کسانی که با محیط آردوینو آشنا هستند) و Espruino.

برای ساخت WebSocket Server در این پروژه از کتابخانه ESPAsyncWebServer استفاده می‌کنیم. این کتابخانه برای اجرا نیاز به AsyncTCP دارد. از آنجا که هیچ‌یک از این دو کتابخانه در Library Manager آردوینو موجود نیستند، باید آن‌ها را به‌صورت دستی نصب کنید.

از لینک‌های زیر برای دانلود استفاده کنید:

پس از دانلود فایل‌های ZIP، وارد مسیر زیر شوید و آن‌ها را به Arduino IDE اضافه کنید:

Sketch > Include Library > Add .ZIP Library

میتوانید از آموزش نصب کتابخانه در آردوینو کمک بگیرید.

کد سرور وب سوکت برد ESP32

کد کامل پروژه را در Arduino IDE کپی کنید. قبل از آپلود، باید اطلاعات شبکه Wi-Fi خود را در قسمت مشخص‌ شده وارد کنید تا ESP32 بتواند به شبکه متصل شود:

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

پس از انجام این تغییرات، کد را روی برد ESP32 آپلود کنید.

این کد شامل قسمت‌های زیر است:

  • اتصال به Wi-Fi
  • ایجاد WebSocket Server
  • نمایش رابط کاربری تحت وب با HTML و CSS
  • ارسال و دریافت پیام بین مرورگر و ESP32 برای کنترل LED داخلی (GPIO2)

 

کد کامل در فایل دانلودی انتهای صفحه قرار داده شده است. در ادامه قسمت های مختلف کد توضیح داده میشود.

اجرای پروژه و نمایش عملکرد

بعد از آپلود کد، Serial Monitor را باز کنید و نرخ baud rate را روی 115200 تنظیم نمایید. سپس دکمه EN روی برد ESP32 را فشار دهید. اتصال به Wi-Fi ممکن است چند ثانیه طول بکشد. پس از برقراری اتصال، در Serial Monitor آدرس IP اختصاص‌داده‌شده توسط مودم نمایش داده می‌شود.

اجرای پروژه وب سوکت ESP32

در مرورگر کامپیوتر، آدرس IP نمایش‌داده‌شده را وارد کنید. صفحه‌ای باز می‌شود که شامل کلید تغییر وضعیت (Toggle) و نمایش وضعیت فعلی LED داخلی ESP32 است.

محیط وب سوکت ESP32

اکنون با کلیک روی کلید، LED روشن و خاموش می‌شود. همچنین در صورت باز کردن همان آدرس در دستگاه‌های دیگر مانند گوشی یا تبلت (که به همان شبکه متصل‌اند)، مشاهده می‌کنید که وضعیت LED در همه مرورگرها به‌صورت هم‌زمان به‌روزرسانی می‌شود.

در همین زمان، می‌توانید در Serial Monitor مشاهده کنید که هر مرورگر یا دستگاهی که به ESP32 متصل می‌شود یا قطع اتصال می‌دهد، همراه با آدرس IP آن ثبت می‌شود.

گزارش گیری اتصالات Web Socket در سریال مانیتور

توضیح کامل کد

 

در ابتدای برنامه، سه کتابخانه ضروری وارد شده‌اند که هر یک وظیفه خاصی دارند:

#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
  • WiFi.h: شامل توابع اختصاصی WiFi برای اتصال ESP32 به شبکه بی‌سیم است.
  • AsyncTCP.h: کتابخانه‌ای است که ارتباط TCP غیرهم‌زمان (Asynchronous) را فراهم می‌کند و پیش‌نیاز کتابخانه ESPAsyncWebServer محسوب می‌شود.
  • ESPAsyncWebServer.h: این کتابخانه امکان ایجاد یک وب‌سرور HTTP را فراهم می‌کند که از WebSocket نیز پشتیبانی می‌کند.

تعریف متغیرها و ثابت‌ها

در مرحله بعد، اطلاعات شبکه Wi-Fi شامل SSID (نام شبکه) و رمز عبور تعریف شده‌اند که باید با اطلاعات شبکه شخصی شما جایگزین شوند:

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

سپس دو متغیر دیگر برای کنترل وضعیت LED تعریف می‌شوند:

bool ledState = 0;
const int ledPin = 2;
  • ledState برای ذخیره وضعیت فعلی LED (روشن یا خاموش) استفاده می‌شود.
  • ledPin پایه‌ای از ESP32 است که LED داخلی به آن متصل است (GPIO2).

مقداردهی اولیه Web Server و WebSocket

در این قسمت، دو شیء (object) از کلاس‌های وب‌سرور و وب‌سوکت ساخته می‌شوند:

AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
  • AsyncWebServer server(80) → سرور HTTP روی پورت 80 اجرا می‌شود که پورت پیش‌فرض برای درخواست‌های وب است.
  • AsyncWebSocket ws("/ws") → آدرس endpoint برای WebSocket را تعریف می‌کند. در اینجا، مسیر /ws تعیین شده است.

بنابراین مرورگرها از طریق آدرس زیر به WebSocket متصل می‌شوند:
ws://[IP-ESP32]/ws

ایجاد صفحه وب

در ادامه، متغیر ثابت زیر تعریف شده که حاوی کد HTML، CSS و JavaScript برای رابط کاربری صفحه وب است:

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html> ... </html>
)rawliteral";

در اینجا چند نکته مهم وجود دارد:

  • از PROGMEM استفاده شده تا داده‌های HTML در حافظه فلش (Flash Memory) ذخیره شوند و فضای SRAM اشغال نشود.
  • HTML شامل عناصر زیر است:
    • یک سوئیچ (toggle switch) برای کنترل LED
    • نمایش وضعیت فعلی LED (ON/OFF)
  • CSS ظاهر صفحه را زیبا و واکنش‌گرا می‌سازد (فونت، رنگ‌ها، افکت‌ها و دکمه سوئیچ).
  • JavaScript وظیفه برقراری اتصال WebSocket با ESP32 را بر عهده دارد و تغییرات وضعیت LED را به‌صورت زنده نمایش می‌دهد.

عملکرد JavaScript در صفحه وب

درون بخش <script>، منطق تعامل بین مرورگر و ESP32 نوشته شده است:

  1. پس از بارگذاری صفحه (window.addEventListener('load', function() {...}))، یک اتصال WebSocket به مسیر /ws برقرار می‌شود.
    var websocket = new WebSocket(`ws://${window.location.hostname}/ws`);
    
  2. زمانی که ESP32 پیامی ارسال کند، تابع onmessage اجرا می‌شود و وضعیت LED روی صفحه تغییر می‌کند:
    websocket.onmessage = function(event) {
      if (event.data == "1") {
        document.getElementById('state').innerHTML = "ON";
        document.getElementById('toggle-btn').checked = true;
      } else {
        document.getElementById('state').innerHTML = "OFF";
        document.getElementById('toggle-btn').checked = false;
      }
    };
    
  3. وقتی کاربر روی سوئیچ کلیک کند، مرورگر پیامی با محتوای "toggle" به ESP32 ارسال می‌کند:
    document.getElementById('toggle-btn').addEventListener('change', function() {
      websocket.send('toggle');
    });
    

به این ترتیب، با هر تغییر در سوئیچ، پیام به‌صورت بی‌درنگ به ESP32 ارسال می‌شود و LED روشن یا خاموش می‌گردد، سپس نتیجه به تمام مرورگرهای متصل اطلاع داده می‌شود.

کد CSS

میان تگ‌های <style></style>، کد CSS مربوط به طراحی و استایل‌دهی صفحه وب قرار دارد. این بخش ظاهر کلی صفحه، فونت‌ها، رنگ‌ها و موقعیت عناصر را مشخص می‌کند. می‌توانید در صورت تمایل، این استایل‌ها را تغییر دهید تا ظاهر صفحه مطابق سلیقه‌تان شود.

<style>
html{font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}
body{margin-top: 50px;}
h1{color: #444444;margin: 50px auto;}
p{font-size: 19px;color: #888;}
#state{font-weight: bold;color: #444;}
.switch{margin:25px auto;width:80px}
.toggle{display:none}
.toggle+label{display:block;position:relative;cursor:pointer;outline:0;user-select:none;padding:2px;width:80px;height:40px;background-color:#ddd;border-radius:40px}
.toggle+label:before,.toggle+label:after{display:block;position:absolute;top:1px;left:1px;bottom:1px;content:""}
.toggle+label:before{right:1px;background-color:#f1f1f1;border-radius:40px;transition:background .4s}
.toggle+label:after{width:40px;background-color:#fff;border-radius:20px;box-shadow:0 2px 5px rgba(0,0,0,.3);transition:margin .4s}
.toggle:checked+label:before{background-color:#4285f4}
.toggle:checked+label:after{margin-left:42px}
</style>

کد HTML

میان تگ‌های <body></body> محتوای اصلی صفحه وب قرار دارد.

<h1>ESP32 WebSocket Server</h1>
<div class="switch">
  <input id="toggle-btn" class="toggle" type="checkbox" %CHECK%>
  <label for="toggle-btn"></label>
</div>
<p>On-board LED: <span id="state">%STATE%</span></p>

خط اول با تگ <h1> عنوان صفحه را تعیین می‌کند که می‌توانید آن را متناسب با پروژه خود تغییر دهید.

بخش بعدی یک کلید سوئیچ ایجاد می‌کند که در واقع یک چک‌باکس با استایل خاص است تا ظاهر یک کلید روشن/خاموش داشته باشد.

در نهایت، پاراگرافی وجود دارد که وضعیت LED روی برد را نمایش می‌دهد. مقدار واقعی وضعیت (“ON” یا “OFF”) درون تگ <span> قرار دارد.

عبارت‌های جایگزین %CHECK% و %STATE% متغیرهایی هستند که ESP32 هنگام ارسال صفحه به مرورگر با مقادیر واقعی جایگزین می‌کند. %STATE% متن “ON” یا “OFF” را بسته به وضعیت فعلی LED نمایش می‌دهد و %CHECK% مشخص می‌کند کلید هنگام بارگذاری صفحه روشن باشد یا خاموش.

این مکان‌نماها فقط هنگام اولین اتصال کاربر به ESP32 استفاده می‌شوند. پس از برقراری اتصال WebSocket، جاوااسکریپت کنترل به‌روزرسانی را بر عهده می‌گیرد. برای همین، عناصری که دارای این متغیرها هستند، شناسه (id) دارند تا جاوااسکریپت بتواند آن‌ها را شناسایی و تغییر دهد.

کد JavaScript

کد جاوااسکریپت میان تگ‌های <script></script> قرار دارد و مسئول برقراری اتصال WebSocket با سرور و مدیریت ارسال و دریافت داده‌ها است. همچنین، این کد وضعیت LED را به‌صورت لحظه‌ای در صفحه به‌روزرسانی می‌کند.

<script>
  window.addEventListener('load', function() {
	var websocket = new WebSocket(`ws://${window.location.hostname}/ws`);
	websocket.onopen = function(event) {
	  console.log('Connection established');
	}
	websocket.onclose = function(event) {
	  console.log('Connection died');
	}
	websocket.onerror = function(error) {
	  console.log('error');
	};
	websocket.onmessage = function(event) {
	  if (event.data == "1") {
		document.getElementById('state').innerHTML = "ON";
		document.getElementById('toggle-btn').checked = true;
	  }
	  else {
		document.getElementById('state').innerHTML = "OFF";
		document.getElementById('toggle-btn').checked = false;
	  }
	};
	document.getElementById('toggle-btn').addEventListener('change', function() { websocket.send('toggle'); });
  });
</script>

در ابتدا، رویداد load تعریف شده تا اطمینان حاصل شود کد جاوااسکریپت فقط پس از بارگذاری کامل صفحه اجرا شود.
سپس با استفاده از آدرس فعلی هاست (IP برد ESP32)، یک اتصال WebSocket با پروتکل ws:// ایجاد می‌شود. (نسخه رمزنگاری‌شده‌ی آن نیز wss:// است، مشابه HTTPS برای وب‌سوکت‌ها).

چهار رویداد اصلی در WebSocket وجود دارد:

  • onopen – هنگام برقراری اتصال
  • onclose – هنگام قطع اتصال
  • onerror – در صورت بروز خطا در اتصال
  • onmessage – هنگام دریافت داده از سرور

در رویداد onmessage، اگر داده دریافتی “1” باشد، متن وضعیت LED روی “ON” تنظیم می‌شود و کلید در حالت فعال قرار می‌گیرد. اگر “0” باشد، متن “OFF” نمایش داده می‌شود و کلید در حالت غیرفعال باقی می‌ماند.

در انتها، برای کلید تغییر وضعیت (toggle) یک شنونده رویداد تعریف می‌شود. با هر تغییر وضعیت، پیام “toggle” از طریق WebSocket به سرور (ESP32) ارسال می‌شود تا وضعیت LED تغییر کند.

تابع setup()

تا اینجا نحوه‌ی مدیریت اتصال WebSocket در سمت کاربر (مرورگر) را دیدیم. حالا بیایید بررسی کنیم این فرایند در سمت سرور (یعنی ESP32) چگونه انجام می‌شود.

در ابتدای تابع setup()، ارتباط سریال برای دیباگ فعال می‌شود:

Serial.begin(115200);

سپس پایه‌ی LED به عنوان خروجی (OUTPUT) تنظیم و مقدار اولیه‌ی آن LOW قرار داده می‌شود:

pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);

در ادامه، ماژول ESP32 تلاش می‌کند به شبکه‌ی Wi-Fi متصل شود. روند اتصال و آدرس IP دریافت‌شده در سریال مانیتور چاپ می‌شود:

Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.print(".");
}
Serial.println("");
Serial.println("Connected..!");
Serial.print("Got IP: ");  
Serial.println(WiFi.localIP());

سپس یک شنونده‌ی رویداد (event listener) برای WebSocket تنظیم می‌شود. یعنی هر زمان رویدادی مرتبط با WebSocket (شیء ws) رخ دهد، تابع eventHandler() فراخوانی شده و آن رویداد را پردازش می‌کند. این تابع نوع رویداد (مثل اتصال کاربر جدید، دریافت داده، قطع ارتباط و غیره) را تشخیص داده و پاسخ مناسب را ارائه می‌دهد:

ws.onEvent(eventHandler);

در خط بعد، WebSocket به سرور وب متصل می‌شود تا تمام درخواست‌های مرتبط با WebSocket به این شیء ارجاع داده شوند:

server.addHandler(&ws);

در مرحله‌ی بعد، یک مسیر (endpoint) برای سرور تعیین می‌شود. در اینجا مسیر ریشه / تعریف شده است. وقتی کاربر در مرورگر به این مسیر دسترسی پیدا کند، تابع لامبدا اجرا می‌شود و محتوای HTML صفحه به کاربر ارسال می‌گردد:

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/html", index_html, processor);
});

در این دستور:

  • مقدار 200 نشان‌دهنده‌ی موفق بودن درخواست (HTTP status code) است.
  • "text/html" نوع محتوای بازگشتی را مشخص می‌کند.
  • index_html همان صفحه‌ی وب ذخیره‌شده در حافظه‌ی فلش ESP32 است.
  • تابع processor محتوای HTML را قبل از ارسال پردازش کرده و متغیرهای جایگزین (مانند %STATE%) را مقداردهی می‌کند.

در نهایت، سرور شروع به کار کرده و منتظر درخواست‌های ورودی کاربران می‌ماند:

server.begin();

تابع loop()

در سرورهای هم‌زمان (synchronous servers)، معمولاً از دستور server.handleClient(); در داخل loop استفاده می‌شود تا بررسی شود آیا درخواستی از سمت کاربر وجود دارد یا نه.

اما در سرورهای ناهم‌زمان (asynchronous)، نیازی به این کار نیست. کتابخانه AsyncWebServer به کمک AsyncTCP درخواست‌ها را در پس‌زمینه مدیریت کرده و بر اساس رویدادها، توابع مربوطه را فراخوانی می‌کند. بنابراین معمولاً تابع loop خالی است.

با این حال، در این پروژه از متد cleanupClients() استفاده می‌شود:

void loop() {
  ws.cleanupClients();
}

این متد، بخشی از کلاس AsyncWebSocket است و به‌طور منظم بررسی می‌کند که آیا کلاینت‌هایی وجود دارند که دیگر فعال نیستند یا اتصالشان قطع شده است. در این صورت، آن‌ها را از لیست حذف می‌کند تا منابع سیستم آزاد شوند و از کرش کردن سرور جلوگیری شود.

مدیریت رویدادهای WebSocket در سمت سرور

در تابع setup()، با استفاده از ws.onEvent(eventHandler) تعیین کردیم که هر زمان رویدادی مربوط به WebSocket اتفاق بیفتد، تابع eventHandler() اجرا شود. این تابع نوع رویداد را شناسایی کرده و واکنش مناسب را انجام می‌دهد.

پارامتر type نوع رویداد را مشخص می‌کند و می‌تواند یکی از موارد زیر باشد:

  • WS_EVT_CONNECT: اتصال کاربر جدید به WebSocket
  • WS_EVT_DISCONNECT: قطع اتصال کاربر
  • WS_EVT_DATA: دریافت داده از سمت کاربر
  • WS_EVT_PONG: پاسخ به ping
  • WS_EVT_ERROR: بروز خطا در ارتباط

نمونه‌ی پیاده‌سازی تابع:

void eventHandler(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:
      handleWebSocketMessage(arg, data, len);
      digitalWrite(ledPin, ledState);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

در این کد:

  • هنگامی که نوع رویداد WS_EVT_CONNECT یا WS_EVT_DISCONNECT باشد، آدرس IP و شناسه‌ی کلاینت در Serial Monitor نمایش داده می‌شود.
  • در مورد WS_EVT_PONG و WS_EVT_ERROR فعلاً عملی انجام نمی‌شود، اما می‌توان در آینده برای بهبود عملکرد آن‌ها را توسعه داد.
  • مهم‌ترین بخش، رویداد WS_EVT_DATA است که هنگام دریافت داده از کاربر اجرا می‌شود. در این حالت، داده به تابع handleWebSocketMessage() فرستاده شده و وضعیت LED بر اساس مقدار جدید به‌روزرسانی می‌شود.

خواندن پیام‌های WebSocket و ارسال هم‌زمان به کلاینت‌ها

تابع handleWebSocketMessage() برای مدیریت پیام‌های دریافتی از طریق WebSocket تعریف شده است. زمانی که یک پیام معتبر با محتوای "toggle" دریافت شود، این تابع وضعیت LED را تغییر می‌دهد و سپس با استفاده از متد textAll()، این تغییر را به تمام کلاینت‌های متصل اطلاع می‌دهد.

متد textAll() که از کلاس AsyncWebSocket فراخوانی می‌شود، به ماژول ESP32 این امکان را می‌دهد تا یک پیام یکسان را به تمام مرورگرهای متصل به‌صورت هم‌زمان ارسال کند. این کار تضمین می‌کند که وضعیت LED در تمامی کلاینت‌ها همگام و به‌روز باقی بماند.

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;
    if (strcmp((char*)data, "toggle") == 0) {
      ledState = !ledState;
      ws.textAll(String(ledState));
    }
  }
}

پردازش متغیرهای صفحه وب (Placeholders)

در کد HTML صفحه وب، دو متغیر جایگزین (placeholder) با نام‌های %CHECK% و %STATE% وجود دارد. تابع processor() مسئول جستجو و جایگزینی این متغیرها با مقادیر واقعی است، تا پیش از ارسال صفحه وب به مرورگر، داده‌ها به‌درستی در آن قرار گیرند.

متغیر %STATE% با توجه به وضعیت فعلی LED با مقدار "ON" یا "OFF" جایگزین می‌شود. همچنین متغیر %CHECK% تعیین می‌کند که هنگام بارگذاری صفحه، سوئیچ LED در حالت فعال (checked) یا غیرفعال باشد.

String processor(const String& var){
  if(var == "STATE"){
      return ledState ? "ON" : "OFF";
  }
  if(var == "CHECK"){
    return ledState ? "checked" : "";
  }
  return String();
}

این بخش از کد باعث می‌شود تا رابط کاربری وب همیشه وضعیت واقعی LED را نشان دهد، حتی در صورت تازه‌سازی صفحه توسط کاربر. چنین ساختاری برای هماهنگی بلادرنگ بین سخت‌افزار و رابط وب در پروژه‌های IoT اهمیت زیادی دارد.

 

5 (2 نفر)

برای دریافت مطالب جدید کانال تلگرام یا پیج اینستاگرام ما را دنبال کنید.

محمد رحیمی

محمد رحیمی هستم. سعی میکنم در آیرنکس مطالب مفید قرار بدهم. سوالات مربوط به این مطلب را در قسمت نظرات همین مطلب اعلام کنید. سعی میکنم در اسرع وقت به نظرات شما پاسخ بدهم.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *