Ok, so even though i am expecting a rather complex response from people i decided to ask this question regardless.
I use ESP8266's a lot, and generally to create webpages of all sorts.
Now at some point RAM usage becomes an issue in the way that i was doing it.
I create a local String and add whatever part of the webpage i want, and send it either in Chunks (Chunked content) or as 1 single stream.
For different pages there are sections that are always the same or very similar, so to prevent lots of mistakes from typos, i started out with making things like the Header, the bodystyle etc a const char * that i define once and use in many places. This of course goes at the expense of RAM, so i though if i make them
static const char characters[] PROGMEM "896*^(";
and call the using
s += FPSTR(characters);
they are placed in PROGMEM, and they are only added to the 'String' locally, so they do not impact global RAM usage, nor do they impact Flash memory much (i am adding to the String on the fly with the same section of characters that is being loaded from PROGMEM) and i do prevent the risk of excessive typos, which during development of HTML in particular makes quite a lot of difference, since the compiler does not check for mistakes.
Now i found that i am impacting RAM ! I couldn't work out where all of my global RAM usage was coming from, until i started commenting out some of the compiled pages, and all of a sudden the RAM usage dropped.
So i figured i am doing something wrong, and it is time to fix that, and where better to ask than here.
an example of what i have doing so far
static const char pageheader[] PROGMEM = "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN''http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>";
static const char htmlhead[] PROGMEM = "<html><head><title>DmagiX LED Controllers</title><meta http-equiv='Content-Type' content='text/html;charset=utf-8' ></head>";
static const char headmetaopen[] PROGMEM = "<html><head><title>DmagiX LED Controllers</title><meta http-equiv='Content-Type' content='text/html;charset=utf-8'";
static const char headmetaclose[] PROGMEM = " ></head>";
static const char bodystyle[] PROGMEM = "<body style='color: wheat; background-color: DarkSlateBlue; font-size: 12pt; font-family: sans-serif;'>";
static const char htmlclose[] PROGMEM = "</body></html>";
void MainPage() {
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
String s;
s += FPSTR(pageheader);
s += FPSTR(htmlhead);
s += FPSTR(bodystyle);
s += "<h1>Welcome to DmagiX Wifi !</h1><p>From here you can control your DmagiX Controller. DmagiX Patterns consist of 2 layerss, with their own ";
s += "RGB color, and a few global parameters. There are also 30 presets available for quick recall, and a random mode that can have a timed trigger.";
s += "</p>";
s += "<form action='";
s += webIP;
s += "' method='get' name='todmagix'><input type='hidden' name='page' value='dmagix'>";
s += "<input type='hidden' name='request' value='dmagix'>";
s += "<input type='submit' value=' DmagiX '></form><br>";
s += "<p>General Settings can be modified at any time and of course be bookmarked for later use. The Settings that were present ";
s += "at login will be kept for easy retrieval and the option to actually store the new settings on the EEPROM is separate from applying them. ";
s += "Settings include the number of LED's the RGB sequence, Random-mode trigger, as well as settings relating to DMX. </p>";
server.send(200, "text/html", s);
s = "";
s += "<form action='";
s += webIP;
s += "' method='get' name='tosettings'><input type='hidden' name='page' value='settings'>";
s += "<input type='submit' value=' Settings '></form><br>";
s += "<p>A DmagiX unit starts up as an Access Point that you can log onto, but it can connect to a WiFi network just as easily, and you can store";
s += "a network that you have connected to, and it will look for stored networks to connect to at startup. A dynamic IP address will be assigned ";
s += "which is found on the WiFi page after connection, and a mDNS-lookup name can set and stored. Also you can change the Access Point name into ";
s += "a more meaningful one and you can disable the password.</P>";
s += "<form action='";
s += webIP;
s += "' method='get' name='wifidata'>";
s += "<input type='hidden' name='page' value='wifi'>";
s += "<input type='submit' value=' WIFI '></form><br>";
s += "<p>User Accounts can be set up to protect certain areas and settings. A device specific Admin password allows you to set up a primary ";
s += "user account which can modify all other accunts and any data on the controller.<br> This is unit : <b>";
s += DefaultAPname();
s += "</b></p>";
server.sendContent(s);
s = "";
s += "<form action='";
s += webIP;
s += "' method='get' name='userdata'>";
s += "<input type='hidden' name='page' value='user'>";
s += "<font size='+2'>";
s += "<input type='submit' value=' Accounts '></font></form><br>";
s += "<form action='";
s += webIP;
s += "' method='get' name='changeuser'>";
s += "<input type='hidden' name='page' value='maincu'>";
s += "<input type='submit' value='Change User'></form><br>";
if (CheckAuth() & B100) { // so the backdoor also reveals the admin password
s += "<b>'admin' password : ";
s += AdminPW();
s += "</b><br>";
s += TimeSwitchedOn();
s += "<br>User accounts are turned ";
if (useuser) s += "on";
else s += "off";
s += ".<br>Guest account is turned ";
if (guestaccount) s += "on";
else s += "off";
s += ".<br><br>";
//s += TestFrameStoreTime();
s += "<br>";
s += "<form action='";
s += webIP;
s += "' method='get' name='reboot'>";
s += "<input type='hidden' name='page' value='reboot'>";
s += "<input type='submit' value='Reboot Unit'></form><br>";
}
s += FPSTR(htmlclose);
yield();
server.sendContent(s);
server.sendContent("");
}
It seems that these global PROGMEM c-strings are not put in PROGMEM, and i fact i suspect that there is even a copy stored for each time i use them in a page.
This example page does not contain much dynamic content, but most of the other pages contain a lot of content that is added on the fly so storage in SPIFFS, which should reduce the RAM usage, may not be so practical. (sure it can be done, but i'd be reading from several different files for every page thaat is being displayed, so i would prefer to avoid that option)