ESP32 Arduino HTTP server: Serving image as attachment

Introduction

In this tutorial we will check how to serve an image as attachment from a HTTP web server running on the ESP32. We will be using the Arduino core and the HTTP web server async library.

We are going to make use of a Arduino IDE plugin that allows to upload files to the ESP32 SPIFFS file system. You can check here an introductory tutorial.

In my case I’ll be serving the image shown below. I’ll call it test.jpg and upload it to the root of the SPIFFS file system using the mentioned plugin. This means that, when accessing it later on the Arduino code, the image should be located on “/test.jpg“.

Testing image that will be served as attachment.
Figure 1 – Testing image.

The tests shown here were performed using an ESP32 board from DFRobot.

The code

As usual, we start by including all the libraries we will need for our code to work. We will need the WiFi.h, to connect the ESP32 to a WiFi network, the SPIFFS.h, to be able to access the file system, and the ESPAsyncWebServer.h, to be able to setup the server.

#include "WiFi.h"
#include "SPIFFS.h"
#include "ESPAsyncWebServer.h"

Then we will need the credentials of the WiFi network, more precisely, the network name and password. We will also need an object of class AsyncWebServer, which we will use below to configure the server routes.

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";
 
AsyncWebServer server(80);

Moving on to the setup function, we will start by opening a serial connection, to be able to output some messages from our program.

Serial.begin(115200);

Then we are going to mount the SPIFFS file system. The file system always needs to be mounted before we can interact with it.

if(!SPIFFS.begin()){
        Serial.println("An Error has occurred while mounting SPIFFS");
        return;
}

After mounting the file system, we are going to connect the ESP32 to the WiFi network, using the previously declared credentials.

WiFi.begin(ssid, password);
 
while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
}
 
Serial.println(WiFi.localIP());

Then we are going to take care of configuring the server routes. The first route we are going to declare will be the one that will serve the image as attachment. We will call this route “/download” and it will only listen to HTTP GET requests.

As implementation of the route handling function, we will basically be serving the image file. To do that, we will use one of the available signatures of the send method of the AsyncWebServerRequest class. Recall from previous tutorials that, as input of the route handling function, we will receive a pointer to an object of this class, which we can use to answer to the client.

The method will receive the following parameters:

  • An object of class FS, which allows to interact with a file system. In our case we will pass the SPIFFS object, which is an extern variable of class SPIFFSFS, which inherits from FS. This object will be used under the hood to interact with the file system.
  • The path to the file in the file system, as a string. In our case, the file is called test.jpg and it is located in the root of the file system, so the path should be “/test.jpg
  • A string with the content-type of the file that will be returned to the client. In our case it is a JPEG image, so we should pass the value “image/jpeg“.
  • A Boolean flag indicating if the file should be downloaded as attachment (true) or interpreted and displayed inline (false). In our case, we should pass the value true, so the client downloads and saves the image locally, as an attachment.
server.on("/download", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/test.jpg", "image/jpeg", true);
});

For comparison, we will also declare a route where we will be serving the same file, but to be interpreted and displayed by the client. We will call this route “/render“.

server.on("/render", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/test.jpg", "image/jpeg", false);
});

To finalize, we simply need to call the begin method on our server object, so it starts listening to incoming requests. The final code can be seen below and already includes this call.

#include "WiFi.h"
#include "SPIFFS.h"
#include "ESPAsyncWebServer.h"
 
const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";
 
AsyncWebServer server(80);
 
void setup(){
  Serial.begin(115200);
 
  if(!SPIFFS.begin()){
        Serial.println("An Error has occurred while mounting SPIFFS");
        return;
  }
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
 
  Serial.println(WiFi.localIP());

  server.on("/download", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/test.jpg", "image/jpeg", true);
  });
 
  server.on("/render", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/test.jpg", "image/jpeg", false);
  });
 
  server.begin();
}
 
void loop(){}

Testing the code

To test the code, simply compile it and upload it to your device, using the Arduino IDE. When the procedure finishes, open the serial monitor and wait for the ESP32 to connect to the WiFi network. When it does, it should print an IP address. Copy it.

Then, open a web browser of your choice and type the following, changing #yourDeviceIp# by the IP you have just copied:

http://#yourDeviceIp#/render

You should get an output similar to figure 2. As can be seen, the image was rendered by the browser and displayed.

Getting image being served by the ESP32.
Figure 2 – Web browser receiving the image and displaying it inline.

Then, to get the image as an attachment, access the following URL:

http://#yourDeviceIp#/download

You should get a result similar to figure 3. as can be seen, the image was downloaded by the browser instead of being displayed.

Web browser getting image from the ESP32 SPIFFS file system and saving it as an attachment.
Figure 3 – Web browser downloading the image as attachment.

Related Posts

4 thoughts on “ESP32 Arduino HTTP server: Serving image as attachment”

  1. Hello,
    with my ESP32 I have a problem with:
    server.on(“/render”, HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, “/test.jpg”, “image/jpeg”, false);
    });
    My browser Firefox say “Status 500”.
    This problem I have since the last tutorials

    Kind Regards
    Juergen B.

    1. Hi,

      I think the ESP32 gives the 500 when the route is not found.

      If you are accessing the correct route and it is giving a 500 then it is a weird issue.

      You mention firefox in particular, does the issue not happen with other browsers?

      Best regards,
      Nuno Santos

  2. Hello,

    I also have the problem with other browsers (Chrome, Internet Ex…).

    Kind Regards

    Juergen B.

    1. Hi!

      That’s a weird issue. To be honest I’m not sure what might be causing the problem.

      I haven’t had the chance to re-test the code again but at the time everything worked fine for me.

      My suggestion is to ask around the GitHub page of the library to see if someone there has an idea.

      Additionally, did the file upload procedure worked well? Can you confirm if you have the file in the file system?

      Best regards,
      Nuno Santos

Leave a Reply to antepherCancel reply

Discover more from techtutorialsx

Subscribe now to keep reading and get access to the full archive.

Continue reading