2017/09/11

ESP8266 - Working with SPIFFS disk

This post is about my experience working with the SPIFFS disk.

The environment

OS: Windows 8.1
Arduino IDE Version: 1.8.4 / 1.8.1
ESP8266 Module: NodeMCU v1.0

Getting the Arduino plugin for uploading files to ESP8266

The project page for this plugin as well the installation instruction is at https://github.com/esp8266/arduino-esp8266fs-plugin.


The source code can be downloaded at the link below.
https://github.com/esp8266/arduino-esp8266fs-plugin/releases/tag/0.3.0


Installing the Arduino plugin for uploading files to ESP8266

Make sure you use one of the supported versions of Arduino IDE and have ESP8266 core installed.

1. Download the tool archive from releases page.

2. In your Arduino sketchbook directory, create tools directory if it doesn't exist yet.

Q. How to find the sketchbook directory
Ans.: In Arduino IDE, go to File -> Preferences to find the Sketchbook location.


Create a directory call "tools".


3. Unpack the tool into tools directory (the path will look like <home_dir>/Arduino/tools/ESP8266FS/tool/esp8266fs.jar).


Note, Don't just copy the file "esp8266fs.jar" to the newly created "tools" directory. Copy the entire directory structure that contains "esp8266fs.jar" to the new directory.

4. Restart Arduino IDE.

A new option called "ESP8266 Sketch Data Upload" is now available.


Uploading sketch data to the SPIFFS disk

1. Open the "ConfigFile" sample sketch that comes with the ESP8266 samples.


2. Save the ConfigFile to a new location.


3. Create a new directory called "data" inside the "ConfigFile" directory.

Note,  Anything inside this "data" folder will be uploaded to the SPIFFS disk when the "ESP8266 Sketch Data Upload" is executed.


4. Create a JSON configuration file that stores some settings.

