In this tutorial we will check how use a ESP32 to query a service advertised with mDNS. The tests from this tutorial were done using two DFRobot ESP32 development boards.
Introduction
In this tutorial we will check how use a ESP32 to query a service advertised with mDNS. The service advertiser will also be a ESP32. We will be using the Arduino core to program both devices.
For an introductory tutorial on how to advertise a service using mDNS, please check here.
We will be querying a given service type and obtain as result the hostname and IP address of the provider, and also the port where the service is being exposed.
The code shown here is based on the example from the Arduino core, which I encourage you to check.
The tests from this tutorial were done using two DFRobot ESP32 development boards.
If you prefer a video version of this tutorial, please check my YouTube channel below.
The service provider code
On this section we will analyze the code of the ESP32 that will act as service provider. Note that the actual service won’t be implemented since we will focus on the mDNS part.
We will start by the library includes. We will need the ESPmDNS.h, to be able to advertise the service, and the WiFi.h, to be able to connect the ESP32 to the WiFi network.
We will also define two variables to hold the WiFi credentials: network name and password.
#include <ESPmDNS.h> #include <WiFi.h> const char* ssid = "yourNetworkName"; const char* password = "yourNetworkPassword";
Moving on to the Arduino setup, we will start by opening a serial connection, to be able to output the results of the program.
Then we will connect the ESP32 to the WiFi network, using the previously defined credentials.
Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); }
After this we will setup the mDNS responder with a call to the begin method on the MDNS extern variable. As input, we pass a string with the ESP32 hostname. We will use the value “esp32“.
if(!MDNS.begin("esp32")) { Serial.println("Error starting mDNS"); return; }
Once we have started the mDNS responder, we simply need to call the addService method on the MDNS variable. As first input we pass a string with the name of the service, as second input the protocol the service runs on and as third and last input the network port.
We will assume that we are exposing a HTTP service over TCP, on port 80.
MDNS.addService("http", "tcp", 80);
To finalize, we will print the local IP address of the ESP32, so we can then confirm it matches the address obtained from the inquirer microcontroller.
Serial.println(WiFi.localIP());
The complete code can be seen below.
#include <ESPmDNS.h> #include <WiFi.h> const char* ssid = "yourNetworkName"; const char* password = "yourNetworkPassword"; void setup(){ Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); } if(!MDNS.begin("esp32")) { Serial.println("Error starting mDNS"); return; } MDNS.addService("http", "tcp", 80); Serial.println(WiFi.localIP()); } void loop(){}
The service inquirer code
Like before, we will do the same library includes and define two global variables to hold the network credentials.
#include <ESPmDNS.h> #include <WiFi.h> const char* ssid = "yourNetworkName"; const char* password = "yourNetworkPassword";
Then, moving on to the Arduino setup, we will start by opening a serial connection and, after that, connect the ESP32 to the WiFi network.
Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("Connecting...\n\n"); }
Then we will take care of initializing mDNS. Note however that if we use the approach we followed in the network service provider code, we will need to provide a hostname. Nonetheless, in this case, we simply want our ESP32 to be able to query a service, so it doesn’t make sense to force us to provide a hostname.
So, we can make use of a lower level function from IDF called mdns_init. This function takes no arguments and returns the constant ESP_OK in case the initialization procedure successfully completed.
if(mdns_init()!= ESP_OK){ Serial.println("mDNS failed to start"); return; }
Then, to query a service type, we simply need to call the queryService method on the MDNS extern variable.
This method receives as first input the service name (in our case “http“) and as second input the protocol (in our case “tcp“). Note that these two values allow to define the type of service we want to query.
As output, this method returns the number of services found.
int nrOfServices = MDNS.queryService("http", "tcp"); if (nrOfServices == 0) { Serial.println("No services were found."); }
In case we found services (the mentioned counter is greater than 0) we will first print the number of services found.
Since we have only one ESP32 advertising such service, we expect this count to be equal to 1. Naturally, if there were more devices on the network advertising a “http” over “tcp” service, this count would be higher.
Serial.print("Number of services found: "); Serial.println(nrOfServices);
Then we will use a for loop to iterate over each detected service and prints its information.
for (int i = 0; i < nrOfServices; i=i+1) { // print service information }
To get the hostname of the service provider, we simply need to call the hostname method on the MDNS extern variable, passing as input the index of the service to which we want to obtain this information.
Serial.println(MDNS.hostname(i));
To obtain the IP address of the network service provider, we can call the IP method. Like before, this method receives as input the index of the service.
Serial.println(MDNS.IP(i));
To obtain the network port we can call the port method and, once again, pass as input the index of the service.
Serial.println(MDNS.port(i));
The loop code can be seen below.
for (int i = 0; i < nrOfServices; i=i+1) { Serial.println("---------------"); Serial.print("Hostname: "); Serial.println(MDNS.hostname(i)); Serial.print("IP address: "); Serial.println(MDNS.IP(i)); Serial.print("Port: "); Serial.println(MDNS.port(i)); Serial.println("---------------"); }
The complete code can be seen below.
#include <ESPmDNS.h> #include <WiFi.h> const char* ssid = "yourNetworkName"; const char* password = "yourNetworkPassword"; void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("Connecting...\n\n"); } if(mdns_init()!= ESP_OK){ Serial.println("mDNS failed to start"); return; } int nrOfServices = MDNS.queryService("http", "tcp"); if (nrOfServices == 0) { Serial.println("No services were found."); } else { Serial.print("Number of services found: "); Serial.println(nrOfServices); for (int i = 0; i < nrOfServices; i=i+1) { Serial.println("---------------"); Serial.print("Hostname: "); Serial.println(MDNS.hostname(i)); Serial.print("IP address: "); Serial.println(MDNS.IP(i)); Serial.print("Port: "); Serial.println(MDNS.port(i)); Serial.println("---------------"); } } } void loop() {}
Testing the code
To test the whole system, start by compiling and upload the code to the device that will act as a service provider. Once the procedure finishes, open the Arduino IDE serial monitor.
You should obtain a result similar to figure 1. As can be seen, the IP address of the device gets printed after it connects to the network.
Figure 1 – Output of the ESP32 acting as service provider.
After this, compile and upload the code to the ESP32 that will query the service. After opening the serial monitor, you should get a result similar to figure 2.
As illustrated, one service is found. The hostname obtained is “esp32”, like we defined on the service provider. The IP address obtained also matches the one from the service provider, shown in figure 1.
To finalize, we also obtain network port 80, which matches what was advertised.
Figure 2 – Output of the ESP32 acting as service inquirer.