ESP32: Publishing messages to MQTT topic

The objective of this post is to explain how to publish a message to a MQTT topic, using the ESP32 and the Arduino IDE libraries.


Introduction

The objective of this post is to explain how to publish a message to a MQTT topic, using the ESP32 and the Arduino IDE libraries.

We will assume that the broker will be hosted on CloudMQTT, which is the host we’ve been using in previous tutorials about MQTT. Since CloudMQTT has a free plan, we can just create an account and test it. Setting an account is really simple. You can check here how to do it and how to create a broker instance.

After completing the procedure, check the instance information page, which should be similar to the one shown in figure 1. The important credentials that we will be using on the ESP32 code are the server, the user, the password and the port.

ESP8266 CloudMQTT Credentials

Figure 1 – CloudMQTT instance information.

For the ESP32 side, we are going to use a MQTT library, called PubSubClient. This was the same library used in the previous tutorial on how to connect the ESP8266 to a MQTT broker. Although at the time of writing there is no support mentioned for the ESP32, as can be seen here, the library works fine.

As usual, the easiest way to install the library is via Arduino IDE library manager, as can be seen in figure 2.

Arduino MQTT Pub Sub library

Figure 2 – PubSub library installation, via Arduino IDE library manager.


The code

The code needed for us to connect to the MQTT broker and publish a message to a topic will be very similar to the one used on the ESP8266 post. These are good news since the code can be reused for the ESP32, making it easier to port applications.

As usual, we need to include some libraries in our code. We need the WiFi library, in order to be able to connect the ESP32 to a WiFi network, and the PubSubClient library, which will allow us to connect to a MQTT broker. For a more detailed explanation on how to connect the ESP32 to a WiFi network, check here.

In order to have an easy to modify and readable code, we will declare the credentials and information needed to connect to both the WiFi network and the MQTT broker in global variables. For the connection to the MQTT broker, we will need the server address, the port, the username and the password, which can be obtained in the instance information page, as shown in figure 1 of the introduction section.

#include <WiFi.h>
#include <PubSubClient.h>

const char* ssid = "yourNetworkName";
const char* password = "yourNetworkPassword";
const char* mqttServer = "m11.cloudmqtt.com";
const int mqttPort = 12948;
const char* mqttUser = "yourMQTTuser";
const char* mqttPassword = "yourMQTTpassword";

After that, we will declare an object of class WiFiClient, which allows to establish a connection to a defined IP and port. Nevertheless, we will not explicitly use this object because it will be used by the MQTT library under the hood.

We will also declare an object of class PubSubClient and pass as input of the constructor the previously defined WiFiClient.

WiFiClient espClient;
PubSubClient client(espClient);

As usual, in the setup function, we open a serial connection, since this is the easiest way to output the results of our program. We will also connect to WiFi network, so we can reach the MQTT broker and publish messages to topics.

Serial.begin(115200);
WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi..");
}

Serial.println("Connected to the WiFi network");

Next, we need to specify the address and the port of the MQTT server, which were previously declared in our global variables.  To do so, we call the setServer method on the PubSubClient object, which receives as parameters both the address and the port.

After that, we will connect to the MQTT server. To do the actual connection, we call the connect method, passing as input parameters a unique identifier for our client, the authentication username and password. We will use as identifier “ESP32Client”.

This method call will return true on connection success and false otherwise.

client.setServer(mqttServer, mqttPort);

while (!client.connected()) {
    Serial.println("Connecting to MQTT...");

    if (client.connect("ESP32Client", mqttUser, mqttPassword )) {

      Serial.println("connected");  

    } else {

      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);

    }
}

Note that in the previous code we used two auxiliary methods. The connected method returns true if the connection is established or false otherwise. The state method will return a code with information about why the connection failed. Check here the possible returning values.

Finally, we will publish a message to a topic. To do so, we call the publish method, passing as input parameters the topic name and the message to publish. We will just publish a “Hello from ESP32” message on the “esp/test” topic.

client.publish("esp/test", "Hello from ESP32");

Check bellow the full source code, which already includes the main loop function. There, we will call the loop method of the PubSubClient. This method needs to be called regularly in order to allow the receiving of messages and maintaining the connection to the broker. Naturally, in our case, since we only want to publish a message to the topic and we will not do anything more, we are including it just as an example.

