I recently began a project where I needed to build some dead simple, HTML only static web pages during runtime with the ESP8266 to represent data stored on the filesystem. Depending on the number of files located on the filesystem various buttons, forms, and text needed to be generated. In addition I needed some templating capability to replace certain “tokens” located in the web page with other substrings. Projects with similar functionality exist usually number the name of FSBrowser.
Naturally with the popularity of the ESP8266 and Arduino, some libraries that do a pretty good job of this already exist. They are:
- The ESPAsyncWebServer contains a simple templating engine in addition to it’s web server capability. It works by “extracting placeholder names from response text and passing it to user provided function which should return actual value to be used instead of placeholder”.
- PageBuilder is a “HTML assembly aid” that provides a way to combine “PageElements” to a build a web page which can be stored in SPIFFS. It provides templating capability by allowing “tokens” to be tied to template handling functions. It can also be bound to a web server.
- ESPTemplateProcessor is a templating library that reads a file from SPIFFS, processes the read file with a template handling function, then sends the result to a bound web server.
- EspHtmlTemplateProcessor is based off ESPTemplateProcessor, although it has a few extra features.
While I certainly could have managed by using one of these libraries, I soon found the implementation resulting from their usage to be difficult to read and not very flexible. I found myself having to develop upwards of ten templating handler functions to replace tokens in a very small amount of generated HTML code. I also found the libraries that bound to web servers to be restrictive in the web server based libraries that could be used.
So with these observations I made the decision to make a dead simple string templating library that would fill the niche of my application.
ESPStringTemplate Requirements
The requirements for the ESPStringTemplate library are:
- Ability to build web pages using string “elements”.
- Web pages should be stored in statically allocated buffers, where elements can be added to them.
- String elements should be able to be stored in both RAM and program flash memory (PROGMEM).
- Templating ability on string elements using simple string literals (instead of handler functions).
- Multiple token templating ability on string elements (without the use of handler functions).
The ESPStringTemplate Library
The ESPStringTemplate Library can be found on GitHub here. It is also a part of Arduino’s Library Manager, and can be found using the Arduino IDE when it is searched for. The GitHub README gives a good outline of the usage of the library. Simple examples also exist to help get people started. I hope this library can be useful for someone else down the track!
Just as a note, there is actually nothing stopping the use of ESPStringTemplate on any microcontroller!
ESPStringTemplate Examples
These examples are taken straight from the ESPStringTemplate GitHub page, but are also included here.
Simple example – Using string literals to build a page in a statically allocated buffer.
static char buffer[200];
ESPStringTemplate webpage(buffer, sizeof(buffer));
webpage.add("Hi!<br><br>");
webpage.add("This is an example of the ESPStringTemplate Library.<br><br>");
webpage.add("These strings are stored in RAM, and are added to the provided statically allocated buffer.<br><br>");
Using string literals stored in flash (program memory) to build a web page.
static char buffer[200];
ESPStringTemplate webpage(buffer, sizeof(buffer));
webpage.add_P(PSTR("This is an example of the ESPStringTemplate Library.<br><br>");
webpage.add_P(PSTR("This string is stored in flash using PROGMEM, and are added to the provided statically allocated buffer."));
Using reusable HTML elements with a simple token replacement.
static const char _PAGEHEADER[] PROGMEM = "<html><body>";
static const char _CONTENT[] PROGMEM = "%CONTENT%";
static const char _PAGEFOOTER[] PROGMEM = "</body></html>";
static char buffer[200];
ESPStringTemplate webpage(buffer, sizeof(buffer));
webpage.add_P(_PAGEHEADER);
webpage.add_P(_CONTENT, "%CONTENT%", "TEST CONTENT");
webpage.add_P(_PAGEFOOTER);
Using reusable HTML elements with a multiple token replacement.
static const char _PAGEHEADER[] PROGMEM = "<html><body>";
static const char _CONTENT[] PROGMEM = "%CONTENTA% and %CONTENTB% and %CONTENTC%";
static const char _PAGEFOOTER[] PROGMEM = "</body></html>";
static char buffer[200];
ESPStringTemplate webpage(buffer, sizeof(buffer));
TokenStringPair pair[3];
webpage.add_P(_PAGEHEADER);
pair[0].setPair("%CONTENTA%", "Replacing this token");
pair[1].setPair("%CONTENTB%", "this token");
pair[2].setPair("%CONTENTC%", "this last token as well...");
webpage.add_P(_CONTENT, pair, 3);
webpage.add_P(_PAGEFOOTER);
Using ESPAsyncWebServer to serve created webpage
static char buffer[200];
WiFi.softAP("ESPStringTemplate Example");
AsyncWebServer server(80);
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{
ESPStringTemplate webpage(buffer, sizeof(buffer));
webpage.add("Hi!");
/* Send the webpage from SPIFFS where it is stored. */
request->send(200, "text/html", buffer);
}
server.begin();