Language: EN

como-servir-contenido-desde-memoria-flash-en-el-esp8266

How to serve content from Flash memory on ESP8266 or ESP32

In this post in the section on the ESP8266 and ESP32, we will see how to serve content from Flash memory to avoid unnecessary consumption of RAM.

We will refer to the ESP8266, but the same code is compatible with the ESP32, adjusting the names of the libraries. At the end you have the code for both the ESP8266 and the ESP32.

In previous entries we have seen how to create a simple server, how to distinguish between requests and read parameters, and how to serve dynamic content by generating a String in the request.

We already said that one of the problems of generating content dynamically is that it puts a load on the processor (compared to generating a static file) and that, if the response is long, it takes up a lot of memory in the variable space.

One way to avoid the latter is to store the static parts of the response in Flash memory and combine them with those that will actually change. This partly alleviates the problem of memory usage.

Note that this should only be used for dynamic content, i.e. content that will change between requests. For serving static content, we have better alternatives such as SPIFFS, which we will see in the next entry.

Serving content from Flash

Serving content from Flash memory is really simple.

Our Sketch is practically the same, we have only included a new file ‘index.h’ that will contain the String to be served.

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

bool ledStatus = false;  // Example variable

#include "config.h"  // Replace with your network data
#include "index.h"
#include "ESP8266_Utils.hpp"
#include "Server.hpp"

void setup(void) 
{
   Serial.begin(115200);

   ConnectWiFi_STA();
   
   InitServer();
}
 
void loop()
{
   server.handleClient();
}

Finally, our ‘Server.hpp’ file looks like this.

ESP8266WebServer server(80);

void handleRoot() {
   String response = MAIN_page;
   server.send(200, "text/html", response);
}

void handleNotFound() {
   server.send(404, "text/plain", "Not found");
}

void InitServer()
{
   server.on("/", handleRoot);
   server.onNotFound(handleNotFound);
   server.begin();
   Serial.println("HTTP server started");
}

On the other hand, we create the ‘index.h’ file, where we have simply created a Char array that contains the “Hello world” web page we want to serve.

To save it in flash memory, we have used ‘PROGMEM’, so that this constant is not stored in the memory dedicated to variables.

const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>

<div>
   <h1>Hello world!</h1>
</div>

</body>
</html>
)=====";

In this simple example, we have only routed the root URL to the previous MAIN_page variable. The served content is a constant and does not change (it is static). Next, we will see a slightly more realistic example.

Remember that we have better methods for serving static content, and we will see them in the following entries.

Serving dynamic content from Flash

So, in what circumstances can this be useful? To serve ‘pseudo-dynamic’ content, that is, to host the parts that do not vary from a dynamic response reducing the memory dedicated to variables used.

For example, suppose that, following the example from the previous entry, we want to serve a web page that shows the state of any variable. In this example, the variable will be ‘ledStatus’.

In the previous entry, we returned a brief String informing about the state of the variable. But if we want to serve a web page, there is a lot of content that is similar, and only a part of the served web page changes.

In this case, it may make sense to store the ‘static’ parts of the response in PROGMEM variables.

We modify the ‘Server.hpp’ file to serve ‘HTML_PART_1’, then our dynamic content, and finish with ‘HTML_PART_2’.

ESP8266WebServer server(80);

void handleRoot() {
   String response = ledStatus ? "ON" : "OFF";

   server.setContentLength(sizeof(HTML_PART_1) + sizeof(response) + sizeof(HTML_PART_2));
   server.send(200, "text/html", HTML_PART_1);
   server.sendContent(response);
   server.sendContent(HTML_PART_2);
}

void handleNotFound() {
   server.send(404, "text/plain", "Not found");
}

void InitServer()
{
   server.on("/", handleRoot);
   server.onNotFound(handleNotFound);
   server.begin();
   Serial.println("HTTP server started");
}

We modify ‘index.h’ to contain

const char HTML_PART_1[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<body>

<div>
   <h1>Hello world!</h1>
   <p>LED: 
)=====";

const char HTML_PART_2[] PROGMEM = R"=====(
   </p>
</div>

</body>
</html>
)=====";

And if we now access with the browser we will see that, instead of a simple “LED: OFF” we have served a complete web page in which we only modify the content we want.

esp8266-server-from-flash

Of course, we have other ways to perform an application of this type. Usually we will serve a static web page, and the frontend will make a request to an Endpoint to obtain the content of the variable.

However, although in upcoming entries we will see how to achieve a result similar to the example in a more convenient way, the important thing is to illustrate that it is possible to use Flash memory to serve content and lighten the RAM consumption.

We will see all of this soon. In the next entry we will learn how to use the SPIFFS file system to serve static content. See you soon!

Download the code

All the code from this post is available for download on Github.

github-full

ESP8266 version: https://github.com/luisllamasbinaburo/ESP8266-Examples

ESP32 version: https://github.com/luisllamasbinaburo/ESP32-Examples