#include <WiFi.h>
#include <PubSubClient.h>

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPassword";
const char* mqttServer = "m11.cloudmqtt.com";
const int mqttPort = 12948;
const char* mqttUser = "yourMQTTuser";
const char* mqttPassword = "yourMQTTpassword";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {

  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");

  client.setServer(mqttServer, mqttPort);

  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");

    if (client.connect("ESP32Client", mqttUser, mqttPassword )) {

      Serial.println("connected");

    } else {

      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);

    }
  }

  client.publish("esp/test", "Hello from ESP32");

}

void loop() {
  client.loop();
}


Testing the code

To test the code, we are going to use an application called MQTTLens, which will allow us to subscribe to a MQTT topic and receive published messages. So, open the application and subscribe to the “esp/test” topic, which was the one we specified in the ESP32 code.

After that, just upload and run the code on the ESP32. On the Arduino IDE serial monitor, you should get a result similar to figure 3.

ESP32 connection to MQTT broker

Figure 3 – Connection to MQTT broker on the ESP32.

On the MQTTLens side, you should receive the message published on the topic, as shown in figure 4.

MQTTLens receiving MQTT ESP32 message

Figure 4 – Receiving the message on MQTTLens.


Related Content


Related Posts

 

Technical details

  • PubSubClient library: v2.6.0

8 Replies to “ESP32: Publishing messages to MQTT topic”

  1. I run this program, exactly as provided in this tutorial and using MQTT Link for tests. MQTT does not display the message sent by the code at Line 42 in your program. I can use MQTT Link to send a message to the ESP8266, though, and I see it in the Arduino Terminal window. When I run the program I see the same output shown in your Figure 3. Although I have configured MQTT Link as shown in Figure 4, it is difficult to read. I have esp/test as the subscribe and esp/test as the publish as per Figure 4. MQTT’s message area shows no messages received. Can you suggest what’s wrong? Perhaps some timing issue with your code and how MQTT tests for and responds to a message?

  2. I run this program, exactly as provided in this tutorial and using MQTT Link for tests. MQTT does not display the message sent by the code at Line 42 in your program. I can use MQTT Link to send a message to the ESP8266, though, and I see it in the Arduino Terminal window. When I run the program I see the same output shown in your Figure 3. Although I have configured MQTT Link as shown in Figure 4, it is difficult to read. I have esp/test as the subscribe and esp/test as the publish as per Figure 4. MQTT’s message area shows no messages received. Can you suggest what’s wrong? Perhaps some timing issue with your code and how MQTT tests for and responds to a message?

  3. I think I found the problem: Several instances of MQTT Link running. Got program to run. Probably not an issue with your code, but you might mention that people should have only one MQTT Link app running.

    Suggestion: Add a couple of lines of code to let people confirm publishing success, as per:

    bool MQTT_Reply = client.publish(“esp/test”, “Hello from ESP8266”);
    if (MQTT_Reply = true)
    {
    Serial.print(“Publish success.”);
    }
    else
    {
    Serial.print(“Publish failure.”);
    }

    1. Hi!

      Thanks for the suggestions and I’m glad you have found the solution. 🙂

      Regarding the problem of having multiple instances running, I did not test that use case, so I was not even aware of that problem.

      I try to share that kind of problems if I encounter them during my tests, but I do this as an hobby so unfortunately don’t have the time to test all the possible scenarios.

      In this particular tutorial, the one you described with multiple instances running is an example of something I did not test, so I could not anticipate it.

      This is why I really encourage people to share eventual problems they encounter and improvement suggestions, so others can see them and hopefully everyone benefits 🙂

      Best regards,
      Nuno Santos

  4. I think I found the problem: Several instances of MQTT Link running. Got program to run. Probably not an issue with your code, but you might mention that people should have only one MQTT Link app running.
    Suggestion: Add a couple of lines of code to let people confirm publishing success, as per:
    bool MQTT_Reply = client.publish(“esp/test”, “Hello from ESP8266”);
    if (MQTT_Reply = true)
    {
    Serial.print(“Publish success.”);
    }
    else
    {
    Serial.print(“Publish failure.”);
    }

    1. Hi!
      Thanks for the suggestions and I’m glad you have found the solution. 🙂
      Regarding the problem of having multiple instances running, I did not test that use case, so I was not even aware of that problem.
      I try to share that kind of problems if I encounter them during my tests, but I do this as an hobby so unfortunately don’t have the time to test all the possible scenarios.
      In this particular tutorial, the one you described with multiple instances running is an example of something I did not test, so I could not anticipate it.
      This is why I really encourage people to share eventual problems they encounter and improvement suggestions, so others can see them and hopefully everyone benefits 🙂
      Best regards,
      Nuno Santos

Leave a Reply to KairozS Cancel reply