ESP32: Sending JSON messages over MQTT

The objective of this post is to explain how to send JSON messages over MQTT using the ESP32.


Introduction

The objective of this post is to explain how to send JSON messages over MQTT using the ESP32. To do so, we will be using two libraries that handle the low level details and expose us both the JSON encoding and the MQTT publishing functionalities in easy to use interfaces. These libraries are the PubSubClient, for the MQTT related functionality, and the ArduinoJson, for the JSON related functionality.

Both of the libraries work with the ESP8266 and the ESP32 and have some examples to help us getting started, which I encourage you to try. Also, I’ve been covering their use with both devices in previous posts, which are listed in the related posts section bellow.

As MQTT broker, we will use CloudMQTT, which offers a free plan that allows us to create an account and test an instance of a broker. If you haven’t done it yet, please register and create an instance. We will need the instance information (address, port, username and password) latter.


The code

The first thing we need to do is including both the ArduinoJson.h and the PubSubClient.h libraries, in order to be able to access all the classes needed. We will also need to include the WiFi.h library, so we can connect to a WiFi network and thus be able to publish the messages to a MQTT topic.

In order to make the code more readable and easy to modify, we will declare some global variables to hold the credentials needed to connect to the WiFi network and to the MQTT broker. For the connection to the MQTT broker, we will need the information about the instance created, which is available in CloudMQTT instance information page.

#include <ArduinoJson.h>
#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 = "yourInstanceUsername";
const char* mqttPassword = "yourInstancePassword";

After that, we will declare an object of class WiFiClient. We will also declare an object of class PubSubClient, which receives as input of the constructor the previously declared WiFiClient instance. Note that we are not going to use the WiFiClient in our code, since it will be used by the PubSubClient library. So, we don’t need to worry about the implementation details.

WiFiClient espClient;
PubSubClient client(espClient);

After declaring the global variables, we will define the setup function. The first thing we do is opening a serial connection. Then, we connect to the WiFi network. Check here a detailed post which explains how to connect to a WiFi network with the ESP32.

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 broker we want to connect to.  To do so, we call the setServer method on the PubSubClient object, passing as inputs the address and the port. These arguments were the ones specified as global variables and obtained from the CloudMQTT instance page information.

Now, we will connect to the MQTT server by calling the connect method. This method receives as input a string which corresponds to the unique identifier of the client (we will use “ESP32Client”). It also receives both the username and password needed to connect to the broker,  available at the CloudMQTT instance page information.

This method call will return true on connection success and false otherwise. We will do the connection attempt in a loop.

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);

    }
  }

In the previous loop, we used two additional methods. The connected method returns true if the connection is established or false if not. Thus, we use it as stopping condition for our connection loop.

The state method will return a code with information about why the connection failed. So, we use the value to print the reason of failure when it is not possible to connect to the broker.

After this, we should already be connected to the MQTT broker and we can start publishing messages to topics. Nevertheless, we will do this on the main loop function, and thus we don’t need more code on the setup function.

Now, in the main loop function, we declare an object of class StaticJsonBuffer, which will be used for creating the JSON message to be sent over MQTT. We will need to specify the capacity of the buffer in bytes as a template parameter. Then, we get a reference to a JsonObject from the StaticJsonBuffer object we created, by calling the createObject method.

StaticJsonBuffer<300> JSONbuffer;
JsonObject& JSONencoder = JSONbuffer.createObject();

We will create a JSON message as indicated bellow. Note that we will create a message with static content just for keeping the code simple, but we could obtain the values from a sensor or other dynamic source.

{
"device": "ESP32",
"sensorType" : "Temperature",
"Value" : [20,21,23]
}

Next, we add the values to our JsonObject. You can check in more detail in this previous post how to do it.

JSONencoder["device"] = "ESP32";
JSONencoder["sensorType"] = "Temperature";
JsonArray& values = JSONencoder.createNestedArray("values");

values.add(20);
values.add(21);
values.add(23);

Now, we will print the JSON message to a char buffer by using the printTo method on the JsonObject reference. This method prints the message in a compact format, so it has the less overhead possible.

char JSONmessageBuffer[100];
JSONencoder.printTo(JSONmessageBuffer, sizeof(JSONmessageBuffer));

Next, we send the JSON message to a topic called “esp/test“. We do it by calling the publish method on our PubSubClient object. This method will receive as inputs both the topic name and the message we want to publish.

As can be seen here, this method returns “true” if the publish is successful and “false” otherwise. We will use this information for error handling.

Finally, we call the loop method on the same object reference. This should be called regularly so our program can process incoming messages and maintain the connection to the MQTT server. Since we are going to be sending the messages in the Arduino main loop function, with a small delay between each message, we call the loop method at the end of each iteration.

Serial.println(JSONmessageBuffer);

if (client.publish("esp/test", JSONmessageBuffer) == true) {
    Serial.println("Success sending message");
} else {
    Serial.println("Error sending message");
}

client.loop();

You can check final source code bellow, with some additional prints to help debugging.

#include <ArduinoJson.h>
#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 = "yourInstanceUsername";
const char* mqttPassword = "yourInstancePassword";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {

  Serial.begin(115200);
  Serial.println();

  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);

    }
  }

}

