Extracting both SPIFFS file data and non-file data from ESP8266

Currently I am using the included sketch to pull up SPIFFS file data through a web browser 'Get' request. It works fine. I want to add a webpage display of data from the ESP8266 that is not in the SPIFFS file.
What would be the additional library file(s), if any, I would need to display the webpage data through a client request and not conflict with the AsyncWebServer? There is a ton of ESP8266 IDE Examples but I am unsure which is appropriate for my situation.
Or could I somehow grab the SPIFFS files data during my client request and have that output through a client.print function along with the other data?

thanks for your interest....


```cpp
#include <ESP8266WiFi.h>  

#include <LittleFS.h>
#include <time.h> 
#include <tz.h>   

#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#elif defined(ESP8266)
#include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebSrv.h>

AsyncWebServer server(80);

const char *ssid = "Homestead-LAN_EXT";
const char *password = "XXXXXXXX";
const char *PARAM_MESSAGE = "message";

int Initial_Connect_Attempts = 0;
int Try_Count = 0;

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Nope....notta....Not found");
}
int RunLEDState = LOW;
int OutageLEDState = LOW;

unsigned long currentMillis;
unsigned long previous_Blink_Millis = 0;
const long blink_interval = 2000;


unsigned long previous_TimeStamp_Millis = 0;
unsigned long previous_LED_Millis = 0;
const long TimeStamp_interval = 86400000;  // milliseconds [1 per day]

const long LED_interval = 200;  // Power Outage LED pulsate time period

const int Min_Voltage = 400;  // Input range 0 - 1023; 0 = 0 vdc, 1023 = 3 vdc
const int Restore_Voltage = 830;

bool update_clock = false;
bool Pwr_Restore_timestamp = false;
bool Pwr_Out_timestamp = false;
bool Outage_Detected = false;
bool End_Of_Outage = false;
bool Reset_Pressed = false;

const int Outage_LED = D7;        // GPIO13 = Bd. Label D7
const int LED_Reset_Button = D8;  // GPI15  = Bd. Label D8
int testOR0 = 0;                  // change to 1000 for testing

const int Vdc_Input = A0;  // ADCO   = Bd. Label A0

int Voltage_Value = 800;  // DC input from power module using voltage divider

void update_time();
void setup() {

  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  /* if (WiFi.waitForConnectResult() != WL_CONNECTED) {
        Serial.printf("WiFi Failed!\n");
        return;
    }
    */
  Serial.println("\nConnecting to WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(1000);
  }
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // LittleFS.begin();

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Enter /power for Outage file.");
  });
  server.on("/power", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(LittleFS, "PowerOutageFile.txt", "text/plain");
  });


  // Send a GET request to <IP>/get?message=<message>
  server.on("/get", HTTP_GET, [](AsyncWebServerRequest *request) {
    String message;
    if (request->hasParam(PARAM_MESSAGE)) {
      message = request->getParam(PARAM_MESSAGE)->value();
    } else {
      message = "What's up?";
    }
    request->send(200, "text/plain", "Hello, GET: " + message);
  });

  server.onNotFound(notFound);

  server.begin();

  //                    *********************************************************************
  Serial.setDebugOutput(true);

  configTime(TZ_America_Chicago, "pool.ntp.org", "time.nist.gov");
  Serial.println("\nWaiting for time");
  while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }
  if (!LittleFS.begin()) {
    Serial.println();
    Serial.println("Crap. An Error has occurred while mounting SPIFFS");
    return;
  }

  pinMode(LED_BUILTIN, OUTPUT);      // Processor run indicator
  pinMode(Outage_LED, OUTPUT);       // RED LED on shield
  pinMode(LED_Reset_Button, INPUT);  // Pushbutton on 8266 Shield

}

void loop() {
  time_t now = time(nullptr);
  Serial.println(ctime(&now));
  delay(testOR0);  // change to 1000 to slow serial output for testing

  currentMillis = millis();
  if (currentMillis - previous_Blink_Millis >= blink_interval) {
    previous_Blink_Millis = currentMillis;
    if (RunLEDState == LOW) {
      RunLEDState = HIGH;
    } else (RunLEDState = LOW);
    digitalWrite(LED_BUILTIN, RunLEDState);
  }

  if (currentMillis - previous_TimeStamp_Millis >= TimeStamp_interval) {
    previous_TimeStamp_Millis = currentMillis;
    update_clock = true;
  }

  Voltage_Value = analogRead(Vdc_Input);
  Serial.println("Voltage Input:  ");
  Serial.print(Voltage_Value);
  Serial.println();

  if (update_clock == true && Voltage_Value >= Restore_Voltage) {  // prevent timestamp update attempt
    update_time();                                                 // during power outage
    update_clock = false;
  }

  if (Voltage_Value <= Min_Voltage && Outage_Detected == false && Pwr_Out_timestamp == false) {
    Serial.print("Outage detected!  ");  // Low/No voltage detected.
    Serial.print("Outage Date/Time: ");
    Serial.println(ctime(&now));
    Serial.println();

    Pwr_Out_timestamp = true;
    Outage_Detected = true;

    File fileToAppend = LittleFS.open("/PowerOutageFile.txt", "a");

    if (!fileToAppend) {
      Serial.println("Crap. There was an error opening the file for appending outage detected.");
      return;
    }
    if (fileToAppend.print("Outage Start:    "))
      ;  // timestamp outage start time

    if (fileToAppend.println(ctime(&now))) {
      Serial.println("Yay! Timestamp was added.");
    } else {
      Serial.println("Crap. File append failed");
    }

    fileToAppend.close();
  }
  if (Voltage_Value >= Restore_Voltage && Outage_Detected == true && Pwr_Restore_timestamp == false)  // Outage ends : power returns
  {
    Pwr_Restore_timestamp = true;

    File fileToAppend = LittleFS.open("/PowerOutageFile.txt", "a");  // timestamp end of outage to file

    if (!fileToAppend) {
      Serial.println("Crap. There was an error opening the file for appending power restoration");
      return;
    }
    if (fileToAppend.print("Power Restored:  "))
      ;  // timestamp outage restoration time

    if (fileToAppend.println(ctime(&now))) {
      Serial.println("Yay! Power restored timestamp was appended to file!");
    } else {
      Serial.println("Crap. File append failed");
    }

    fileToAppend.close();

    End_Of_Outage = true;
    Serial.print("End Of Outage = ");
    Serial.println(End_Of_Outage);
    Serial.println();
  }

  if (digitalRead(LED_Reset_Button) == HIGH)  // reset button pressed to acknowledge outage
  {                                           // and reset boolean flags
    End_Of_Outage = false;
    Outage_Detected = false;
    Pwr_Restore_timestamp = false;
    Pwr_Out_timestamp = false;
    digitalWrite(Outage_LED, LOW);  // Turn off Red LED
    Serial.print("End Of Outage =   ");
    Serial.println(End_Of_Outage);
    Serial.println();
    Serial.print("Outage Detected =   ");
    Serial.println(Outage_Detected);
    Serial.println();
  }

  if (Pwr_Restore_timestamp == true)  // Pulsate Power Outage LED AFTER power returns
  {
    if (currentMillis - previous_LED_Millis >= LED_interval) {
      previous_LED_Millis = currentMillis;
      if (OutageLEDState == LOW) {
        OutageLEDState = HIGH;
      } else {
        OutageLEDState = LOW;
      }
      digitalWrite(Outage_LED, OutageLEDState);
    }
  } 
  

}

void update_time() {

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    Initial_Connect_Attempts++;
    Serial.println("Attempting to Connect To Local Network:   ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    delay(4000);
    if (Initial_Connect_Attempts == 5) return ;  // give up after 5 trys and wait for next cycle
    Serial.print(".");
  }

  configTime(TZ_America_Chicago, "pool.ntp.org", "time.nist.gov");
  Serial.println("\nWaiting for time");
  while (!time(nullptr)) {
    Serial.print(".");
    delay(1000);
  }
}

So you want display data from Esp8266 to webpage .Data which is updated through out the time that is not stored in SPIFFS

Do you know HTML? Do you want to?

You can do all this "by hand". If the page is relatively small, you could build a single C-string or String and send it in one shot

  server.on("/webpage", HTTP_GET, [](AsyncWebServerRequest *request) {
    String html;
    html.reserve(1000);
    html += "<!DOCTYPE html>";
    html += "<ul>";
    for (int i = 1; i < 100; ++i) {
      html += "<li>";
      html += i;
    }
    html += "</ul>";
    request->send(200, "text/html", html);
  });

If it's bigger, you can "print as you go" with a chunked response, but that is more complicated. Still doable.

And you can combine data from the SPIFFS file to generate a single page, by adding code to open and read the file. No additional (third party) libraries needed either.

The SPIFFS file data only changes when an infrequent power outage event occurs.
The other data will be information like the current time & date. I want to verify
the ESP is working off an accurate date/time so my SPIFFS file entries will be accurate.

I know what the mnemonic means...lol. I have played with it through some online tutorials and would like to understand it better at some point; just to embellish my webpages would
be nice.
I like this idea of using a Get request to ask for BOTH the SPIFFS file contents and the
non-file data. Do you know of any good links that demonstrate this process in more detail?
I definitely will play around with the code you provided to see if I can get some things working.
Thanks for your input!

Then you can try using websocket or set the webpage to update itself at regular intervals

Better to have a specific objective when trying to learn something new. Additionally, one feature of AsyncWebServer is templates.

const uint8_t outage_template[] PROGMEM = R"=/=(
<!DOCTYPE html>
<p>Date and time %DATE_TIME%
<p>Outages %OUTAGE_EMPTY%
<pre>
%OUTAGE_TXT%
</pre>
)=/=";

If you're not familiar, this is a raw string, with an R before the opening double-quote, and then parentheses ( ) around text, with optional arbitrary delimiters (=/= here) in case a closing parenthesis is in your text. So you can easily copy&paste your HTML. That's a C++ language feature.

The template placeholders are delimited with '%'. The handler is then like

  server.on("/power", HTTP_GET, [](AsyncWebServerRequest *request) {
    File outage_file = LittleFS.open("/PowerOutageFile.txt", FILE_READ);
    bool outage_missing = !outage_file;
    String outage_string;
    if (outage_file) {
      outage_string = outage_file.readString();
      outage_file.close();
    }
    auto outage_processor = [&](const String &var) -> String {
      if (var == "DATE_TIME") {
        time_t now = time(nullptr);
        return ctime(&now);
      } else if (var == "OUTAGE_EMPTY") {
        return outage_missing ? "missing" : outage_string.length() ? "" : "empty";
      }
      return outage_string;
    };
    request->send_P(200, "text/html", outage_template, sizeof(outage_template), outage_processor);
  });

BTW, your sketch uses LittleFS (I don't have any boards with a LittleFS partition), not SPIFFS.

kenb4,

I did successfully run your first code block that generated the dot with each
successive number down the screen ending at 100. I was looking at the code to see
what actually generated the "dot."

And now you have provided further explanation about 'templates' which allows such things
as retrieving date/time. This was very helpful. I need to read up further on using this feature
as it zeros in on my objective.

I misspoke there. LittleFS is the newer filesystem succesor to SPIFFS and I need to stop referring to SPIFFS, as you pointed out that is incorrect. :+1:

If I am going to continue with this microcontroller hobby I need to dedicate more energy to my coding education by getting reference books/taking online courses. I can see by your use of terminology like 'handler' and 'placeholder' you either have a formal education regarding code or have thoroughly learned it on your own.
I appreciate your input and will next study your latest code block.
I never think my coding proficiencies will become 2nd nature but I still want to better develop my understanding.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.