In this ESP32 tutorial we will check how to serve an image as attachment from a HTTP web server running on the ESP32. The tests shown here were performed using an ESP32 board from DFRobot.
ESP32 Arduino HTTP server: Serving image as attachment
Introduction
In this esp32 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“.
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.
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.