Demo 45: Copy data from/to SPIFFS without using mkspiffs (web file server)

1. Introduction
This tutorial assumed that you are familiar with SPIFFS Filesystem (a file system intended for SPI NOR flash devices on embedded targets).
If you want to store small data, you can use SPIFFS instead of sdcard module.
In order to use sdcard module, refer Demo 7: How to use Arduino ESP32 to store data to sdcard
If you are using SPIFFS, you may face the inconvenient situation that you want to copy data from/to SPIFFS. You have to install ESP32FS as a plugin of Arduino-version following steps:
  + Download the ESP32FS-x.x.zip at the link.
  + Unzip and copy unziped folder to "where_to_installed_Arduino/tools/"
then it will become "where_to_installed_Arduino/tools/ESP32FS/tool/esp32fs.jar"
  + Create a Sketch project named "xyz". A folder named "xyz" will be created.
  + Create a folder named "data" and copied the files that you want to copy to SPIFFS into "data" folder.
  + From Arduino menu, choose Tools > ESP32 Sketch Data Upload
Note: when copying files to SPIFFS, keep pressing the Boot button on ESP module.
This tutorial will help you to copy files from/to (2 directions) SPIFFS easier.
Figure: copy files to/from SPIFFS as Web File Server
2. Hardware
You only need a ESP32 module.
3. Software
I will use webserver to create a web file server.
Please refer Demo 12: How to turn the Arduino ESP32 into a Web Server
Here is the full source code with comments:

  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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#include <WiFiClient.h>
#include <ESP32WebServer.h>
#include <WiFi.h>
#include <ESPmDNS.h>
#include "FS.h"
#include "SPIFFS.h"

String serverIndex = "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
    "<input type='file' name='update'>"
    "<input type='submit' value='Upload'>"
"</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
"$('form').submit(function(e){"
    "e.preventDefault();"
      "var form = $('#upload_form')[0];"
      "var data = new FormData(form);"
      " $.ajax({"
            "url: '/update',"
            "type: 'POST',"               
            "data: data,"
            "contentType: false,"                  
            "processData:false,"  
            "xhr: function() {"
                "var xhr = new window.XMLHttpRequest();"
                "xhr.upload.addEventListener('progress', function(evt) {"
                    "if (evt.lengthComputable) {"
                        "var per = evt.loaded / evt.total;"
                        "$('#prg').html('progress: ' + Math.round(per*100) + '%');"
                    "}"
               "}, false);"
               "return xhr;"
            "},"                                
            "success:function(d, s) {"    
                "console.log('success!')"
           "},"
            "error: function (a, b, c) {"
            "}"
          "});"
"});"
"</script>";

const char* ssid = "707";
const char* password = "0000000000";
bool opened = false;
File file;

#define FORMAT_SPIFFS_IF_FAILED true
ESP32WebServer server(80);

String listDir(fs::FS &fs, const char * dirname, uint8_t levels){
    String response = "";
    Serial.printf("Listing directory: %s\r\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.println(file.name());
            if(levels){
                listDir(fs, file.name(), levels -1);
            }
        } else {
            Serial.print("  FILE: ");
            Serial.print(file.name());
            Serial.print("\tSIZE: ");
            Serial.println(file.size());
            response += String("<a href='") + String(file.name()) + String("'>") + String(file.name()) + String("</a>") + String("</br>");
        }
        file = root.openNextFile();
    }
    return String("List files:</br>") + response + String("</br></br> Upload file:") + serverIndex;
}

void handleRoot() {
  String res = listDir(SPIFFS, "/", 0);
  server.send(200, "text/html", res);
}

bool loadFromSPIFFS(String path){
  String dataType = "text/plain";
  if(path.endsWith("/")) path += "index.htm";

  if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  else if(path.endsWith(".jpg")) dataType = "image/jpeg";
  else if(path.endsWith(".txt")) dataType = "text/plain";
  else if(path.endsWith(".zip")) dataType = "application/zip";  

  File dataFile = SPIFFS.open(path.c_str());

  if (!dataFile)
    return false;

  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
    Serial.println("Sent less data than expected!");
  }

  dataFile.close();
  return true;
}

void handleNotFound(){
  if(loadFromSPIFFS(server.uri())) return;
  String message = "SDCARD Not Detected\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){
    message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  Serial.println(message);
}

void setup(void){
  Serial.begin(115200);
  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());
  
  //use IP or iotsharing.local to access webserver
  if (MDNS.begin("iotsharing")) {
    Serial.println("MDNS responder started");
  }
  //init spiffs
  if(!SPIFFS.begin(FORMAT_SPIFFS_IF_FAILED)){
    Serial.println("SPIFFS Mount Failed");
    return;
  }
  //handle uri  
  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  /*handling uploading file */
  server.on("/update", HTTP_POST, [](){
    server.sendHeader("Connection", "close");
    opened = false;
  },[](){
    HTTPUpload& upload = server.upload();
    if(opened == false){
        opened = true;
        file = SPIFFS.open(String("/") + upload.filename, FILE_WRITE);
        if(!file){
            Serial.println("- failed to open file for writing");
            return;
        }
    } 
    if(upload.status == UPLOAD_FILE_WRITE){
      if(file.write(upload.buf, upload.currentSize) != upload.currentSize){
        Serial.println("- failed to write");
        return;
      }
    } else if(upload.status == UPLOAD_FILE_END){
        opened = false;
    }
  });
  server.begin();
  Serial.println("HTTP server started");
}

void loop(void){
  server.handleClient();
}
4. Result
Type "iotsharing.local" in web-browser you will see this.
Figure: GUI of demo

Post a Comment

2 Comments

markson said…
Being inventive with what you have: More information by and large implies more work for the examiner. machine learning course in pune
Unknown said…
Is this possible with a soft AP?