پروژه اتصال سنسور های دما به ESP32 و نمایش در وب سرور

آیا تا به حال دوست داشتهاید در سرتاسر خانه و باغتان سنسورهایی داشته باشید که دما را بهصورت منظم به یک سرور مرکزی گزارش دهند؟ اگر بله، این پروژه اینترنت اشیاء (IoT) میتواند نقطه شروعی عالی برای شما باشد!
در این پروژه از ماژول ESP32 بهعنوان کنترلکننده اصلی استفاده میشود که بهراحتی به شبکه وایفای متصل شده و یک وبسرور ایجاد میکند. زمانی که هر دستگاهی به این وبسرور متصل شود، ESP32 دمای چندین سنسور DS18B20 را خوانده و از طریق مرورگر وب در یک رابط کاربری زیبا نمایش میدهد. هیجانانگیز است؟ پس شروع کنیم!
اتصال چند سنسور DS18B20 در باس مشترک
یکی از ویژگیهای مهم DS18B20 این است که میتوان چندین سنسور را روی یک باس تکسیم (1-Wire) بهصورت همزمان استفاده کرد. هر DS18B20 یک کد سریال 64 بیتی منحصربهفرد دارد که در کارخانه درون آن برنامهریزی شده است، بنابراین شناسایی هر سنسور از دیگری بسیار ساده است.
این قابلیت زمانی مزیت بزرگی محسوب میشود که بخواهید تعداد زیادی از سنسورها را در یک محیط بزرگ کنترل کنید. در این آموزش دقیقاً همین کار را انجام خواهیم داد.
اتصال چند سنسور DS18B20 به ESP32
اتصال سنسورهای DS18B20 به ماژول ESP32 بسیار ساده است.

ابتدا همه سنسورهای DS18B20 را بهصورت موازی وصل کنید؛ یعنی پایههای VDD، GND و سیگنال (Data) را به یکدیگر متصل کنید. سپس VDD را به پایه 3.3 ولت ESP32، پایه GND را به زمین (Ground)، و پایه سیگنال را به پایه دیجیتال 15 ماژول ESP32 وصل نمایید.
در گام بعد، برای پایداری انتقال داده، باید یک مقاومت Pull-up با مقدار 4.7kΩ بین پایه سیگنال و پایه تغذیه (VDD) قرار دهید.

