با ساخت ایستگاه هواشناسی با ESP8266 و BME280 دیگر به برنامههای آب و هوای گوشیهای هوشمند یا ایستگاههای تجاری گزارش آب و هوا (که اطلاعات آنها بر اساس ایستگاههایی است که ممکن است کیلومترها دورتر از شما باشد) نیاز نخواهید داشت و بهوسیله این پروژه اینترنت اشیا میتوانید با اطمینان بیشتری برنامههای بیرون از خانه را تدارک ببینید.
این پروژه از ESP8266 NodeMCU به عنوان یک دستگاه کنترل کننده استفاده میکند که به سادگی به یکی از شبکههای وایفای موجود متصل میشود. این کنترل کننده وب سروری میسازد تا هر یک از دستگاههای متصل به شبکه با دسترسی به این وب سرور بتوانند پارامترهای دما، رطوبت، فشار هوا و ارتفاع از سطح دریا را از سنسور BME280 خوانده و با یک رابط کاربری زیبا، به مرورگر وب ارسال میکند. هیجانانگیز است نه؟ پس بیایید شروع کنیم!
سنسور دما، رطوبت و فشار BME280
برای ساخت ایستگاه هواشناسی با ESP8266 در ابتدا نیاز است نگاهی به ماژول BME280 بیندازیم.
ماژول سنسور BME280 توسط شرکت Bosch ساخته شده و به عنوان نسل جدیدی از سنسورهای دما، رطوبت و فشار شناخته میشود. این سنسور جایگزین بهبودیافته سنسورهایی مانند BMP180، BMP085 و BMP183 است.
ولتاژ کاری ماژول BME280، از 3.3 تا 5 ولت است که برای کار با میکروکنترلرهایی مانند ESP8266 ایدهآل است.
ارتباط با این ماژول با پروتکل ساده دو سیمه I2C انجام میگیرد. آدرس I2C ماژول BME280 به صورت پیشفرض برابر 0x76 است که البته این آدرس قابل تغییر است.
نحوه اتصال سنسور BME280 به ماژول ESP8266 NodeMCU
اتصالات نسبتاً ساده هستند. ابتدا پین VIN را به خروجی 3.3 ولت برد ESP8266 NodeMCU، و GND را به زمین متصل کنید.
سپس پین SCL را به پین کلاک I2C برد ESP8266 یعنی D1 متصل کنید و در نهایت، پین SDA را به پین داده I2C یعنی D2 وصل کنید.
شکل زیر نحوه اتصالات ماژول BME280 برای ساخت ایستگاه هواشناسی با ESP8266 را نشان میدهد:
آمادهسازی IDE آردوینو
یک افزونه برای آردوینو وجود دارد که به شما اجازه میدهد با استفاده از IDE آردوینو، ESP8266 NodeMCU را پروگرم کنید. اگر تا به حال با ESP8266 کار نکردهاید، آموزش زیر را دنبال کنید:
نصب کتابخانه برای ارتباط با BME280
برقراری ارتباط با BME280 ساده نیست و نیاز به کار دارد. اما خوشبختانه با استفاده از کتابخانه Adafruit BME280، میتوانیم بدون درگیری با پیچیدگیهای آن و با کمک دستورات سادهای میتوانیم دما، رطوبت و فشار بارومتریک را بخوانیم.
برای نصب کتابخانه به مسیر Arduino IDE > Sketch > Include Library > Manage Libraries بروید. صبر کنید تا Library Manager لیست کتابخانهها را دانلود کرده و لیست کتابخانههای نصب شده را آپدیت کند.
سپس جستجوی خود را با نوشتن عبارت ‘bme280’ فیلتر کنید. از بین چند گزینهای که میبینید، Adafruit BME280 Library از Adafruit را پیدا کرده و آن را نصب کنید.
کتابخانه سنسور BME280 از کتابخانه Adafruit Unified Sensor استفاده میکند. پس این کتابخانه را نیز جستجو و نصب کنید.
نمایش دما، رطوبت، فشار و ارتفاع از سطح دریا بر روی وب سرور ESP8266
در این مرحله میخواهیم ESP8266 خود را در مد ایستگاه (STA) تنظیم کنیم و یک وب سرور بسازیم. این وب سرور قرار است صفحات وب را به هر سرویسگیرندهای که به شبکهی موجود متصل است، تحویل دهد.
اگر میخواهید در مورد ساخت وب سرور با ESP8266 NodeMCU در مدهای AP و STA بیشتر بدانید، آموزش زیر را دنبال کنید:
برای کارکرد درست برنامه، قبل از اینکه برنامه را آپلود کنید ابتدا باید تغییری در آن اعمال کنید. در واقع آنچه باید انجام دهید این است که دو متغیر زیر را برحسب مشخصات شبکه خود تغییر دهید. با این کار ESP8266 میتواند به شبکه موجود متصل شود.
const char* ssid = "YourNetworkName"; // Enter SSID here
const char* password = "YourPassword"; //Enter Password here
پس از انجام تغییرات، برنامه زیر را امتحان کنید:
#include <ESP8266WebServer.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme;
float temperature, humidity, pressure, altitude;
/*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);
bme.begin(0x76);
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();
دسترسی به وب سرور
پس از آپلود برنامه، سریال مانیتور را باز و بادریت را بر روی 115200 تنظیم کنید. سپس دکمه RST روی NodeMCU را فشار دهید. اگر همه چیز درست باشد، پیغام HTTP server started به همراه یک آدرس IP داینامیک نمایش داده میشود. این همان آدرسی است که از روتر شما گرفته شدهاست.
حال یک مرورگر باز کنید و آدرس آیپی که از سریال مانیتور دریافت کردید را در آن وارد نمایید. ESP8266 باید صفحه وبی را تحویل دهد که مقادیر دما، رطوبت، فشار و ارتفاع از سطح دریا که توسط BME280 اندازهگیری شده را نشان میدهد.
توضیح جزئیات کد
برنامه با اضافه کردن توابع زیر شروع میشود:
- ESP8266WebServer.h: این کتابخانه توابع مربوط به وایفای ESP8266 را ارائه میکند که برای اتصال به شبکه آنها را فراخوانی میکنیم. این کتابخانه همچنین شامل توابعی است که به ما در ساخت یک وب سرور و مدیریت درخواستهای HTTP دریافتی، بدون نگرانی در مورد برنامهنویسی سطح پایین کمک میکند.
- Wire.h: این کتابخانه با هر دستگاهی که از پروتکل I2C پشتیبانی کند مانند BME280 ارتباط برقرار میکند.
- Adafruit_BME280.h و Adafruit_Sensor.h: این کتابخانههای سختافزاری، مدیریت توابع سطح پایین را برعهده دارند.
#include <ESP8266WebServer.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
سپس متغیرهایی برای ذخیره دما، رطوبت، فشار و ارتفاع و همچنین یک شی از سنسور ایجاد میکنیم.
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme;
float temperature, humidity, pressure, altitude;
سپس متغیرهایی برای ذخیره دما، رطوبت، فشار و ارتفاع و همچنین یک شی از سنسور ایجاد میکنیم.
در این پروژه 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
درون تابع setup، قبل از اجرای سرور HTTP ابتدا آن را کانفیگ میکنیم.
ابتدا، ارتباط سریال با کامپیوتر و نیز شی BME را با استفاده از تابع ()begin راهاندازی میکنیم. این تابع رابط I2C را با آدرس داده شده (0x76) فعال کرده و بررسی میکند که ID تراشه صحیح باشد. در ادامه، تراشه را به صورت نرمافزاری ریست میکند و منتظر میماند تا سنسور خود را کالیبره کند.
Serial.begin(115200);
delay(100);
bme.begin(0x76);
حال باید با تابع ()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 به شبکه متصل شد، برنامه آدرس آیپی اختصاص داده شده به ESP8266 را روی سریال مانیتور چاپ میکند. این کار با تابع ()WiFi.localIP انجام میشود.
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
برای رسیدگی به درخواستهای HTTP دریافتی، از تابع on استفاده میکنیم تا مشخص کنیم هنگام رخ دادن هر URL، چه برنامهای اجرا شود. این تابع دو آرگومان دریافت میکند. اولین آرگومان مسیر URL است و آرگومان دوم نام تابعی است که باید هنگام رخدادن آن URL، اجرا شود.
برای مثال، در خط اول کد زیر وقتی سرور یک درخواست HTTP روی مسیر ریشه (/) دریافت میکند، تابع ()handle_OnConnect اجرا میشود. توجه کنید که URL مشخص شده، یک مسیر نسبی (Relative Path) است.
erver.on("/", handle_OnConnect);
در صورتی که سرویسگیرنده آدرسی را درخواست بدهد که با تابع ()server.on مشخص نشده، سرور باید با وضعیتHTTP 404 (Not Found) پاسخ دهد و یک پیام مناسب به کاربر نمایش دهد. این موارد را هم در یک تابع تحت عنوان server.onNotFound(handle_NotFound)، قرار میدهیم تا در صورت دریافت یک آدرس شناخته نشده، تابع onNotFound اجرا شود.
server.onNotFound(handle_NotFound);
اکنون برای شروع به کار سرور، تابع begin را روی شیء server فراخوانی میکنیم.
server.begin();
Serial.println("HTTP server started");
تابع ()Loop
برای پاسخگویی به درخواستهای HTTP دریافتی، تابع ()handleClient را روی شیء server فراخوانی میکنیم.
server.handleClient();
سپس، باید تابعی را که با دستور server.on به URL ریشه (/) متصل کردیم، بسازیم. اگر یادتان باشد در ابتدای این تابع مقادیر دما، رطوبت، فشار و ارتفاع از سطح دریا را از سنسور دریافت میکنیم. سپس برای پاسخگویی به درخواست HTTP، از تابع send استفاده میکنیم. با اینکه این تابع میتواند با ترکیب پارامترهای دیگری هم فراخوانی شود، سادهترین فرم فراخوانی آن شامل کد پاسخ به HTTP، نوع محتوا و خود محتوای صفحه است. در اینجا، ما کد 200 (یکی از کدهای وضعیت HTTP) را ارسال میکنیم که به معنای OK است. نوع محتوا را بهعنوان “text/html” مشخص میکنیم و در نهایت تابع ()SendHTML را فراخوانی میکنیم. این تابع یک صفحه HTML داینامیک تولید میکند که شامل مقادیر خوانده شده از سنسور است.
void handle_OnConnect() {
temperature = bme.readTemperature();
humidity = bme.readHumidity();
pressure = bme.readPressure() / 100.0F;
altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
server.send(200, "text/html", SendHTML(temperature,humidity,pressure,altitude));
}
به همین شکل تابعی برای مدیریت صفحه خطا 404 میسازیم:
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
نمایش صفحه وب HTML
تابع ()SendHTML برای ساخت یک صفحه وب مورد استفاده قرار میگیرد. بدین منظور، ابتدا باید وب سرور ESP8266 درخواست ساخت یک صفحه وب را از سرویسگیرنده دریافت کند. این تابع ذخیره کد HTML در یک رشته (string) بزرگ و برگرداندن آن به تابع ()server.send را برعهده دارد. در مورد تابع ()server.send نیز قبلاً توضیح دادیم. این تابع پارامترهای دما، رطوبت، فشار و ارتفاع را میگیرد و به طور داینامیک محتوای صفحه HTML را تولید میکند.
اولین متنی که همیشه باید ارسال کنیم اعلان <!DOCTYPE> است. این اعلان مشخص میکند که در حال ارسال کد HTML هستیم.
String SendHTML(float temperature,float humidity,float pressure,float altitude){
String ptr = "<!DOCTYPE html> <html>\n";
سپس، المان meta>viewport> قرار گرفته است که باعث واکنشگرایی صفحه وب روی همه مرورگرها میشود. تگ title هم عنوان صفحه را مشخص میکند.
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP8266 Weather Station</title>\n";
طراحی صفحه وب
در ادامه، با استفاده از چند خط کد CSS، ظاهر صفحه وب را طراحی میکنیم. ما فونت Helvetica را انتخاب کردیم، نمایش محتویات صفحه را بهصورت inline-block تعریف و محل قرارگیری آن را در وسط صفحه قرار دادهایم.
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
کد زیر رنگ، فونت و حاشیه دور بدنه و تگهای H1 و 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 Station</h1>\n";
نمایش مقادیر خوانده شده روی صفحه وب
برای نمایش دما، رطوبت، فشار و ارتفاع خوانده شده از سنسور، این مقادیر را در تگ پاراگراف (<p>) قرار میدهیم. برای نمایش نماد درجه نیز از ° استفاده میکنیم.
ptr +="<p>Temperature: ";
ptr +=temperature;
ptr +="°C</p>";
ptr +="<p>Humidity: ";
ptr +=humidity;
ptr +="%</p>";
ptr +="<p>Pressure: ";
ptr +=pressure;
ptr +="hPa</p>";
ptr +="<p>Altitude: ";
ptr +=altitude;
ptr +="m</p>";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
طراحی حرفهایتر صفحه وب
در ادامهی ساخت ایستگاه هواشناسی با ESP8266 قصد داریم صفحه وب هواشناسی خود را زیباتر کنیم.
در صورتی که فکر میکنید طراحی صفحه وب کار دشواری است، با ما همراه باشید تا به روشی ساده این کار را انجام دهیم! عکس زیر ایده کلی کاری که میخواهیم انجام دهیم را به شما نشان میدهد:
پس بدون اتلاف وقت، کد زیر را کپی کرده و در برنامه بالا جایگزین تابع ()SendHTML کنید. با این کار صفحه وب جذابتر و حرفهایتری خواهید داشت.
String SendHTML(float temperature,float humidity,float pressure,float altitude){
String ptr = "<!DOCTYPE html>";
ptr +="<html>";
ptr +="<head>";
ptr +="<title>ESP8266 Weather Station</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: 0px;} ";
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 +=".reading{font-weight: 300;font-size: 50px;padding-right: 25px;}";
ptr +=".temperature .reading{color: #F29C1F;}";
ptr +=".humidity .reading{color: #3B97D3;}";
ptr +=".pressure .reading{color: #26B99A;}";
ptr +=".altitude .reading{color: #955BA5;}";
ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;top: 10px;}";
ptr +=".data{padding: 10px;}";
ptr +=".container{display: table;margin: 0 auto;}";
ptr +=".icon{width:65px}";
ptr +="</style>";
ptr +="</head>";
ptr +="<body>";
ptr +="<h1>ESP8266 Weather Station</h1>";
ptr +="<div class='container'>";
ptr +="<div class='data temperature'>";
ptr +="<div class='side-by-side icon'>";
ptr +="<svg enable-background='new 0 0 19.438 54.003'height=54.003px id=Layer_1 version=1.1 viewBox='0 0 19.438 54.003'width=19.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='M11.976,8.82v-2h4.084V6.063C16.06,2.715,13.345,0,9.996,0H9.313C5.965,0,3.252,2.715,3.252,6.063v30.982";
ptr +="C1.261,38.825,0,41.403,0,44.286c0,5.367,4.351,9.718,9.719,9.718c5.368,0,9.719-4.351,9.719-9.718";
ptr +="c0-2.943-1.312-5.574-3.378-7.355V18.436h-3.914v-2h3.914v-2.808h-4.084v-2h4.084V8.82H11.976z M15.302,44.833";
ptr +="c0,3.083-2.5,5.583-5.583,5.583s-5.583-2.5-5.583-5.583c0-2.279,1.368-4.236,3.326-5.104V24.257C7.462,23.01,8.472,22,9.719,22";
ptr +="s2.257,1.01,2.257,2.257V39.73C13.934,40.597,15.302,42.554,15.302,44.833z'fill=#F29C21 /></g></svg>";
ptr +="</div>";
ptr +="<div class='side-by-side text'>Temperature</div>";
ptr +="<div class='side-by-side reading'>";
ptr +=(int)temperature;
ptr +="<span class='superscript'>°C</span></div>";
ptr +="</div>";
ptr +="<div class='data humidity'>";
ptr +="<div class='side-by-side icon'>";
ptr +="<svg enable-background='new 0 0 29.235 40.64'height=40.64px id=Layer_1 version=1.1 viewBox='0 0 29.235 40.64'width=29.235px x=0px xml:space=preserve xmlns=http://www.w3.org/2000/svg xmlns:xlink=http://www.w3.org/1999/xlink y=0px><path d='M14.618,0C14.618,0,0,17.95,0,26.022C0,34.096,6.544,40.64,14.618,40.64s14.617-6.544,14.617-14.617";
ptr +="C29.235,17.95,14.618,0,14.618,0z M13.667,37.135c-5.604,0-10.162-4.56-10.162-10.162c0-0.787,0.638-1.426,1.426-1.426";
ptr +="c0.787,0,1.425,0.639,1.425,1.426c0,4.031,3.28,7.312,7.311,7.312c0.787,0,1.425,0.638,1.425,1.425";
ptr +="C15.093,36.497,14.455,37.135,13.667,37.135z'fill=#3C97D3 /></svg>";
ptr +="</div>";
ptr +="<div class='side-by-side text'>Humidity</div>";
ptr +="<div class='side-by-side reading'>";
ptr +=(int)humidity;
ptr +="<span class='superscript'>%</span></div>";
ptr +="</div>";
ptr +="<div class='data pressure'>";
ptr +="<div class='side-by-side icon'>";
ptr +="<svg enable-background='new 0 0 40.542 40.541'height=40.541px id=Layer_1 version=1.1 viewBox='0 0 40.542 40.541'width=40.542px 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='M34.313,20.271c0-0.552,0.447-1,1-1h5.178c-0.236-4.841-2.163-9.228-5.214-12.593l-3.425,3.424";
ptr +="c-0.195,0.195-0.451,0.293-0.707,0.293s-0.512-0.098-0.707-0.293c-0.391-0.391-0.391-1.023,0-1.414l3.425-3.424";
ptr +="c-3.375-3.059-7.776-4.987-12.634-5.215c0.015,0.067,0.041,0.13,0.041,0.202v4.687c0,0.552-0.447,1-1,1s-1-0.448-1-1V0.25";
ptr +="c0-0.071,0.026-0.134,0.041-0.202C14.39,0.279,9.936,2.256,6.544,5.385l3.576,3.577c0.391,0.391,0.391,1.024,0,1.414";
ptr +="c-0.195,0.195-0.451,0.293-0.707,0.293s-0.512-0.098-0.707-0.293L5.142,6.812c-2.98,3.348-4.858,7.682-5.092,12.459h4.804";
ptr +="c0.552,0,1,0.448,1,1s-0.448,1-1,1H0.05c0.525,10.728,9.362,19.271,20.22,19.271c10.857,0,19.696-8.543,20.22-19.271h-5.178";
ptr +="C34.76,21.271,34.313,20.823,34.313,20.271z M23.084,22.037c-0.559,1.561-2.274,2.372-3.833,1.814";
ptr +="c-1.561-0.557-2.373-2.272-1.815-3.833c0.372-1.041,1.263-1.737,2.277-1.928L25.2,7.202L22.497,19.05";
ptr +="C23.196,19.843,23.464,20.973,23.084,22.037z'fill=#26B999 /></g></svg>";
ptr +="</div>";
ptr +="<div class='side-by-side text'>Pressure</div>";
ptr +="<div class='side-by-side reading'>";
ptr +=(int)pressure;
ptr +="<span class='superscript'>hPa</span></div>";
ptr +="</div>";
ptr +="<div class='data altitude'>";
ptr +="<div class='side-by-side icon'>";
ptr +="<svg enable-background='new 0 0 58.422 40.639'height=40.639px id=Layer_1 version=1.1 viewBox='0 0 58.422 40.639'width=58.422px 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='M58.203,37.754l0.007-0.004L42.09,9.935l-0.001,0.001c-0.356-0.543-0.969-0.902-1.667-0.902";
ptr +="c-0.655,0-1.231,0.32-1.595,0.808l-0.011-0.007l-0.039,0.067c-0.021,0.03-0.035,0.063-0.054,0.094L22.78,37.692l0.008,0.004";
ptr +="c-0.149,0.28-0.242,0.594-0.242,0.934c0,1.102,0.894,1.995,1.994,1.995v0.015h31.888c1.101,0,1.994-0.893,1.994-1.994";
ptr +="C58.422,38.323,58.339,38.024,58.203,37.754z'fill=#955BA5 /><path d='M19.704,38.674l-0.013-0.004l13.544-23.522L25.13,1.156l-0.002,0.001C24.671,0.459,23.885,0,22.985,0";
ptr +="c-0.84,0-1.582,0.41-2.051,1.038l-0.016-0.01L20.87,1.114c-0.025,0.039-0.046,0.082-0.068,0.124L0.299,36.851l0.013,0.004";
ptr +="C0.117,37.215,0,37.62,0,38.059c0,1.412,1.147,2.565,2.565,2.565v0.015h16.989c-0.091-0.256-0.149-0.526-0.149-0.813";
ptr +="C19.405,39.407,19.518,39.019,19.704,38.674z'fill=#955BA5 /></g></svg>";
ptr +="</div>";
ptr +="<div class='side-by-side text'>Altitude</div>";
ptr +="<div class='side-by-side reading'>";
ptr +=(int)altitude;
ptr +="<span class='superscript'>m</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 برای صفحه وب خود اشکال گرافیکی بسازید. ما برای ساخت ایستگاه هواشناسی با ESP8266 از آیکنهای SVG زیر استفاده کردیم:
بهبود کد با اضافه کردن بهروزرسانی خودکار صفحه
یکی از بهبودهایی که میتوانیم در برنامه خود اعمال کنیم، بهروزرسانی خودکار صفحه بهمنظور بهروزرسانی مقادیر خوانده شده از سنسورها است.
تنها با اضافهکردن یک تگ meta به فایل HTML، میتوانیم به مرورگر نشان دهیم صفحه را پس از مدتزمان معینی بهروزرسانی کند.
<meta http-equiv="refresh" content="2" >
این کد را در تگ <head> برنامه خود قرار دهید، این متا تگ باعث میشود مرورگر هر دو ثانیه یکبار صفحه را بهروزرسانی کند.
بارگذاری داینامیک اطلاعات سنسور با استفاده از 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";
با ساخت ایستگاه هواشناسی با ESP8266 و ماژول BME280 به راحتی میتوانید تمام پارامترهای مورد نیاز در هواشناسی را کنترل کنید، و با این پروژه به دنیای بزرگ اینترنت اشیا پا بگذارید. پس اگر شماهم به اینترنت اشیا علاقه دارید ازاین پروژه کاربردی در خانه، باغچه یا گلخانه خودتان استفاده کنید.
برای آموزش ساخت پروژههای متنوع اینترنت اشیا، میتوانید مقالات آکادمی روبوایکیو را مطالعه کنید.
ما مشتاقانه پذیرای هرگونه سوال و نظرات شما هستیم، پس آنهارا در بخش دیدگاه با ما درمیان بگذارید.
۶ دیدگاه. Leave new
سلام مطلب بسیار کاملی بود تشکر و خسته نباشید
سلام و درود،
خیلی ممنون از شما
خیلی مفید بود , خسته نباشید
سلام و درود،
ممنون از شما
سلام ممنون بابت پروژه اموزشی زیباتون
سوال داشتم و این که این پروژه رو به اینترنت موبایل متصل میکنم ip میگیرم اما سرچ میکنم چیزی پیدا نمیشه
ولی با مودم خانگی وصل میشم ip میگیرم از دستگاه مشکلی ندارم.
ممنون میشم راهنماییم کنید.
درود برشما سینای عزیز
سپاسگذاریم بابت همراهی بینظیرت
پیشنهاد میکنیم تنظیمات هات اسپات موبایلت رو بررسی کنی. معمولاً این مشکلات به خاطر پروکسی به وجود میاد.