在ESP8266的SPIFFS檔案系統存放網頁檔案(一)

本文旨在補充《超圖解物聯網IoT實作入門》第12章「在程式記憶體區儲存靜態網頁」一節(12-31頁),書本的範例把HTML網頁透過C++的Raw String語法存入快閃記憶體。本單元將採用ESP8266的FS.h檔案系統,將網頁和相關資源(如:圖像和JavaScript程式檔)存入快閃記憶體的SPIFFS區域。

連接ESP8266網站伺服器

ESP8266的快閃記憶體結構

下圖是ESP8266的快閃記憶體的分割概略圖,取自12-24頁的註解以及13-13頁「透過OTA更新ESP8266的韌體」,檔案系統區域的大小取決於ESP8266模組的快閃記憶體大小。

ESP8266的快閃記憶體結構

SPIFFS宛如內建於ESP8266的SD記憶卡,可存放程式所需的資料、設定檔或者網站檔案。要存入SPIFFS區域的資料,都得事先擺在程式原始碼的資料夾裡的“data”資料夾(請自行新增“data”資料夾)。例如,本單元程式叫做espStaticWeb,其資料夾結構如下(請按此連結下載本單元的原始檔):

data資料夾裡的網頁內容

使用ESP8266FS工具上傳資料檔案到SPIFFS區域

負責把資料上傳到SPIFFS的工具程式叫做ESP8266FS,需要另外安裝,步驟如下:

  1. 下載ESP8266FS工具
  2. 將它解壓縮到Arduino IDE安裝路徑底下的tools資料夾

ESP8266FS工具的安裝路徑

重新啟動Arduino IDE之後,開啟espStaticWeb.ino檔。你可以執行主功能表「草稿碼→顯示草稿碼資料夾」指令,確認目前的程式原始碼路徑裡面包含data資料夾。

執行主功能表「工具→ESP8266 Sketch Data Upload」(ESP8266草稿碼資料上傳)指令:

ESP8266 Sketch Data Upload指令

IDE將開始上傳data資料夾裡的內容。

開始上傳資料到SPIFFS

當IDE訊息窗格顯示“SPIFFS Image Uploaded”,代表SPIFFS映像檔上傳完畢。

撰寫引用檔案系統的ESP8266網站伺服器程式

本單元的程式改寫自第12章「使用ESP8266WebServer程式庫建立HTTP伺服器」的WiFi_server.ino檔,並加入第13章「設置區域網路域名」的mDNS.ino檔裡面的設定專屬域名和服務回應訊息的程式碼。

凡是有使用檔案系統的程式,都要在程式開頭引用“FS.h”檔。請先在檔案開頭加入引用FS.h的敘述:

把原本處理網站根路徑請求的rootRouter函式,改成以「唯讀」方式開啟SPIFFFS根路徑裡的index.htm檔,並且交給server物件傳給用戶端。SPIFFS與檔案的相關操作指令說明,請參閱下文「ESP8266檔案系統的相關操作指令」一節。

rootRouter函式

完整的程式碼如下,setup函式裡面要執行SPIFFS.begin()啟用SPIFFS檔案系統

編譯並上傳程式碼到ESP8266之後,開啟瀏覽器連線到jarvis.local或者ESP8266的IP位址,即可看見如下的網頁:

呈現在瀏覽器的jarvis.local網頁畫面

咦…網頁圖片並沒有顯現。這是因為上面的程式只處理來自根路徑(“/”和“/index.htm”)的請求,沒有處理影像路徑“/img/ESP8266.png”的請求(參閱第五章「使用Socket.io建立即時連線」一節的圖說,5-27頁),所以網站無法傳遞影像檔給瀏覽器。

雖然我們可以加入像底下處理影像路徑的請求:

以及對應的處理函式:

但很顯然地,這種寫法很不妥當,因為程式無法處理存取非特定資源路徑的請求。相關處理方式請參閱下一篇文章介紹。

ESP8266檔案系統的相關操作指令

底下的指令說明摘譯自ESP8266專案網站的這一篇說明文件

檔案系統物件(SPIFFS)

SPIFFS.begin()
掛載SPIFFS檔案系統的方法。它必須在其他任何FS API被使用之前呼叫。若檔案系統掛載成功,傳回true,否則傳回false。

SPIFFS.format()
格式化檔案系統。可以在執行begin()之前或之後呼叫。若格式化成功則傳回true。

SPIFFS.open(路徑, 模式)
開啟檔案。路徑必需要斜線開頭的絕對路徑(如:/dir/filename.txt)。模式參數是個用字串指定的存取模式,其值為”r”, “w”, “a”, “r+”, “w+”和”a+”之中的一個,這些模式字串的意義和C語言的fopen函式相同(註:請參閱第七章「利用SD記憶卡紀錄溫濕度變化」一節,7-39頁)。

傳回File(代表「檔案」)物件。若要檢查檔案是否開啟成功,請使用布林運算子:

