SPIFFSの使い方、フラッシュメモリに簡単データ保存 ESP32

SDカード不要で、マイクロコントローラの内蔵「フラッシュメモリ」にデータを保存、読込する方法をサンプルプログラムで詳しく紹介します。

プログラム領域に影響を与えることなく、測定データの保存やWebページの「HTMLデータ」を保存できるため、メモリ領域を有効活用でき、データの管理も楽になります。
スポンサーリンク

1.SPIFFSとは

「SPIFFS(Serial Peripheral Interface Flash File System)」とは、小規模なデータを「フラッシュメモリ」上に保存するための「ファイルシステム」で、主にリソースが制約されたマイクロコントローラーで使用されます。

「SPIFFS」は、データの読み書きと削除を行うための「API」を提供します。「SPIFFS」を使用することで、マイクロコントローラー上の「フラッシュメモリ」にファイルを保存し、必要な時にデータを読み出して使用できます。

Arduinoのライブラリとしてプログラム内で簡単に利用することができるので、測定データや設定情報の保存など、さまざまな用途で使用することができます。
SPIFFSは比較的小規模なデータの保存に適しており、大量のデータや高速なアクセスが必要な場合には他のファイルシステム(例えば、FATファイルシステム)の使用を検討する必要があります。
スポンサーリンク

2.使用可能なデバイス

「SPIFFS」は、主に「Espressif社」が提供するマイクロコントローラー「ESP32」や「ESP8266」等の「フラッシュメモリ」を搭載したデバイスで使用できます。

「M5Stack社」のほとんどのデバイスには「ESP32系」のコントローラが使用されており「SPIFFS」を使用してフラッシュメモリのデータの読み書きをすることができます。

今回の動作確認には「M5Stack社」の「M5StickC Plus2」を使用します。

「M5StickC Plus2」については以下のリンクで詳しく紹介しています。

M5StickC Plus2の使い方、初期設定、旧モデルとの違い等サンプルプログラムで詳しく紹介
M5StickCの最新版M5StickC Plus2について、旧モデルとの違いを確認しながら、初期設定や端子配列、機能、使い方をサンプルプログラムで詳しく紹介します。
スポンサーリンク

3.初期設定、フォーマットについて

「SPIFFS」を使用してデータの読み書きを行うには、「SPIFFS」ライブラリを使用します。

また、開発環境ごとに初期設定が必要な場合があり、「フラッシュメモリ」を初めて使用する時には初回のみ「フォーマット」を行う必要があるため、以下からそれぞれの方法を紹介します。

・ライブラリのインクルード

「SPIFFS」ライブラリを使用するには、プログラムの冒頭に以下のように記述します。

#include <SPIFFS.h>
「M5Stackシリーズ」のデバイスでは「SPIFFS」ライブラリは標準でインストールされているため別途インストールする必要はありませんが、他のデバイスを使用する場合には別途専用のライブラリをインストールする必要がある場合があります。

初期設定

「SPIFFS」を使用するためには開発環境ごとに初期設定が必要な場合があります。

ArduinoIDE

ArduinoIDE」では特に設定を行う必要はありません。
「SPIFFS」についての設定は「ArduinoIDE」の開発画面で以下のように「メニューバー」の[ツール]をクリックすると確認できます。

SPIFFSの使い方ArduinoIDE
今回使用した「M5StickC Plus2」の初期設定の場合、「8MB」のフラッシュメモリの中で「1.5MB」が「SPIFFS」の保存領域として設定されています。

PlatformIO

PlatformIO」では「platformio.ini」ファイルに「SPIFFS」を使用する設定を記入する必要があります。
また「SPIFFS」に使用するフラッシュメモリ領域のパーティション設定も必要に応じて行いますが、記入しなくてもデフォルトの設定で使用できます。

今回動作確認に使用した「M5StickC Plus2」の「platformio.ini」の内容は以下になります。

SPIFFSの使い方PlatformIO

パーティション設定で指定できる「.csv」は他にもたくさんあり、以下のGitHubで一覧が確認できます。

arduino-esp32/tools/partitions at master · espressif/arduino-esp32
Arduino core for the ESP32. Contribute to espressif/arduino-esp32 development by creating an account on GitHub.
設定できるパーティションの設定方法はデバイスごとに異なります。

