ESP32: WebSerial and mDNS

Introduction

In this tutorial we will learn how to use WebSerial and perform the resolution of the ESP32 domain name using mDNS.

In this past tutorial, we have learned the basics of WebSerial and how it can be useful to debug when a physical serial connection to the ESP32 is not available. Nonetheless, it is easy to notice that, in the sample code provided, we had to actually open a wired serial connection in order to output the IP address assigned to the ESP32 on the WiFi network, since we needed it to reach the server that serves the WebSerial console interface.

Typically, the IP address assigned to the ESP32 doesn’t change frequently, meaning that we could potentially do this once with a wired connection and then keep using the same IP address every time we connect to the ESP32. Nonetheless, the address may indeed change and it may also be impractical if we are flashing many different devices.

As such, the more adequate solution is to use mDNS, a protocol that allows to resolve locally defined names without the need for a dedicated infrastructure. For a detailed tutorial on how to use mDNS on the ESP32, please go here.

Note that the fact that we are adding this domain resolution layer doesn’t affect the way WebSerial works. As such, the WebSerial related methods we are going to call are not aware of the existance of mDNS, which allows us to have a cleaner code with a good separation of concerns.

IMPORTANT: The device you use to reach the ESP32 server (your computer, for example) will need to be able to perform the resolution of addresses using mDNS. This varies between operating systems. If you are having troubles reaching the ESP32, please make sure to investigate if your computer operating system is able to perform the resolution or if you need any additional software to enable that support.

If you prefer a video version of this tutorial, please check below:

The tests shown below were performed on a ESP32-E FireBeetle board from DFRobot. The Arduino core version used was 2.0.0 and the Arduino IDE version was 1.8.15, working on Windows 8.1. The code was also tested on Platformio.

The code

As usual, we start by the library includes:

  • WiFi.h: Connecting the ESP32 to a WiFi network.
  • ESPAsyncWebServer.h: Setting up a HTTP server, to be used under the hood by the WebSerial lib.
  • WebSerial.h: WebSerial related functionality.
  • ESPmDNS.h: Setting up the domain name of the ESP32.

After that, we will define two variables to hold the credentials of the WiFi network (name and password).

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";

Then we will create an object of class AsyncWebServer, to be used under the hood by the WebSerial lib. As input of the constructor of this class we need to pass the number of the port where the server will be listening to incoming requests. We will use port 80, the default HTTP port.

AsyncWebServer server(80);

Moving on to the Arduino setup, we will now connect the ESP32 to the WiFi network, using the previously defined credentials. Please note that, this time, we are not opening a wired serial connection at the beginning of our setup, meaning we won’t be able to output debug messages in case of error. Naturally, in a real application scenario, it is recommended that you find an adequate way to handle any possible error situation, depending on your application requirements.

WiFi.begin(ssid, password);
  
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
}

After the connection to the WiFi network is performed, we will take care of setting up mDNS. To do so we simply need to call the begin method on the MDNS extern variable, passing as input the hostname we want to assign to the ESP32. Note that this is the name we later will need to use when reaching the ESP32 to serve to us the WebSerial UI. I’ll be using “esp32” as hostname, but you can use another name if you prefer, as long as you use it also later, when accessing the server in a web browser.

This method returns a Boolean value indicating if the initialization was successful (true) or not (false). Since we don’t have a wired serial interface to print any debug message, we are simply going to return in case of error.

if(!MDNS.begin("esp32")) {
   return;
}

After that, we are going to call the begin method on the WebSerial object, passing as input the address of our AsyncWebServer object. Under the hood, this method will take care of all the configurations necessary to servr the WebSerial UI and to expose the WebSocket endpoint that is used to exchange data with the WebSerial console.

WebSerial.begin(&server);   

Finally we will call the begin method on our server object, so it starts listening to incoming requests.

server.begin();

The complete Arduino setup is available below.

void setup() {
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }
  
  if(!MDNS.begin("esp32")) {
     return;
  }
 
  WebSerial.begin(&server);   
  server.begin();
}

We will take care of printing a periodic message to the serial interface once every second in the Arduino main loop. To print a message, we simply need to call the println method on the WebSerial object (notice the similarity of the method name with the Serial object we use when printing to a wired serial connection).

The full loop, already containing this print and the delay between iterations, is shown below.

void loop() {
  WebSerial.println("Hello World");
  delay(1000);    
}

The complete code can be seen below.

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <WebSerial.h>
#include <ESPmDNS.h>

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";
 
AsyncWebServer server(80);
  
void setup() {
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }
  
  if(!MDNS.begin("esp32")) {
     return;
  }
 
  WebSerial.begin(&server);   
  server.begin();
}
  
void loop() {
  WebSerial.println("Hello World");
  delay(1000);    
}

Testing the code

To test the code, simply compile it and upload it to your device using a tool of your choice (Arduino IDE, platformio). After the procedure is finished, open a web browser of your choice and type the following in the address bar:

http://esp32.local/webserial

You should see a result similar to figure 1. As can be observed in the image, we used a local domain name and we were able to reach the ESP32 server, which served the UI of the WebSerial console.

ESP32 WebSerial interface, with domain name resolved by mDNS.
Figure 1 – ESP32 WebSerial interface, with domain name resolved by mDNS.

mDNS and SoftAP

To finalize, we present an example where the ESP32 will be acting as SoftAP and the domain resolution will be done using mDNS. The code is similar to the one from before, except that instead of connecting to a WiFi network, we host one from the ESP32.

#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <WebSerial.h>
#include <ESPmDNS.h>
   
const char *ssid = "MyESP32AP";
const char *password = "apPassword";
 
AsyncWebServer server(80);
  
void setup() {
  
  WiFi.softAP(ssid, password);
  
  if(!MDNS.begin("esp32")) {
     return;
  }
 
  WebSerial.begin(&server);   
  server.begin();
}
  
void loop() {
  WebSerial.println("Hello World");
  delay(1000);    
}

Suggested ESP32 Readings

Leave a Reply