آموزش ارتباط سنسور DHT11 و DHT22 با ESP8266 NodeMCU، با استفاده از وب سرور

آیا علاقه دارید در هرگوشه ازخانه و باغچه‌تان، سنسورهایی داشته باشید که دمای محیط را مرتب به یک سرور مرکزی اعلام کنند؟ پس این پروژه اینترنت اشیاء احتمالاً بهترین نقطه شروع برای شماست! در این پروژه چگونگی برقرار کردن ارتباط سنسور DHT11 و DHT22 با ماژول ESP8266 NodeMCU را به ساده‌ترین روش ممکن، به شما آموزش میدهیم.

در این آموزش، ما از ESP8266 NodeMCU به عنوان یک کنترل کننده‌ استفاده می‌کنیم، که به سادگی به شبکه‌های وای‌فای موجود متصل می‌شود و یک وب سرور می‌سازد. وقتی هر یک از دستگاه‌های متصل به شبکه، به این وب سرور دسترسی پیدا کند، ESP8266 NodeMCU دما و رطوبت نسبی را از سنسورهای DHT11 و DHT22 خوانده و با یک رابط کاربری زیبا به مرورگر وب آن دستگاه ارسال می‌کند. هیجان زده‌اید؟ پس بیایید شروع کنیم! این کار ممکن است کمی دشوار به نظر بیاید، ولی مفاهیمی هستند که قبل از شروع کار، باید با آنها آشنا باشید. اگر هرکدام از مفاهیم زیر برایتان ناآشنا به نظر می‌رسد، بهتر است ابتدا مقاله مربوط به آن را مطالعه کنید:



سیم کشی و ارتباط سنسور DHT11 و DHT22 با ESP8266 NodeMCU

برای ارتباط سنسور DHT11 و DHT22 با ESP8266، ابتدا نیاز است آنهارا روی یک بردبورد متصل کنیم. اتصال سنسور DHT11 و DHT22 به ماژول ESP8266 NodeMCU بسیار ساده است. برای شروع، NodeMCU را روی برد بورد قرار دهید و  توجه کنید که دو سمت برد NodeMCU، روی یک قسمت برد بورد نباشند.

حال سنسور را روی برد بورد در کنار NodeMCU قرار دهید. پین VCC سنسور را به پین 3.3V برد NodeMCU، و زمین سنسور را به زمین برد متصل کنید. همچنین پین دیتا سنسور را به پین D8 برد متصل کنید. در آخر، باید یک مقاومت پول‌آپ 10 کیلو اهمی بین VCC و خط دیتا قرار دهیم تا خط دیتا در حالت پیشفرض یک (1) شود و ارتباط سنسور و NodeMCU به شکل مناسبی برقرار شود. اگر برد breakout سنسور را در اختیار دارید، این مقاومت روی برد قرار گرفته و نیازی به قرار دادن آن به صورت جداگانه نیست. پس از انجام اتصالات باید مدار شما مشابه شکل زیر باشد.

اتصال سنسور DHT11 به ESP8266
سیم‌کشی سنسور دما و رطوبت DHT11 و ماژول ESP8266
اتصال سنسور DHT22 به ESP8266
سیم‌کشی سنسور دما و رطوبت DHT22 و ماژول ESP8266

نصب کتابخانه سنسور DHT11 و DHT22

ازآنجاکه سنسورهای DHT11، DHT22 و AM2302 برای انتقال اطلاعات، پروتکل ارتباطی تک سیمه مختص به خودشان را دارند، ارتباط با آن‌ها مقداری کار می‌برد. همچنین این پروتکل به زمان‌بندی دقیق احتیاج دارد. خوشبختانه جای نگرانی نیست چون ما از کتابخانه DHT در Adafruit استفاده می‌کنیم که تقریبا همه چیز را رعایت کرده است. این کتابخانه به حدی قدرتمند است که هم روی معماری آردوینو و هم روی ESP کار می‌کند. برای نصب کتابخانه به مسیر Sketch > Include Library > Manage Libraries بروید و صبر کنید تا Library Manager لیست کتابخانه‌ها را دانلود کرده و کتابخانه‌های نصب شده را به‌روزرسانی کند.

مسیر نصب کتابخانه سنسور DHT11 و DHT22

با نوشتن DHT sensor جستجوی خود را فیلتر کنید. باید چند گزینه ببینید. به دنبالDHT sensor Library از Adafruit بگردید. روی آن کلیک کرده و نصب کنید.

جستجو کتابخانه DHT sensor  در Library manager و نصب آن

