دانشجوی مهندسی برق و علاقه مند به رباتیک و اینترنت اشیاء
وب سرور پیشرفته با ESP8266
سلام
قسمت نهم
در قسمت هشتم با کتابخانه ESP Async WebServer یک صفحه وب طراحی کردیم که به کمک آن یک LED را می توان کنترل کرد. در این قسمت برای این صفحه وب Username و Password خواهیم گذاشت و طریقه سرو (Serve) کردن فایل های وب از حافظه جانبی را بررسی میکنیم + یکم HTML
Authentication
برای محدود کردن دسترسی به پنل (همون صفحه وب خودمون) می توانیم از نام کاربری و پسورد استفاده کنیم.
در این قسمت روش ساده و خیلی کاربر نپسند(!) اون رو پیاده میکنیم و در قسمت های آینده روش های بهتر و گرافیکی تر را دنبال می کنیم.
لازمه این بخش Redirect ها هستن پس اگر با اون ها آشنایی ندارید توصیه می کنیم از اینجا مطالعه کنید.
ابتدا یک صفحه را جهت لاگین در نظر می گیریم. مثلا login/
server.on("/login", HTTP_GET, [](AsyncWebServerRequest *request){
if(!request->authenticate("user", "pass"))
return request->requestAuthentication();
request->send(200, "text/plain", "Login Success!");
});
در خط دوم این دستورات handle کردن این پیج، چک میکنیم آیا کاربر با یورزنیم user و پسورد pass لاگین کرده یا نه! اگر لاگین نکرده بود که تابع ()requestAuthentication را برمیگردانیم تا لاگین کند و اگر لاگین کرده بود مثلا پیغامی مبنی بر لاگین موفق ارسال می کنیم.
پس از وارد کردن یورزنیم و پسورد و کلیک بر روی Sign in درصورتی که یورزنیم و پسورد صحیح باشند متن Login Success! نمایش داده می شود.
برای صفحه اصلی نیز چنین Authentication در نظر میگیریم.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
if(!request->authenticate("user", "pass"))
request->redirect("/login");
String index = "<html><head><title>My Async WebServer</title></head>"
index += "<body><center>Hello, World</center></br>"
index += "<center>" + getLedStatus() + "<center></br>"
index += "<button><a href=\"/on\">ON</a></button>"
index += "<button><a href=\"/off\">OFF</a></button>"
index += "</body></html>"
request->send(200, "text/html", index);
});
فقط ابتدا فراخوانی این صفحه چک میکنیم که آیا Authentication موفقیت آمیز بوده یا خیر و اگر ناموق بوده به صفحه login ریدایرکت می کنیم.
برای بهتر شدن کار در صفحه لاگین پس از لاگین موفق با استفاده از کد زیر به صفحه اول ریدایرکت می کنیم.
request->redirect("/");
اکنون فقط کاربرانی که لاگین کرده اند میتوانند به صفحه اصلی دسترسی پیدا کنند ولی همچنان صفحات on و off باز هستند و با لود کردن آنها توابع خاموش و روشن شدن led اجرا می شوند. پس همین کار را نیز برای سایر صفحات انجام می دهیم.
چرا یک بار ریدایرکت میکنیم به login و سپس بر میگردیم؟ به دو دلیل: 1) اگر بعدا تغییر در صفحه لاگین دادیم روی تمام لاگین ها اعلام شود. 2) اصولی تره!
کد های این قسمت را میتوانید از اینجا دریافت کنید. فایل های مربوط به Auth در فولدر SimpleAuth_ESP8266 قابل دانلود هستند.
سرو کردن فایل ها از روی حافظه فلش
هدف: فایل های html , ... را به جای اینکه در کد بنویسیم در جای دیگری ذخیره کنیم و زمانی که کاربر به آن ها نیاز داشت، فراخوانی کنیم.
مقدمات LittleFS
لیتل اف اس یک فایل سیستم سبک مخصوص میکروکنترلر هایی است که یک حافظه فلش به صورت SPI به آنها متصل است که ESP از این نوع هست. خیلی وارد تئوریجات نشیم!
در اصل ما فایل های html, css, js و... حتی عکس و فیلم و... رو توسط LittleFS روی حافظه فلش ذخیره می کنیم و زمانی که لازم شد آن ها رو از این حافظه بارگزاری می کنیم.
در کنار LittleFS موارد دیگری مانند SPIFFS هم هستند (آخرین باری که آردوینو رو آپدیت کردم با SPIFFS مشکل پیدا کرد و من هم رفتم سراغ LittleFS ولی عموما مشکلی نداره)
در ابتدا لازم هست به آردوینو بگیم که فضایی که برای این کار میخواهیم چقدر باشه! از مسیر Tools --> Flash Size گزینه مورد نظر رو انتخاب میکنیم.
موارد قابل انتخاب بسته به بورد مورد استفاده ممکنه متفاوت باشه. من در اینجا 4MB حافظه فلش دارم که 2 مگابایت اون رو برای فایل سیستم در نظر می گیرم و تقریبا 1 مگ هم برای OTA (به زودی باش آشنا میشیم خیلی خفنه!) و حدود 1 مگ باقی میمونه که میشه حافظه فلش خودمون که کد ها رو نگه میداره.
بریم سراغ کد ^_^
اول دو کتابخونه زیر رو باید import کنیم
#include <FS.h>
#include <LittleFS.h>
در setup باید littleFS را فعال کنیم و مطمئن میشیم که فعال میشه!
if (!LittleFS.begin()) {
Serial.println("LittleFS mount failed");
return;
}
برای تست عملکرد صحیح ابتدا یک فایل در LittleFS مینویسیم و سپس میخوانیم و در سریال مانیتور چاپ میکنیم. پس توابع خواند و نوشتن به شرح زیر هستند:
void readFile(const char * path) {
File file = LittleFS.open(path, "r");
if (!file) {
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while (file.available()) {
Serial.write(file.read());
}
file.close();
}
تابع readFile یک مسیر دریافت می کند و در صورت وجود فایل آن را خوانده و در سریال چاپ می کند.
void writeFile(const char * path, const char * message) {
File file = LittleFS.open(path, "w");
if (!file) {
Serial.println("Failed to open file for writing");
return;
}
if (file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
تابع writeFile یک مسیر و عبارت دریافت می کند و در فایل می نویسد.
در این توابع مسیر شامل اسم فایل هم هستند مثلا برای ایجاد یک فایل متنی با اسم text مسیر به صورت زیر است:
"/text.txt"
در setup این دو تابع را فراخوانی میکنیم و ازصحت عملکرد LittleFS مطمئن می شویم.
writeFile("/text.txt", "This is a test file");
readFile("/text.txt");
و نتیجه کار، LittleFS به خوبی کار می کند.
راستی با دستور ()LittleFS.format می تونید فایل سیستم رو فرمت کنید. (چه کول!)
کد های این قسمت را میتوانید از اینجا دریافت کنید. فایل های مربوط به مقدمات در فولدر LittleFS_ESP8266 موجود می باشند.
آپلود فایل روی LittleFS
برای آپلود فایل روی فایل سیستم ESP باید پلاگین زیر رو دانلود و نصب کنید
ESP8266 LittleFS Plugin For Arduino IDE
بعد از دانلود فایل zip کافیه محتوایاتش رو در پوشه tools آدوینو کپی کنید. (این پوشه رو عموما در documents فولدر arduino می تونید پیدا کنید.) در نهایت باید چنین چیزی داشته باشید.
<home_dir>/Arduino/tools/ESP8266LittleFS/tool/esp8266littlefs.jar
یک بار اردوینو رو ببندید و بعد از باز کردن همانند تصویر زیر پلاگین به آردوینو اضافه می شود.
برای استفاده از این قابلیت لازمه در کنار فایل آردوینو یک فولدر به اسم data داشته باشید و فایل هایی که قراره آپلود بشن رو در این فولدر قرار بدین.
حتما باید سریال مانیتور بسته باشه و ESP در مود پروگرم باشه تا فرایند انجام بشه.
هنوز HTML یادتونه؟ پس بریم همون صفحه اصلی رو در یک فایل HTML بنویسیم.
<html>
<head>
<title>My Async WebServer</title>
</head>
<body>
<center>
ESP8266 Control Panel</br>
<button><a href="/on">ON</a></button>
<button><a href="/off">OFF</a></button>
</center>
</body>
</html>
این متن رو در یک فایل به اسم index.html ذخیره میکنیم. (در اینجا نمی تونیم وضعیت LED رو داشته باشیم چون String هر دفعه که صفحه لود میشه ساخته نمیشه که بتونیم محتواش رو تغییر بدیم فقط فایل از حافظه اصطلاحا سرو میشه! البته واسه اینم راهکارهای خوبی داریم که در قسمت Ajax, js آشنا میشیم.)
و اصل ماجرا! چطوری بگیم این فایل هارو سرو کن؟
کافیه توابع handle کردن صفحات رو به صورت زیر تغییر دهیم:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
if(!request->authenticate("user", "pass"))
request->redirect("/login");
request->send(LittleFS, "index.html", "text/html");
});
به جای ارسال متن در تابع send می گوییم از LittleFS (آرگومان اول) فایل index.html (آرگومان دوم) را که فرمت text/html دارد (آرگومان سوم) ارسال کن.
حالا کافیه کد را مثل همیشه آپلود کنید و از طریق منو tools--> ESP8266 LittleFS Data Upload فایل های موجود در فولدر data را نیز آپلود کنید (بستن سریال مانیتور حین آپلود فراموش نشه!)
یکم فراتر بریم و یک عکس به نام img.png هم در فولدر Data قرار میدیم.
برای ارسال عکس میتونیم از کد زیر استفاده کنیم
server.on("/img", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "img.png", "image/png", true);
});
این تابع در صورت درخواست آدرس img/ تصویر را ارسال می کند. و همانند قبل آرگومان اول محل ذخیره عکس، ارگومان دوم اسم فایل، ارگومان سوم نوع فایل که در اینجا عکس ما image/png است و آرگومان چهارم مشخص می کند که این عکس باید دانلود شود یا نه. اگر true باشد پس در درخواست عکس شروع به دانلود شدن می کند و اگر false باشد عکس در همان مرورگر نمایش داده می شود.
از سرو کردن اصولی لذت ببرید ^_^
کد های این قسمت را میتوانید از اینجا دریافت کنید. فایل های مربوط در فولدر Advanced_SimpleAuth_ESP8266 موجود هستند.
ممنون که تا انتها با ما همراه بودین.
در قسمت دهم از آموزش سعی میکنیم صفحه گرافیکی تری طراحی کنیم و همچنین اتفاقات را در یک فایل log ذخیره کنیم و جهت دانلود روی سرور قرار دهیم.
مطلبی دیگر از این انتشارات
بهانه ای برای ورود به دنیای امبدد سیستم ها
مطلبی دیگر از این انتشارات
پرواز اصلی کوادروتور -2-
مطلبی دیگر از این انتشارات
آردوینو(Arduino) ؛ آچار فرانسه رباتیک!!