A favicon.ico for the Arduino Webserver

So you want to serve a favicon.ico on your Arduino Webserver. Here I want to show you my way of the favicon.ico on the Arduino.

Epilog: The Arduino UNO Webserver

One option is to convert the picture into Base64 and serve the picture within the HTML-Header. There are already examples existing - and can be found via Google.

Here you will see a different approach: serve the picture as separate "file" in the Arduino flash (program) memory.

If you haven't read my post about the Arduino UNO webserver you should read here. It explains how to improve the IDE example and serves as base for this page.

Adopt the Arduino UNO Webserver

If you want to serve more pages on your webserver you have to adopt the Arduino UNO webserver in two steps:

  • define a function serving the page, remember to use the F-Makro to save RAM
  • add an identifier to your if statement which handles the URI
else if (!strcmp(uri, "/favicon.ico") 

At the end of this page, you can download the working example of my webserver with favicon.

Handling the favicon.ico with the Arduino Webserver

As you have seen from the IDE Example, most of the browser request a so called favicon from the server. The filename is favicon.ico. The IDE Example simple answers each request with the main page. In my improved webserver can learn how, to get a valid 204 response. Check it in your netmonitor:

Even if you HTTP response code 204 a good solution for the limited resources on an Arduino UNO webserver you can introduce a real favicon on the Arduino webserver.

Serving a favicon.ico on the Arduino Webserver

First of all, you must ensure, that the webserver sends the proper answer to your browser. So you introduce just a new page:

else if (!strcmp(uri, "/favicon.ico"))
  sendFavicon(client);

Then, you need a new function sendFavicon(). The HTTP-header "Content-Type" for a favicon.ico is

Content-Type: image/x-icon

To get the proper picture you can use this workflow:

  • design the favicon and store it on the local hard disk
  • use an online hexeditor to convert the image into hex picture data
  • copy the hex data into a good editor (like notepad++) and replace all blanks with commas

At the end of the page you will find links to the tools I'm using.

The hex data can be used in our Arduino sketch. Just be very carefully, that even for a 16x16 favicon you will need 257 bytes or more memory. This will be to much for the limited RAM of the Arduino UNO. Therefore you should put the whole array into PROGMEM (flash) and read the data if needed.

void sendFavicon(EthernetClient &client)
{
  // create a favion: https://www.favicon.cc/
  // convert to hex: http://tomeko.net/online_tools/file_to_hex.php?lang=en or https://www.onlinehexeditor.com/
  // Please note that if PROGMEM variables are not globally defined, 
  // you have to define them locally with static keyword, in order to work with PROGMEM.
  const static byte tblFavicon[] PROGMEM = {0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x10, 0x00, 0x01, 0x00, 0x04, 0x00, 0x28, 0x01, 
                                            0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 
                                            0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x82, 0x7E, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x01, 0x00, 0x01, 0x00, 0x10, 0x00, 0x10, 0x10, 
                                            0x01, 0x00, 0x01, 0x00, 0x10, 0x00, 0x11, 0x10, 0x01, 0x00, 0x01, 0x00, 0x11, 0x10, 0x10, 0x10, 
                                            0x01, 0x00, 0x01, 0x00, 0x10, 0x10, 0x10, 0x10, 0x11, 0x10, 0x11, 0x10, 0x11, 0x10, 0xFF, 0xFF, 
                                            0x00, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 
                                            0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFA, 0xBF, 0x00, 0x00, 0xFC, 0x7F, 
                                            0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x5B, 0xB7, 0x00, 0x00, 0x5B, 0xB7, 
                                            0x00, 0x00, 0x1B, 0xB1, 0x00, 0x00, 0x5B, 0xB5, 0x00, 0x00, 0x51, 0x11, 0x00, 0x00 
                                           };

  const size_t MESSAGE_BUFFER_SIZE = 64;
  char buffer[MESSAGE_BUFFER_SIZE];  // a buffer needed for the StreamLib
  BufferedPrint message(client, buffer, sizeof(buffer));
  message.print(F("HTTP/1.0 200 OK\r\n"
                 "Content-Type: image/x-icon\r\n"
                 "\r\n"));

  for (uint16_t i = 0; i < sizeof(tblFavicon); i++)
  {
    byte p = pgm_read_byte_near(tblFavicon + i);
    message.write(p);
  }
  message.flush();
  client.stop();
}

PROGMEM puts the image data into FLASH (instead of SRAM). Please note that if PROGMEM variables are not globally defined, you have to define them locally with static keyword, in order to work with PROGMEM.

Using this method, the favicon (or any other small picture) will even fit into an Arduino UNO. If you check your browser: the favicon.ico will now be displayed:

und also check the Network Monitor everything is working ok now:

Serving the icon as separate file has the advantage, that the browser could cache it locally and the favicon.ico could be re-used for all pages you are serving on your Arduino. The HTML pages might be smaller and therefore transmitted faster from the UNO to the browser.

Summary

You have learned how to handle and serve a nice Icon - the favicon.ico - for your Arduino webserver.

If you have any questions to the Arduino Webserver - best place to ask is in the Arduino.cc forum.

Links

Protocol

First upload: 2020-10-26 | Version: 2020-11-14