کتابخانه DHT sensor از کتابخانه Adafruit Sensor support backend استفاده می‌کند، پس در library manager به دنبال Adafruit Unified Sensor بگردید و آن را هم نصب کنید (البته پس از نصب کتابخانه DHT، پیغام نصب این کتابخانه ظاهر می‌شود که با کلیک روی گزینه yes کتابخانه نصب می‌شود و نیاز به جستجو و نصب جداگانه نیست).

ساخت وب سرور ESP8266 NodeMCU با استفاده از حالت STA

حال بیایید به بخش جذاب ماجرا بپردازیم!

همان‌طور که در تیتر این بخش مشخص است، می‌خواهیم ESP8266 NodeMCU خود را در حالت STA (Station) تنظیم کنیم، و یک وب سرور بسازیم که صفحات وب را به سرویس‌گیرنده‌های متصل به شبکه، تحویل می­دهد. قبل از اینکه برنامه را آپلود کنید، باید تغییری در آن اعمال کنید. دو متغیر زیر را برحسب مشخصات شبکه خود تغییر دهید تا ماژول ESP8266 NodeMCU بتواند به شبکه موجود متصل شود.

const char* ssid = "YourNetworkName";  // Enter SSID here
const char* password = "YourPassword";  //Enter Password here

پس از انجام این تغییرات، برنامه را روی آردوینو آپلود کرده و امتحان کنید. در ادامه به بررسی دقیق کد خواهیم پرداخت.

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

// Uncomment one of the lines below for whatever DHT sensor type you're using!
//#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

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

ESP8266WebServer server(80);

// DHT Sensor
uint8_t DHTPin = D8; 
               
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);                

float Temperature;
float Humidity;
 
void setup() {
  Serial.begin(115200);
  delay(100);
  
  pinMode(DHTPin, INPUT);

  dht.begin();              

  Serial.println("Connecting to ");
  Serial.println(ssid);

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

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

  server.on("/", handle_OnConnect);
  server.onNotFound(handle_NotFound);

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

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

void handle_OnConnect() {

 Temperature = dht.readTemperature(); // Gets the values of the temperature
  Humidity = dht.readHumidity(); // Gets the values of the humidity 
  server.send(200, "text/html", SendHTML(Temperature,Humidity)); 
}

void handle_NotFound(){
  server.send(404, "text/plain", "Not found");
}

String SendHTML(float Temperaturestat,float Humiditystat){
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  ptr +="<title>ESP8266 Weather Report</title>\n";
  ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
  ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
  ptr +="</style>\n";
  ptr +="</head>\n";
  ptr +="<body>\n";
  ptr +="<div id=\"webpage\">\n";
  ptr +="<h1>ESP8266 NodeMCU Weather Report</h1>\n";
  
  ptr +="<p>Temperature: ";
  ptr +=(int)Temperaturestat;
  ptr +="°C</p>";
  ptr +="<p>Humidity: ";
  ptr +=(int)Humiditystat;
  ptr +="%</p>";
  
  ptr +="</div>\n";
  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}

دسترسی به وب سرور ESP8266 NodeMCU

پس از آپلود کد، سریال مانیتور را باز کنید و باد ریت را روی 115200 قرار دهید. حال دکمه ریست NodeMCU را بزنید. اگر همه چیز درست باشد پیغام HTTP server started و یک آدرس IP داینامیک که از روتر گرفته شده است، نمایش داده می‌شود.

سریال مانیتور وب سرور ESP8266 NodeMCU

سپس یک مرورگر باز کنید و به آدرسی که در سریال مانیتور می‌بینید، بروید.ESP8266 NodeMCU صفحه وبی بالا می‌آورد که دما و رطوبت نسبی را نشان می‌دهد.

گزارش دما و رطوبت گرفته شده از سنسور DHT11 و DHT22

توضیح کد ارتباط سنسور DHT11 و DHT22 با ESP8266

برنامه با اضافه کردن کتابخانه ESP8266WiFi.h، شروع می‌شود. این کتابخانه، دارای توابع WiFi مخصوص ESP8266 NodeMCU است، که برای اتصال به شبکه فراخوانی می‌شوند. در ادامه کتابخانه ESP8266WebServer.h را اضافه کرده‌ایم، این کتابخانه توابعی دارد که برای ساخت وب سرور و مدیریت درخواست‌های HTTP دریافتی به ما کمک می‌کند، بدون اینکه در مورد پیاده‌سازی سطح پایین نگرانی داشته باشیم.
سرانجام کتابخانه DHT.h را جهت ارتباط سنسور DHT11 و DHT22 با ESP8266 اضافه کرده‌ایم.

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

در ادامه باید نوع سنسور DHT را مشخص کنیم، یکی از خط‌های کد زیر را متناسب با نوع سنسور خود از حالت کامنت خارج کنید.

//#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321

ازآنجاکه ESP8266 NodeMCU را در حالت STA تنظیم می‌کنیم، ماژول به یک شبکه وای‌فای موجود متصل می‌شود، پس باید SSID و پسورد شبکه خود را وارد کنیم.

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

سپس یک شیء از کتابخانه ESP8266WebServer ایجاد می‌کنیم تا به توابع آن دسترسی پیدا کنیم. تابع سازنده (constructor) این شیء، پورت (جایی که سرور به آن گوش خواهد کرد) را به ‌عنوان پارامتر خود می‌گیرد. ازآنجاکه پورت پیش‌فرض HTTP ، هشتاد (80) است، از این عدد استفاده می‌کنیم. حال می‌توانیم بدون نیاز به مشخص‌کردن پورت در URL، به سرور دسترسی پیدا کنیم.

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

سپس باید شماره پین ESP8266 NodeMCU را که به پین دیتا سنسور متصل است تعریف کنیم و یک شیء از کلاس DHT بسازیم. با ساخت این شیء به توابع خاص مربوط به کتابخانه DHT دسترسی خواهیم داشت.

// DHT Sensor
uint8_t DHTPin = D8;
 
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);