SPIFFS.exists(path)
如果指定的路徑存在,則傳回true,否則傳回false。

SPIFFS.openDir(path)
開啟絕對路徑資料夾,傳回一個Dir物件。

SPIFFS.remove(path)
刪除絕對路徑的檔案,若刪除成功則傳回true。

SPIFFS.rename(原始路徑檔名, 新路徑檔名)
重新命名檔案,路徑必須是絕對路徑,若重新命名成功則傳回true。

Dir(Directory,目錄)物件

Dir物件的作用是遍覽目錄(資料夾)裡的所有檔案,它提供三個方法:next(下一個檔案)、fileName(讀取檔名)和openFile(開啟檔案),它們的用法如底下的範例:

在遍覽目錄的過程中,只要還有檔案,dir.next()就傳回true,這個方法必須在fileName()和openFile()函式之前呼叫。openFile()方法接收一個「開啟檔案的模式」參數,這個參數的意義和SPIFFS.open()函式相同。

File(檔案)物件

SPIFFS.open和dir.openFile函式都會傳回File物件。這個物件支援Stream的所有函式,因此你可以使用readBytes, findUntil, parseInt, println以及其他所有Stream方法。底下是File物件特有的函式:

file.seek(位移字元量, 模式)
這個函式的行為就像C語言的fseek()函式。根據的「模式」參數值,它將在目前的檔案中移動:

  • 若「模式」值是SeekSet,則從檔案開頭移動指定的字元量。
  • 若「模式」值是SeekCur,則從目前的位置位移指定的字元量。
  • 若「模式」值是SeekEnd,則從檔案結尾移動指定的字元量。

若位移成功,則傳回true。

file.position()
傳回目前在檔案中的位置,單位是byte。

file.size()
傳回檔案大小,單位是byte。

傳回檔案名稱,其格式相當於const char*,若要儲存檔名,請將它轉成String。

file.close()
關閉檔案。執行此函式之後,就不能在該檔案物件上執行其他操作。

延伸閱讀

8 thoughts on “在ESP8266的SPIFFS檔案系統存放網頁檔案(一)

  1. 趙老師您好:
    我在完成13-7頁的動手做時,發現用網頁去操控LED開關和LED照度時,會有延遲,也就是我網頁操作一個動作後,隔了1~2秒,接在esp8266的LED燈才有動作,所以我在找原因出在哪,可能原因如下

    1. 在程式記憶體區引用CDN的jQuery和程式碼,是透過網路下載所以變慢
    2. ESP8266和網頁之間沒有建立socket,所以沒辦法做到即時

    針對1的部分,我才找看看有沒有辦法將jQuery或jQuery mobile的css檔案和js檔案直接燒進esp8266,如果網頁有用到圖檔,也把圖檔燒進esp8266,剛好用老師寫的這篇說明來實做看看

    針對2的部分,我在https://swf.com.tw/?p=901有詢問過老師,把ESP8266當作網頁伺服器(server),瀏覽器為用戶端(client),兩者之間建立socket,不知老師是否能建立一個 “建立Arduino的Socket即時通訊程式(三)”來說明這部分

    另外在13-30頁下方 的 dtostrf(charTemp, 5, 2, 12.34) 是否應該改成 dtostrf(12.34, 5, 2, charTemp)
    另外想請問在13-23頁中文字的圖檔(temperature.png)是用甚麼軟體建立的,我用小畫家 -> 常用 -> 調整大小 -> 選擇像素 ->
    水平改成32,垂直改成16 -> 選擇文字把文字放在區塊上,再調整區塊背景顏色(黑),文字前景顏色(白)及透明,發現不太好操作。

    1. hi alex:

      ESP8266網站伺服器程式有時候反應比較慢,是因為HTTP訊息比較多的原因,如果是電腦或樹莓派這種主記憶體空間比較大的微控器,就不會出現類似的問題。透過CDN下載或者從本機伺服器讀取的jQuery程式庫,只要下載完成,就會一直待在用戶端裝置的記憶體,所以只有在首次開啟網頁的時候,會比較慢。

      我會陸續更新相關內容,本週會先更新一篇「在ESP8266的SPIFFS檔案系統存放網頁檔案(二)」。

      13-23頁的中文字點陣圖,我是從Flash輸出的。你可以嘗試免費的Paint.NET繪圖軟體,有中文操作介面。

      thanks,
      jeffrey

    1. 小丁:

      你指的不用IP,是說採用網域名稱(像swf.com.tw)嗎?請使用 AT+CIPSTART 指令連結看看,詳細的指令參數請參閱這一篇留言,安信可公司提供的PDF文件。

      thanks,
      jeffrey

  2. 老師您好請教一下
    也就是說ESP系列比AVR單晶片的EEPROM多了一項可讀寫的記憶體空間
    使用SPIFFS的方式存取
    這樣講對嗎?

  3. 老师您好,我想问一下这句代码server.streamFile(file, “text/html”);中为什么要用streamFile?
    streamFile是什么意思?

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *