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

این کار نه تنها ناکارآمد است بلکه در سیکل های زمانی بیشتری انجام می شود که در آن می توان کارهای دیگر را انجام داد. راه حل این مشکل با نام Asynchronous JavaScript and XML یا به اختصار AJAX شناخته می شود. با استفاده از AJAX، می توانیم داده های real-time را بدون رفرش کردن کل صفحه وب، رصد کنیم.

پس با ما همراه باشید که در این مقاله، یاد خواهیم گرفت چگونه وب سرور مبتنی ESP8266 را به کمک AJAX پیاده سازی کنیم.

 

AJAX چیست؟

همانطور که قبلاً گقته شد، AJAX مخفف Asynchronous JavaScript and XML است که برای آپدیت بخشی از صفحه وب بدون لود مجدد صفحه مربوطه استفاده شود. این کار را با درخواست و دریافت خودکار داده از سرور انجام می دهد.

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

یک نمونه روزمره از AJAX، ویژگی پیشنهادات Google است، همانطور که در نوار جستجوی Google تایپ می کنیم، Google شروع به پیشنهاد کلمه های جستجوی مرتبط می کند.

در طی این فرآیند، صفحه وب لود نمی شود، اما اطلاعاتی که باید تغییر کنند با استفاده از AJAX در پس زمینه آپدیت می شوند.

 

AJAX چگونه کار می کند؟

AJAX ترکیبی است از:

  1. XML - Extensible Markup Language
  2. JavaScript and HTML

 

 XML (Extensible Markup Language) 

XML یک زبان نشانه گذاری است. XML بیشتر برای دریافت داده های سرور با یک قالب خاص استفاده می شود. اگرچه می تواند داده ها را به صورت متن ساده دریافت کند. هنگامی که یک کاربر از یک صفحه وب بازدید می کند و یا رویدادی رخ می دهد، اینجا فشردن دکمه است، JavaScript یک شی XMLHttpRequest ایجاد می کند، سپس اطلاعات را در قالب XML بین مرورگر وب و وب سرور انتقال می دهد.

شی XMLHttpRequest درخواستی را برای داده های صفحه آپدیت شده به وب سرور، (اینجا ESP8266) ارسال می کند، سرور درخواست را پردازش می کند، پاسخی در سمت سرور ایجاد می شود و به مرورگر ارسال می شود، سپس از JavaScript برای پردازش پاسخ و نمایش آن در صفحه وب استفاده می کند.

 

JavaScript and HTML

JavaScript فرآیند آپدیت را در AJAX انجام می دهد. درخواست برای محتوای آپدیت شده در XML آماده می شود تا آن را قابل فهم کند، و JavaScript محتوای قابل نمایش کاربر را که آپدیت شده رفرش می کند.

 

نحوه کار AJAX

برای درخواست AJAX، مرورگر با استفاده از javascript یک XMLHttpRequest را به سرور می فرستد. این شی شامل داده هایی است که به سرور می گوید که چه چیزی درخواست می شود. سرور فقط با داده هایی که از طرف مشتری درخواست شده است پاسخ می دهد.

سپس مرورگر داده ها را دریافت می کند، فقط بخشی از صفحه را که باید آپدیت شود (به جای لود مجدد کل صفحه وب)، را  آپدیت می کند.

 

نیازمندی های پروژه

جهت نشان دادن توانایی ESP8266EX برای هندل کردن AJAX تنها به چند سخت افزار نیاز داریم، که شما می توانید بیشتر آنها را در فروشگاه های شهر خود پیدا کنید.

 

سخت افزار

  •  برد توسعه Wemos D1 Mini
  •  کلید فشاری

نرم افزار

 

مدار

مدار بسیار ساده است. با یک کلید فشاری که به یک پین برد ویموس متصل شده است ajax را به آزمون خواهیم گذاشت. قرار است با هر بار فشردن کلید یک متغیر از نوع عدد صحیح را کم یا زیاد کنیم و مقدار جدید بدون اینکه صفحه مروگر را رفرش کنیم آپدیت شود.