همچنین دو متغیر float به نام‌های Temperature و Humidity، برای ذخیره دما و رطوبت تعریف کردیم.

float Temperature;
float Humidity;

درون تابع ()Setup

قبل از اجرا سرور HTTP خود، باید تنظیمات آن را انجام دهیم. ابتدا یک اتصال سریال برای دیباگ کردن بازکرده و پورت‌های GPIO موردنظر را به عنوان ورودی تعریف می‌کنیم. همچنین باید با تابع ()begin، شیء DHT را مقداردهی اولیه کنیم.

Serial.begin(115200);
delay(100);
  
pinMode(DHTPin, INPUT);

dht.begin();

حال باید با تابع ()WiFi.begin، به شبکه وای‌فای متصل شویم. این تابع پارامترهای SSID (نام شبکه) و پسورد را می‌گیرد.

Serial.println("Connecting to ");
Serial.println(ssid);

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

مادامی که ESP8266 تلاش می‌کند به شبکه متصل شود، می‌توانیم وضعیت اتصال را با تابع ()WiFi.status بررسی کنیم.

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

وقتی ESP8266 NodeMCU به شبکه متصل می‌شود، آدرس IP تخصیص‌یافته به ESP8266 را با نمایش مقدار ()WiFi.localIP، روی سریال مانیتور چاپ می‌کند.

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

برای رسیدگی به درخواست‌های HTTP دریافتی، باید مشخص کنیم هنگام زدن هر URL خاص، کدام کد اجرا شود. برای این کار، از تابع on استفاده می‌کنیم. این تابع دو پارامتر می‌گیرد که پارامتر اول مسیر URL است و پارامتر دوم نام تابعی است که می‌خواهیم هنگام رخ‌دادن آن URL، اجرا شود.
برای مثال، خط اول تکه کد زیر وقتی سرور یک درخواست HTTP روی مسیر ریشه (/) دریافت کند، تابع ()handle_OnConnect را اجرا می‌کند. توجه کنید که URL مشخص شده، یک مسیر نسبی (Relative Path) است.

server.on("/", handle_OnConnect);

اگر سرویس‌گیرنده، درخواست یک URL غیر از موارد مشخص شده با تابع ()server.on را بدهد، در این صورت سرور باید با وضعیت HTTP 404 (Not Found) پاسخ دهد و یک پیام به کاربر نمایش دهد. این موارد را هم در یک تابع قرار می‌دهیم و از تابع server.onNotFound(handle_NotFound) استفاده می‌کنیم تا اگر سرور درخواستی برای یک URL دریافت کرد، که با ()server.on مشخص نشده باشد، این تابع اجرا شود.

server.onNotFound(handle_NotFound);

حال برای راه‌اندازی سرور، تابع begin را روی شیء server فراخوانی می‌کنیم.

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

درون تابع ()Loop

برای پاسخگویی به درخواست‌های HTTP ورودی، باید تابع ()handleClient را روی شیء server فراخوانی کنیم.

server.handleClient();

