PROGMEM with String

I am currently trying to make a webserver using ESP8266 (NodeMCU). I have been having issues with what I believe is running out of heap. In order to save on heap, I have been trying to implement PROGMEM into the core of my webserver. I have been trying to deploy the following chunks of code where rname1 is a String.

const char DEVICES1[] PROGMEM = R"=====(
<a href='OneOn'><button style='font-size:300%;background-color:darkgray; color:green; border-radius:100px;'> rname1 </button></a><br>
<a href='OneOff'><button style='font-size:300%;background-color:darkgray; color:red; border-radius:100px;'> rname1 </button></a><br>
<hr>
)=====";

In the Root page of the webserver I have the following code

if (Device>=1){
 String  rname1= read_String(110); // Read EEPROM address 110 for content of rname1 
content += DEVICES1;
  }

What results are two html buttons one green and one red (as expected) on my webserver, but the text within them are just "rname1" as opposed to the actual content of the string. Is there a way to correct this?
I previously successfully implemented this code just by doing the following

if (Device>=1){
  String rname1= read_String(110);
  content += "<a href='OneOn'><button style='font-size:300%;background-color:darkgray; color:green; border-radius:100px;'>" + rname1 + "</button></a><br>";
  content += "<a href='OneOff'><button style='font-size:300%;background-color:darkgray; color:red; border-radius:100px;'>" + rname1 + "</button></a><br>";
  content += "<hr>";
  }

However, as mentioned too much heap is consumed. When Device is greater than 10 my webpage will either be glitchy or will restart after compilation. Was hoping the PROGMEM implementation would help on heap. Any ideas to resolve the issue with seeing "rname1" as opposed to the actual content of the rname1 String when using PROGMEM?

Any help would be greatly appreciated!!

Thanks
Matt

avr-libc: Data in Program Space (nongnu.org)

there must be another problem. The ESP has for sure no problem with a page with 10 buttons.

What comes in my mind when I see your HTML - don't waste resources with duplicated inline styles.

instead of 10 x this

style='font-size:300%;background-color:darkgray; color:red; border-radius:100px;'

create a CSS and style the 10 buttons once with CSS.

2 Likes
  1. There is no EEPROM on ESP8266 – Arduino framework code is a dummy to maintain compatibility.
  2. PROGMEM can save a little bit of memory on ESP8266, but not much really – less than 10% – it will not solve the issue of running out of RAM.
  3. How to really solve it? Split your response generation into multiple HTTP requests. Serve CSS separtly from HTML. Same JS. Keep HTML simple, basic template only, nothing else. Move as much code as you can into JS –> and JS can be split into multiple modules. 10 HTTP requests with small amounts of data in response are much less likely to use up all your RAM than one big response.
1 Like

As far as I know, there is also no PROGMEM. It's also a 'placeholder' for compatibility.

#ifndef PROGMEM
#define PROGMEM
#endif

Nope, PROGMEM is more than just a placeholder:

it actually stores the string literals in the "flash" [irom], instead of loading it to RAM at the boot. So, it is only loaded to RAM per usage, and not being there for all the time => hence my <10% RAM savings.

1 Like

Thank you for this suggestion, it worked. Prior to implementing the code below, my heap was around 5000 (and acting glitchy) with 10 devices. Once implemented my heap improved to over 8000 (no glitches) with 10 devices. Able to successfully run 16 devices (my goal) with over 7500 heap available with no glitches.

const char BUTTONG[] = R"=====(
style='font-size:300%;background-color:darkgray; color:green; border-radius:100px;'
)=====";

const char BUTTONR[] = R"=====(
style='font-size:300%;background-color:darkgray; color:red; border-radius:100px;'
)=====";

/////Other unrelated Code

if (Devicess>=1){
  String rname1= read_String(110);
  content += "<a href='OneOn'><button "; 
  content += BUTTONG;
  content += ">" + rname1 + "</button></a><br>";
  
  content += "<a href='OneOff'><button ";
  content += BUTTONR;
  content += ">" + rname1 + "</button></a><br>";
  
  content += "<hr>";
  }

Thanks again
Matt

but that's not really what I meant.

You should have created a separate resource. A CSS file. For example named f.css
And link the CSS file in your HTML file (so the browser requests that CSS file also.

<link rel='stylesheet' type='text/css' href='f.css)'>

You even don't need to duplicate most of the attributes in the CSS. Just make a separate class with the differences and use that class for the "active" button.

f.css:

button {font-size:300%;background-color:darkgray; color:red; border-radius:100px}
.active {color:green}

in that example all "button" would be styled 300%, darkgray, red, with border radius, and ones with class "active" will get green.

one more advantage is, that most browsers will cache the CSS, and so you will reduce even more bandwidth.

If that is still a miracle, you might try my example of a Webserver.
It should work on ESP8266 and ESP32 out of the box and shows how I meant to style the page with CSS.

https://werner.rothschopf.net/microcontroller/202108_esp_generic_webserver_en.htm

Hi Noiasca,
I was able to implement your reccomendation, but I am having an issue with the button colors when the code is compiled.

In my main code I added

server.on("/f.css", handleCss);

//other unrelated code

content += "<link rel='stylesheet' type='text/css' href='f.css'>\n";


 
  if (Devicess>=1){
  String rname1= read_String(110);
  content += "<a href='OneOn'><button "; 
  content += ">" + rname1 + "</button></a><br>";
  
  content += "<a href='OneOff'><button inactive";
  content += ">" + rname1 + "</button inactive></a><br>";
  
  content += "<hr>";
  }

I created a new tab and put the following in

void handleCss()
{
message = "button {font-size:300%;background-color:darkgray; color:green; border-radius:100px} .inactive {color:red}";
 server.send(200, "text/css", message);
}

The issue is when I run the code all of my buttons are green. I experimented by adding inactive in various places within the main code where button is written, but nothing seemed to do the trick. How exactly do you modifiy the code to differentiate the green from the red buttons?

Thanks
Matt

I guess it is now a CSS issue, not Arduino one, but you're lucky, as I am a web developer :wink:

.my-button {
  font-size: 300%;
  background-color: darkgray;
  border-radius: 100px;
}

.red {
  color: red;
}

.green {
  color: green;
}
<button>Normal one</button>
<button class="my-button">Button with custom styles</button>
<button class="my-button green">Green button with custom styles</button>
<button class="my-button red">Red button with custom styles</button>

You can try it here: Edit fiddle - JSFiddle - Code Playground

1 Like

Hi Daveet,
That resolved the issue. Thank you!!

Thanks
Matt

I'm coming back to my proposal of modifying the button element and adding a class for the difference (in color). You missed to give the green button a different class.

That's what I meant:

two comments on your last attempt:

  • don't name the class by an attribute content. One day you decide to use a different color scheme and then you don't have green or red anymore, but maybe a grey and and a bold black but you have spread the class='red' all over in your code and you will have fun to adopt that.
  • even on the ESP I would try to spare bytes and reduce HTML and CSS to a minium. Therefore the styling of the html elements to avoid the need of assigning a class to each element.
1 Like

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