フォーマット

「SPIFFS」を使用するには、初回のみデバイスごとにフォーマットを行う必要があります。
フォーマットを行うには、プログラムの初期設定「setup()」に以下のように記入して書き込みを行います。

void setup() {
  SPIFFS.format(); // 初回フォーマット時のみ有効にする(次回書き込みからは無効にする)

  // ・・・その他の初期設定・・・
}
初回フォーマットの書き込みではプログラムは動作しません。
初回の書き込みが完了したら「SPIFFS.format();」の部分をコメントアウト、または消去して再度書き込みを行うとプログラムが動作します。

4.基本的なデータ読み書き方法

まずは「SPIFFS」を使用した、基本的なデータの保存、読込方法を紹介します。
「M5StickC Plus2」を使用して「サンプルプログラム」で実際に動作確認しながら使い方を確認してみましょう。

・サンプルプログラム

「フラッシュメモリ」にテキストデータを保存し、保存したデータを読み込む方法を紹介します。

「M5StickC Plus2」に「サンプルプログラム」を書き込んで実行すると下画像のような動作が確認できます。

SPIFFS基本的な読み書き方法

本体正面の「ボタンA」を押すと、上画像のように表示され、プログラムで指定したテキストデータと実行時間(ms)が指定ファイルに書き込まれます。

SPIFFS基本的な読み書き方法

側面の「ボタンB(上画像手前)」を押すとテキストデータと実行時間を読み出して液晶画面に表示します。

SPIFFS基本的な読み書き方法

本体正面の「ボタンA」を押すとデータが更新されます。

側面の「ボタンB」を押すと更新したデータが読み込まれます。起動時間が経過しているため、データが正しく更新されたことが確認できます。


サンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

初回書き込み時にはフラッシュメモリのフォーマットを行います。
「65行目」の「SPIFFS.format()」を無効にして、2回目の書き込み後に動作するようになります。

#include <M5StickCPlus2.h>
#include <SPIFFS.h>

/*************************** ファイル作成関数 ***************************/
void createFile() {
  // ファイル作成
  File file = SPIFFS.open("/file.txt", FILE_WRITE); // ファイルを作成して開く
  if(!file){  // ファイルが開けなければ
    M5.Lcd.println("Failed to create file"); // エラー表示
    return;
  } else {    // ファイルが開ければ
    M5.Lcd.println("Create file"); // ファイル作成実行表示
  }
  // ファイルにデータを書き込む
  String text = "Hello World!";   // 書き込む文字列を準備
  file.println(text);             // 文字列書き込み実行
  file.printf("%dms", millis());  // 実行時間書き込み
  file.close(); // ファイルを閉じる
}

/************************** ファイル読み込み関数 **************************/
void readFile() {
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setCursor(0, 0);   // 座標設定(x, y)

  String file_name = "/file.txt";  // ファイル名の指定
  if (SPIFFS.exists(file_name)) {  // ファイルが存在すれば
    // ファイルを開く
    File file = SPIFFS.open(file_name, FILE_READ); // ファイルオープン
    if(!file){  // ファイルが開けなければ
      M5.Lcd.println("Failed to open file"); // エラー表示
      return;
    } else {    // ファイルが開ければ
      M5.Lcd.println("Open file to read");   // 読み取り実行表示
    }
    // ファイルの内容を読み取り表示
    M5.Lcd.setTextColor(WHITE, BLACK); // (文字色, 背景)
    while(file.available()){  // ファイルのデータ分繰り返す
      char c = file.read(); // ファイルから1バイトずつデータを読み取り
      M5.Lcd.print(c);      // 液晶へ表示
    }
    M5.Lcd.setTextColor(ORANGE, BLACK); // (文字色, 背景)
    M5.Lcd.print("\n");                 // 改行
    // ファイルを閉じる
    file.close(); 
  } else {  // ファイルが存在しなければ
    M5.Lcd.println("File does not exist");  // エラー表示
  }
}