سپس، باید تابعی که با دستور server.on به آدرس ریشه (/) متصل کردیم را بسازیم. اگر یادتان باشد در ابتدای این تابع، مقادیر دما و رطوبت را از سنسور دریافت کردیم. برای پاسخ‌دادن به درخواست HTTP، از تابع send استفاده می‌کنیم. با اینکه این تابع می‌تواند با ترکیب دیگری از پارامترها هم فراخوانی شود، ساده‌ترین فرم آن شامل کد پاسخ به HTTP، نوع محتوای صفحه و خود محتوای است.

در اینجا، ما کد 200 (یکی از کدهای وضعیت HTTP) را ارسال می‌کنیم که به معنای OK است. سپس نوع محتوا را به‌عنوان “text/html” مشخص و در نهایت تابع ()SendHTML را فراخوانی می‌کنیم. این تابع یک صفحه HTML داینامیک تولید می‌کند که شامل مقادیر دما و رطوبت است.

void handle_OnConnect() {

 Temperature = dht.readTemperature(); // Gets the values of the temperature
  Humidity = dht.readHumidity(); // Gets the values of the humidity 
  server.send(200, "text/html", SendHTML(Temperature,Humidity)); 
}

به همین شکل باید تابعی برای مدیریت صفحه ارور 404 بسازیم.

void handle_NotFound(){
  server.send(404, "text/plain", "Not found");
}

نمایش صفحه وب HTML

هنگامی که وب سرور ESP8266 درخواستی از سرویس‌گیرنده دریافت می‌کند، تابع ()SendHTML مسئولیت ساخت صفحه وب را برعهده دارد. این تابع فقط کد HTML را در یک ‌رشته (string) بزرگ ذخیره می‌کند و به تابع server.send که در مورد آن صحبت کردیم برمی‌گرداند. این تابع پارامترهای دما و رطوبت را می‌گیرد تا محتوای داینامیک صفحه HTML را تولید کند. اولین متنی که باید همیشه ارسال کنید اعلان <!DOCTYPE> است که مشخص می‌کند در حال ارسال کد HTML هستیم.

String SendHTML(float Temperaturestat,float Humiditystat){
String ptr = "<!DOCTYPE html> <html>\n";

سپس، المان viewport <meta> باعث واکنش‌گرایی صفحه وب، روی همه مرورگرها می‌شود. همچنین تگ title، عنوان صفحه را مشخص می‌کند.

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

طراحی صفحه وب

در ادامه، چند خط کد CSS برای طراحی ظاهر دکمه‌ها و صفحه وب داریم. ما فونت Helvetica را انتخاب کردیم، نمایش محتویات صفحه را به‌صورت inline-block و محل قرارگیری آن را در وسط صفحه تنظیم کرده‌ایم.

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;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";

قرار دادن تیتر صفحه وب

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

ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 Weather Report</h1>\n";

نمایش دما و رطوبت اندازه‌گیری شده توسط سنسور DHT11 و DHT22 روی صفحه وب

برای نمایش مقادیر دما و رطوبت به‌صورت داینامیک، این مقادیر را در تگ پاراگراف (<p>)، قرار می‌دهیم. با این کار روی آن‌ها type casting انجام شده و به integer تبدیل می‌شوند. برای نماد درجه، از &deg entity HTML استفاده می‌کنیم (HTML entity ، برای نمایش برخی کاراکترهای خاص به کار می‌رود).

ptr +="<p>Temperature: ";
ptr +=(int)Temperaturestat;
ptr +="°C</p>";
ptr +="<p>Humidity: ";
ptr +=(int)Humiditystat;
ptr +="%</p>";

ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}

طراحی حرفه‌ای‌­تر صفحه وب

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

گزارش دما و رطوبت با استفاده از آیکون‌های جذابتر

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

