Before we get started with the Project, it is necessary to know the basic usage of anESP32 Dev Board and Arduino programming. Slowly, we'll move ahead and get you started with the integration with all required instructions.
******************************** I M P O R T A N T ******************************
Please go through THIS PROJECT PAGE to get started with the ESP32 Dev Board and understand how to use the development board for Building Projects
**************************************************************************************
OverviewWe will make a couple of projects under this one category, i.e. Web Servers -
1. 'Hello World' on WebPage (hosted from ESP32)
2. Display LIVE Data from BME280 (environment sensor) connected with ESP32
3. Make ESP32 as Access Point (HotSpot) and view the Web Page by connecting with ESP32 directly
4. Using SPIFFS (File Management within ESP32)
5. Use SPIFFS to host page from HTML, CSS, and JS files (including images, etc)
6. Use mDNS to use custom domain names and access the WebServer
7. Use NGROK to tunnel the server and host it LIVE on the Internet
Now, you have a full-fledged working webserver on that small embedded system board.
Get PCBs for Your Projects ManufacturedYou must check out PCBWAY for ordering PCBs online for cheap!
You get 10 good-quality PCBs manufactured and shipped to your doorstep for cheap. You will also get a discount on shipping on your first order. Upload your Gerber files onto PCBWAY to get them manufactured with good quality and quick turnaround time. PCBWay now could provide a complete product solution, from design to enclosure production. Check out their online Gerber viewer function. With reward points, you can get free stuff from their gift shop.
Libraries Required/Used- Wire - This library allows you to communicate with I2C / TWI devices. In ESP32,
SDA -> D21
andSCL -> D22
. Used to set I2C communication with the BME280 sensor. - SparkFunBME280 - This library allows the user to: Read pressure in Pa, Read temperature in C and F, Read humidity in %RH and Read Altitude in feet and meters. more details
- Adafruit Sensor - To use the BME280 library, you also need to install the Adafruit_Sensor library. Follow the next steps to install the library in your Arduino IDE: Go to
Sketch
>Include Library
>Manage Libraries
and type “Adafruit Unified Sensor” in the search box. Scroll all the way down to find the library and install it. - WiFi - This library lets the board connect to the internet, wifi service. more details
- WebServer - Supports in creating a webserver and run an independent simple webserver. more details
- ESPAsyncWebServer - Creates Async HTTP and WebSocket Server on ESP32. Requires AsyncTCP to use with ESP32. more details
- SPIFFS - It lets you access the flash memory like you would do in a normal filesystem in your computer, but simpler and more limited. You can read, write, close, and delete files. more details
- ESP32mDNS - mDNS is a multicast UDP service that is used to provide local network service and host discovery. It is installed by default on most operating systems or is available as a separate package. more details
In this project, we will host a server on the ESP32 dev board, which will display a header with 'Hello World' on it. We can view this page, from the IP address of the ESP32 Dev Board when it is connected to the same wifi/network as the one I am connected with.
Hardware Required
ESP32 Dev Board ONLY.
Code
Use below libraries -
#include <WiFi.h>
#include <WebServer.h>
Enter the WiFi name and Password here -
/*Put your SSID & Password*/
const char* ssid = "<wifi_name>"; // Enter SSID here
const char* password = "<password>"; // Enter Password here
Here, we are opening a port 80 for the webserver to be accessed.
WebServer server(80);
Inside the void setup(), we will first connect to the wifi network with available SSID and password using the WiFi.h library's function. Once the connection is established, print the IP address that was designated to the ESP32 by the wifi router, on the Serial monitor of Arduino IDE.
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("Connecting to ");
Serial.println(ssid);
//connect to your local wi-fi network
WiFi.begin(ssid, password);
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
Using the below functions, we are creating server paths that can be accessed from the browser once the IP address is tried to be accessed from that device. It is the URL path that will/must be requested by the device trying to request for a data from the ESP32's Web Server.
These are the Endpoints that will help us in controlling the ESP32 from the URL. Basically, we are making a REST server locally that does not require internet.
server.on() function has 2 parameters, first part is the endpoint waiting from the clientside. and 2nd part is a function that gets executed upon the endpoint being triggered. The function is defined in the same code file.
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
Using the below function, the server is started.
server.begin();
Serial.println("HTTP server started");
Now, let us define the response (HTML Page) that will be sent back to the device/user which sent the request. The function handles the server that has been started and controls all the endpoint functions when receiving a request.
When the request is, https://<ip_address>/
i.e. - "/" -> Response will be the function handle_OnConnect()
void handle_OnConnect() {
server.send(200, "text/html", SendHTML());
}
In here we can see, the server will send a response code '200' with content as 'text/html' and finally the main HTML text. Below is the way HTML text is responded -
String SendHTML(){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP32 Hello World</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>Hello World !!</h1>\n";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
When the request is, ANYTHING ELSE -> Response will be the function handle_NotFound()
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
Now, let us go through the FINAL CODE -(Code Section)
#include <WiFi.h>
#include <WebServer.h>
/*Put your SSID & Password*/
const char* ssid = "<wifi_name>"; // Enter SSID here
const char* password = "<password>"; //Enter Password here
WebServer server(80);
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("Connecting to ");
Serial.println(ssid);
//connect to your local wi-fi network
WiFi.begin(ssid, password);
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
}
void handle_OnConnect() {
server.send(200, "text/html", SendHTML());
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP32 Hello World</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>Hello World !!</h1>\n";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
In this project, we will host a server on the ESP32 dev board, which will display Temperature, Humidity, Altitude, and Pressure from the BME280 sensor module (You can use any other sensor to get environment data / Or use a randomized value to view data here). We can view this page, from the IP address of the ESP32 Dev Board when it is connected to the same wifi/network as the one I am connected with.
Hardware Required
1 x ESP32 Dev Board1 x Any sensor module (I am using BME280)
Code
Use below libraries (MUST) -
#include <WiFi.h>
#include <WebServer.h>
Additionally, I am using libraries for the BME280 module -
#include <Wire.h>
#include"SparkFunBME280.h"
Next, we need to read the data from the sensors and store it in a variable, when the client(user) opens the Page on Browser -
void handle_OnConnect() {
temperature = bme.readTempC();
humidity = bme.readFloatHumidity();
pressure = bme.readFloatPressure() / 100.0F;
altitude = bme.readFloatAltitudeFeet();
server.send(200, "text/html", SendHTML(temperature,humidity,pressure,altitude));
Serial.print(temperature);
Serial.print(humidity);
Serial.print(pressure);
Serial.println(altitude);
}
Now that we have the data, we can push the float variables to the HTML page to view it -
String SendHTML(float temperature,float humidity,float pressure,float altitude){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP32 Weather Station</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP32 Weather Station</h1>\n";
ptr +="<p>Temperature: ";
ptr +=temperature;
ptr +="°C</p>";
ptr +="<p>Humidity: ";
ptr +=humidity;
ptr +="%</p>";
ptr +="<p>Pressure: ";
ptr +=pressure;
ptr +="hPa</p>";
ptr +="<p>Altitude: ";
ptr +=altitude;
ptr +="m</p>";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
Now, let us go through the FINAL CODE -(Code Section)
#include <WiFi.h>
#include <WebServer.h>
#include <Wire.h>
#include "SparkFunBME280.h"
#define SEALEVELPRESSURE_HPA (1013.25)
BME280 bme;
float temperature, humidity, pressure, altitude;
/*Put your SSID & Password*/
const char* ssid = "<wifi_name>"; // Enter SSID here
const char* password = "<password>"; //Enter Password here
WebServer server(80);
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("Connecting to ");
Serial.println(ssid);
//connect to your local wi-fi network
WiFi.begin(ssid, password);
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: ");
Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
Wire.begin();
if (bme.beginI2C() == false) //Begin communication over I2C
{
Serial.println("The sensor did not respond. Please check wiring.");
while(1); //Freeze
}
}
void loop() {
server.handleClient();
}
void handle_OnConnect() {
temperature = bme.readTempC();
humidity = bme.readFloatHumidity();
pressure = bme.readFloatPressure() / 100.0F;
altitude = bme.readFloatAltitudeFeet();
server.send(200, "text/html", SendHTML(temperature,humidity,pressure,altitude));
Serial.print(temperature);
Serial.print(humidity);
Serial.print(pressure);
Serial.println(altitude);
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(float temperature,float humidity,float pressure,float altitude){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
ptr +="<title>ESP32 Weather Station</title>\n";
ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
ptr +="p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP32 Weather Station</h1>\n";
ptr +="<p>Temperature: ";
ptr +=temperature;
ptr +="°C</p>";
ptr +="<p>Humidity: ";
ptr +=humidity;
ptr +="%</p>";
ptr +="<p>Pressure: ";
ptr +=pressure;
ptr +="hPa</p>";
ptr +="<p>Altitude: ";
ptr +=altitude;
ptr +="m</p>";
ptr +="</div>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
(Similar explanation already on IoT Car with ESP32 project)
Here, the ESP32 will itself create a Hotspot, with below SSID and Password -
const char* ssid = "WeatherBoy; //Set your own name for ESP32
const char* password = "PASSWORD123"; //Set the password of SSID
Below are the network configurations we need to make, to start a network and open the network for connections from other clients. Since the IP and Gateway are same (Gateway must be x.x.x.1), we are hardcoding the device to be the Host here -
IPAddress local_ip(192,168,1,1);
IPAddress gateway(192,168,1,1);
IPAddres subnet(255,255,255,0);
In the above configurations, the network components may not be clear, but you can go through CCNA or other Computer Network Configuration articles/courses to learn and understand these components.
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(local_ip, gateway, subnet);
WiFi.softAP(ssid, password);
In the above section, we have selected the mode of WiFi i.e. AP, and therefore using the softAP() function to configure and create a WiFi Hotspot on the ESP32 dev board.
And that's it! Type http://192.168.1.1/
in the Browser and view the HTML page -
Having a File System within the board is definitely an advantage -
- Create files to save small amounts of data instead of using a microSD card;
- Save HTML and CSS files to build a web server;
- Save images, figures and icons
In the Flash Memonry of 4 MB, around 1MB is reserved for storage by the users. To use it along with Arduino, we need to install the File Uploader Plugin on Arduino IDE.
Then follow below steps -
Follow the next steps to install the filesystem uploader:
1) Download the ZIP file from the Github Repo Releases Page. Reach out to the latest release. (ESP32FS-1.0.zip)
2) Go to the Arduino IDE directory, and open the Tools folder.
3) Unzip the downloaded .zip folder to the Tools folder. You should have a similar folder structure:
../Arduino-Directory/tools/ESP32FS/tool/esp32fs.jar
4) Now, restart the Arduino IDE. We'll see the uploader plugin visible in the Tools section.
Select the Partition Scheme and choose the amount of space you require for your SPIFFS Data.
By Default, select 1.5MB SPIFFS (FAT32 is meant for SD Card modules).Now we are READY and SET to upload data to the ESP32.
Next, let us upload sample data to the ESP32 board.
To upload files to the ESP32 filesystem follow the next instructions -
1) Create an Arduino sketch and save it. For demonstration purposes, we can use the below sketch -
#include "SPIFFS.h"
void setup() {
Serial.begin(115200);
if(!SPIFFS.begin(true)){
Serial.println("SPIFFS Not Found");
return;
}
File file = SPIFFS.open("/test_example.txt");
if(!file){
Serial.println("Unable to Open/Read File");
return;
}
Serial.println("File Content:");
while(file.available()){
Serial.write(file.read());
}
file.close();
}
void loop() {
}
2) Then, open the sketch folder. You can go to Sketch > Show Sketch Folder. The folder where your sketch is saved should open.
3) Inside that folder, create a new folder called data.
4) Inside the datafolder is where you should put the files you want to be saved into the ESP32 filesystem. As an example, create a .txt file with some text called sample.txt.
5)Then, to upload the files, in the Arduino IDE, you just need to go to Tools > ESP32 Sketch Data Upload.
After the Data is uploaded, below response will be visible in console (verbose).
Note: in some ESP32 development boards you need to keep the ESP32 on-board “BOOT” button pressed while it’s uploading the files. When you see the “Connecting …….____……” message, you need to press the ESP32 on-board “BOOT” button.
Now, let’s just check if the file was actually saved into the ESP32 filesystem -
Upload the Code to the ESP32 this time, and view the Serial Monitor
In this project, we will host a server on the ESP32 dev board, which will display Temperature, Humidity, Altitude, and Pressure from the BME280 sensor module. It is the same as LIVE Display of Data on ESP32but this time the file for Web Page can be easily scripted in HTML, CSS and JS for all the functionalities.
Here, we shall upload the data (HTML, CSS, images - files) to the ESP32 board using SPIFFS first.
The data folder components are present in the Code Section
Next, use the below code to extract SPIFFS data and use it on the WebServer as the client requests for information, and ESP32 (Server) responses with data from the file system (Database).
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
#include <Wire.h>
#include "SparkFunBME280.h"
// Replace with your network credentials
const char* ssid = "<wifi_name>";
const char* password = "<password>";
#define SEALEVELPRESSURE_HPA (1013.25)
BME280 bme;
String temperature, humid, pressr, alt ;
// Create AsyncWebServer object on port 80
AsyncWebServer server (80);
// Replaces placeholder with value
String processor(const String& var){
Serial.print(var);
if(var == "humid"){
humid = bme.readFloatHumidity();
Serial.println(humid);
return humid;
}
else if(var == "temp"){
temperature = bme.readTempC();
Serial.println(temperature);
return temperature;
}
else if(var == "pressr"){
pressr = bme.readFloatPressure()/100;
Serial.println(pressr);
return pressr;
}
else if(var == "alt"){
alt = bme.readFloatAltitudeFeet();
Serial.println(alt);
return alt;
}
return String();
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
//pinMode(ledPin, OUTPUT);
// Initialize SPIFFS
if(!SPIFFS.begin(true)){
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
// Print ESP32 Local IP Address
Serial.println(WiFi.localIP());
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/index.html", String(), false, processor);
});
// Route to load style.css file
server.on("/main.css", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/main.css", "text/css");
});
server.on("/bgimage.jpg", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SPIFFS, "/bgimage.jpg", "image/jpg");
});
// Start server
server.begin();
Wire.begin();
if (bme.beginI2C() == false) //Begin communication over I2C
{
Serial.println("The sensor did not respond. Please check wiring.");
while(1); //Freeze
}
}
void loop(){
}
What we have over here, is a FULL-FLEDGED Web System (Local) - Without any OS running the whole thing. Even though it is small scale and meant for only single runtime data, we at least have an understanding of the whole system.
In this project, we will assign a Domain name to the IP Address and access the WebServer on ESP32 not using IP Address, but with a name directly. So, it won't matter what the IP Address is, it can always be ACCESSED with the Domain Name,
We will use the mDNS library for this, and assign a name to the IP Address.
#include <ESPmDNS.h>
Next, let us create a 'host' variable which will be the hostname to access the IP Address -
const char* host = "weatherboy";
Inside the void setup() function, just insert the below block of code -
if (!MDNS.begin(host)) { //http://<hostname>.local
Serial.println("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
As you can see above, I was able to access my site using http://weatherboy.local
and this opens endless possibilities with the projects we can make on WebServers.
For complete code, refer to Code Section.
NGROK to host on CloudIn this project, we will host the page we created from the server on ESP32 to the cloud. The IP Address is tunneled and the port is made available on the hosting server of NGROK.
1)First, sign up and login to ngrok.com -
2) Once you are Logged IN to the dashboard, download and unzip the file -
3) Now, run the ngrok.exe file. Go to Dashboard and copy the command with Auth Token. Use the command on the terminal that opened on opening ngrok application.
This will save the auth token to the configurations ngrok.yml file for future uses.
4) The very last thing, is to run the tunnel service from this terminal -
We can also use the IP Address or the hostname here. But to make sure we also need to mention the port we used to create the webserver.> ngrok http <host/IP-Address>:portnumber
There
we go, this will tunnel the IP Address and make it publicly available - for Free (temporary features)
That's it we have the service running on the URL Address on the 'Forwarding' key.
Do not worry about inability to copy the URL Link, go to the Dashboard > Endpoints and both the HTTP and HTTPS links will be available and clickable in there.
THERE WE GOOOO !! Control/Monitor your ESP32 through the Internet, from any corner in the world. Now you have a RealTime WebServer that is physically present with you, and you'd be able to access the website on the Device from the NGROK's link.
We are at the END of the Documentation on WebServers on ESP32.I have shared ALL the possibilities I am aware of, related to the WebServer. There are 2 separate ways to build a Web Server Page though, one of them runs/works inside the void loop() function instead of setup() as an endpoint. (Similar to Backend technologies)
Comments