آمادهسازی محیط Arduino IDE
برای برنامهنویسی ماژول ESP32 میتوانید از محیط Arduino IDE استفاده کنید. اگر تاکنون این محیط را برای ESP32 آماده نکردهاید، با آموزش زیر تنظیمات لازم را انجام دهید.
چندین پلتفرم توسعه برای برنامهنویسی ESP32 وجود دارد، اما برای کسانی که با آردوینو آشنا هستند، بهترین گزینه استفاده از Arduino IDE است.
نصب کتابخانه DS18B20
پروتکل Dallas 1-Wire نسبتاً پیچیده است و برای پردازش دادهها به کد زیادی نیاز دارد. برای سادهسازی این روند، کتابخانهی DallasTemperature.h را نصب میکنیم تا بتوانیم تنها با چند دستور ساده، دمای سنسورها را بخوانیم.
برای نصب کتابخانه، در Arduino IDE به مسیر زیر بروید:
Sketch > Include Library > Manage Libraries…
صبر کنید تا لیست کتابخانهها بارگذاری شود، سپس در کادر جستجو عبارت ds18b20 را وارد کنید. کتابخانه DallasTemperature ساختهی Miles Burton را پیدا کرده و گزینه Install را انتخاب کنید.
کتابخانه Dallas Temperature یک کتابخانه سختافزاری اختصاصی است که وظیفه پردازش سطوح پایین را بر عهده دارد. برای برقراری ارتباط با دستگاههای 1-Wire از جمله DS18B20 باید همراه آن، کتابخانه OneWire را نیز نصب کنید. برای این کار، همان مراحل را تکرار کرده و کتابخانه OneWire را نیز نصب نمایید.
یافتن آدرس سنسورهای DS18B20 روی باس
همانطور که میدانیم، هر سنسور DS18B20 دارای یک آدرس منحصربهفرد 64 بیتی است که برای تمایز آن از دیگر سنسورها استفاده میشود. در ابتدا باید این آدرسها را بهدست آوریم تا بتوانیم هر سنسور را بهصورت جداگانه شناسایی کنیم. سپس از این آدرسها برای خواندن دادههای هر سنسور بهصورت مستقل استفاده خواهیم کرد.
در کد زیر، تمام سنسورهای متصل به باس شناسایی میشوند و آدرس آنها در Serial Monitor نمایش داده میشود.
برای راحتی کار میتوانید هر بار تنها یک سنسور را متصل کنید تا آدرس آن را پیدا کرده و یادداشت نمایید. در نهایت، با این روش تمام سنسورها را بر اساس آدرسشان برچسبگذاری خواهید کرد.
کد شناسایی آدرس سنسورهای DS18B20:
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 15
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
DeviceAddress Thermometer;
int deviceCount = 0;
void setup(void)
{
Serial.begin(115200);
sensors.begin();
Serial.println("Locating devices...");
Serial.print("Found ");
deviceCount = sensors.getDeviceCount();
Serial.print(deviceCount, DEC);
Serial.println(" devices.\n");
Serial.println("Printing addresses...");
for (int i = 0; i < deviceCount; i++)
{
Serial.print("Sensor ");
Serial.print(i + 1);
Serial.print(" : ");
sensors.getAddress(Thermometer, i);
printAddress(Thermometer);
}
}
void loop(void) { }
void printAddress(DeviceAddress deviceAddress)
{
for (uint8_t i = 0; i < 8; i++)
{
Serial.print("0x");
if (deviceAddress[i] < 0x10) Serial.print("0");
Serial.print(deviceAddress[i], HEX);
if (i < 7) Serial.print(", ");
}
Serial.println("");
}
پس از آپلود کد، Serial Monitor را باز کنید. خواهید دید که آدرس تمام سنسورهای DS18B20 متصل به باس نمایش داده میشود. این آدرسها را کپی کرده و برای مراحل بعدی نگه دارید.

ایجاد وبسرور با ESP32 در حالت (STA)
در این مرحله، ماژول ESP32 را در حالت Station (STA) پیکربندی میکنیم تا به شبکه وایفای موجود متصل شده و یک وبسرور ایجاد کند. این وبسرور صفحات وب را برای دستگاههایی که به همان شبکه متصل هستند نمایش میدهد.
برای آشنایی بیشتر با حالتهای مختلف، میتوانید آموزش «ایجاد وبسرور ساده ESP32 در حالت Access Point و Station» را مطالعه کنید.
پیش از آپلود کد، باید دو متغیر زیر را با نام شبکه (SSID) و رمز عبور (Password) خود جایگزین کنید تا ESP32 بتواند به شبکه خانگی شما متصل شود:
const char* ssid = "YourNetworkName"; const char* password = "YourPassword";
همچنین باید آدرس سنسورهایی را که در مرحله قبل پیدا کردهاید، در بخش زیر وارد کنید:
uint8_t sensor1[8] = { 0x28, 0xEE, 0xD5, 0x64, 0x1A, 0x16, 0x02, 0xEC };
uint8_t sensor2[8] = { 0x28, 0x61, 0x64, 0x12, 0x3C, 0x7C, 0x2F, 0x27 };
uint8_t sensor3[8] = { 0x28, 0x61, 0x64, 0x12, 0x3F, 0xFD, 0x80, 0xC6 };
دسترسی به وبسرور ESP32
پس از آپلود کد در ماژول ESP32، Serial Monitor را با نرخ 115200 باز کنید و کلید EN روی برد را فشار دهید. اگر همهچیز درست باشد، ESP32 آدرس IP خود را که از روتر دریافت کرده است نمایش میدهد و پیغام HTTP server started روی مانیتور ظاهر میشود.

اکنون مرورگر خود را باز کنید و آدرس IP نمایشدادهشده را در نوار آدرس وارد نمایید. صفحهای باز میشود که دمای تمام سنسورهای DS18B20 را بهصورت زنده نمایش میدهد.

