ESP32 / ESPAsyncWebServer and storing email address to SPIFFS issue

Hi all, my first post in this forum :slight_smile:

Have an ESP32 and running everything from Arduino IDE.
Using ESPAsyncWebServer and trying to use forms to store some data locally using SPIFFS.

Everything works except storing the email address, resulting in panic and reboot of the ESP.

If anybody could assist me in resolving the issue about storing the email address, I would be quite happy :slight_smile:

/*********
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-esp8266-input-data-html-form/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*********/

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <SPIFFS.h>
#include <ESPAsyncWebServer.h>

AsyncWebServer server(80);


#define ESP_getChipId()   ((uint32_t)ESP.getEfuseMac())
String espID = String(ESP_getChipId(), HEX);
  
// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "SSID";
const char* password = "PASSWORD";

const char* PARAM_AP_SSID = "ap_ssid";
const char* PARAM_AP_PWD = "ap_pwd";
const char* PARAM_EMAIL = "email";
const char* PARAM_AMOUNT = "amount";

// HTML web page to handle 3 input fields (email, inputInt, inputFloat)
const char index_html[] PROGMEM = R"rawliteral(
  <!DOCTYPE HTML>
  <html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

    
    <style>
      div.center {text-align: center;}
    </style>
    

    

  
    <script>
      function submitMessage() {
        alert("Saved value to ESP SPIFFS");
        setTimeout(function(){ document.location.reload(false); }, 500);   
      }
    </script>
    </head>
    <body>
      <div class="container">
        <form action="/get" target="hidden-form">

          <div class="form-group">
            <label for="ap_ssid">Skriv inn aksesspunkt SSID for internett (nåværende: %ap_ssid%)</label>
            <input type="text" class="form-control" id="ap_ssid" placeholder="SSID" name="ap_ssid">
          </div>
        <button onclick="submitMessage()" type="submit" class="btn btn-primary">Lagre</button>
        </form>
      </div>
  


      <div class="container">
        <form action="/get" target="hidden-form">
          <div class="form-group">
            <label for="pwd">Passord for aksesspunkt (nåværende: %ap_pwd%)</label>
            <input type="password" class="form-control" id="ap_pwd" placeholder="Passord" name="ap_pwd">
          </div>
        <button onclick="submitMessage()" type="submit" class="btn btn-primary">Lagre</button>
        </form>
      </div>
  


      <div class="container">
        <form action="/get" target="hidden-form">        
          <div class="form-group">
            <label for="email">Skriv inn epost adressen som skal motta varsler (nåværende: %email%)</label>
            <input type="email" class="form-control" id="email" placeholder="Din epostadresse" name="email">
          </div>
        <button onclick="submitMessage()" type="submit" class="btn btn-primary">Lagre</button>
        </form>
      </div>
  


      <div class="container">
        <form action="/get" target="hidden-form">
          <div class="form-group">
            <label for="amount">Skriv inn antall ML i dosering - 1, 2 eller 3 (nåværende: %amount%)</label>
            <input type="number " class="form-control" id="email" placeholder="1, 2 eller 3" name="amount">
          </div>
        <button onclick="submitMessage()" type="submit" class="btn btn-primary">Lagre</button>
        </form>
      </div>
      <iframe style="display:none" name="hidden-form"></iframe>
    </body>
    </html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}
//      <input type="submit" value="Lagre" onclick="submitMessage()">
String readFile(fs::FS &fs, const char * path){
  Serial.printf("Reading file: %s\r\n", path);
  File file = fs.open(path, "r");
  if(!file || file.isDirectory()){
    Serial.println("- empty file or failed to open file");
    return String();
  }
  Serial.println("- read from file:");
  String fileContent;
  while(file.available()){
    fileContent+=String((char)file.read());
  }
  Serial.println(fileContent);
  return fileContent;
}

void writeFile(fs::FS &fs, const char * path, const char * message){
  Serial.printf("Writing file: %s\r\n", path);
  File file = fs.open(path, "w");
  if(!file){
    Serial.println("- failed to open file for writing");
    return;
  }
  if(file.print(message)){
    Serial.println("- file written");
  } else {
    Serial.println("- write failed");
  }
}

// Replaces placeholder with stored values
String processor(const String& var){
  //Serial.println(var);
  if(var == "ap_ssid"){
    return readFile(SPIFFS, "/ap_ssid.txt");
  }
  else if(var == "ap_pwd"){
    return readFile(SPIFFS, "/ap_pwd.txt");
  }
  else if(var == "email"){
    return readFile(SPIFFS, "/email.txt");
  } 
  else if(var == "amount"){
    return readFile(SPIFFS, "/amount.txt");
  }
  return String();
}

