آیا تا به حال به این فکر کردهاید که سنسورهایی در جاهای مختلف خانه و باغچهتان داشته باشید که به طور مرتب دمای خود را به یک سرور مرکزی گزارش کنند؟ اگر پاسخ شما مثبت است، این پروژه اینترنت اشیاء میتواند بهترین نقطه شروع برای شما باشد!
در این پروژه برای نمایش مقادیر چند سنسور DS18B20 از ماژول ESP8266 NodeMCU به عنوان یک دستگاه کنترلکننده استفاده میکنیم که به سادگی به یک شبکه وایفای متصل میشود و یک وب سرور میسازد. زمانیکه هر یک از دستگاههای متصل به شبکه به این وب سرور دسترسی پیدا کنند، ESP8266 دما را از سنسورهای دمای DS18B20 خوانده و با یک ظاهر زیبا، به مرورگر وب دستگاه ارسال میکند. هیجان زده شدید؟ پس بیایید شروع کنیم!
استفاده از چند سنسور DS18B20 روی یک خط باس
یکی از قابلیتهای مهم DS18B20 این است که چندین سنسور DS18B20 میتوانند به طور همزمان روی یک باس تک سیمه مشترک وجود داشته باشند. هر سنسور DS18B20 یک شماره سریال 64 بیتی مختص به خود دارد که در زمان ساخت در کارخانه روی آن ریخته میشود تا تشخیص سنسورهای مختلف از هم امکانپذیر باشد.
این قابلیت زمانی اهمیت پیدا میکند که بخواهید چندین DS18B20 را که در یک محوطهی بزرگ پخش شدهاند، کنترل کنید.
نحوهی اتصال چند سنسور DS18B20 به ESP8266 NodeMCU
برای نمایش مقادیر چند سنسور DS18B20 و استفاده از آن نیاز است ابتدا با پایهها و نحوه اتصال این سنسوربه ESP8266 آشنا شوید. اتصال سنسورهای DS18B20 به ESP8266 NodeMCU نسبتاً ساده است.
با اتصال سنسورها به صورت موازی شروع کنید. همانطورکه در تصویر زیر نشان داده شدهاست، بدین منظور باید همه پینهای VDD را به هم متصل نمایید، برای پینهای GND و signal نیز به همین صورت عمل کنید. سپس پین VDD را به ولتاژ 3.3 متصل کنید، GND را زمین کنید و پین signal را به پین دیجیتال D2 روی برد ESP8266 NodeMCU متصل نمایید. سپس باید یک مقاومت پولآپ 4.7 کیلواهم بین خط سیگنال و تغذیه قرار دهید تا انتقال اطلاعات به شکل پایدارتری صورت بگیرد.
آمادهسازی IDE آردوینو
محیط برنامهنویسی آردوینو افزونهای دارد که به شما اجازه میدهد با استفاده آن، ESP8266 NodeMCU را پروگرام کنید. اگر تا به حال این کار را نکردهاید، آموزش زیر را دنبال کنید:
نصب کتابخانه برای DS18B20
پروتکل تک سیمه Dallas مقداری پیچیده است و برای تحلیل اطلاعات نیاز به چندین خط کد دارد. برای عدم رویارویی با این پیچیدگی، کتابخانه DallasTemperature.h را نصب میکنیم تا بتوانیم با استفاده از چند فرمان ساده، دما را از سنسور بخوانیم.
برای نصب کتابخانه به مسیر Arduino IDE > Sketch > Include Library > Manage Libraries بروید. صبر کنید تا Library Manager لیست کتابخانهها را دانلود کرده و لیست کتابخانههای نصب شده را آپدیت کند. سپس جستجوی خود را با نوشتن عبارت ‘ds18b20’ فیلتر کنید. از بین چند گزینهای که میبینید، DallasTemperature از Miles Burton را پیدا کرده و آن را نصب کنید.
کتابخانه DallasTemperature، یک کتابخانه سمت سختافزار است که توابع سطح پایین را مدیریت میکند. این کتابخانه باید با کتابخانه One Wire جفت شود تا با قطعاتی مانند DS18B20 که ارتباط تک سیمه دارند ارتباط برقرار کند. پس این کتابخانه را هم نصب کنید.
پیدا کردن آدرس سنسورهای DS18B20 بر روی خط باس
همانطور که میدانید برای تمایز سنسورهای دمای DS18B20، به هر کدام یک آدرس 64 بیتی منحصر به فرد اختصاص داده شدهاست. ابتدا مشخص میکنیم هر سنسور چه آدرسی دارد و در ادامه از این آدرس استفاده میکنیم تا دمای هر سنسور را به طور جداگانه بخوانیم. برنامه زیر همه سنسورهای DS18B20 موجود روی باس را تشخیص میدهد و آدرسِ تک سیمه آنها را روی سریال مانیتور چاپ میکند. شما میتوانید هر بار فقط یک سنسور را متصل کنید و آدرس آن را بیابید (یا اینکه به ترتیب، با هر بار اجرای برنامه یک سنسور جدید اضافه کنید تا بتوانید آدرس هر سنسور را تشخیص دهید).
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port D2 on the ESP8266
#define ONE_WIRE_BUS D2
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// variable to hold device addresses
DeviceAddress Thermometer;
int deviceCount = 0;
void setup(void)
{
// start serial port
Serial.begin(115200);
// Start up the library
sensors.begin();
// locate devices on the bus
Serial.println("Locating devices...");
Serial.print("Found ");
deviceCount = sensors.getDeviceCount();
Serial.print(deviceCount, DEC);
Serial.println(" devices.");
Serial.println("");
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("");
}
حال سریال مانیتور را باز کنید. باید چیزی شبیه به شکل زیر ببینید:
همه آدرسها را کپی و ذخیره کنید، چون در ادامه به آنها نیاز خواهید داشت.
ساخت وب سرور ESP8266 در مد ایستگاه (STA)
حال میخواهیم ESP8266 خود را در مد Station تنظیم کنیم، و یک وب سرور بسازیم که صفحات وب را به دستگاههای متصل به شبکه تحویل دهد.
اگر میخواهید در مورد ساخت وب سرور با ESP8266 NodeMCU در مدهای AP و STA بیشتر بدانید، آموزش زیر را دنبال کنید.
قبل از آپلود برنامه، لازم است تغییرات زیر را اعمال نمایید.
- ابتدا باید متغیرهای زیر را برحسب مشخصات شبکهی خود تغییر دهید، تا ESP8266 بتواند با شبکه اتصال برقرار کند.
const char* ssid = "YourNetworkName"; // Enter SSID here
const char* password = "YourPassword"; //Enter Password here
- ESP8266 قبل از آمادهسازی صفحه وب، دمای هر یک از سنسورهای DS18B20 را با کمک آدرس آنها میخواند. پس شما باید آدرس سنسورها را طبق آدرسهایی که در برنامه قبل بهدست آوردید، تغییر دهید.
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 };
پس از انجام این تغییرات، برنامه زیر را امتحان کنید:
#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port D2 on the ESP8266
#define ONE_WIRE_BUS D2
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
float tempSensor1, tempSensor2, tempSensor3;
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 };
/*Put your SSID & Password*/
const char* ssid = "YourNetworkName"; // Enter SSID here
const char* password = "YourPassword"; //Enter Password here
ESP8266WebServer server(80);
void setup() {
Serial.begin(115200);
delay(100);
sensors.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() {
sensors.requestTemperatures();
tempSensor1 = sensors.getTempC(sensor1); // Gets the values of the temperature
tempSensor2 = sensors.getTempC(sensor2); // Gets the values of the temperature
tempSensor3 = sensors.getTempC(sensor3); // Gets the values of the temperature
server.send(200, "text/html", SendHTML(tempSensor1,tempSensor2,tempSensor3));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(float tempSensor1,float tempSensor2,float tempSensor3){
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 Temperature Monitor</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 Temperature Monitor</h1>\n";
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;
}
دسترسی به وب سرور و نمایش مقادیر چند سنسور DS18B20
برای نمایش مقادیر چند سنسور DS18B20 پس از آپلود برنامه، سریال مانیتور را باز و با بادریت را روی 115200 تنظیم کنید. سپس دکمه ریست روی NodeMCU را فشار دهید. اگر همه چیز درست باشد، پیغام HTTP server started به همراه یک آدرس آیپی داینامیک نمایش داده میشود. این همان آدرسی است که از روتر شما گرفته شدهاست.
حال یک مرورگر باز کنید و به آدرسی که از سریال مانیتور دریافت کردید بروید. ESP8266 باید یک صفحهی وب بارگذاری کند که دمای همه سنسورهای DS18B20 را نشان میدهد.
توضیح کد
برنامه با افزودن کتابخانههای زیر آغاز میشود:
- ESP8266WebServer.h: این کتابخانه توابع مربوط به وایفای ESP8266 را ارائه میدهد که برای اتصال به شبکه آنها را فراخوانی میکنیم. همچنین این کتابخانه شامل توابعی است که به ما در ساخت یک وب سرور و مدیریت درخواستهای HTTP کمک میکند.
- DallasTemperature.h : این کتابخانهی سخت افزاری، توابع سطح پایین را مدیریت میکند و برای اینکه عملکرد صحیحی داشته باشد، باید با کتابخانهی One Wire جفت شود.
- OneWire.h: این کتابخانه نه فقط با DS18B20 بلکه با هر قطعهای که ارتباط تک سیمه داشته باشد، میتواند ارتباط برقرار میکند.
#include <ESP8266WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
در ادامه متغیرهای مورد نیاز برای ارتباط با سنسور و ذخیرهی دما را میسازیم. سنسور دما نیز به پین D2 متصل شدهاست.
// Data wire is plugged into port D2 on the ESP8266
#define ONE_WIRE_BUS D2
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
float tempSensor1, tempSensor2, tempSensor3;
سپس نوبت وارد کردن آدرس سنسورهاست. برای سنسورهای ما آدرسها به شکل زیر هستند:
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 };
در این پروژه ESP8266 را در مد STA تنظیم کردیم پس این ماژول باید به شبکهی وایفای موجود متصل شود. در نتیجه باید پسورد و SSID شبکه خود را به آن بدهیم. سپس وب سرور را در پورت 80 راهاندازی میکنیم.
/*Put your SSID & Password*/
const char* ssid = "YourNetworkName"; // Enter SSID here
const char* password = "YourPassword"; //Enter Password here
ESP8266WebServer server(80);
تابع ()Setup
قبل از اجرای سرور HTTP، ابتدا آن را کانفیگ میکنیم. در اولین قدم، ارتباط سریال با کامپیوتر و همچنین شیء DallasTemperature را با استفاده از تابع ()begin راهاندازی میکنیم. این تابع ارتباط باس را فعال و همهی سنسورهای DS18B20 حاضر روی آن را شناسایی میکند. سپس به هر سنسور یک شماره اختصاص میدهد و رزولوشن را روی 12 بیت تنظیم میکند.
Serial.begin(115200);
delay(100);
sensors.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 به شبکه، برنامه آدرس آیپی تخصیصیافته به آن را از طریق نمایش مقدار تابع ()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 استفاده میکنیم تا اگر سرور یک درخواست نامشخص دریافت کرد، این تابع اجرا شود.
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() {
sensors.requestTemperatures();
tempSensor1 = sensors.getTempC(sensor1);
tempSensor2 = sensors.getTempC(sensor2);
tempSensor3 = sensors.getTempC(sensor3);
server.send(200, "text/html", SendHTML(tempSensor1,tempSensor2,tempSensor3));
}
به همین شکل باید تابعی برای مدیریت صفحه خطای 404 بسازیم.
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
نمایش صفحه وب HTML
هر زمان که وب سرور ESP8266، درخواستی از سرویسگیرنده دریافت میکند، تابع ()SendHTML ساخت یک صفحه وب را برعهده میگیرد. این تابع فقط کد HTML را در یک رشتهی بزرگ (string) ذخیره میکند و آن را به تابع ()server.send که در مورد آن صحبت کردیم، برمیگرداند. تابع ()SendHTML دماهای خوانده شده را میگیرد و محتوای صفحه HTML را تولید میکند.
اولین متنی که همیشه باید ارسال کنید اعلان <!DOCTYPE> است که مشخص میکند در حال ارسال کد HTML هستیم.
String SendHTML(float tempSensor1,float tempSensor2,float tempSensor3){
String ptr = "<!DOCTYPE html> <html>\n";
سپس، المان ویوپورتِ <meta> را ارسال میکنیم که صفحه وب را در هر مرورگری نمایش میدهد. تگ title نیز عنوان صفحه را مشخص میکند.
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP8266 Temperature Monitor</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 Temperature Monitor</h1>\n";
نمایش مقادیر دما در صفحه وب
برای نمایش داینامیک دماهای خوانده شده، مقادیر را در تگ پاراگراف (<p>) قرار میدهیم و برای نماد درجه نیز از ° استفاده میکنیم.
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>ESP8266 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>ESP8266 Temperature Monitor</h1>";
ptr +="<div class='container'>";
ptr +="<div class='data living-room'>";
ptr +="<div class='side-by-side icon'>";
ptr +="<svg enable-background='new 0 0 65.178 45.699'height=45.699px id=Layer_1 version=1.1 viewBox='0 0 65.178 45.699'width=65.178px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><polygon fill=#3B97D3 points='8.969,44.261 8.969,16.469 7.469,16.469 7.469,44.261 1.469,44.261 1.469,45.699 14.906,45.699 ";
ptr +="14.906,44.261 '/><polygon fill=#3B97D3 points='13.438,0 3,0 0,14.938 16.438,14.938 '/><polygon fill=#3B97D3 points='29.927,45.699 26.261,45.699 26.261,41.156 32.927,41.156 '/><polygon fill=#3B97D3 points='58.572,45.699 62.239,45.699 62.239,41.156 55.572,41.156 '/><path d='M61.521,17.344c-2.021,0-3.656,1.637-3.656,3.656v14.199H30.594V21c0-2.02-1.638-3.656-3.656-3.656";
ptr +="c-2.02,0-3.657,1.636-3.657,3.656v14.938c0,2.021,1.637,3.655,3.656,3.655H61.52c2.02,0,3.655-1.637,3.655-3.655V21";
ptr +="C65.177,18.98,63.54,17.344,61.521,17.344z'fill=#3B97D3 /><g><path d='M32.052,30.042c0,2.02,1.637,3.656,3.656,3.656h16.688c2.019,0,3.656-1.638,3.656-3.656v-3.844h-24";
ptr +="L32.052,30.042L32.052,30.042z'fill=#3B97D3 /><path d='M52.396,6.781H35.709c-2.02,0-3.656,1.637-3.656,3.656v14.344h24V10.438";
ptr +="C56.053,8.418,54.415,6.781,52.396,6.781z'fill=#3B97D3 /></g></svg>";
ptr +="</div>";
ptr +="<div class='side-by-side text'>Living Room</div>";
ptr +="<div class='side-by-side temperature'>";
ptr +=(int)tempSensor1;
ptr +="<span class='superscript'>°C</span></div>";
ptr +="</div>";
ptr +="<div class='data bedroom'>";
ptr +="<div class='side-by-side icon'>";
ptr +="<svg enable-background='new 0 0 43.438 35.75'height=35.75px id=Layer_1 version=1.1 viewBox='0 0 43.438 35.75'width=43.438px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><g><path d='M25.489,14.909H17.95C13.007,14.908,0,15.245,0,20.188v3.688h43.438v-3.688";
ptr +="C43.438,15.245,30.431,14.909,25.489,14.909z'fill=#F29C1F /><polygon fill=#F29C1F points='0,31.25 0,35.75 2.5,35.75 4.5,31.25 38.938,31.25 40.938,35.75 43.438,35.75 43.438,31.25 ";
ptr +="43.438,25.375 0,25.375 '/><path d='M13.584,11.694c-3.332,0-6.033,0.973-6.033,2.175c0,0.134,0.041,0.264,0.105,0.391";
ptr +="c3.745-0.631,7.974-0.709,10.341-0.709h1.538C19.105,12.501,16.613,11.694,13.584,11.694z'fill=#F29C1F /><path d='M30.009,11.694c-3.03,0-5.522,0.807-5.951,1.856h1.425V13.55c2.389,0,6.674,0.081,10.444,0.728";
ptr +="c0.069-0.132,0.114-0.268,0.114-0.408C36.041,12.668,33.34,11.694,30.009,11.694z'fill=#F29C1F /><path d='M6.042,14.088c0-2.224,3.376-4.025,7.542-4.025c3.825,0,6.976,1.519,7.468,3.488h1.488";
ptr +="c0.49-1.97,3.644-3.489,7.469-3.489c4.166,0,7.542,1.801,7.542,4.025c0,0.17-0.029,0.337-0.067,0.502";
ptr +="c1.08,0.247,2.088,0.549,2.945,0.926V3.481C40.429,1.559,38.871,0,36.948,0H6.49C4.568,0,3.009,1.559,3.009,3.481v12.054";
ptr +="c0.895-0.398,1.956-0.713,3.095-0.968C6.069,14.41,6.042,14.251,6.042,14.088z'fill=#F29C1F /></g></svg>";
ptr +="</div>";
ptr +="<div class='side-by-side text'>Bedroom</div>";
ptr +="<div class='side-by-side temperature'>";
ptr +=(int)tempSensor2;
ptr +="<span class='superscript'>°C</span></div>";
ptr +="</div>";
ptr +="<div class='data kitchen'>";
ptr +="<div class='side-by-side icon'>";
ptr +="<svg enable-background='new 0 0 48 31.5'height=31.5px id=Layer_1 version=1.1 viewBox='0 0 48 31.5'width=48px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><circle cx=24.916 cy=15.75 fill=#26B99A r=15.75 /><path d='M14.917,15.75c0-5.522,4.478-10,10-10c2.92,0,5.541,1.26,7.369,3.257l1.088-1.031";
ptr +="c-2.103-2.285-5.106-3.726-8.457-3.726c-6.351,0-11.5,5.149-11.5,11.5c0,3.127,1.252,5.958,3.277,8.031l1.088-1.031";
ptr +="C16.011,20.945,14.917,18.477,14.917,15.75z'fill=#FFFFFF /><path d='M45.766,2.906c-1.232,0-2.232,1-2.232,2.234v11.203c0,0,2.76,0,3,0v12H48v-12V2.906";
ptr +="C48,2.906,46.035,2.906,45.766,2.906z'fill=#26B99A /><path d='M6.005,2.917v5.184c0,0.975-0.638,1.792-1.516,2.083V2.917H3.021v7.267c-0.878-0.29-1.516-1.107-1.516-2.083";
ptr +="V2.917H0v5.458c0,1.802,1.306,3.291,3.021,3.592v16.376H4.49v-16.38c1.695-0.318,2.979-1.8,2.979-3.588V2.917H6.005z'fill=#26B99A /></svg>";
ptr +="</div>";
ptr +="<div class='side-by-side text'>Kitchen</div>";
ptr +="<div class='side-by-side temperature'>";
ptr +=(int)tempSensor3;
ptr +="<span class='superscript'>°C</span></div>";
ptr +="</div>";
ptr +="</div>";
ptr +="</body>";
ptr +="</html>";
return ptr;
}
اگر این تابع را با تابع قبلی مقایسه کنید متوجه میشوید که به جز تغییرات زیر، در سایر موارد مشابه هم هستند:
- ما برای صفحه وب خود از فونت سفارشی گوگل به نام Open Sans استفاده کردهایم. توجه کنید فونتهای گوگل به صورت آنلاین بارگذاری میشوند، پس بدون دسترسی به اینترنت با دستگاه خود نمیتوانید فونتهای گوگل را ببینید.
ptr +="<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400,600' rel='stylesheet'>";
- آیکونهایی که برای نمایش مقادیر دما استفاده شدهاند، در حقیقت بردارهای گرافیکی با قابلیت تغییر اندازه (Scalable Vector Graphics یا SVG) هستند که با تگ <svg> تعریف شدهاند. ساخت SVG به مهارت برنامهنویسی خاصی نیاز ندارد. شما میتوانید با استفاده از ابزار Google SVG Editor برای صفحه وب خود اشکال گرافیکی بسازید. ما از آیکونهای SVG زیر استفاده کردیم:
افزودن بهروزرسانی خودکار صفحه وب
یکی از بهبودهایی که میتوانیم در برنامه اعمال کنیم بهروزرسانی خودکار صفحه وب، به منظور بهروزرسانی مقادیر خوانده شده از سنسورهاست.
تنها با اضافهکردن یک تگ meta به فایل HTML، میتوانیم به مرورگر نشان دهیم صفحه را پس از مدتزمان معینی بهروزرسانی کند.
<meta http-equiv="refresh" content="2" >
این کد را در تگ <head> قرار دهید. تگ meta باعث میشود مرورگر هر دو ثانیه یکبار صفحه را بهروزرسانی کند.
بارگذاری داینامیک اطلاعات سنسور با AJAX
هنگامی که صفحه سنگینی داشته باشید، بهروزرسانی آن به درستی انجام نخواهد شد. یک روش بهتر، استفاده از “جاوا اسکریپت و Xml آسنکرون” (Asynchronous Javascript And Xml یا AJAX) است. در این روش میتوانیم به صورت آسنکرون (در پس زمینه) و بدون نیاز به بهروزرسانی، اطلاعات را از سرور درخواست کنیم.
معمولاً برای اجرای AJAX روی صفحات وب با جاوا اسکریپت، از شیء XMLHttpRequest استفاده میشود. این شئ به سرور درخواست GET میدهد و بخشی از صفحه وب را بهروز میکند. AJAX یک فناوری جدید یا یک زبان متفاوت نیست؛ بلکه فقط استفادهای جدید از فناوریهای موجود است. جدا از این، AJAX قابلیتهای زیر را به ما میدهد:
- درخواست اطلاعات از سرور پس از بارگذاری صفحه وب
- دریافت اطلاعات از سرور پس از بارگذاری صفحه وب
- ارسال اطلاعات به سرور در پسزمینه
در ادامه اسکریپت 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";
اسکریپت با تگ <script> آغاز میشود. با توجه به اینکه اسکریپت AJAX از جنس جاوا اسکریپت است، باید آن را در تگ <script> بنویسیم و برای اینکه این تابع مرتب فراخوانی شود از تابع جاوا اسکریپت setInterval() استفاده میکنیم. این تابع دو پارامتر به عنوان ورودی میگیرد. اولین پارامتر تابعی برای اجرا است و دومین پارامتر فاصله زمانی بین اجرای دوباره تابع (برحسب میلیثانیه) میباشد.
ptr +="<script>\n";
ptr +="setInterval(loadDoc,1000);\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 و status به ترتیب برابر 4 و 200 باشد، یعنی پاسخ آماده است. اکنون محتوای بدنهی صفحه که مقادیر دمای خوانده شده را دربردارد بهروز میشود.
ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.body.innerHTML =this.responseText}\n";
ptr +="};\n";
سپس درخواست HTTP با توابع ()open و ()send آماده و ارسال میگردد.
ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";
امیدواریم از این آموزش لذت برده باشید، اگر چگونگی نمایش مقادیر چند سنسور DS18B20 بر روی وب سرور ESP8266 NodeMCU برای شما مفید بوده و به حوزه اینترنت اشیا علاقهمند هستید پیشنهاد میکنیم مقالات قبلی وبلاگ مارا مطالعه کنید و در ادامه همراه ما باشید. مثل همیشه نظرات و پیشنهادات خود را با ما در میان بگذارید.