https://blog.csdn.net/solar_Lan/article/details/74231360
用到的網頁文件:鏈接:https://pan.baidu.com/s/1vk6xmsYZuJe8CMFzJNKdJw 密碼:oiz2
注:對於ESP8266開源技術感興趣的可以加群,我們一起探索交流學習,群號:579932824。群名:ESP8266開源技術交流群。
在第一篇教程中,由ESP8266返回的網頁都是通過直接發送String來完成響應,這個方法是挺快的,但是在復雜結構的網頁下就顯得格外麻煩,調整的時候需要一個個找,而且還是在html結構打亂的情況下找,把css和js寫入到同一個頁面內無疑也是增加了調試的成本,
所以官方引入了一個SPIFFS的文件系統(SPIFFS的github地址:https://github.com/pellepl/spiffs),
這個文件系統是通過共用板載的Flash芯片來完成
(官方說明文檔:https://github.com/esp8266/Arduino/blob/master/doc/filesystem.md),
之前在配置環境的時候相比應該還記得有個選擇Flash Size的選項吧,這個就是分配程序和SPIFFS空間的選項。一般市面上的12E型都已經搭載了4M的Flash,所以大家在選擇的時候就選擇使用4M的,剩下是1M還是3M的SPIFFS就看實際需要,一般推薦使用1M,因為燒寫SPIFFS的時候不像燒寫程序那樣只是根據程序大小燒寫部分區塊,而是整個區塊完整燒寫的,3M燒寫一次的時間差不多有4-5分鍾,燒寫1M的則會很快。
這次教程的代碼:
#include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <FS.h> ESP8266WebServer server ( 80 ); String ssid = "...."; // 需要連接的wifi熱點名稱 String password = "........"; // 需要連接的wifi熱點密碼 /** * 根據文件后綴獲取html協議的返回內容類型 */ String getContentType(String filename){ if(server.hasArg("download")) return "application/octet-stream"; else if(filename.endsWith(".htm")) return "text/html"; else if(filename.endsWith(".html")) return "text/html"; else if(filename.endsWith(".css")) return "text/css"; else if(filename.endsWith(".js")) return "application/javascript"; else if(filename.endsWith(".png")) return "image/png"; else if(filename.endsWith(".gif")) return "image/gif"; else if(filename.endsWith(".jpg")) return "image/jpeg"; else if(filename.endsWith(".ico")) return "image/x-icon"; else if(filename.endsWith(".xml")) return "text/xml"; else if(filename.endsWith(".pdf")) return "application/x-pdf"; else if(filename.endsWith(".zip")) return "application/x-zip"; else if(filename.endsWith(".gz")) return "application/x-gzip"; return "text/plain"; } /* NotFound處理 * 用於處理沒有注冊的請求地址 * 一般是處理一些頁面請求 */ void handleNotFound() { String path = server.uri(); Serial.print("load url:"); Serial.println(path); String contentType = getContentType(path); String pathWithGz = path + ".gz"; if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ if(SPIFFS.exists(pathWithGz)) path += ".gz"; File file = SPIFFS.open(path, "r"); size_t sent = server.streamFile(file, contentType); file.close(); return; } String message = "File Not Found\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += ( server.method() == HTTP_GET ) ? "GET" : "POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for ( uint8_t i = 0; i < server.args(); i++ ) { message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n"; } server.send ( 404, "text/plain", message ); } void handleMain() { /* 返回信息給瀏覽器(狀態碼,Content-type, 內容) * 這里是訪問當前設備ip直接返回一個String */ Serial.print("handleMain"); File file = SPIFFS.open("/index.html", "r"); size_t sent = server.streamFile(file, "text/html"); file.close(); return; } /* 引腳更改處理 * 訪問地址為htp://192.162.xxx.xxx/pin?a=XXX的時候根據a的值來進行對應的處理 */ void handlePin() { if(server.hasArg("a")) { // 請求中是否包含有a的參數 String action = server.arg("a"); // 獲得a參數的值 if(action == "on") { // a=on digitalWrite(2, LOW); // 點亮8266上的藍色led,led是低電平驅動,需要拉低才能亮 server.send ( 200, "text/html", "Pin 2 has turn on"); return; // 返回數據 } else if(action == "off") { // a=off digitalWrite(2, HIGH); // 熄滅板載led server.send ( 200, "text/html", "Pin 2 has turn off"); return; } server.send ( 200, "text/html", "unknown action"); return; } server.send ( 200, "text/html", "action no found"); } void setup() { // 日常初始化網絡 pinMode(2, OUTPUT); Serial.begin ( 115200 ); SPIFFS.begin(); int connectCount = 0; WiFi.begin ( ssid.c_str(), password.c_str() ); while ( WiFi.status() != WL_CONNECTED ) { delay ( 1000 ); Serial.print ( "." ); if(connectCount > 30) { Serial.println( "Connect fail!" ); break; } connectCount += 1; } if(WiFi.status() == WL_CONNECTED) { Serial.println ( "" ); Serial.print ( "Connected to " ); Serial.println ( ssid ); Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() ); connectCount = 0; } server.on ("/", handleMain); // 綁定‘/’地址到handleMain方法處理 server.on ("/pin", HTTP_GET, handlePin); // 綁定‘/pin’地址到handlePin方法處理 server.onNotFound ( handleNotFound ); // NotFound處理 server.begin(); Serial.println ( "HTTP server started" ); } void loop() { /* 循環處理,因為ESP8266的自帶的中斷已經被系統占用, * 只能用過循環的方式來處理網絡請求 */ server.handleClient(); }
代碼修改自之前路由系統,畢竟web頁面配合路由的請求會很方便。
主要是增加了getContentType方法和修改了handleMain、handleNotFound。修改handleMain引導訪問根目錄到index.html文件上,修改handleNotFound加入文件檢查,有則直接返回,沒有則404。
需要用到的css和js文件(度盤連接),這里的文件是壓縮成gz格式,在瀏覽器中是支持這種格式的壓縮文件的,壓縮成gz的目的是減少數據量,節約傳輸的帶寬,8266雖然說是54M的制式,但是從Flash讀取出數據再傳輸到客戶端上的數據流量大約只有6-9kb/s,一個jquery min沒壓縮前大約94kb,最快的情況傳輸需要10秒鍾,而壓縮成gz格式之后只有32kb,傳輸也就只需要3秒鍾,中間的等待時間就少了很多。在handleNotFound里邊做了判斷,如果找到同名文件帶有gz格式的文件優先返回gz文件。
接下來就是將文件上傳到Flash上了,在這里需要下載一個Arduino IDE的插件(github地址:https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.3.0/ESP8266FS-0.3.0.zip,度盤:)。下載完成之后解壓到IDE的tools文件夾中,解壓之后完整的路徑應該是“Arduino IDE的文件夾/tools/ESP8266FS/tool/esp8266fs.jar”,然后重啟Arduino IDE,打開項目,在對應的項目文件夾下創建名稱為data的文件夾,這個data文件夾就是上傳數據用的文件夾,上傳之后這個目錄就是8266的根目錄,將需要上傳的文件復制到這個文件夾中,讓8266進入燒寫狀態並關閉IDE的串口管理器,最后選擇Tools(工具)->ESP8266 Sketch Data Upload選項,將文件上傳到給8266的板載Flash。進入燒寫狀態之后就慢慢等着文件上傳完成了,完成之后8266會重啟,但是保險起見,建議手動重啟一次。
之后待8266連接上wifi之后訪問它在串口管理器打印的IP,就可以看到上傳到8266上的頁面了。