کد کامل ایجاد وبسرور ESP32 برای نمایش دمای چندین DS18B20 در فایل دانلودی انتهای صفحه قرار داده شده است. در اینجا قسمت های مختلف کد را توضیح میدهیم.
توضیح کامل کد پروژه مانیتور دما با ESP32 و DS18B2
در ابتدای کد، کتابخانههای زیر اضافه میشوند:
- WiFi.h: برای اتصال ماژول ESP32 به شبکه وایفای و استفاده از توابع مخصوص ارتباط شبکه.
- WebServer.h: برای راهاندازی یک وبسرور داخلی و مدیریت درخواستهای HTTP بدون نیاز به کدنویسی سطح پایین.
- DallasTemperature.h: برای کار با سنسورهای DS18B20 و خواندن دمای آنها به روشی سادهتر. این کتابخانه نیازمند OneWire.h است تا بتواند با دستگاههای مبتنی بر پروتکل One-Wire ارتباط برقرار کند.
- OneWire.h: کتابخانهای برای ارتباط با هر نوع دستگاه One-Wire از جمله DS18B20.
#include <WiFi.h> #include <WebServer.h> #include <OneWire.h> #include <DallasTemperature.h>
سپس نمونههایی از کتابخانهها و متغیرهایی برای ذخیرهسازی دمای سنسورها ایجاد میکنیم. در این پروژه، سیم دیتا (Data) سنسورها به پایه GPIO15 متصل است.
#define ONE_WIRE_BUS 15 OneWire oneWire(ONE_WIRE_BUS); DallasTemperature sensors(&oneWire); float tempSensor1, tempSensor2, tempSensor3;
در ادامه، آدرسهایی که قبلاً برای هر سنسور بهدست آوردیم را تعریف میکنیم تا ESP32 بتواند هرکدام را بهصورت مجزا شناسایی کند:
uint8_t sensor1[8] = { 0x28, 0xEE, 0xD5, 0x64, 0x1A, 0x16, 0x02, 0xEC };
uint8_t sensor2[8] = { 0x28, 0x61, 0x64, 0x12, 0x3C, 0x7C, 0x2F, 0x27 };
uint8_t sensor3[8] = { 0x28, 0x61, 0x64, 0x12, 0x3F, 0xFD, 0x80, 0xC6 };
از آنجا که ESP32 را در حالت Station (STA) پیکربندی میکنیم، باید اطلاعات شبکه وایفای خود را در متغیرهای زیر وارد کنیم تا دستگاه به آن متصل شود. سپس یک وبسرور روی پورت 80 راهاندازی میشود:
const char* ssid = "YourNetworkName"; const char* password = "YourPassword"; WebServer server(80);
عملکرد تابع Setup()
در تابع setup() ابتدا ارتباط سریال برای مانیتورینگ فعال میشود و شیء مربوط به سنسورهای دما با دستور begin() مقداردهی اولیه میشود تا تمام سنسورهای DS18B20 موجود روی باس شناسایی شوند.
Serial.begin(115200); delay(100); sensors.begin();
سپس با استفاده از تابع WiFi.begin() ماژول ESP32 تلاش میکند تا به شبکه وایفای متصل شود. این تابع دو ورودی دارد: نام شبکه (SSID) و رمز عبور.
Serial.println("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
برای بررسی وضعیت اتصال، از WiFi.status() استفاده میشود. تا زمانی که اتصال برقرار نشده باشد، برنامه هر ثانیه یک نقطه در سریال چاپ میکند.
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
پس از برقراری اتصال، آدرس IP اختصاص دادهشده به ESP32 توسط روتر نمایش داده میشود.
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
برای مشخصکردن عملکرد وبسرور، از تابع server.on() استفاده میشود. این تابع دو پارامتر دارد: مسیر (URL path) و تابعی که هنگام درخواست آن مسیر اجرا میشود. در اینجا مسیر اصلی (/) به تابع handle_OnConnect متصل شده است.
server.on("/", handle_OnConnect);
در صورتی که کاربر به URL نامعتبر دسترسی پیدا کند، تابع handle_NotFound فراخوانی میشود تا پیام خطای 404 Not Found نمایش داده شود.
server.onNotFound(handle_NotFound);
در نهایت وبسرور با دستور زیر فعال میشود:
server.begin();
Serial.println("HTTP server started");
عملکرد تابع Loop()
در تابع loop()، برای بررسی و پاسخدهی به درخواستهای جدید کاربران از تابع زیر استفاده میشود:
server.handleClient();
تابع handle_OnConnect()
این تابع زمانی اجرا میشود که کاربر از طریق مرورگر به آدرس IP دستگاه متصل شود. در اینجا ESP32 دمای هر سنسور را میخواند و صفحه HTML تولیدشده را به مرورگر ارسال میکند.
void handle_OnConnect() {
sensors.requestTemperatures();
tempSensor1 = sensors.getTempC(sensor1);
tempSensor2 = sensors.getTempC(sensor2);
tempSensor3 = sensors.getTempC(sensor3);
server.send(200, "text/html", SendHTML(tempSensor1,tempSensor2,tempSensor3));
}
در اینجا:
- کد وضعیت 200 یعنی درخواست با موفقیت انجام شده است.
- نوع محتوا text/html مشخص میکند که پاسخ شامل کد HTML است.
- تابع
SendHTML()وظیفه دارد صفحه وب را با مقادیر دما بهصورت پویا تولید کند.
تابع handle_NotFound()
اگر کاربر URL نادرستی را وارد کند، این تابع اجرا میشود و پاسخ 404 Not Found برمیگرداند.
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
تابع SendHTML()
این تابع کل محتوای صفحه وب را بهصورت رشتهای از کد HTML میسازد و به مرورگر میفرستد. سه مقدار دمایی را بهصورت ورودی میگیرد تا آنها را در صفحه نمایش دهد.
ابتدا با دستور <!DOCTYPE html> مشخص میکنیم که در حال ارسال محتوای HTML هستیم:
String SendHTML(float tempSensor1,float tempSensor2,float tempSensor3){
String ptr = "<!DOCTYPE html> <html>\n";
در بخش <head>، تگ <meta> باعث میشود صفحه در تمام دستگاهها (موبایل، تبلت و دسکتاپ) واکنشگرا باشد. تگ <title> نیز عنوان صفحه را مشخص میکند:
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n"; ptr +="<title>ESP32 Temperature Monitor</title>\n";
استایلدهی (CSS)
در این بخش با استفاده از CSS ظاهر صفحه را زیباتر میکنیم. از فونت Helvetica استفاده میشود و متنها در وسط صفحه قرار میگیرند. رنگ، اندازه و فاصله بین المانها نیز تنظیم شده است:
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>ESP32 Temperature Monitor</h1>\n";
نمایش مقادیر دما در صفحه وب
برای نمایش پویا و لحظهای مقادیر دما، مقادیر خواندهشده از سنسورها درون تگهای <p> قرار داده میشوند. برای نمایش نماد درجه حرارت، از موجودیت HTML یعنی ° استفاده میکنیم.
ptr +="<p>Living Room: "; ptr +=tempSensor1; ptr +="°C</p>"; ptr +="<p>Bedroom: "; ptr +=tempSensor2; ptr +="°C</p>"; ptr +="<p>Kitchen: "; ptr +=tempSensor3; ptr +="°C</p>"; ptr +="</div>\n"; ptr +="</body>\n"; ptr +="</html>\n"; return ptr; }
استایلدهی صفحه وب برای ظاهر حرفهای تر
معمولاً برنامهنویسها کمتر به بخش طراحی توجه میکنند، اما با کمی تلاش میتوان ظاهر صفحه وب را حرفهایتر و جذابتر کرد. تصویر زیر ایدهای کلی از نتیجهی نهایی را نشان میدهد.

عالی است، درست است؟ حال بیایید استایلدهی را به صفحهی HTML قبلی اضافه کنیم. برای این کار کافی است کد زیر را در تابع SendHTML() جایگزین نسخهی قبلی آن کنید.
String SendHTML(float tempSensor1,float tempSensor2,float tempSensor3){
String ptr = "<!DOCTYPE html>";
ptr +="<html>";
ptr +="<head>";
ptr +="<title>ESP32 Temperature Monitor</title>";
ptr +="<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
ptr +="<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600' rel='stylesheet'>";
ptr +="<style>";
ptr +="html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #444444;}";
ptr +="body{margin-top: 50px;} ";
ptr +="h1 {margin: 50px auto 30px;} ";
ptr +=".side-by-side{display: table-cell;vertical-align: middle;position: relative;}";
ptr +=".text{font-weight: 600;font-size: 19px;width: 200px;}";
ptr +=".temperature{font-weight: 300;font-size: 50px;padding-right: 15px;}";
ptr +=".living-room .temperature{color: #3B97D3;}";
ptr +=".bedroom .temperature{color: #F29C1F;}";
ptr +=".kitchen .temperature{color: #26B99A;}";
ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -5px;top: 15px;}";
ptr +=".data{padding: 10px;}";
ptr +=".container{display: table;margin: 0 auto;}";
ptr +=".icon{width:82px}";
ptr +="</style>";
ptr +="</head>";
ptr +="<body>";
ptr +="<h1>ESP32 Temperature Monitor</h1>";
...
return ptr;
}
تفاوت نسخهی جدید با نسخهی قبلی
اگر این تابع را با نسخهی قبلی مقایسه کنید، متوجه میشوید که تفاوت اصلی در بخش ظاهر و فونت است. در اینجا از فونت تحت وب Open Sans که توسط Google ارائه شده استفاده شده است. توجه داشته باشید که برای نمایش فونت گوگل، دستگاه باید به اینترنت متصل باشد، زیرا فونتها بهصورت آنلاین بارگذاری میشوند.
ptr +="<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600' rel='stylesheet'>";
نمادهای دما که در کنار هر مقدار نمایش داده میشوند، در واقع آیکونهای SVG هستند که در تگ <svg> تعریف شدهاند. ساخت SVG نیاز به مهارت خاصی ندارد و میتوانید از ابزارهایی مانند Google SVG Editor برای طراحی آیکونهای دلخواه استفاده کنید.