void setup() {
  Serial.begin(115200);
 
  // Initialize SPIFFS
  if(!SPIFFS.begin(true)){
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }


  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
  }
  Serial.println();
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Send web page with input fields to client
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Send a GET request to <ESP_IP>/get?email=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String inputMessage;
    
    // GET email value on <ESP_IP>/get?ap_ssid=<inputMessage>
    if (request->hasParam(PARAM_AP_SSID)) {
      inputMessage = request->getParam(PARAM_AP_SSID)->value();
      writeFile(SPIFFS, "/ap_ssid.txt", inputMessage.c_str());
    }
    
    // GET inputInt value on <ESP_IP>/get?ap_pwd=<inputMessage>
    else if (request->hasParam(PARAM_AP_PWD)) {
      inputMessage = request->getParam(PARAM_AP_PWD)->value();
      writeFile(SPIFFS, "/ap_pwd.txt", inputMessage.c_str());
    }
    
    // GET inputFloat value on <ESP_IP>/get?email=<inputMessage>
    else if (request->hasParam(PARAM_EMAIL)) {
      inputMessage = request->getParam(PARAM_AMOUNT)->value();
      writeFile(SPIFFS, "/email.txt", inputMessage.c_str());
    }

    // GET inputFloat value on <ESP_IP>/get?amount=<inputMessage>
    else if (request->hasParam(PARAM_AMOUNT)) {
      inputMessage = request->getParam(PARAM_AMOUNT)->value();
      writeFile(SPIFFS, "/amount.txt", inputMessage.c_str());
    }    
    else {
      inputMessage = "No message sent";
    }
    Serial.println(inputMessage);
    request->send(200, "text/text", inputMessage);
  });
  server.onNotFound(notFound);
  server.begin();
}

void loop() {
  // To access your stored values on email, inputInt, inputFloat
  String your_ap_ssid = readFile(SPIFFS, "/ap_ssid.txt");
  Serial.print("*** Ditt Aksesspunkt: ");
  Serial.println(your_ap_ssid);

  String your_ap_pwd = readFile(SPIFFS, "/ap_pwd.txt");
  Serial.print("*** Ditt AP passord: ");
  Serial.println(your_ap_pwd);
  
  String your_email = readFile(SPIFFS, "/email.txt");
  Serial.print("*** Din epost: ");
  Serial.println(your_email);
  
  int your_amount = readFile(SPIFFS, "/amount.txt").toInt();
  Serial.print("*** Ditt tall: ");
  Serial.println(your_amount);
  
  delay(5000);
}

Aren't you supposed to close the files after access ?

Weird thing is that all the others work, only the email fails.

thestigh:
Weird thing is that all the others work, only the email fails.

Make sure you close the files, reset the SPIFFS by uploading a sketch with no SPIFFS.
I did have a couple of other questions.writeFile(SPIFFS, "/ap_ssid.txt", inputMessage.c_str());The way you cast the inputMessage to a cstring here. Are you absolutely sure that the memory is still allocated when it is being read ? Optimizers can do unexpected things. I would create a char buffer (of a defined size) just in case.
return String(); is the same as return "";i guess.fileContent+=String((char)file.read());works, but the cast to a String is overkill.fileContent += (char) file.read();will do, you can add characters to String. I am not sure if it causes fragments the way you do it, and the size of you files are such that it shouldn't matter, but anyway. Just trying to be helpful here.

Are you absolutely sure that the memory is still allocated when it is being read ?

Easy way to check would be to replace it with an actual const char * and see if the problem persists.

thestigh:

// GET inputFloat value on <ESP_IP>/get?email=<inputMessage>

else if (request->hasParam(PARAM_EMAIL)) {
     inputMessage = request->getParam(PARAM_AMOUNT)->value();
     writeFile(SPIFFS, "/email.txt", inputMessage.c_str());
   }

Why "PARAM_AMOUNT" in line 3 ??

Erik_Baas:
Why "PARAM_AMOUNT" in line 3 ??

That was it (!) A typo !

What is the panic message?

Did you put the debug code into the ESP Exception Decoder GitHub - me-no-dev/EspExceptionDecoder: Exception Stack Trace Decoder for ESP8266 and ESP32?

What is the exception decoder message?

Deva_Rishi:
Make sure you close the files, reset the SPIFFS by uploading a sketch with no SPIFFS.
I did have a couple of other questions.[

I can't really answer your questions yet, still learning about SPIFFS. The basics in this code was originally a tutorial that has been modified to suit my needs. I would definitely like to optimize the code to use less memory as this is only a small part of code that at the end will be running on my ESP32.

It will also contain a HX711 to control a weight, an INA219 to monitor a batterpack, an IRF520 to control a motor and post the data to a cloud service for creating statistics.

If I could ask the experts on how to optimize this for mem usage, that would be highly appreciated!

PS; the code in the void loop was just there for debugging.

That was it (!) A typo !

A copy-paste error, it happens.

Idahowalker:
What is the panic message?

Did you put the debug code into the ESP Exception Decoder GitHub - me-no-dev/EspExceptionDecoder: Exception Stack Trace Decoder for ESP8266 and ESP32?

What is the exception decoder message?

Didn't know about that one :slight_smile: Thanks (still learning!)