// 初期設定 -----------------------------------------
void setup() {
  auto cfg = M5.config();  // 本体初期設定
  StickCP2.begin(cfg);

  // 画面の初期設定
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setRotation(3);    // 画面向き設定(USB位置基準 0:下/ 1:右/ 2:上/ 3:左)

  M5.Lcd.setFont(&fonts::Font4);      // フォント
  M5.Lcd.setCursor(0, 0);             // 座標設定(x, y)
  M5.Lcd.setTextColor(ORANGE, BLACK); // (文字色, 背景)
  M5.Lcd.println("SPIFFS TEST");      // タイトル表示

  SPIFFS.format(); // 初回フォーマット時のみ有効にする(次回書き込みからは無効にする)
  
  // SPIFFS の初期化
  if(!SPIFFS.begin()){
    M5.Lcd.println("SPIFFS initialization failed!");  // エラー表示
    return;
  }
}

// メイン -----------------------------------------
void loop() {
  M5.update();  //本体ボタン状態更新
  // ボタンA(ファイル作成)
  if (M5.BtnA.wasPressed()) {
    createFile(); // ファイルの作成
  }
  // ボタンB(ファイル読込)
  if (M5.BtnB.wasPressed()) {
    readFile(); // ファイルの読み込み
  }
  delay(200); // 遅延時間
}

・基本的な読み書きプログラムの詳細

「SPIFFS」でフラッシュメモリにデータを保存し読み込む方法について、「サンプルプログラム」からエラー処理や液晶表示処理を除いて、以下で各処理ごとに紹介します。

ライブラリのインクルード

まずは以下のように「SPIFFS」ライブラリをインクルードします。

#include <SPIFFS.h>

初期設定

次に初期設定の「SPIFFS.format()」でフラッシュメモリのフォーマットを行い、「SPIFFS.begin()」で初期化を行います。

void setup() {
  SPIFFS.format(); // 初回フォーマット時のみ有効にする(次回書き込みからは無効にする)
  SPIFFS.begin();  // SPIFFSの初期化

  // ・・・その他の初期設定・・・
}
SPIFFS.format()」は初回のみ実行する必要があります。初回書き込み時にはフラッシュメモリのフォーマットが行われるため、他のプログラムは実行されません。
SPIFFS.format()」を無効にして、再度書き込むことで「SPIFFS」を利用したプログラムが実行できるようになります。

ファイルの保存

フラッシュメモリのファイルにデータを保存するには以下のように行います。
以下の例では「createFile()」関数としてまとめていおり、この関数を呼び出すことでファイルにデータを保存することができます。

void createFile() {
  File file = SPIFFS.open("/file.txt", FILE_WRITE); // ファイルを作成して開く

  // ファイルにデータを書き込む
  String text = "Hello World!";   // 書き込む文字列を準備
  file.println(text);             // 文字列書き込み実行
  file.printf("%dms", millis());  // 実行時間書き込み

  file.close(); // ファイルを閉じる
}

まず、「SPIFFS.open()」を使って、「/file.txt」という名前のファイルを作成し、書き込みモード(FILE_WRITE)で開きます。

次に、書き込むテキストを文字列変数「text」に準備します。
ここでは「“Hello World!”」という文字列を設定しています。

file.println(text)」使って、テキストをファイルに書き込みます。
println()」関数では末尾に改行をつけて書き込みます。

また、書き込みデータの変化を確認するために「file.printf(%dms”, millis())」を使って、実行時間をミリ秒単位でファイルに書き込みます。
millis()」関数はマイクロコントローラの起動からのミリ秒単位の時間を整数で返します。

print()」関数では、特定のフォーマットで文字列を書き込むことができます。
ここでは、「%d」は整数値を表し、「ms」は文字列として追加されます。

最後に、「file.close()」を使用してファイルを閉じます。
ファイルを操作した後は、必ずファイルを閉じる必要があります。

ファイルの読み込み

フラッシュメモリのファイルからデータを読み込むには以下のように行います。
以下の例では「readFile()」関数としてまとめるており、この関数を呼び出すことでファイルからデータを読み出すことができます。

void readFile() {
  String file_name = "/file.txt";  // ファイル名の指定

  if (SPIFFS.exists(file_name)) {  // ファイルが存在すれば
    File file = SPIFFS.open(file_name, FILE_READ); // ファイルを開く

    // ファイルの内容を読み取り表示
    while(file.available()){  // ファイルのデータ分繰り返す
      char c = file.read(); // ファイルから1バイトずつデータを読み取り
      M5.Lcd.print(c);      // 液晶へ表示
    }
    file.close(); // ファイルを閉じる
  }
}