همچنین در صفحه مروگر سه Button قرار می دهیم یکی به نام Right و یکی به نام Stop و دیگری به نام Left. در صورتی که هر یک از Button ها در مرورگر کلیک شود متغیر به صورت زیر آپدیت میشود.

  •  Right به این معنی است که اگر دکمه فشاری فشرده شد متغیر یکی اضافه شود.
  • Stop به این معنی است که اگر دکمه فشاری فشرده شد متغیر تغییری نکند.
  • Left به این معنی است که اگر دکمه فشاری فشرده شد متغیر یکی کم شود.

 

کد در Wemos D1 Mini

قبل از هر چیز به این نکته اشاره کنیم که کدها را در محیط ویرایشگر VS Code که افزونه Platform IO را روی آن نصب شده باشد وارد می کنیم.آن نرم افزار عالی برای برنامه نویسی و توسعه سیستم  های امبدد هست البته برای این کار نیاز است تا افزونه Platform IO را روی آن نصب کنید. اگر با آردوینو کار کرده اید متوجه شده اید که برای توسعه لایبرری ها و ... IDE آردوینو کمی ساده است اما با Platform IO می توانید در همان فریمورک آردوینو اما در یک محیط حرفه ای کار کنید. نحوه نصب افزونه Platform IO روی VS Code

یک پروژه جدید در Platform IO ایجاد کنید (البته یادتون باشه که برد را باید Wemos D1 mini lite انتخاب کنید).

 

ایجاد فایل هدر برای صفحه HTML

ابتدا، صفحه HTML که برای نمایش مقدار متغیر و دکمه های کنترل متغیر نوشته شده است، باید به یک فایل Header تبدیل شود، که ما آن را در کد اصلی خود استفاده خواهیم کرد. این صرفاً به خاطر راحتی کار است.

برای این کار یک فایل جدید در فولدر include به نام index.h ایجاد کنید

 

حالا کد HTML زیر را در آن اضافه کنید.

#ifndef INDEX_H_
#define INDEX_H_

#include <Arduino.h>
#include <pgmspace.h>

const char homepage[] PROGMEM =  R"=====(
<!DOCTYPE html>
<html>
<style type="text/css">
.button {
  background-color: #319fe9; 
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  border-radius: 5px;
  font-weight: 600;
}
.button:hover{
  cursor: pointer;
}
.button:active {
 background: #57cc5d;
 border-width: 0;
}
.button:focus {
  background: #57cc5d; 
  border-width: 0;
}
</style>
<body style="background-color: #ffffff ">
<center>
<div>
<h1>AJAX IN ESP8266EX FOR DYNAMIC WEB PAEGE</h1>
  <button class="button" onclick="send('RIGHT')">RIGHT</button>
  <button class="button" onclick="send('STOP')">STOP</button>
  <button class="button" onclick="send('LEFT')">LEFT</button><BR>
</div>
 <br>
<div><h2>
  <span id="COMMAND">STOP</span><br><br>
  STATUS: <span id="STATUS">0</span><br><br>
</h2>
</div>
<script>
function send(CMD) 
{
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("COMMAND").innerHTML = this.responseText;
    }  
  };
  xhttp.open("GET", "MOV?CMD="+CMD, true);
  xhttp.send();
}
setInterval(function() {getData();}, 200); 
function getData() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("STATUS").innerHTML =
      this.responseText;
    }
  };
  xhttp.open("GET", "GET_STATUS", true);
  xhttp.send();
}
</script>
</center>
</body>
</html>
)=====";

#endif

 

حالا در فولدر src فایل main.c را باز کرده و کدهای زیر را در آن اضافه کنید.

#ifndef UNIT_TEST
#include <Arduino.h>
#endif

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include "index.h"

#define USE_IRAM_ATTR ICACHE_RAM_ATTR

const char *ssid = "ssid";
const char *password = "12345678";