void loop() {

  StaticJsonBuffer<300> JSONbuffer;
  JsonObject& JSONencoder = JSONbuffer.createObject();

  JSONencoder["device"] = "ESP32";
  JSONencoder["sensorType"] = "Temperature";
  JsonArray& values = JSONencoder.createNestedArray("values");

  values.add(20);
  values.add(21);
  values.add(23);

  char JSONmessageBuffer[100];
  JSONencoder.printTo(JSONmessageBuffer, sizeof(JSONmessageBuffer));
  Serial.println("Sending message to MQTT topic..");
  Serial.println(JSONmessageBuffer);

  if (client.publish("esp/test", JSONmessageBuffer) == true) {
    Serial.println("Success sending message");
  } else {
    Serial.println("Error sending message");
  }

  client.loop();
  Serial.println("-------------");

  delay(10000);

}


Testing the code

To test the code, we will use MQTTLens to subscribe to the topic where the ESP32 will be publishing. So, open the application and subscribe to the “esp/test” topic.

After that, upload the code to the ESP32 and open the serial console. You should get an output similar to figure 1.

ESP32 Sending JSON over MQTT

Figure 1 – Output of the program.

Now, go back to MQTTLens. You should get an output similar to figure 2, with the JSON messages being printed. MQTTLens recognizes the JSON format and, although we sent the message in a compact format, it allows us to see it in an indented user friendly format.

MQTT receiving JSON over MQTT

Figure 2 – JSON messages sent by the ESP32.


Related posts


Technical details

  • ArduinoJson library: v5.9.0.
  • PubSubClient library: v2.6.0

20 thoughts on “ESP32: Sending JSON messages over MQTT”

  1. Guys,

    This is one of the few tutorials where the writer is actually explaining from a newbie standpoint rather than teaching to himself. Thanks for a very clear and detailed explanation!

    1. Hi! Thank you very much for the feedback, it’s very important for me to know that you are finding the content useful and easy to learn 🙂

      One of my objectives is to help people getting started with microcontrollers and IoT without having to face a steep learning curve. I think the tools we have nowadays allow it as long as we have good documentation and comprehensive tutorials available.

      Hope you keep finding the content interesting and easy to follow.

      Best regards,
      Nuno Santos

      1. Eduardo Zamora

        Hi Nuno,
        I’m actually working on a IoT networking of low cost microcontrollers, I am using ESP8266-01, 10, 12E/F, ESP32, MKR1000, AtMega2560. There are a few topics I don’t see covered here that I’d like to understand. I know you may not have time for personal replies, but it’s worth a try to give you my email just in case we can exchange a few ideas involving IoT work? Let me know where I can send an email to you, Perhaps you can point me out in the right direction.

        Thanks again!
        -EZ

        1. Hi Eduardo,

          Sorry for the delay, it has been a busy week. It seems a very interesting project and I would like to ear more about it. You can contact me at nuno_santos_slb@hotmail.com.

          Although unfortunately I don’t have much time to check source code or make extensive debugs, I’m always available to share some ideias or talk about high level architectures.

          I may have some delay in answering but I will do my best to help.

          Just for curiosity, are you Portuguese or Brazilian? You have a Portuguese like name 🙂

          Best regards,
          Nuno Santos

  2. Guys,
    This is one of the few tutorials where the writer is actually explaining from a newbie standpoint rather than teaching to himself. Thanks for a very clear and detailed explanation!

    1. Hi! Thank you very much for the feedback, it’s very important for me to know that you are finding the content useful and easy to learn 🙂
      One of my objectives is to help people getting started with microcontrollers and IoT without having to face a steep learning curve. I think the tools we have nowadays allow it as long as we have good documentation and comprehensive tutorials available.
      Hope you keep finding the content interesting and easy to follow.
      Best regards,
      Nuno Santos

      1. Eduardo Zamora

        Hi Nuno,
        I’m actually working on a IoT networking of low cost microcontrollers, I am using ESP8266-01, 10, 12E/F, ESP32, MKR1000, AtMega2560. There are a few topics I don’t see covered here that I’d like to understand. I know you may not have time for personal replies, but it’s worth a try to give you my email just in case we can exchange a few ideas involving IoT work? Let me know where I can send an email to you, Perhaps you can point me out in the right direction.
        Thanks again!
        -EZ

        1. Hi Eduardo,
          Sorry for the delay, it has been a busy week. It seems a very interesting project and I would like to ear more about it. You can contact me at nuno_santos_slb@hotmail.com.
          Although unfortunately I don’t have much time to check source code or make extensive debugs, I’m always available to share some ideias or talk about high level architectures.
          I may have some delay in answering but I will do my best to help.
          Just for curiosity, are you Portuguese or Brazilian? You have a Portuguese like name 🙂
          Best regards,
          Nuno Santos

  3. Pingback: ESP32 Espruino: Deserializing JSON | techtutorialsx

  4. Pingback: ESP32 Espruino: Deserializing JSON | techtutorialsx

    1. Hi!

      Thank you very much for the feedback 🙂

      Did you experience any problem during compiling? It seems to be there, it displays if you scroll to the right 🙂

      Best regards,
      Nuno Santos

    1. Hi!
      Thank you very much for the feedback 🙂
      Did you experience any problem during compiling? It seems to be there, it displays if you scroll to the right 🙂
      Best regards,
      Nuno Santos

        1. Hi!

          Which version of ArduinoJson are you using? I think V6 has some breaking changes, and this tutorial was done prior to that release.

          Best regards,
          Nuno Santos

  5. Ok this is a relativ old topic. 😉

    Thanks for the great reference!

    The only thing I can contribute is that in the loop it might be better to build the pause with millis()

Leave a Reply to kaebmooCancel reply

Discover more from techtutorialsx

Subscribe now to keep reading and get access to the full archive.

Continue reading