まず、読み取るファイル名を文字列変数「file_name」で指定します。
ここではファイル名を「“/file.txt”」としています。

次に、「SPIFFS.exists(file_name)」を使用して、指定されたファイル名が存在するかどうかをチェックしています。
ファイルが存在する場合は、「if文」のブロック内のデータ読み込み処理が実行されます。

SPIFFS.open()」関数を使って、「file_name」で指定した名前のファイルを読み取りモード(FILE_READ)で開きます。

そして、「while(file.available())」を使って、ファイルからのデータがある限り繰り返し処理を行います。
available()」関数は、まだ読み込まれていない文字(バイト数)がある場合に「true」を返します。

char c = file.read()」を使って、ファイルから1文字(1バイト)ずつデータを読み取ります。
最後に、「M5.Lcd.print(c)」で読み取った文字を1文字づつ液晶ディスプレイに表示しています。

すべてのデータの読み取りが完了したら「file.close()」を使用してファイルを閉じます。

ファイル名について、現時点の「SPIFFS」ではディレクトリ構造をサポートしていません。
このため、ファイル名を「/data/file.txt」のように指定しても「data」というディレクトリに「file.txt」という名前のファイルを指定されるわけではなく、「/data/file.txt」という名前のファイルとして扱われます。

5.パソコンからファイルを保存する方法

「SPIFFS」を使用してプログラムで指定したデータを書き込む方法を「サンプルプログラム」で紹介しましたが、事前にパソコンからフラッシュメモリにデータを保存しておくこともできるため、この方法についても紹介します。

フラッシュメモリにパソコンからデータの書き込みを行う時には、シリアルモニタを終了させておく必要があります。

・PlatformIO

PlatformIOの場合は以下のように、編集中のプログラムフォルダに「data」という名前でフォルダを作成して、その中に保存したいデータを入れておきます。

作成した「data」フォルダの中に保存したファイルが、デバイスのフラッシュメモリに書き込むことができるようになります。
SPIFFSパソコンからデータ保存PlatformIO

デバイスのフラッシュメモリに書き込むには以下のように、左メニューの「PlatformIO」アイコンをクリックして、[ボード名(ここではm5stick-c)]→[Platform]をクリックします。

下画像のようにメニューが展開されたら[Build Filesystem Image]をクリックしてフォーマットをした後に[Upload Filesystem Image]をクリックすることで「data」フォルダ内に保存されているデータが書き込まれます。

SPIFFSパソコンからデータ保存PlatformIO
上記の手順でフォーマットやファイルの保存を実行すると、デバイスのフラッシュメモリの内容は上書きされるので注意してください。

・ArduinoIDE

ArduinoIDEでは現時点ではバージョン2でフラッシュメモリに直接書き込む方法は提供されていません。
バージョン1では以下の方法で書き込みツールを追加することができるため、この方法を紹介しておきます。

まずは以下のページにアクセスして「ESP32FS-1.1.zip」ファイルをダウンロードしてください。

Release Release v1.1 with support for more chips · me-no-dev/arduino-esp32fs-plugin
Full Changelog: 1.0...1.1

ダウンロードしたファイルはダウンロードフォルダにあるのでこれを展開しておきます。
次にArduinoのスケッチが保存されているフォルダ(C:\Users\UserName\Documents\Arduino)を開きます。
このフォルダに「tools」という名前でフォルダを作成し、この中に展開した「ESP32FS 2」をフォルダごと移動します。

ArduinoIDEを起動して、メニューバーの[ツール]をクリックすると、ドロップダウンメニューの中に[ESP32 Sketch Data Upload]があれば準備完了です。

スケッチと同じフォルダに「data」というフォルダを作成して、この中に書き込みたいデータを保存します。

データの準備が完了したら[ツール]→[ESP32 Sketch Data Upload]をクリックすると書き込みが開始されます。

6.保存データの情報確認

デバイスのフラッシュメモリ内に保存されているデータの容量や、ファイル名一覧の確認方法について紹介します。

・フラッシュメモリ容量確認

フラッシュメモリの容量や使用量、空き容量を確認するには以下のように行います。
以下の例では「spiffsInfo()」関数としてまとめていますので、コピペで貼り付けて使用してください。