بهبود کد – بهروزرسانی خودکار صفحه
یکی از بهبودهایی که میتوانید روی این کد انجام دهید، افزودن قابلیت تازهسازی خودکار (Auto Refresh) صفحه است تا مقادیر دما بهصورت منظم و خودکار بهروزرسانی شوند.
برای این کار کافی است از تگ متا زیر در بخش <head> استفاده کنید:
<meta http-equiv="refresh" content="2">
با قرار دادن این کد، مرورگر هر دو ثانیه یکبار صفحه را رفرش میکند.
بارگذاری پویا با استفاده از AJAX
رفرش کامل صفحه ممکن است در صفحات سنگین باعث تأخیر شود. برای حل این مشکل میتوان از AJAX (Asynchronous JavaScript and XML) استفاده کرد تا دادهها از سرور بهصورت پسزمینه بارگذاری شوند، بدون نیاز به رفرش کامل صفحه.
شیء XMLHttpRequest در JavaScript برای اجرای AJAX استفاده میشود. این شیء یک درخواست GET به سرور ارسال میکند و محتوای صفحه را بهروزرسانی میکند.
در اینجا اسکریپت AJAX را مشاهده میکنید که باید پیش از بستن تگ <head> قرار داده شود:
ptr +="<script>\n";
ptr +="setInterval(loadDoc,1000);\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.body.innerHTML =this.responseText}\n";
ptr +="};\n";
ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";
ptr +="</script>\n";
تابع setInterval() باعث میشود که تابع loadDoc() هر 1000 میلیثانیه (یعنی هر یک ثانیه) اجرا شود. درون تابع loadDoc()، شیء XMLHttpRequest ساخته میشود تا دادهها را از سرور دریافت کند و در صورت موفقیت، محتوای صفحه بهروزرسانی شود.
در هنگام اجرای درخواست، خاصیتهای زیر بررسی میشوند:
readyState = 4یعنی پاسخ آماده است.status = 200یعنی درخواست موفق بوده است.
زمانی که هر دو شرط برقرار باشند، محتوای صفحه با دادههای جدید بهروز میشود.
موارد موجود در فایل : سورس کامل
برای دانلود فایل ها باید حساب کاربری داشته باشید ثبت نام / ورود