Note, You could use tools such as "JSON Editor Online" (http://www.jsoneditoronline.org/) to simplify the job.


5. Copy the content on the left of "JSON Editor Online" above and paste it into a file called "config.json" which is saved under the "data" directory created above.


Below is the content of "config.json".


Note, Be sure to have ArduinoJson library installed as it will help greatly with the encoding and decoding of JSON data.


6. Upload the sketch data to NodeMCU.

Follow the settings below to setup the parameters for uploading Arduino sketch and the sketch data.

Note,

- If "4M (3M SPIFFS)" is selected instead of "4M (1M SPIFFS)", it will take 3X the time to upload the sketch data even when the sketch data may contain only 1K byte of data.

- NodeMCU is perfectly O.K. to handle upload speed of 921600. When possible, select this speed to reduce the uploading time.


Select "Tools' -> "ESP8266 Sketch Data Upload" menu item. This should start uploading the sketch data to the SPIFFS disk and the progress is display in the message window below.

Note, Be sure to close the Serial Monitor window before uploading the sketch data or the upload will fail.


Reading the content of "config.json" from the SPIFFS disk

1. Modify the original "ConfigFile.ino".

The "ConfigFile.ino" below is modified to read the configuration from the "config.json" file stored in the SPIFFS. The modified parts are highlighted in red.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
// Example: storing JSON configuration file in flash file system
//
// Uses ArduinoJson library by Benoit Blanchon.
// https://github.com/bblanchon/ArduinoJson
//
// Created Aug 10, 2015 by Ivan Grokhotkov.
//
// This example code is in the public domain.

#include <ArduinoJson.h>
#include "FS.h"

bool loadConfig() {
  File configFile = SPIFFS.open("/config.json", "r");
  if (!configFile) {
    Serial.println("Failed to open config file");
    return false;
  }

  size_t size = configFile.size();
  if (size > 1024) {
    Serial.println("Config file size is too large");
    return false;
  }

  // Allocate a buffer to store contents of the file.
  std::unique_ptr<char[]> buf(new char[size]);

  // We don't use String here because ArduinoJson library requires the input
  // buffer to be mutable. If you don't use ArduinoJson, you may as well
  // use configFile.readString instead.
  configFile.readBytes(buf.get(), size);
  Serial.println(buf.get());

  StaticJsonBuffer<1024> jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(buf.get());

  if (!json.success()) {
    Serial.println("Failed to parse config file");
    return false;
  }

  const char* serverName = json["serverName"];
  const char* accessToken = json["accessToken"];

  // Real world application would store these values in some variables for
  // later use.

  Serial.print("Loaded serverName: ");
  Serial.println(serverName);
  Serial.print("Loaded accessToken: ");
  Serial.println(accessToken);
  return true;
}

bool saveConfig() {
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();
  json["serverName"] = "api.example.com";
  json["accessToken"] = "128du9as8du12eoue8da98h123ueh9h98";

  File configFile = SPIFFS.open("/config.json", "w");
  if (!configFile) {
    Serial.println("Failed to open config file for writing");
    return false;
  }

  json.printTo(configFile);
  return true;
}

void setup() {
  Serial.begin(115200);
  Serial.println("");
  delay(1000);
  Serial.println("Mounting FS...");

  if (!SPIFFS.begin()) {
    Serial.println("Failed to mount file system");
    return;
  }
/*
  if (!saveConfig()) {
    Serial.println("Failed to save config");
  } else {
    Serial.println("Config saved");
  }
*/
  if (!loadConfig()) {
    Serial.println("Failed to load config");
  } else {
    Serial.println("Config loaded");
  }
}

void loop() {
  yield();
}

2. Upload the modified "ConfigFile.ino" to NodeMCU.

3. Run the sketch.

After the sketch data and Arduino sketch have both been uploaded, open the Serial Terminal Window then press the RST button on the NodeMCU board to run the Arduino sketch.


The content of "config.json" written into the SPIFFS disk is read by the Arduino sketch and display below.


Changing the content of "config.json" in the SPIFFS disk using Arduino sketch

The sketch below writes new configuration to "config.json" stored on the SPIFFS disk.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 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
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
// Example: storing JSON configuration file in flash file system
//
// Uses ArduinoJson library by Benoit Blanchon.
// https://github.com/bblanchon/ArduinoJson
//
// Created Aug 10, 2015 by Ivan Grokhotkov.
//
// This example code is in the public domain.

#include <ArduinoJson.h>
#include "FS.h"

bool loadConfig() {
  File configFile = SPIFFS.open("/config.json", "r");
  if (!configFile) {
    Serial.println("Failed to open config file");
    return false;
  }

  size_t size = configFile.size();
  if (size > 1024) {
    Serial.println("Config file size is too large");
    return false;
  }

  // Allocate a buffer to store contents of the file.
  std::unique_ptr<char[]> buf(new char[size]);

  // We don't use String here because ArduinoJson library requires the input
  // buffer to be mutable. If you don't use ArduinoJson, you may as well
  // use configFile.readString instead.
  configFile.readBytes(buf.get(), size);
  Serial.println(buf.get());

  StaticJsonBuffer<1024> jsonBuffer;
  JsonObject& json = jsonBuffer.parseObject(buf.get());

  if (!json.success()) {
    Serial.println("Failed to parse config file");
    return false;
  }

  const char* serverName = json["serverName"];
  const char* accessToken = json["accessToken"];

  // Real world application would store these values in some variables for
  // later use.

  Serial.print("Loaded serverName: ");
  Serial.println(serverName);
  Serial.print("Loaded accessToken: ");
  Serial.println(accessToken);
  return true;
}

bool saveConfig() {
  StaticJsonBuffer<200> jsonBuffer;
  JsonObject& json = jsonBuffer.createObject();
  json["serverName"] = "api.example.com";
  json["accessToken"] = "128du9as8du12eoue8da98h123ueh9h98";

  File configFile = SPIFFS.open("/config.json", "w");
  if (!configFile) {
    Serial.println("Failed to open config file for writing");
    return false;
  }

  json.printTo(configFile);
  return true;
}

void setup() {
  Serial.begin(115200);
  Serial.println("");
  delay(1000);
  Serial.println("Mounting FS...");

  if (!SPIFFS.begin()) {
    Serial.println("Failed to mount file system");
    return;
  }

// Comment the section below to disable writing config.json to SPIFFS disk
//------------------------------------------------------------------------
  if (!saveConfig()) {
    Serial.println("Failed to save config");
  } else {
    Serial.println("Config saved");
  }
//------------------------------------------------------------------------

  if (!loadConfig()) {
    Serial.println("Failed to load config");
  } else {
    Serial.println("Config loaded");
  }
}

void loop() {
  yield();
}

Below is the result.


Below is the output result after commenting out line 85 ~ 89 (the part that saves configuration to the SPIFFS disk) of the above code. Indeed the new configuration has been written into the "config.json" on the SPIFFS disk.


Upload the sketch data then run the same code again. The content of the newly uploaded sketch data is displayed.


From the examples above, it's clear that the SPIFFS disk can be read and written by Arduino sketch.

Reference:

 #121 SPIFFS and JSON to save configurations on an ESP8266
https://youtu.be/jIOTzaeh7fs.

No comments:

Post a Comment