String SendHTML(float TempCstat,float TempFstat,float Humiditystat){
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  ptr +="<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600\" rel=\"stylesheet\">\n";
  ptr +="<title>ESP8266 Weather Report</title>\n";
  ptr +="<style>html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #333333;}\n";
  ptr +="body{margin-top: 50px;}\n";
  ptr +="h1 {margin: 50px auto 30px;}\n";
  ptr +=".side-by-side{display: inline-block;vertical-align: middle;position: relative;}\n";
  ptr +=".humidity-icon{background-color: #3498db;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
  ptr +=".humidity-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
  ptr +=".humidity{font-weight: 300;font-size: 60px;color: #3498db;}\n";
  ptr +=".temperature-icon{background-color: #f39c12;width: 30px;height: 30px;border-radius: 50%;line-height: 40px;}\n";
  ptr +=".temperature-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
  ptr +=".temperature{font-weight: 300;font-size: 60px;color: #f39c12;}\n";
  ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -20px;top: 15px;}\n";
  ptr +=".data{padding: 10px;}\n";
  ptr +="</style>\n";
  ptr +="</head>\n";
  ptr +="<body>\n";
  
   ptr +="<div id=\"webpage\">\n";
   
   ptr +="<h1>ESP8266 Weather Report</h1>\n";
   ptr +="<div class=\"data\">\n";
   ptr +="<div class=\"side-by-side temperature-icon\">\n";
   ptr +="<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n";
   ptr +="width=\"9.915px\" height=\"22px\" viewBox=\"0 0 9.915 22\" enable-background=\"new 0 0 9.915 22\" xml:space=\"preserve\">\n";
   ptr +="<path fill=\"#FFFFFF\" d=\"M3.498,0.53c0.377-0.331,0.877-0.501,1.374-0.527C5.697-0.04,6.522,0.421,6.924,1.142\n";
   ptr +="c0.237,0.399,0.315,0.871,0.311,1.33C7.229,5.856,7.245,9.24,7.227,12.625c1.019,0.539,1.855,1.424,2.301,2.491\n";
   ptr +="c0.491,1.163,0.518,2.514,0.062,3.693c-0.414,1.102-1.24,2.038-2.276,2.594c-1.056,0.583-2.331,0.743-3.501,0.463\n";
   ptr +="c-1.417-0.323-2.659-1.314-3.3-2.617C0.014,18.26-0.115,17.104,0.1,16.022c0.296-1.443,1.274-2.717,2.58-3.394\n";
   ptr +="c0.013-3.44,0-6.881,0.007-10.322C2.674,1.634,2.974,0.955,3.498,0.53z\"/>\n";
   ptr +="</svg>\n";
   ptr +="</div>\n";
   ptr +="<div class=\"side-by-side temperature-text\">Temperature</div>\n";
   ptr +="<div class=\"side-by-side temperature\">";
   ptr +=(int)TempCstat;
   ptr +="<span class=\"superscript\">°C</span></div>\n";
   ptr +="</div>\n";
   ptr +="<div class=\"data\">\n";
   ptr +="<div class=\"side-by-side humidity-icon\">\n";
   ptr +="<svg version=\"1.1\" id=\"Layer_2\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\"; width=\"12px\" height=\"17.955px\" viewBox=\"0 0 13 17.955\" enable-background=\"new 0 0 13 17.955\" xml:space=\"preserve\">\n";
   ptr +="<path fill=\"#FFFFFF\" d=\"M1.819,6.217C3.139,4.064,6.5,0,6.5,0s3.363,4.064,4.681,6.217c1.793,2.926,2.133,5.05,1.571,7.057\n";
   ptr +="c-0.438,1.574-2.264,4.681-6.252,4.681c-3.988,0-5.813-3.107-6.252-4.681C-0.313,11.267,0.026,9.143,1.819,6.217\"></path>\n";
   ptr +="</svg>\n";
   ptr +="</div>\n";
   ptr +="<div class=\"side-by-side humidity-text\">Humidity</div>\n";
   ptr +="<div class=\"side-by-side humidity\">";
   ptr +=(int)Humiditystat;
   ptr +="<span class=\"superscript\">%</span></div>\n";
   ptr +="</div>\n";

  ptr +="</div>\n";
  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}

می‌دانیم اعلان <!DOCTYPE>، ارسال کد HTML را به مرورگر اطلاع می‌دهد و المان meta>viewport> باعث واکنش‌گرایی صفحه وب روی همه مرورگرها می‌شود. به علاوه می‌خواهیم از فونت‌های گوگل استفاده کنیم. گوگل صدها فونت وب دارد که برای استفاده شخصی یا تجاری رایگان هستند.

ما برای صفحه وب خود از فونت تجاری Open Sans گوگل استفاده می‌کنیم. فونت گوگل با استفاده از تگ link در <head> سند HTML شما، نهفته است. ما از وزن‌های فونت 300(light)، 400(Regular) و 600(bold) در صفحه وب استفاده می‌کنیم. شما می‌توانید هر تعداد وزن فونت انتخاب کنید، اما در نظر داشته باشید که انتخاب تعداد زیادی وزن غیرضروری، باعث افزایش زمان بارگذاری صفحه می‌شود. شما همچنین می‌توانید با ‌اضافه کردن کاراکتر i به انتهای وزن فونت، (مثلا 400i) به متن خود سبک italic بدهید. توجه داشته باشید که بدون داشتن اتصال اینترنت، نمی‌توانید فونت‌های گوگل را روی دستگاهی که به صفحه وب دسترسی پیدا می‌کند ببینید. فونت‌های گوگل به‌صورت آنلاین و در فضای ابری بارگذاری می‌شوند.

