Skip to content
Giorgioggì edited this page Jan 10, 2021 · 5 revisions

If you want to put a WebServer on your Arduino, you probably want it to display some changing data, maybe a temperature or the state of some input pin. Webbino helps you doing this with its support for Replacement Tags.

The whole concept of Replacement Tags revolves around putting some placeholder text inside your HTML file and having it replaced with some value at the page request time. Actually they can appear not only in HTML files, but also in JavaScript and Text files (See here).

The placeholder text must be a single word enclosed between Placeholder Markers, which is the Dollar Sign, $. It is customary for it to be all upper case. Then Webbino allows you to associate it with a replacement function, so that whenever it sees the placeholder in some content it is sending a client, it will call that function and send the client whatever it returns instead of the placeholder.

The ReplacementTags example sketch will show you how this can be achieved.

Code

Since most of the sketch is very similar to SimpleServer, I will only comment about the differences. Please see First Steps for any clarifications.

/******************************************************************************
 * DEFINITION OF TAGS                                                         *
 ******************************************************************************/

#define REP_BUFFER_LEN 32
static char replaceBuffer[REP_BUFFER_LEN];
PString subBuffer (replaceBuffer, REP_BUFFER_LEN);

The Replacement Tags functionality relies on the PString library. This is a great and simple library, it should really be embedded in the default Arduino distribution, in my opinion. It is really easy to use and allows "printing to strings" just like you would do with the Serial monitor.

PString requires a backing character buffer, which is what we are declaring here. Note that it must have some finite size, which you have to choose carefully as whatever text your tag replacement functions will produce cannot be longer than that. (I know what you are thinking: Why not use String? You probably already know the answer, too: String uses dynamic memory allocation, which is not really suited for the very small RAM a microcontroller has. Convince yourself.)

Once we have decided the size and declared the backing buffer, we instantiate a PString object named subBuffer which we'll use in all our tag replacement functions.

A number of tag replacement functions follow. I will only comment one for brevity, as they are all similar and work the same way.

static PString& evaluate_uptime (void *data __attribute__ ((unused))) {
	unsigned long uptime = millis () / 1000;
	byte d, h, m, s;

	d = uptime / 86400;
	uptime %= 86400;
	h = uptime / 3600;
	uptime %= 3600;
	m = uptime / 60;
	uptime %= 60;
	s = uptime;

	if (d > 0) {
		subBuffer.print (d);
		subBuffer.print (d == 1 ? F(" day, ") : F(" days, "));
	}

	if (h < 10)
		subBuffer.print ('0');
	subBuffer.print (h);
	subBuffer.print (':');
	if (m < 10)
		subBuffer.print ('0');
	subBuffer.print (m);
	subBuffer.print (':');
	if (s < 10)
		subBuffer.print ('0');
	subBuffer.print (s);

	return subBuffer;
}

This is a tag replacement function. It will be called whenever some placeholder we'll see later is encountered. All it has to do is to return a PString containing the text to replace the placeholder with. In this case, the function takes the value returned by the millis() function, which represents the milliseconds since power up, and transforms it in some more readable text. I won't comment about the way it does this, but notice that it just keeps printing to the subBuffer we declared before and finally returns (a reference to) it. Easy, huh?

Note that all your tag replacement functions will have a very similar declaration (first line): you should only change the actual function name.

(Please disregard the static and __attribute__ ((unused)) keywords if you don't know their purpose, they are not required anyway and will be removed in a future version.)

EasyReplacementTag (tagUptime, UPTIME, evaluate_uptime);

This is where the placeholder and the replacement function are associated. The EasyReplacementTag macro needs three arguments:

  1. The first is some "handle" for the replacement tag. Note that this must be a legal C++ variable name.
  2. Then comes the actual placeholder text, which must be a single word. Note that, a bit surprisingly perhaps, this must NOT include the placeholder markers and must NOT be enclosed within quotes.
  3. The last argument shall be the name of the tag replacement function (formally, a function pointer).
EasyReplacementTagArray tags[] PROGMEM = {
	// ...
	&tagUptime,
	// ...
	NULL
};

This is just a list of all the tag handles we have formerly declared. Note that the list MUST be ended with a NULL entry.

webserver.enableReplacementTags (tags);

This is the only line that changes in the setup() function, with regard to the SimpleServer example: it tells Webbino to enable its tag replacement functionality by passing the list of tags we declared before.

Things to Keep in Mind

  • Tag replacement functions must be fast: they are called while data is being sent to the client, so the longer they take, the less responsive the page will be for the client. Similarly, the more replacement functions need to be called, the slower the data will be sent.
  • subBuffer is cleared automatically after a tag replacement function is called, so you can just assume it to be empty at the beginning of every tag replacement function.
  • Older Webbino versions used the Pound Sign, #, as tag marker, but this was messy because it is often used in HTML with its own meaning, so it had to be changed.

Further Reading

There are some advanced aspects of Replacement Tags that are covered in a separate page.