void spiffsInfo() {
  M5.Lcd.fillScreen(BLACK);  // 背景色
  M5.Lcd.setCursor(0, 0);    // 座標設定(x, y)

  File file = SPIFFS.open("/");            // ルートディレクトリを開く
  size_t totalBytes = SPIFFS.totalBytes(); // 総容量を取得
  size_t usedBytes = file.size();          // 使用中の容量を取得

  M5.Lcd.print("Total :  "); // 総容量
  M5.Lcd.println(totalBytes);
  M5.Lcd.print("Used :  ");  // 使用中の容量
  M5.Lcd.println(usedBytes);
  M5.Lcd.print("Free :  ");  // 空き容量
  M5.Lcd.println(totalBytes - usedBytes);
}

この関数を「setup()」の末尾や、ボタンを押した時等に実行されるように、以下のように記入して呼び出すと液晶画面上でファイル容量を確認することができます。

spiffsInfo();  // フラッシュメモリの容量確認関数呼び出し

・保存されているファイル名確認

フラッシュメモリに保存されているファイル名の一覧を確認するには以下のように行います。
以下の例では「spiffsFileList()」関数としてまとめていますので、コピペで貼り付けて使用してください。

void spiffsFileList() {
  M5.Lcd.fillScreen(BLACK);  // 背景色
  M5.Lcd.setCursor(0, 0);    // 座標設定(x, y)

  File file = SPIFFS.open("/"); // ルートディレクトリを開く

  // ファイル名、サイズの表示
  while (true) {
    File entry = file.openNextFile(); // ファイルを1つづつ開く
    if (!entry) { // ディレクトリの末尾に達したら終了
      break;
    }
    M5.Lcd.print(entry.name()); // ファイルまたはディレクトリの名前を表示
    M5.Lcd.print("  ");         // スペースを表示
    M5.Lcd.println(entry.size()); // ファイルのサイズを表示
    
    entry.close(); // 使い終わったファイルを閉じる
  }
}

この関数を「setup()」の末尾や、ボタンを押した時等に実行されるように、以下のように記入して呼び出すと液晶画面上で保存されているファイル名と容量の一覧を確認することができます。

spiffsFileList();  // フラッシュメモリのファイル名確認関数呼び出し

7.Webページを保存して開く方法

Wi-Fi機能のあるデバイスをサーバーとして使用するときに、Webページ用のデータ(HTML/CSS/JavaScript)もフラッシュメモリに保存しておくと、編集しやすくなりメモリの節約にもなって便利なため、この方法も紹介します。

Webページの規模が大きい場合は「HTML/CSS/JavaScript」の各ファイルを個別に保存しておいた方が編集しやすくなりますが、今回は「HTML」ファイルに「CSS/JavaScript」のデータも含めた、簡易なWebページを表示させるサンプルプログラムでの方法で紹介します。

・動作確認

Webページを表示させるサンプルプログラムを準備しました。
サンプルプログラムでは以下の動作が確認できます。

SPIFFSでWebページ表示動作確認

電源を入れるとWi-Fi接続が開始されます。

SPIFFSでWebページ表示動作確認

接続に成功すると上画像のように「IPアドレス」と「mDNS名」が表示されます。

SPIFFSでWebページ表示

パソコンやスマホのブラウザを起動して、アドレスバーに「mDNS名」の「logi0.local」を入力すると上画像の画面が表示されます。

SPIFFSでWebページ表示動作確認

本体には上画像のように表示されます。

「mDNS名」で接続できない場合は、ブラウザのアドレスバーに「IPアドレス(上画像では192.168.10.12 ※環境によって異なります)」を入力してください。
SPIFFSでWebページ表示動作確認

ブラウザの[ONボタン]を押すと「本体LEDが点灯」し、[OFFボタン]を押すと「本体LEDが消灯」します。本体正面の「ボタンA」でもLEDは点灯し、側面の「ボタンB」を押すとLEDは消灯します。

ブラウザボタン下の「LED_ON/LED_OFF」の表示はブラウザを操作した時のみ更新されます。本体側の操作とは連動していません。

・サンプルプログラム(Webページ・HTML)

Webページのデータは事前にフラッシュメモリに書き込んでおく必要があります。
フラッシュメモリへの書き込みは「5.パソコンからファイルを保存する方法 ー PlatforunIO」を参照してください。

