SPIFFS_time

はじめに

SPIFFSをテストするプログラムです。以下の関数を定義しています。

プログラム

定義等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include "FS.h"
#include "SPIFFS.h"
#include <time.h> 
#include <WiFi.h>

const char* ssid     = "your-ssid";
const char* password = "your-password";

long timezone = 1; 
byte daysavetime = 1;

ssidはWi-FiのSSID、passwordはパスワードです。自分の環境に合わせて設定します。

timezoneとdaysavetimeをそれぞれ設定します。

listDir()

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    Serial.printf("Listing directory: %s\n", dirname);

    File root = fs.open(dirname);
    if(!root){
        Serial.println("Failed to open directory");
        return;
    }
    if(!root.isDirectory()){
        Serial.println("Not a directory");
        return;
    }

    File file = root.openNextFile();
    while(file){
        if(file.isDirectory()){
            Serial.print("  DIR : ");
            Serial.print (file.name());
            time_t t= file.getLastWrite();
            struct tm * tmstruct = localtime(&t);
            Serial.printf("  LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec);
            if(levels){
                listDir(fs, file.path(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("  SIZE: ");
            Serial.print(file.size());
            time_t t= file.getLastWrite();
            struct tm * tmstruct = localtime(&t);
            Serial.printf("  LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct->tm_year)+1900,( tmstruct->tm_mon)+1, tmstruct->tm_mday,tmstruct->tm_hour , tmstruct->tm_min, tmstruct->tm_sec);
        }
        file = root.openNextFile();
    }
}

この関数では、指定したディレクトリ内のファイルを表示します。

この関数の引数は、以下の通りです。

  • fs: ファイルシステム(SPIFFS)
  • dirname: ディレクトリ名
  • levels: 表示する階層(0の場合は、指定したディレクトリだけ。1の場合は、1階層下のディレクトリまで)

open()を使って、dirnameをオープンします。オープンした結果は、rootに代入されます。

16行目のif文では、open()で返ってきた値が有効かどうかを、operator boolを使って調べています。指定したファイルパスのオープンに失敗していた場合は、ここで処理を終了します。

20行目のif文では、isDirectory()を使い、オープンしたファイルパスがディレクトリかどうかを調べています。ディレクトリでない場合は、ここで処理を終了します。

25行目では、openNextFile()を使い、ディレクトリ内のファイルパスをオープンします。

fileが有効な間、26行目から46行目のwhileループを実行します。

27行目から35行目は、ファイルパスがディレクトリだった場合の処理です。29行目では、name()によりディレクトリ名を取得し、表示しています。

30行目では、getLastWrite()により、ディレクトリの最終更新時刻を取得しています。getLastWrite()は、time_t型を返すので、31行目で、localtime()を使い、struct tm型に変換しています。

levelsが0でなければ、levelsから1を引いて、listDir(この関数)を再帰呼び出しします。

36行目から44行目は、ファイルパスがディレクトリではなかった場合の処理です。

38行目では、name()によりファイル名を、40行目では、size()を使って、ファイルサイズを取得して表示しています。

41行目では、getLastWrite()により、ファイルの最終更新時刻を取得しています。getLastWrite()は、time_t型を返すので、42行目で、localtime()を使い、struct tm型に変換しています。

最後に、openNextFile()を使って、次のファイルを取得し、26行目に戻ります。

createDir()

49
50
51
52
53
54
55
56
void createDir(fs::FS &fs, const char * path){
    Serial.printf("Creating Dir: %s\n", path);
    if(fs.mkdir(path)){
        Serial.println("Dir created");
    } else {
        Serial.println("mkdir failed");
    }
}

この関数では、ディレクトリを作成します。

この関数の引数は、以下の通りです。

  • fs: ファイルシステム(SPIFFS)
  • path: ディレクトリ名

51行目で、mkdir()を使って、ディレクトリを作成しています。

removeDir()

58
59
60
61
62
63
64
65
void removeDir(fs::FS &fs, const char * path){
    Serial.printf("Removing Dir: %s\n", path);
    if(fs.rmdir(path)){
        Serial.println("Dir removed");
    } else {
        Serial.println("rmdir failed");
    }
}

この関数では、ディレクトリを削除します。

この関数の引数は、以下の通りです。

  • fs: ファイルシステム(SPIFFS)
  • path: ディレクトリ名

60行目で、rmdir()を使って、ディレクトリを削除しています。

readFile()

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
void readFile(fs::FS &fs, const char * path){
    Serial.printf("Reading file: %s\n", path);

    File file = fs.open(path);
    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();
}

この関数では、指定したファイルの内容を表示します。

この関数の引数は、以下の通りです。

  • fs: ファイルシステム(SPIFFS)
  • path: ファイル名

open()を使って、pathをオープンします。オープンした結果は、fileに代入されます。ファイルのオープンに失敗した場合や、pathで指定したファイルパスがディレクトリだった場合は、終了します。

available()が0になるまで、read()で1バイトずつ読み出し表示します。

最後に、close()で、ファイルパスをクローズします。

writeFile()

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
void writeFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Writing file: %s\n", path);

    File file = fs.open(path, FILE_WRITE);
    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();
}

この関数では、指定したファイルにメッセージを書き込みます。

この関数の引数は、以下の通りです。

  • fs: ファイルシステム(SPIFFS)
  • path: ファイル名
  • message: ファイルに書き込むメッセージ

open()を使って、pathをオープンします。ファイルに書き込みを行うので、モードにFILE_WRITEを指定します。オープンした結果は、fileに代入されます。ファイルのオープンに失敗した場合や、pathで指定したファイルパスがファイルでなかった場合は、終了します。

Fileクラスは、Printクラスを引き継いだStreamクラスを引き継いでいるので、91行目のprint()はSerial.print()と同じと思います。

最後に、close()で、ファイルパスをクローズします。

appendFile()

 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
void appendFile(fs::FS &fs, const char * path, const char * message){
    Serial.printf("Appending to file: %s\n", path);

    File file = fs.open(path, FILE_APPEND);
    if(!file){
        Serial.println("Failed to open file for appending");
        return;
    }
    if(file.print(message)){
        Serial.println("Message appended");
    } else {
        Serial.println("Append failed");
    }
    file.close();
}

基本的には、writeFile()と同じです。ただし、ファイルをopen()する際のモードにFILE_APPEND(追記)を指定しています。

renameFile()

115
116
117
118
119
120
121
122
void renameFile(fs::FS &fs, const char * path1, const char * path2){
    Serial.printf("Renaming file %s to %s\n", path1, path2);
    if (fs.rename(path1, path2)) {
        Serial.println("File renamed");
    } else {
        Serial.println("Rename failed");
    }
}

rename()を使って、ファイル名を変更します。

deleteFile()

124
125
126
127
128
129
130
131
void deleteFile(fs::FS &fs, const char * path){
    Serial.printf("Deleting file: %s\n", path);
    if(fs.remove(path)){
        Serial.println("File deleted");
    } else {
        Serial.println("Delete failed");
    }
}

remove()を使って、指定したファイルを削除します。

setup()

133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
void setup(){
    Serial.begin(115200);
    // We start by connecting to a WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println("Contacting Time Server");
	configTime(3600*timezone, daysavetime*3600, "time.nist.gov", "0.pool.ntp.org", "1.pool.ntp.org");
	struct tm tmstruct ;
    delay(2000);
    tmstruct.tm_year = 0;
    getLocalTime(&tmstruct, 5000);
	Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n",(tmstruct.tm_year)+1900,( tmstruct.tm_mon)+1, tmstruct.tm_mday,tmstruct.tm_hour , tmstruct.tm_min, tmstruct.tm_sec);
    Serial.println("");
    
    if(!SPIFFS.begin()){
        Serial.println("Card Mount Failed");
        return;
    }

    listDir(SPIFFS, "/", 0);
    removeDir(SPIFFS, "/mydir");
    createDir(SPIFFS, "/mydir");
    deleteFile(SPIFFS, "/hello.txt");
    writeFile(SPIFFS, "/hello.txt", "Hello ");
    appendFile(SPIFFS, "/hello.txt", "World!\n");
	listDir(SPIFFS, "/", 0);
}
 

Serial.begin()を使って、シリアル通信の初期化を行います。

WiFi.begin()を使って、Wi-Fiアクセスポイントに接続します。その後、WiFi.status()が、WL_CONNECTEDになるまで待ちます。Wi-Fiアクセスポイントに接続した後は、WiFi.localIP()を使って、IPアドレスを取得し、取得した値を表示します。

155行目では、configTime()を使って、NTPサーバの設定を行い、時刻を同期します。timezoneは、UTCとのオフセットを時間で示したもの、daysavetimeは、夏時間の際のオフセットを時間で示したものです。configTime()の引数は、双方とも秒単位なので、ここでは3600倍して、時間を秒に変換しています。なお、このプログラム例では、それぞれ1と定義されているため、UTCからのオフセットは1時間で、夏時間で1時間進んでいる地域向けの設定となります。日本の場合は、timezoneを9、daysavetimeを0と設定します。

getLocalTime()で、現在時刻を取得して表示します。

次に、SPIFFS::begin()を使って、SPIFFSを初期化します。SPIFFSは、SPIFFSライブラリにより事前定義された変数です。

その後は、以下の関数を順に呼び出します。

なぜか、renameFile()readFile()は呼び出していないようです。

loop()

173
174
175
void loop() {

}

何もしません。

バージョン

Hardware:ESP-WROOM-32
Software:Arduino core for the ESP32 2.0.4

最終更新日

September 4, 2022

inserted by FC2 system