Hello Server(with SPIFFS)

前回までで、それらしいWebページになったのですが、

  • スケッチにHTMLのコード埋め込まれている。HTMLファイルとして扱いたい
  • ボタン等のスタイル設定は、CSSファイルを使いたい。
  • 画像等のファイルを扱いたい。

ということで、ファイルを扱える様にしたいと思います。

ファイルの扱いはSDかMicroSDカードの様な外部メディアを使うのが一般的と思いますが、ESP32は内部フラッシュを外部メディアの変わりに使う事が出来ます。これをSPIFFS(SPI Flash File System) と言います。”SPI接続された内部フラッシュを使ったファイルシステム”って感じでしょうか。

インストールと使い方の説明は、”ESP32-WROOM-32 SPIFFS アップローダープラグインの使い方”を参照しました。

前回使用したスケッチから、”Webのボタンを押すとファイルからデータを読み込みシリアルモニタにそれを表示する”に変更します。

  1. 下記のサンプルファイル、”text.txt”をスケッチフォルダの下のdata フォルダに保存

LED Status: "ON"
LED Status: "OFF"
  1. 修正したスケッチ

#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>

const char* ssid = "XXXXXX";
const char* password = "YYYYYY";

WebServer server(80);

#define LED_pin 2
bool LED_status = LOW;

String index_HD = 
            "<!DOCTYPE html> <html>\n" 
            "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n" 
            "<title>LED Control</title>\n" 
            "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n"
            ".button {display: block;width: 60px;background-color: #3498db;border: none;color: white;padding: 13px 30px;\n"
                "text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n"
            ".button-on {background-color: #3498db;}\n"
            ".button-on:active {background-color: #2980b9;}\n"
            ".button-off {background-color: #34495e;}\n"
            ".button-off:active {background-color: #2c3e50;}\n"
            "</style>\n"
            "</head>\n"
            "<body>\n"
            "<h2>Hello ESP32</h2>\n";

void setup() {
  Serial.begin(115200);
  pinMode(LED_pin, OUTPUT);
  digitalWrite(LED_pin, 0);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }

  server.on("/", handleRoot);
  server.on("/led_on", handle_led_on);
  server.on("/led_off", handle_led_off);
  
  server.begin();
  Serial.println("HTTP server started");

  if (!SPIFFS.begin()) {
    Serial.println("SPIFFS Mount Failed");
    return;
  }
}

void loop() {
  server.handleClient();
}

void handleRoot() {
  LED_status = LOW;
  digitalWrite(LED_pin, LOW);
  server.send(200, "text/html", SendHTML(LED_status)); 
}

void handle_led_on() {
  LED_status = HIGH;
  digitalWrite(LED_pin, HIGH);
  server.send(200, "text/html", SendHTML(true)); 

  File dataFile;
    
    dataFile = SPIFFS.open("/test.txt", FILE_READ);
    Serial.println(dataFile.readStringUntil('\n'));
    dataFile.close();
}

void handle_led_off() {
  LED_status = LOW;
  digitalWrite(LED_pin, LOW);
  server.send(200, "text/html", SendHTML(false)); 

  File dataFile;
    
    dataFile = SPIFFS.open("/test.txt", FILE_READ);
    dataFile.readStringUntil('\n');
    Serial.println(dataFile.readStringUntil('\n'));
    dataFile.close();
}

String SendHTML(uint8_t led_stat){
  String ptr;

  ptr = index_HD;
  if(led_stat)
    ptr +="<a class=\"button button-off\" href=\"/led_off\">OFF</a>\n";
  else
    ptr +="<a class=\"button button-on\" href=\"/led_on\">ON</a>\n";

  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}
  • 4行:#include <SPIFFS.h>
    • ヘッダーファイルに読み込み
  • 62から65行: if (!SPIFFS.begin()) {
    • SPIFFSの初期化。エラー処理付き
  • 83から87行:
    • ここは、ボタンが押されてLEDを点灯させる時に呼び出される関数内
    • サンプルファイル、”test.txt”を読み込みモードで開く
    • 最初の1行分を読み込み。−> LED Status: “ON”
    • それをシリアルモニタに表示してファイルをクローズ。
  • 95から100行:
    • ボタンが押されてLEDを消灯させる時に呼び出される関数内
    • サンプルファイル、”test.txt”を読み込みモードで開く
    • 最初の1行分を読み込み捨て。
    • 次の1行分を読み込み。 −> LED Status: “OFF”
    • それをシリアルモニタに表示してファイルをクローズ。

シリアルモニタを上げて、スケッチを実行して下さい。LEDの動作に合わせてモニタに、LED Status: “ON” または LED Status: “OFF” が表示されます。(”ESP32-WROOM-32 SPIFFS アップローダープラグインの使い方”にもあるのですが、SIPFFSのデータファイルをアップロードする時にはモニターをオフする事を気をつけて下さい)

本題のスケッチ

本題のスケッチを以下の様に書き換えます。


#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <SPIFFS.h>

const char* ssid = "XXXXXX";
const char* password = "YYYYYY";

WebServer server(80);

#define LED_pin 2
bool LED_status = LOW;

void setup() {
  Serial.begin(115200);
  pinMode(LED_pin, OUTPUT);
  digitalWrite(LED_pin, 0);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }

  server.on("/", handleRoot);
  server.on("/led_on", handle_led_on);
  server.on("/led_off", handle_led_off);
  
  server.begin();
  Serial.println("HTTP server started");

  SPIFFS.begin();
}