Webページのサンプルプログラムは以下になります。「コピペ」して作成した「data」フォルダ内に「index.html」というファイル名で保存してください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>M5StickCP2 Controller</title>
    <style>
      #container {display: flex;justify-content: center;align-items: center;flex-direction: column;margin-top: 40px;}
      h1 {color: #666;}
      .button {width: 100px;height: 50px;border-radius: 5px;margin: 10px;cursor: pointer;font-size: 20px;font-weight: bold;color: white;text-align: center;line-height: 50px;}
      #on-button {background-color: green;}
      #off-button {background-color: red;}
    </style>
  </head>
  <body>
    <div id="container">
      <h1>M5StickCP2 Controller</h1>
      <div>
        <button id="on-button" class="button">ON</button>
        <button id="off-button" class="button">OFF</button>
      </div>
      <div><p id="led_state"> </p></div>
    </div>

    <script>
      const onButton = document.getElementById("on-button");
      const offButton = document.getElementById("off-button");
      const ledState = document.getElementById("led_state");

      onButton.addEventListener("touchstart", handleOnClick);
      onButton.addEventListener("click", handleOnClick);

      async function handleOnClick() {
        const response = await fetch("/get/btn_on");
        const text = await response.text();
        ledState.textContent = text;
        console.log(text);
      }

      offButton.addEventListener("touchstart", handleOffClick);
      offButton.addEventListener("click", handleOffClick);

      async function handleOffClick() {
        const response = await fetch("/get/btn_off");
        const text = await response.text();
        ledState.textContent = text;
        console.log(text);
      }
    </script>
  </body>
</html>

・サンプルプログラム(メイン)

「M5StickC Plus2」のサンプルプログラムは以下になります。「コピペ」して書き込んでください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

「10, 11行目」のWi-Fi接続SSIDとパスワードは自宅の環境に合わせて設定してから書き込んでください。

#include <M5StickCPlus2.h>
#include <SPIFFS.h>
#include <WebServer.h>    // サーバー設定用
#include <ESPmDNS.h>      // ドメインネームでIPアドレス取得用

#define LED 19  // 本体LED
WebServer server(80); // サーバー設定ポート80で接続

// Wi-Fiローカル接続先設定
const char ssid[] = "自宅のWi-FiルーターのSSIDを設定";         // 接続先SSID
const char pass[] = "自宅のWi-Fiルーターの接続パスワードを設定"; // 接続先パスワード
const char mdnsName[] = "logi0"; // mDNS Name(mdnsName.localで接続可能)

// 変数宣言
int count_data = 0; // ボタンON回数データ格納用

/************************** ファイル読み込み関数 **************************/
String readFile(const char* file_name) {
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setCursor(0, 0);   // 座標設定(x, y)
  M5.Lcd.setTextColor(ORANGE, BLACK); // (文字色, 背景)

  String html = "";                              //htmlデータ格納用文字列
  File file = SPIFFS.open(file_name, FILE_READ); // フラッシュメモリのhtmlファイルを開く

  if (SPIFFS.exists(file_name)) {  // ファイルが存在すれば
    // ファイル読み込み
    if (file) { //読込が成功したら
      M5.Lcd.println("Client connected!");  // エラー表示
      while (file.available()) { //読込可能な文字がある間繰返す
        char buff = file.read(); //buffへ1文字づつ読み出す
        html += buff;  //読み出した文字を1文字づつhtml文字列に追加
      }
    } else {
      Serial.println("Failed to open file");  // エラー表示
    }
    file.close(); //ファイルを閉じる
  } else {  // ファイルが存在しなければ
    M5.Lcd.println("File does not exist");  // エラー表示
  }
  return html;  // HTMLデータを返す
}

/*********************** Wi-Fi接続(mdns名設定)実行関数 ***********************/
void wifiConnect() {
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setCursor(0, 0);   // 座標設定(x, y)
  M5.Lcd.println(" Wi-Fi Search!");

  // Wi-Fi接続開始
  while (WiFi.localIP()[0] == 0) { // IPアドレスが取得されるまで繰り返し
    WiFi.begin(ssid, pass);        //ローカル Wi-Fi接続実行
    M5.Lcd.print("."); // 液晶表示
    delay(3000);       // 再接続待ち
  }
  // mDNS設定(mdnsName.localでアクセス)
  MDNS.begin(mdnsName);

  // 接続情報シリアル出力表示
  Serial.print("IP : ");
  Serial.println(WiFi.localIP());       // IPアドレス(配列)表示
  Serial.printf("mDNS : %S.local\n", mdnsName); // mDNS名表示

  // 液晶表示
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setCursor(0, 0);   // 座標設定(x, y)
  M5.Lcd.print(" IP : ");
  M5.Lcd.println(WiFi.localIP());  // IPアドレス(配列)表示
  M5.Lcd.printf(" mDNS :\n  %S.local\n", mdnsName);  // mDNS名表示
}

/******************サーバーリクエスト時処理関数 ******************/
// ルートアクセス時の応答(クライアントにWebページ[HTML]を返す)関数
void handleRoot() {
  String html = readFile("/index.html"); //htmlデータ取得関数
  server.send(200, "text/html", html);   //レスポンス200を返し、htmlデータ送信
  Serial.println("200, text/html, index.html");
}
// エラー(Webページが見つからない)時の応答関数
void handleNotFound() {
  server.send(404, "text/plain", "404 Not Found!");  //text送信
}
// ブラウザONボタン処理
void btnOn() {
  digitalWrite(LED, HIGH);  // 本体LED点灯
  server.send(200, "text/plain", "LED_ON");  //レスポンス200を返しhtml送信
  Serial.println("LED_ON"); // シリアルモニタ出力
}
// ブラウザOFFボタン処理
void btnOff() {
  digitalWrite(LED, LOW);   // 本体LED消灯
  server.send(200, "text/plain", "LED_OFF");  //レスポンス200を返しhtml送信
  Serial.println("LED_OFF"); // シリアルモニタ出力
}

/*********************** サーバー設定関数 ***********************/
void serverSetting() {
  server.on("/", handleRoot);         // ルートアクセス時の応答関数を設定
  server.onNotFound(handleNotFound);  // Webページが見つからない時の応答関数を設定
  server.on("/get/btn_on", btnOn);    // ボタンONリクエスト処理
  server.on("/get/btn_off", btnOff);  // ボタンOFFリクエスト処理
  server.begin();                     // Webサーバー開始
}

// 初期設定 ---------------------------------------------------
void setup() {
  auto cfg = M5.config();  // 本体初期設定
  StickCP2.begin(cfg);
  Serial.begin(9600);  // シリアル通信初期化

  // 出力端子設定
  pinMode(LED, OUTPUT);   // 本体LED赤
  digitalWrite(LED, LOW); // 本体LED初期値OFF(LOW)

  // 画面の初期設定
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setRotation(3);    // 画面向き設定(USB位置基準 0:下/ 1:右/ 2:上/ 3:左)

  M5.Lcd.setFont(&fonts::Font4);     // フォント
  M5.Lcd.setCursor(0, 0);            // 座標設定(x, y)
  M5.Lcd.setTextColor(WHITE, BLACK); // (文字色, 背景)

  // SPIFFS の初期化
  if(!SPIFFS.begin()){
    M5.Lcd.println("SPIFFS initialization failed!");  // エラー表示
    return;
  }
  wifiConnect();   // Wi-Fi接続(mdns名設定)実行関数
  serverSetting(); // サーバー設定関数
}

// メイン -----------------------------------------------------
void loop() {
  server.handleClient(); //クライアントからのアクセス処理
  M5.update();           //本体ボタン状態更新

  // ボタンA(ファイル作成、ボタンON回数+1)
  if (M5.BtnA.wasPressed()) {   // ボタンAが押されたら
    digitalWrite(LED, HIGH);  // 本体LED点灯
  }
  // ボタンB(ファイル読込)
  if (M5.BtnB.wasPressed()) {   // ボタンBが押されたら
    digitalWrite(LED, LOW);  // 本体LED消灯
  }
  delay(200); // 遅延時間
}

・プログラムの詳細

「SPIFFS」でフラッシュメモリに保存されたWebページ(HTMLデータ)を表示させるプログラムの詳細は以下になります。

Wi-Fi接続でWebページを表示させる方法や、Webサーバーの設定については以下のリンクで詳しく紹介しています。

WiFi(ローカル接続、サーバー)で遠隔操作する方法(Arduinoプログラミング)
Wi-Fi通信でスマホから遠隔操作を行う方法を詳しく紹介。サーバーの仕組みを利用することで簡単にブラウザからの遠隔操作が実現できます。ATOM LITE使用

Webページを表示するには、まずWi-Fiに接続するためにサンプルプログラムの「10, 11行目」のWi-Fi接続先のSSIDとパスワードをご自宅の環境に合わせて設定してください。

// Wi-Fiローカル接続先設定
const char ssid[] = "自宅のWi-FiルーターのSSIDを設定";         // 接続先SSID
const char pass[] = "自宅のWi-Fiルーターの接続パスワードを設定"; // 接続先パスワード
const char mdnsName[] = "logi0"; // mDNS Name(mdnsName.localで接続可能)
mDNS名はWebページを表示させるためにブラウザのアドレスバーに入力します。
ここでは「logi0」としていますが自由に設定してください。
ブラウザのアドレスバーに「mDNS名.local(ここではlogi0.local)」と入力することで、デバイス内に保存したWebページを表示することができます。

ブラウザからアクセスすると以下のプログラムが実行されます。
文字列変数「html」にWebページのHTMLデータを読み込むために「readFile(“/index.html”)」関数を呼び出して、フラッシュメモリに保存されている「index.html」のデータを取得してブラウザ側へ送信しています。

// ルートアクセス時の応答(クライアントにWebページ[HTML]を返す)関数
void handleRoot() {
  String html = readFile("/index.html"); //htmlデータ取得関数
  server.send(200, "text/html", html);   //レスポンス200を返し、htmlデータ送信
  Serial.println("200, text/html, index.html");
}

readFile(“/index.html”)」関数を呼び出すと以下のプログラムが実行されます。
以下コードの「8行目」でフラッシュメモリに保存されている「index.html」ファイルを開きます。

「14〜16行目」で「index.html」内の文字列データを1文字づつ読み込んで文字列変数「html」に結合して完成した「html」を文字列で返します。

/************************** ファイル読み込み関数 **************************/
String readFile(const char* file_name) {
  M5.Lcd.fillScreen(BLACK); // 背景色
  M5.Lcd.setCursor(0, 0);   // 座標設定(x, y)
  M5.Lcd.setTextColor(ORANGE, BLACK); // (文字色, 背景)

  String html = "";                              //htmlデータ格納用文字列
  File file = SPIFFS.open(file_name, FILE_READ); // フラッシュメモリのhtmlファイルを開く

  if (SPIFFS.exists(file_name)) {  // ファイルが存在すれば
    // ファイル読み込み
    if (file) { //読込が成功したら
      M5.Lcd.println("Client connected!");  // エラー表示
      while (file.available()) { //読込可能な文字がある間繰返す
        char buff = file.read(); //buffへ1文字づつ読み出す
        html += buff;  //読み出した文字を1文字づつhtml文字列に追加
      }
    } else {
      Serial.println("Failed to open file");  // エラー表示
    }
    file.close(); //ファイルを閉じる
  } else {  // ファイルが存在しなければ
    M5.Lcd.println("File does not exist");  // エラー表示
  }
  return html;  // HTMLデータを返す
}
今回のWebページのデータは「HTML」データの中に「CSS」と「JavaScript」のデータを含めましたが、Webページの規模が大きい場合はそれぞれのデータを個別に保存して呼び出すようにすると編集や管理を楽に行うことができるようになります。

8.まとめ

「SPIFFS」を使ってフラッシュメモリにデータを保存して読み込む方法を紹介しました。

フラッシュメモリにデータが保存できると、プログラムエリアを使用せずに測定データの保存やWebページのデータを保存して利用することができるようになります。

フラッシュメモリを使用するには、初回フォーマットが必要ですが、一度フォーマットを行うと自由にデータの読み書きができます。

開発環境の「PlatformIO」を使用すればパソコンからデータをフラッシュメモリに保存することもできるため、Webページの「HTML、CSS、JavaScript」のデータを事前に保存しておけば規模の大きなWebページを扱うこともできるようになるため有効に活用していきましょう。

コメント

タイトルとURLをコピーしました