String SendHTML(float TempCstat,float TempFstat,float Humiditystat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600\" rel=\"stylesheet\">\n";

حال می‌خواهیم فونت Open Sans را به کل صفحه HTML اعمال کنیم، همچنین باید فونت sans-serif را به عنوان فونت پشتیبان مشخص کنیم تا حداکثر سازگاری را بین مرورگرها و سیستم‌عامل‌های مختلف، داشته باشیم. اگر مرورگر از فونت اول پشتیبانی نکند، سراغ فونت دوم می‌رود.

ptr +="<title>ESP8266 Weather Report</title>\n";
ptr +="<style>html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #333333;}\n";
ptr +="body{margin-top: 50px;}\n";
ptr +="h1 {margin: 50px auto 30px;}\n";

سپس باید آیکون‌ها، تیترها و مقادیر دما و رطوبت را با CSS پیاده‌سازی کنیم. هر سه مورد به‌صورت inline و عمودی و پس‌زمینه آیکون‌ها را به شکل دایره قرار می­دهیم.

ptr +=".side-by-side{display: inline-block;vertical-align: middle;position: relative;}\n";
ptr +=".humidity-icon{background-color: #3498db;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
ptr +=".humidity-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".humidity{font-weight: 300;font-size: 60px;color: #3498db;}\n";
ptr +=".temperature-icon{background-color: #f39c12;width: 30px;height: 30px;border-radius: 50%;line-height: 40px;}\n";
ptr +=".temperature-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".temperature{font-weight: 300;font-size: 60px;color: #f39c12;}\n";
ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -20px;top: 15px;}\n";
ptr +=".data{padding: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";

در ادامه، دمای خوانده شده را با آیکون کوچک و زیبای نمایش می‌دهیم.

آیکون دما در حقیقت یک بردار گرافیکی با قابلیت تغییر اندازه (Scalable Vector Graphics یا SVG) است، که با تگ <svg> تعریف شده است. ساخت SVG به مهارت برنامه‌نویسی خاصی نیاز ندارد. شما می‌توانید با استفاده از ابزار Google SVG Editor برای صفحه وب خودتان اشکال گرافیکی بسازید. پس از آیکون، نوبت به نمایش دمای خوانده شده از سنسور می‌رسد.

ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 NodeMCU Weather Report</h1>\n";
ptr +="<div class=\"data\">\n";

ptr +="<div class=\"side-by-side temperature-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n";
ptr +="width=\"9.915px\" height=\"22px\" viewBox=\"0 0 9.915 22\" enable-background=\"new 0 0 9.915 22\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M3.498,0.53c0.377-0.331,0.877-0.501,1.374-0.527C5.697-0.04,6.522,0.421,6.924,1.142\n";
ptr +="c0.237,0.399,0.315,0.871,0.311,1.33C7.229,5.856,7.245,9.24,7.227,12.625c1.019,0.539,1.855,1.424,2.301,2.491\n";
ptr +="c0.491,1.163,0.518,2.514,0.062,3.693c-0.414,1.102-1.24,2.038-2.276,2.594c-1.056,0.583-2.331,0.743-3.501,0.463\n";
ptr +="c-1.417-0.323-2.659-1.314-3.3-2.617C0.014,18.26-0.115,17.104,0.1,16.022c0.296-1.443,1.274-2.717,2.58-3.394\n";
ptr +="c0.013-3.44,0-6.881,0.007-10.322C2.674,1.634,2.974,0.955,3.498,0.53z\"/>\n";
ptr +="</svg>\n";
ptr +="</div>\n";

ptr +="<div class=\"side-by-side temperature-text\">Temperature</div>\n";
ptr +="<div class=\"side-by-side temperature\">";
ptr +=(int)TempCstat;
ptr +="<span class=\"superscript\">°C</span></div>\n";
ptr +="</div>\n";

مقدار رطوبت خوانده شده را با آیکون نمایش می‌دهیم.

این آیکون هم یک SVG است.

پس از نمایش مقدار رطوبت، همه تگ‌های باز کد CSS مانند body و html را می‌بندیم.

ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side humidity-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_2\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\"; width=\"12px\" height=\"17.955px\" viewBox=\"0 0 13 17.955\" enable-background=\"new 0 0 13 17.955\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M1.819,6.217C3.139,4.064,6.5,0,6.5,0s3.363,4.064,4.681,6.217c1.793,2.926,2.133,5.05,1.571,7.057\n";
ptr +="c-0.438,1.574-2.264,4.681-6.252,4.681c-3.988,0-5.813-3.107-6.252-4.681C-0.313,11.267,0.026,9.143,1.819,6.217\"></path>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side humidity-text\">Humidity</div>\n";
ptr +="<div class=\"side-by-side humidity\">";
ptr +=(int)Humiditystat;
ptr +="<span class=\"superscript\">%</span></div>\n";
ptr +="</div>\n";

ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}

بهبود دادن کد و به‌روزرسانی خودکار صفحه

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

تنها با افزودن یک تگ meta به فایل HTML، می‌توانیم به مرورگر نشان دهیم که صفحه را پس از مدت‌زمان معینی تازه‌­سازی (refresh) کند.

<meta http-equiv="refresh" content="2" >

این کد را در تگ <head> سند خود قرار دهید، تگ meta باعث می‌شود مرورگر هر دو ثانیه یک‌بار صفحه را تازه‌سازی کند.

بارگذاری داینامیک اطلاعات سنسورDHT11 و DHT22 با AJAX

تازه‌­سازی یک صفحه وب، هنگامی که صفحه سنگینی داشته باشید، عملی نیست. یک روش بهتر، استفاده از جاوا اسکریپت و Xml آسنکرون (Asynchronous Javascript And Xml یا AJAX) است. در این روش می‌توانیم از سرور به صورت آسنکرون (در پس زمینه) و بدون نیاز به تازه‌­سازی صفحه، درخواست اطلاعات کنیم.

شیء XMLHttpRequest در جاوااسکریپت معمولاً برای اجرای AJAX روی صفحات وب به‌کار می‌رود. این شئ بی سر و صدا درخواست GET به سرور می‌دهد و بخشی از صفحه وب را به روز می‌کند. AJAX یک فناوری جدید یا یک زبان متفاوت نیست؛ بلکه فقط استفاده‌ای جدید از فناوری‌های موجود است. جدا از این، AJAX امکانات زیر را برای ما فراهم میکند.

  • درخواست اطلاعات از سرور پس از بارگذاری صفحه وب
  • دریافت اطلاعات درخواست شده
  • ارسال اطلاعات به سرور در پس‌زمینه

اینجا اسکریپت AJAX مور نظر را مشاهده میکنید. این اسکریپت را قبل از بستن تگ</head> قرار دهید.

ptr +="<script>\n";
ptr +="setInterval(loadDoc,200);\n";
ptr +="function loadDoc() {\n";
ptr +="var xhttp = new XMLHttpRequest();\n";
ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.getElementById(\"webpage\").innerHTML =this.responseText}\n";
ptr +="};\n";
ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";
ptr +="</script>\n";

چون اسکریپت AJAX از جنس جاوااسکریپت است، باید آن را در تگ <script> بنویسیم. برای اینکه این تابع مرتب فراخوانی شود از تابع جاوا اسکریپت ()setInterval استفاده می‌کنیم. این تابع دو پارامتر می‌گیرد، اولین پارامتر، تابعی برای اجرا و پارامتر دوم، فاصله زمانی بین اجرای دوباره تابع (بر حسب میلی ثانیه) است.

ptr +="<script>\n";
ptr +="setInterval(loadDoc,200);\n";

قلب این اسکریپت، تابع ()loadDoc است. درون این تابع یک شیء ()XMLHttpRequest ساخته شده است که از وب سرور درخواست اطلاعات می‌کند.

ptr +="function loadDoc() {\n";
ptr +="var xhttp = new XMLHttpRequest();\n";

به محض تغییر readyState، تابع ()xhttp.onreadystatechange فراخوانی می‌شود. مشخصه readyState وضعیت XMLHttpRequest را نگه می‌دارد که یکی از مقادیر زیر است:

  • 0 : درخواست شروع نشده است.
  • 1 : ارتباط با سرور برقرار شده است.
  • 2 : درخواست دریافت شد.
  • 3 : درخواست در حال پردازش است.
  • 4 : درخواست انجام شده و پاسخ آماده است.

مشخصه status، وضعیت شیء XMLHttpRequest را نگه می‌دارد که یکی از مقادیر زیر است:

  • 200 : OK
  • 403 : ممنوع
  • 404 : صفحه پیدا نشد

وقتی مقدار readyState برابر 4 و status برابر 200 است، پاسخ آماده است. حال محتوای المانی از صفحه که مقادیر دما و رطوبت را نگه می‌دارد، به روز شده است.

ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.getElementById(\"webpage\").innerHTML =this.responseText}\n";
ptr +="};\n";

سپس درخواست HTTP با توابع ()open و ()send آماده و ارسال می‌شود.

ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";

اگر شماهم به ساخت این پروژه جذاب و کاربردی علاقه‌مند شده‌اید و تمایل دارید در حوزه اینترنت اشیا فعالیت داشته باشید، پس هرچه زودتر شروع کنید، شما به‌راحتی میتوانید با برقرار کردن ارتباط سنسورDHT11 و یا DHT22 با ESP8266 از امکانات آن در باغ خانه و یا گلخانه خود استفاده کنید. شما میتوانید سوالات و نظرات خود را دربخش دیدگاه با ما درمیان بگذارید.

مقالات مشابه

۱۲ دیدگاه. Leave new

  • سلام شما کتابخانه ESP8266WiFi رو از کجا دانلود کردید؟ ممنون میشم لینکش رو بفرستید❤

    پاسخ
  • سلام ماله من این ارور Error compiling for board ESPino (ESP-12 Module). میده

    پاسخ
    • سلام محمد مهدی عزیز،
      احتمالا شما بردت رو توی برنامه آردوینو به درستی انتخاب نکردی.
      باید NodeMCU 0.9 (ESP-12 Module) رو انتخاب کنی.

      پاسخ
  • سلام ممنون از مقاله خوبتون
    فقط مشکل که من دارم اینه که DHT11 مقادیری که بازگشت میدهnan هست از کجا میتونم بفهمم مشکل از کجاستت

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

      پاسخ
  • سلام خیلی ممنون از مقاله ی خوبتون من همین کد رو دقیقا رو ی نود ام سی یو مودل وی ۳ با ای اس پی دوازده امتحان کردم کار نکرد می شود راه نمایی کنید ممنون

    پاسخ
    • سلاو و درود برشما علی عزیز و تشکر بابت همراهیتون با مجموعه‌ی ما
      کدهای مقاله تست شده هستند. اگر مشکلتون را با جزئیات ذکر کنید بهتر میتونیم کمک کنیم، برای مثال اینکه در مرحله پروگرم مشکل دارید، در اتصال وایفای چالش دارید، وب سرور رو نمیتونید باز کنید یا…
      البته پیشنهاد می‌کنیم سوالات قبلی رو هم بخونید، شاید کمک کننده‌ شما بشوند.
      منتظر پاسخ شما هستیم 🙂

      پاسخ
  • سلام تگ متا برای بروزرسانی خودکار صفحه رو تو کدوم خط باید اضافه کنیم؟

    پاسخ
    • سلام محمدسجاد عزیز
      شما باید داخل تگ head این کد را قرار بدید. (برای مشاهده یک نمونه تگ متا، می‌تونید داخل کد قسمت:
      ساخت وب سرور ESP8266 NodeMCU با استفاده از حالت STA، خط ۷۴ رو ببینید.)

      پاسخ
  • سلام وقتی کد را اپلود میکنم این ارور رو میده
    Arduino: 1.8.8 (Windows 10), Board: “NodeMCU 1.0 (ESP-12E Module), 80 MHz, Flash, Disabled (new aborts on oom), Disabled, All SSL ciphers (most compatible), 32KB cache + 32KB IRAM (balanced), Use pgm_read macros for IRAM/PROGMEM, 4MB (FS:2MB OTA:~1019KB), 2, v2 Lower Memory, Disabled, None, Only Sketch, 115200”

    Build options changed, rebuilding all
    In file included from C:\Users\Homa Rayaneh\Documents\Arduino\libraries\DHT_sensor_library\DHT_U.cpp:15:
    C:\Users\Homa Rayaneh\Documents\Arduino\libraries\DHT_sensor_library\DHT_U.h:36:10: fatal error: Adafruit_Sensor.h: No such file or directory
    ۳۶ | #include
    | ^~~~~~~~~~~~~~~~~~~
    compilation terminated.

    exit status 1
    Error compiling for board NodeMCU 1.0 (ESP-12E Module).

    This report would have more information with
    “Show verbose output during compilation”
    option enabled in File -> Preferences.

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

      پاسخ

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

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

Fill out this field
Fill out this field
لطفاً یک نشانی ایمیل معتبر بنویسید.
You need to agree with the terms to proceed

پر بازدید ترین مقالات