void loop() {
  server.handleClient();
}

String load_HD() {
  File dataFile;
  String line;
  
    dataFile = SPIFFS.open("/index_hd.txt", FILE_READ);
    while(dataFile.available()) 
      line += (dataFile.readStringUntil('\n') + "\n");
    dataFile.close();

    return line;
}

void handleRoot() {
  LED_status = LOW;
  digitalWrite(LED_pin, LOW);
  server.send(200, "text/html", SendHTML(LED_status)); 
}

void handle_led_on() {
  LED_status = HIGH;
  digitalWrite(LED_pin, HIGH);
  server.send(200, "text/html", SendHTML(true)); 
}

void handle_led_off() {
  LED_status = LOW;
  digitalWrite(LED_pin, LOW);
  server.send(200, "text/html", SendHTML(false)); 
}

String SendHTML(uint8_t led_stat){
  String ptr;

  ptr = load_HD();
  if(led_stat)
    ptr +="<a class=\"button button-off\" href=\"/led_off\">OFF</a>\n";
  else
    ptr +="<a class=\"button button-on\" href=\"/led_on\">ON</a>\n";

  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}
  • 4行:#include
  • 46行:SPIFFS.begin()
    • エラー処理止めました。
  • 53から63行:String load_HD() {
    • SIPFFSを使ってデータを読み出す関数
  • 86行:ptr = load_HD();
    • 前回、スケッチ内に埋め込まれていたHTMLをprtに代入していた行
    • 今回は、SIPFFSを使って読み込んだデータを代入している。
    • それ以降の処理は変更無し。

”index_hd.txt” は以下の通り。

index_hd.txt

<!DOCTYPE html>
<html> 
<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\"> 
<title>LED Control</title> 
<style>
    html { 
            font-family: Helvetica; 
            display: inline-block; 
            margin: 0px auto; 
            text-align: center;
        }
    .button {
            display: block;
            width: 60px;
            background-color: #3498db;
            border: none;
            color: white;
            padding: 13px 30px;
            text-decoration: none;
            font-size: 25px;
            margin: 0px auto 35px;
            cursor: pointer;
            border-radius: 4px;
    }
    .button-on {
            background-color: #3498db;
    }
    .button-on:active {
            background-color: #2980b9;
    }
    .button-off {
            background-color: #34495e;
    }
    .button-off:active {
            background-color: #2c3e50;
    }
</style>
</head>
<body>
    <h2>Hello ESP32</h2>
    <h3>Using SPIFFS</h3>
  • 前回スケッチ内で定義していたHTML(下記)の書き換え。

String index_HD = 
            "<!DOCTYPE html> <html>\n" 
            "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n" 
            "<title>LED Control</title>\n" 
            "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n"
            ".button {display: block;width: 60px;background-color: #3498db;border: none;color: white;padding: 13px 30px;\n"
                "text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n"
            ".button-on {background-color: #3498db;}\n"
            ".button-on:active {background-color: #2980b9;}\n"
            ".button-off {background-color: #34495e;}\n"
            ".button-off:active {background-color: #2c3e50;}\n"
            "</style>\n"
            "</head>\n"
            "<body>\n"
            "<h2>Hello ESP32</h2>\n";
  • SPIFFSを使っている事を明記する為に、最後に行に、”<h3>Using SPIFFS </h3>”を追加しています。

コンパイル、SPIFFS用データを書き込んだ後実行して下さい。

ちゃんと追加した、”Using SPIFFS”も表示されました。もちろんLEDもボタンの表示も問題無く動作します。ちなみにこの状態でページのソースを表示すると

予想通りの結果です。

現時点では、SPIFFSを使ってファイルを読み込んでいるだけで、CCSファイルや画像ファイル等への対応は出来ていません。次回はそれらへの対応をして行きます。