// push btn is connected to GPIO0 (D3)
uint16_t PushBtnPIN = 0;

ESP8266WebServer server(80);
String cmd;
uint16_t status;

static void USE_IRAM_ATTR counter_intr()
{
  if (cmd == "LEFT")
    status--;
  else if (cmd == "RIGHT")
    status++;
}

void handleRoot()
{
  String s = FPSTR(homepage);
  server.send(200, "text/html", s);
}

void MOV()
{
  String state = server.arg("CMD");
  if (state == "LEFT")
  {
    cmd = "LEFT";
  }
  else if (state == "RIGHT")
  {
    cmd = "RIGHT";
  }
  else if (state == "STOP")
  {
    cmd = "STOP";
  }

  server.send(200, "text/plane", cmd);
}

void GET_STATUS()
{
  uint16_t cnt = status;
  String sensor_value = String(cnt);
  server.send(200, "text/plane", sensor_value);
}

void setup()
{
  attachInterrupt(PushBtnPIN, counter_intr, CHANGE);
  Serial.begin(9600);
  WiFi.begin(ssid, password);

  Serial.println("");
  // Wait for connection
  Serial.printf("Connecting to %s ", ssid);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.on("/MOV", MOV);
  server.on("/GET_STATUS", GET_STATUS);
  server.begin();

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

void loop()
{
  server.handleClient();
  delay(50);
}

 

توضیحات کد

 

#include "index.h"

فایل هدر را که قبلاً نوشتیم، به برنامه اصلی الحاق می کنیم. 

const char *ssid = "ssid";
const char *password = "12345678";

اینجا SSID و Password شبکه را وارد می کنید. قبل از آپلود کد روی Wemos D1 Mini، مطمئن شوید که مقادیر با SSID و Password شبکه WiFi (هات اسپات گوشی) یکی باشد.

attachInterrupt(PushBtnPIN, counter_intr, CHANGE);

یک پین را به عنوان وقفه خارجی تعریف می کنیم که به کلید فشاری وصل می شود. همچنین تابع counter_intr را به عنوان تابعی که زمان وقفه اجرا می شود به آن معرفی میکنیم و مد وقفه CHANGE خواهد بود.

ESP8266WebServer server(80);

سپس شی ESP8266WebServer را با نام server و پورت پیش فرض شماره 80 تعریف می کنیم.

void handleRoot() 
{
 String s = FPSTR(homepage);
 server.send(200, "text/html", s);
}

تابع handleRoot به منظور هندل کردن HTML و ارسال homepage به سمت کلاینت در صورت درخواست تعریف شده است.

void MOV()
{
  String state = server.arg("CMD");
  if (state == "LEFT")
  {
    cmd = "LEFT";
  }
  else if (state == "RIGHT")
  {
    cmd = "RIGHT";
  }
  else if (state == "STOP")
  {
    cmd = "STOP";
  }

  server.send(200, "text/plane", cmd);
}

در داخل تابع MOV اطلاعاتی که از صفحه وب می آیند (بعد از کلیک سه دکمه Right, Stop, Left) دریافت می شوند. براساس آن ما در برنامه تصمیم خواهیم گرفت که متغیر ما (STATUS) با هر بار فشردن کلید فشاری کم، زیاد و یا بدون تغییر باقی بماند.

void GET_STATUS()
{
  uint16_t cnt = status;
  String sensor_value = String(cnt);
  server.send(200, "text/plane", sensor_value);
}

در داخل تابع GET_STATUS، مقدار متغیر STATUS به مروگر ارسال می شود. این تابع همان تابعی است که بدلیل درخواست دوره ای از سمت مرورگر (کلاینت) به کمک javascript و ajax به طور مداوم اجرا می شود.

  WiFi.begin(ssid, password);

  Serial.println("");
  // Wait for connection
  Serial.printf("Connecting to %s ", ssid);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

سپس، برای اتصال به اینترنت، تابع () WiFi.begin را فراخوانی می کنیم و SSID و رمز عبور شبکه را به عنوان آرگومان های خود منتقل می کنیم. با استفاده از WiFi.status  اتصال موفقیت آمیز شبکه را بررسی می کنیم و پس از اتصال موفقیت آمیز، پیامی را با آدرس IP دستگاه متصل در سریال مانیتور چاپ می کنیم.

  server.on("/", handleRoot);
  server.on("/MOV", MOV);
  server.on("/GET_STATUS", GET_STATUS);
  server.begin();

سپس، برای فراخوانی توابع تعریف شده مانند "handleRoot" ، "MOV" و "GET_STATUS" زمانی که کلاینت آدرس URL با "/" ، "MOV/" و یا "GET_STATUS/" را درخواست کند، کدهای بالا باید تعریف شده باشد.

 

تست برنامه

پس از بیلد و آپلود کد توسط PlatformIO روی برد Wemos D1 mini، سراغ آزمایش پروژه میرویم. اول از همه، باید مطمئن شویم که hotspot روشن است. سپس قبل از روشن شدن مدار، اتصالات را بررسی کنید. در این پروژه برد Wemos D1 mini از کابل USB به micro USB استفاده می کنیم، که از طریق آن کد را آپلود می کنیم و هم به عنوان منبع تغذیه 5 ولت از آن استفاده می کنیم.

پس از روشن شدن برد، نوبت به دریافت آدرس IP رسیده است. این را می توان با استفاده از سریال مانیتور PlatformIO پیدا کرد. سریال مانیتور را باز کنید و یک بار دکمه Reset برد Wemos D1 mini را فشار دهید، آدرس IP باید روی مانیتور سریال PlatformIO چاپ شود. مانند تصویر زیر:

 آدرس IP را یادداشت کرده و در نوار URL مرورگر وب دستگاه خود (گوشی یا لپ تاپ) وارد کنید. دقت کنید که دستگاه را به شبکه هات اسپات متصل کنید. چیزی که خواهید دید مانند تصویر زیر است.

با کلیک روی دکمه های چپ و راست و سپس فشردن کلید فشاری شماره متغیر آپدیت می شود و بدون اینکه صفحه را رفرش کنید شماره متغیر تغییر خواهید کرد.

حال با الگو از این پروژه می توان ایده های خود را عملی کرد به عنوان مثال یک نمودار که تغییرات دمای گلخانه را نمایش می دهد. خوشحال خواهیم شد که بعد از مطالعه این پروژه اگر ایده ای را عملی کردید در انتهای همین پست با ما به اشتراک بگذارید.

موفق باشید.

 

ویدئو تست این پروژه در زیر آمده است.

  نظرات

جهت ثبت نظر وارد سایت شوید

راهنمای استفاده از کد در کامنت
````
insert your code
``
محمد رحیمی
سه شنبه 17 مرداد 1402 ,12:59 ب.ظ

سلام و عرض ادب. برای شیلد اترنت w5100 هم قابل اجراست؟ و آیا امکانش هست مثالی بزنید که از قابلیت micro sd این شیلد برای صفحات گرافیکی تر و دارای جزئیات بیشتر هم استفاده بشه؟ مثل فراخوانی عکس ، فیلم و صوت از روی حافظه در صفحه وب با استفاده از تعامل بین صفحه وب و آردوینو و ذخیره داده ها در micro sd

مهدی ادهم
سه شنبه 17 مرداد 1402 ,02:54 ب.ظ

سلام، ممنونم از توجه شما

معمولا از ajax برای دریافت اطلاعات با حجم بالاکه نیاز به دریافت اطلاعات بدون وقفه باشد استفاده نمی شود .

معمولا برای بروزرسانی اطلاعاتی نظیر (مقادیر سنسور ها و ورودی ها که در esp است) بر روی مرورگر جهت نمایش به کلاینت استفاده می شود.

جهت ثبت پاسخ وارد سایت شوید