ESP32 MQTT Publish Multiple Sensor Readings to Node-Red with Arduino IDE

In this tutorial, we will learn to publish sensor readings to Node-Red with ESP32 MQTT and Arduino IDE. We will perform MQTT communication with ESP32 and Node-Red by publishing and subscribing to MQTT topics. There will be one ESP32 MQTT publisher and Node-Red as a subscriber. We will publish DS18B20, DHT, and BME280 sensor readings to MQTT with ESP32, and Node-Red Dashboard will subscribe to the MQTT topics and display all the sensor readings on the Dashboard.

ESP32 MQTT Publish BME280 DS18B20 DHT22 to Node-Red

We will use the Mosquitto broker that is installed on the Raspberry Pi. But if you do not have Raspberry Pi, you can also install it on your Windows or Linux Ubuntu machine.

Both Publisher and Subscriber will make connections with the MQTT broker installed on Raspberry Pi. After that, the ESP32 will publish sensor data to the Node-Red dashboard on specified topics.

ESP32 MQTT Publish Multiple Sensors to Node-Red

The diagram below illustrates the process that we will follow in our ESP32 MQTT Publisher Subscriber project involving multiple sensors.

ESP32 MQTT Publish Sensor Readings to Node-Red with Arduino IDE
  1. An ESP32 board connected with DHT22, BME280, and DS18B20 sensors will connect to the MQTT broker. We will use Mosquitto broker on Raspberry Pi. Refer to the following article (Install Mosquitto MQTT Broker on Raspberry Pi) to successfully install it in Raspberry Pi before moving forward.
  2. This ESP32 board publishes the DHT22 temperature readings on the MQTT topic: esp32/dht/temperature and publishes the DHT22 humidity readings on the MQTT topic: esp32/dht/humidity.
  3. It also publishes the BME280 temperature readings on the topic: esp32/bme280/temperature. It publishes the BME280 humidity readings on the topic: esp32/bme280/humidity. Likewise, it publishes the BME280 pressure readings on the topic: esp32/bme280/pressure.
  4. Similarly, this board publishes the DS18B20 temperature readings in Celsius on the MQTT topic: esp32/ds18b20/temperatureC and publishes the DS18B20 temperature readings in Fahrenheit on the MQTT topic: esp32/ds18b20/temperatureF.
  5. We have Node-Red as a subscriber to these seven topics. Node-Red receives the sensor data and displays them in an interactive manner in its dashboard.

MQTT Protocol Introduction

  • MQTT is known as Message Queuing Telemetry Transport protocol.
  • It is a lightweight messaging protocol and helps resource constrained network clients with a simple communication mechanism.
  • Unlike, most messaging system, we don’t have to assign addresses to MQTT clients.
  • MQTT uses simple publish/subscribe communication based on a topic.
  • This protocol runs on top of TCP / IP in order to provide reliable data delivery.
MQTT Protocol Introdution

For a detailed tutorial regarding MQTT, its main components, MQTT broker and working follow the link: 

ESP32 Publish Sensor Readings on MQTT Topics

Our ESP32 MQTT Publisher is connected with a DHT22 sensor, a BME280 sensor, and a DS18B20 sensor.

DHT22 is a sensor which measures relative humidity and temperature. It provides a calibrated digital output with a 1-wire protocol. DHT sensors are pre-calibrated. We can directly connect them with ESP32 to obtain sensor output reading. They are internally composed of a humidity sensing sensor and a thermistor. These two components measure humidity and temperature.

The BME280 sensor is used to measure readings regarding ambient temperature, barometric pressure, and relative humidity. It is mostly used in web and mobile applications where low power consumption is key. This sensor uses I2C or SPI to communicate data with the micro-controllers. Although there are several different versions of BME280 available in the market, the one we will be studying uses the I2C communication protocol.

DS18B20 is a temperature sensor which is single wire programmable in nature. It is widely used to measure temperature of chemical solutions and substances which are present in a hard environment. One of the advantages of using this sensor is that we only require a single pin of our ESP32 board to transfer data. Thus, it is extremely convenient to use with the micro-controller as we can measure multiple temperatures by using the least number of pins on our development board. 

Interfacing DHT22, BME280, and DS18B20 sensors with ESP32

We will now learn how to connect the sensors with the ESP32 board. We will need the following components.

ESP32 MQTT Publish BME280 DS18B20 DHT22 sensors readings

Required Components

  1. ESP32 board
  2. DHT22 sensor
  3. 10k ohm resistor (not required if using the DHT22 sensor module)
  4. BME280 sensor
  5. DS18B20  sensor
  6. 4.7k ohm resistor
  7. Breadboard
  8. Connecting Wires

DHT22 Connections

  • The first pin the DHT22 sensor is a power supply(VCC) pin. Connect it with the 3.3 volt or Vin pin of ESP32.
  • Data out is the pin through which we get temperature and humidity samples from the DHT sensor. Connect this pin with GPIO15 of ESP32 and also connect the data pin with a 10k pull-up resistor. But you can also use any digital pin of ESP32. A Pull-up resistor is used to keep the data pin high for proper communication between the microcontroller and sensor. You can check the datasheet of DHT22 to get more information about it. DHT22 is also known by the name of AM2302. If you are using a DHT22 sensor module then you do not need to add the resistor.
  • Third pin is not used.
  • Connect the fourth pin (GND) to the ground pin of the ESP32 board.

BME280 Connections

The connection of BME280 with the ESP32 boards is very easy. We have to connect the VCC terminal with 3.3V, ground with the ground (common ground), SCL of the sensor with SCL of the module, and SDA of the sensor with the SDA pin of the ESP32 module.

The I2C pin in ESP32 for SDA is GPIO21 and for SCL is GPIO22.

DS18B20 Connections

The DS18B20 sensor can be powered in two different modes.

Normal Mode: The sensor is powered through an external source through the VDD pin and 4.7K ohm pull-up resistor.

Parasite Mode: The sensor obtains power from its own data line. Hence, no external power supply is required.

We will power DS10B20 in normal mode hence it is powered with its Vcc pin from 3.3V pin of ESP32 board.

The DS18B20 sensor has three terminals. The first terminal is grounded with the ESP32 board. The data line of the sensor, which is the middle terminal, is connected through GPIO4 through a pull-up resistor of 4.7k-ohm. We can choose any other GPIO pin as well. The third terminal is powered by 3.3V from the ESP board.

You can use any other GPIO pin of ESP32 module. You can refer to the post below, to know more about ESP32 GPIO pins:

Connect ESP32 with the sensors as shown in the schematic diagram below:

ESP32 with DHT22, BME280 and DS18B20 schematic diagram

We have used the same connections as described above.

Install Arduino Libraries

Before we proceed further, you should make sure that you have the latest version of Arduino IDE installed on your system. Moreover, you should also install an ESP32 add-on in Arduino IDE. If your IDE does not have the plugin installed you can visit the link below:

Installing ESP32 library in Arduino IDE and upload code

For this project, we will have to install libraries for the DHT sensor, BME280 sensor, DS18B20 sensor, and MQTT.

Install DHT11/DHT22 Library in Arduino IDE

Both DHT11 and DHT22 provide the output of temperature and humidity in the complex digital output format which can not be directly read with GPIO pins without writing any technique which can read these output signals. These sensors provide data through a single wire two-way communication protocol. A single process communication consists of 40 bits. But we do not need to worry about the working of these sensors and on which protocol we can receive this data. We have an Arduino library for DHT sensors which can be easily used to get values of temperature and humidity only by calling two lines of functions. We will see later on how to do it. Now let’s see how to install the DHT library in Arduino. This library is provided by Adafruit. Follow these steps to install the DHT sensor library:

Open Arduino IDE and click on Sketch > Library > Manage Libraries.

When you click on the manage libraries option, you will get this window. In this window write ‘DHT sensor‘ in the search bar and press enter.

You will see many options available for DHT11 and DHT22 libraries. Select Adafruit library and click on the install button. You can select the latest version from the version window.

The same library can be used for both DHT11 and DHT22/AM2302 sensors.

Adafruit also provides libraries for other sensors. So they provided a support package which is used to handle all sensor libraries. We also need to install the Adafruit Unified Sensor library. To install this, paste the  Adafruit Unified Sensor search bar and select this option and click on the install button.

Adafruit unified sensor library arduino ide

You may also like to read:

Install DS18B20 Arduino Libraries

To use the Dallas DS18B20 sensor we will have to install two libraries.

  1. OneWire library
  2. DallasTemperature library

Follow the steps below to successfully install them. We will use the Library Manager in our Arduino IDE to install the latest versions of the libraries. Open your Arduino IDE and go to Sketch > Include Libraries > Manage Libraries. Type each library name in the search bar and install them both.

ds18b20 one wire library install
ds18b20 dallas temperature library install

Installing BME280 Arduino Library

As we are connecting the BME280 sensor with ESP32 so we will have to install BME280 libraries to our module. We will require two libraries for this project:

  1. Adafruit_BME280 library
  2. Adafruit_Sensor library

We will use the Library Manager in our Arduino IDE to install the latest versions of the libraries. Open your Arduino IDE and go to Sketch > Include Libraries > Manage Libraries. Type Adafruit BME280 library name in the search bar and install them both.

Adafruit BME280 library Arduino IDE

Open your Arduino IDE and go to Sketch > Include Libraries > Manage Libraries. Type Adafruit unified sensor library name in the search bar and install it.

Adafruit unified sensor library install

Install Async MQTT Client Library and Async TCP Library

We will use Async MQTT Client Library by Marvin Roger to use MQTT with ESP32. AsyncTCP is another library that we will be incorporating as it is required for our ESP32 MQT project. Both of these libraries are not available in the Arduino library manager. Therefore, we will have to download and install them on our ESP32 board ourselves.

  • To install Async MQTT Client library, click here to download. You will download the library as a .zip folder which you will extract. Then, transfer this folder to the library folder in your Arduino IDE.
  • To install the Async TCP library, click here to download. You will download the library as a .zip folder which you will extract and rename as ‘AsyncTCP’. Then, copy the ‘AsyncTCP’ folder to the library folder in your Arduino IDE.

Similarly, you can also go to Sketch > Include Library > Add .zip Library inside the IDE to add the libraries.

After installation of the libraries, restart your IDE.

ESP32 MQTT Publisher for DS18B20, DHT, and BME280 Arduino Sketch

Open your Arduino IDE and go to File > New to open a new file. Copy the code given below in that file and save it. You need to enter your network credentials and your Raspberry Pi IP address. This sketch will develop an ESP32 MQTT publisher by following the steps given below:

  • Connecting the ESP32 board with the local network
  • Setting up the DHT22, BME280, and DS18B20 sensors
  • Connecting the ESP32 to the MQTT broker
  • Publishing the sensor readings to the MQTT topics
#include "DHT.h"
#include <WiFi.h>
extern "C" {
  #include "freertos/FreeRTOS.h"
  #include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <OneWire.h>
#include <DallasTemperature.h>

//replace with your network credentials
#define WIFI_SSID "PTCL-08"
#define WIFI_PASSWORD "44332211"

// Raspberry Pi Mosquitto MQTT Broker
#define MQTT_HOST IPAddress(192, 168, 10, 8)
#define MQTT_PORT 1883

//MQTT Topics
#define MQTT_PUB_TEMP_DHT "esp32/dht/temperature"
#define MQTT_PUB_HUM_DHT  "esp32/dht/humidity"

#define MQTT_PUB_TEMP_BME280 "esp32/bme280/temperature"
#define MQTT_PUB_HUM_BME280  "esp32/bme280/humidity"
#define MQTT_PUB_PRES_BME280 "esp32/bme280/pressure"

#define MQTT_PUB_TEMP_C "esp32/ds18b20/temperatureC"
#define MQTT_PUB_TEMP_F "esp32/ds18b20/temperatureF"

#define DHTPIN 15  
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);

Adafruit_BME280 bme;

const int SensorDataPin = 4;   
  
OneWire oneWire(SensorDataPin);
DallasTemperature sensors(&oneWire);

float temperature_DHT, humidity_DHT; //variables for DHT
float temperature_BME280, humidity_BME280, pressure_BME280;   //variables for BME280
float temperature_Celsius, temperature_Fahrenheit;  //variables for DS18B20

AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;

unsigned long previousMillis = 0;   
const long interval = 10000;        

void connectToWifi() {
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void connectToMqtt() {
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
}

void WiFiEvent(WiFiEvent_t event) {
  Serial.printf("[WiFi-event] event: %dn", event);
  switch(event) {
    case SYSTEM_EVENT_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); 
      xTimerStart(wifiReconnectTimer, 0);
      break;
  }
}

void onMqttConnect(bool sessionPresent) {
  Serial.println("Connected to MQTT.");
  Serial.print("Session present: ");
  Serial.println(sessionPresent);
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  Serial.println("Disconnected from MQTT.");
  if (WiFi.isConnected()) {
    xTimerStart(mqttReconnectTimer, 0);
  }
}

void onMqttPublish(uint16_t packetId) {
  Serial.print("Publish acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void setup() {
  Serial.begin(115200);
  Serial.println();

  dht.begin();
  delay(1000);

  if (!bme.begin(0x76)) {
    Serial.println("Could not detect a BME280 sensor, Fix wiring connections!");
    while (1);
  }
  delay(1000);

  sensors.begin();
  delay(1000);
  
  mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
  wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));

  WiFi.onEvent(WiFiEvent);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onPublish(onMqttPublish);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  connectToWifi();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    //Read from DHT
    humidity_DHT = dht.readHumidity();
    temperature_DHT = dht.readTemperature();
    
    if (isnan(temperature_DHT) || isnan(humidity_DHT)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }
    //delay(3000);

    //Read from BME280
    temperature_BME280 = bme.readTemperature();
    humidity_BME280 = bme.readHumidity();
    pressure_BME280 = bme.readPressure() / 100.0F;
    //delay(3000);

    //Read from DS18B20
    sensors.requestTemperatures(); 
    temperature_Celsius = sensors.getTempCByIndex(0);
    temperature_Fahrenheit = sensors.getTempFByIndex(0);
    //delay(3000);
    
    // Publish an MQTT message on topic esp32/dht/temperature
    uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP_DHT, 1, true, String(temperature_DHT).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_DHT, packetIdPub1);
    Serial.printf("Message: %.2f \n", temperature_DHT);

    // Publish an MQTT message on topic esp32/dht/humidity
    uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM_DHT, 1, true, String(humidity_DHT).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM_DHT, packetIdPub2);
    Serial.printf("Message: %.2f \n", humidity_DHT);

        // Publish an MQTT message on topic esp32/bme280/temperature
    uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_TEMP_BME280, 1, true, String(temperature_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_BME280, packetIdPub3);
    Serial.printf("Message: %.2f \n", temperature_BME280);

    // Publish an MQTT message on topic esp32/bme280/humidity
    uint16_t packetIdPub4 = mqttClient.publish(MQTT_PUB_HUM_BME280, 1, true, String(humidity_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM_BME280, packetIdPub4);
    Serial.printf("Message: %.2f \n", humidity_BME280);

    
    // Publish an MQTT message on topic esp32/bme280/pressure
    uint16_t packetIdPub5 = mqttClient.publish(MQTT_PUB_PRES_BME280, 1, true, String(pressure_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_PRES_BME280, packetIdPub5);
    Serial.printf("Message: %.2f \n", pressure_BME280);

    // Publish an MQTT message on topic esp32/ds18b20/temperatureC
    uint16_t packetIdPub6 = mqttClient.publish(MQTT_PUB_TEMP_C, 1, true, String(temperature_Celsius).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_C, packetIdPub6);
    Serial.printf("Message: %.2f \n", temperature_Celsius);

    // Publish an MQTT message on topic esp32/ds18b20/temperatureF
    uint16_t packetIdPub7 = mqttClient.publish(MQTT_PUB_TEMP_F, 1, true, String(temperature_Fahrenheit).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_TEMP_F, packetIdPub7);
    Serial.printf("Message: %.2f \n", temperature_Fahrenheit);
  }
}

How the Code Works?

We will start off by including the necessary libraries for our project. These include the libraries that we previously installed as well as Wi-Fi library as the ESP32 connects with the internet and FreeRTOS libraries to generate timers.

#include "DHT.h"
#include <WiFi.h>
extern "C" {
  #include "freertos/FreeRTOS.h"
  #include "freertos/timers.h"
}
#include <AsyncMqttClient.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <OneWire.h>
#include <DallasTemperature.h>

Next, define your network credentials in the WIFI_SSID and WIFI_PASSWORD variables. The ESP32 will connect to this network.

//replace with your network credentials
#define WIFI_SSID "YOUR_SSID"
#define WIFI_PASSWORD "YOUR_PASSWORD"

Define your Raspberry Pi IP address. This will be used by ESP32 to connect to the Mosquitto Broker.

#define MQTT_HOST IPAddress(192, 168, 1, XXX)  //specify your Raspberry Pi IP Address

Also, specify the MQTT port which is 1883 (default).

#define MQTT_PORT 1883

Defining Topics

Next we will define the seven topics which the ESP32 board will publish to.

The temperature readings for DHT22 will be published to esp32/dht/temperature and the humidity readings for DHT22 will be published to esp32/dht/humidity.

The temperature readings of BME280 will be published to esp32/bme280/temperature. The humidity readings of BME280 will be published to esp32/bme280/humidity. Likewise, the pressure readings of BME280 will be published to esp32/bme280/pressure.

The temperature readings in degree Celsius for DS18B20 will be published to esp32/ds18b20/temperatureC and the temperature readings in degree Fahrenheit for DS18B20 sensor will be published to esp32/ds18b20/temperatureF.

//MQTT Topics
#define MQTT_PUB_TEMP_DHT "esp32/dht/temperature"
#define MQTT_PUB_HUM_DHT  "esp32/dht/humidity"

#define MQTT_PUB_TEMP_BME280 "esp32/bme280/temperature"
#define MQTT_PUB_HUM_BME280  "esp32/bme280/humidity"
#define MQTT_PUB_PRES_BME280 "esp32/bme280/pressure"

#define MQTT_PUB_TEMP_C "esp32/ds18b20/temperatureC"
#define MQTT_PUB_TEMP_F "esp32/ds18b20/temperatureF"

We will define the name of the GPIO pin of ESP32 with which we will connect the DHT22 sensor. It is GPIO pin number 15. We will also define the DHTTYPE as ‘DHT22.’ It will be used to define which type of DHT sensor we want to use. You can set the type as DHT11, DHT21 or DHT22. Next we will create the object of DHT according to our defined pin number and DHT type. We have defined both these parameters in the last steps.

#define DHTPIN 15  
#define DHTTYPE DHT22 
DHT dht(DHTPIN, DHTTYPE);

Then, define the Adafruit_BME280 object named bme by setting it on the default I2C GPIO pins of ESP32.

Adafruit_BME280 bme;

We will create a variable to store the GPIO pin through which the DS18B20 sensor’s data pin is connected. We have used GPIO4 in this project.

const int SensorDataPin = 4; 

The following instances will be required as well to access the temperature readings. First, we will create a oneWire instance and use the SensorDataPin as an argument inside it. Then we will call the DallasTemperature sensor and pass the oneWire reference which we created above as an argument inside it.

 OneWire oneWire(SensorDataPin);
DallasTemperature sensors(&oneWire);

Create separate float variables to hold the temperature, humidity and pressure values for the sensors.

float temperature_DHT, humidity_DHT; //variables for DHT
float temperature_BME280, humidity_BME280, pressure_BME280;   //variables for BME280
float temperature_Celsius, temperature_Fahrenheit;  //variables for DS18B20

We will obtain the sensor readings after every 10 seconds. The variables below will monitor the time interval between the readings.

unsigned long previousMillis = 0;   
const long interval = 10000;  

To manage the MQTT client, we will create an AsyncMqttClient object named ‘mqttClient.’

AsyncMqttClient mqttClient;

Moreover, we will also be using FreeRTOS timers to reconnect to the Wi-Fi and the broker in case of disconnection. Hence, we will create two task handles, one for the MQTT and another for the Wi-Fi.

TimerHandle_t mqttReconnectTimer;
TimerHandle_t wifiReconnectTimer;

MQTT Functions

Next we have a series of MQTT callback functions that come with the library.

The connectToWifi() function is responsible for connecting the ESP32 board to our Wi-Fi network. The connectToMqtt() function is responsible for connecting the ESP32 board to the MQTT broker. The WiFiEvent() function is responsible for operating the Wi-Fi events. This includes printing the ESP32 IP address when it connects with the Wi-Fi and incase of disconnection, it starts the Wi-Fi reconnection timer and stops the MQTT reconnection timer.


void connectToWifi() {
  Serial.println("Connecting to Wi-Fi...");
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
}

void connectToMqtt() {
  Serial.println("Connecting to MQTT...");
  mqttClient.connect();
}

void WiFiEvent(WiFiEvent_t event) {
  Serial.printf("[WiFi-event] event: %dn", event);
  switch(event) {
    case SYSTEM_EVENT_STA_GOT_IP:
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      connectToMqtt();
      break;
    case SYSTEM_EVENT_STA_DISCONNECTED:
      Serial.println("WiFi lost connection");
      xTimerStop(mqttReconnectTimer, 0); 
      xTimerStart(wifiReconnectTimer, 0);
      break;
  }
}

The onMqttConnect() function is called when the ESP32 successfully connects with the broker. On the other hand, the onMqttDisconect() function is called when the ESP32 disconnects from the broker and if it is connected with Wi-Fi then it starts the MQTT reconnection timer. Relevant messages are printed in the serial monitor in each case.

void onMqttConnect(bool sessionPresent) {
  Serial.println("Connected to MQTT.");
  Serial.print("Session present: ");
  Serial.println(sessionPresent);
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  Serial.println("Disconnected from MQTT.");
  if (WiFi.isConnected()) {
    xTimerStart(mqttReconnectTimer, 0);
  }
}

The onMqttPublish() is responsible for printing the packet id in the serial monitor when the message is published to your topic.

void onMqttPublish(uint16_t packetId) {
  Serial.print("Publish acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

setup()

Inside the setup() function, we start the serial communication at a baud rate of 115200 and then initialize all the three sensors.

 Serial.begin(115200);
  dht.begin();
  delay(1000);

  if (!bme.begin(0x76)) {
    Serial.println("Could not detect a BME280 sensor, Fix wiring connections!");
    while (1);
  }
  delay(1000);

  sensors.begin();
  delay(1000);

Next we create the timers for the MQTT and Wi-Fi reconnection.

  mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
  wifiReconnectTimer = xTimerCreate("wifiTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToWifi));

Call the WiFiEvent() function, to display the Wi-Fi status in the serial monitor.

WiFi.onEvent(WiFiEvent);

Moreover, call the rest of the callback functions that we previously described as well. These include onConnect(), onDisconnect() and onPublish(). Additionally, set the MQTT server by calling the setServer() function on the AsyncMqttClient object. Specify the MQTT_HOST and MQTT_PORT as parameters inside it. Connect ESP32 to the Wi-Fi network by calling connectToWifi() function.

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onPublish(onMqttPublish);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  connectToWifi();

loop()

Inside the loop() function, after every 10 seconds the ESP32 obtains the DHT, BME280 and DS18B20 sensor readings and stores them in their appropriate variables.

unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;

    //Read from DHT
    humidity_DHT = dht.readHumidity();
    temperature_DHT = dht.readTemperature();
    
    if (isnan(temperature_DHT) || isnan(humidity_DHT)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }

    //Read from BME280
    temperature_BME280 = bme.readTemperature();
    humidity_BME280 = bme.readHumidity();
    pressure_BME280 = bme.readPressure() / 100.0F;

    //Read from DS18B20
    sensors.requestTemperatures(); 
    temperature_Celsius = sensors.getTempCByIndex(0);
    temperature_Fahrenheit = sensors.getTempFByIndex(0);

Publishing MQTT Message to Topics

Then it publishes the sensor readings on their respective topics. To publish an MQTT message, we use the publish() method on the AsyncMqttClient object. It takes in four arguments. The first argument is the MQTT topic. The second argument is the quality of service (QoS). It can take values of 0, 1 or 2 and is a mechanism to monitor the deliverance of the message. The third argument is the retain flag. Lastly, the fourth argument is the payload which we want to publish.

// Publish an MQTT message on topic esp32/dht/temperature
    uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP_DHT, 1, true, String(temperature_DHT).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_DHT, packetIdPub1);
    Serial.printf("Message: %.2f \n", temperature_DHT);

    // Publish an MQTT message on topic esp32/dht/humidity
    uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_HUM_DHT, 1, true, String(humidity_DHT).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM_DHT, packetIdPub2);
    Serial.printf("Message: %.2f \n", humidity_DHT);

        // Publish an MQTT message on topic esp32/bme280/temperature
    uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_TEMP_BME280, 1, true, String(temperature_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_BME280, packetIdPub3);
    Serial.printf("Message: %.2f \n", temperature_BME280);

    // Publish an MQTT message on topic esp32/bme280/humidity
    uint16_t packetIdPub4 = mqttClient.publish(MQTT_PUB_HUM_BME280, 1, true, String(humidity_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_HUM_BME280, packetIdPub4);
    Serial.printf("Message: %.2f \n", humidity_BME280);

    
    // Publish an MQTT message on topic esp32/bme280/pressure
    uint16_t packetIdPub5 = mqttClient.publish(MQTT_PUB_PRES_BME280, 1, true, String(pressure_BME280).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_PRES_BME280, packetIdPub5);
    Serial.printf("Message: %.2f \n", pressure_BME280);

    // Publish an MQTT message on topic esp32/ds18b20/temperatureC
    uint16_t packetIdPub6 = mqttClient.publish(MQTT_PUB_TEMP_C, 1, true, String(temperature_Celsius).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP_C, packetIdPub6);
    Serial.printf("Message: %.2f \n", temperature_Celsius);

    // Publish an MQTT message on topic esp32/ds18b20/temperatureF
    uint16_t packetIdPub7 = mqttClient.publish(MQTT_PUB_TEMP_F, 1, true, String(temperature_Fahrenheit).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId %i: ", MQTT_PUB_TEMP_F, packetIdPub7);
    Serial.printf("Message: %.2f \n", temperature_Fahrenheit);

Demonstration

Before uploading the code to our ESP32 board we will choose the correct board and COM port. Go to Tools > Board and select ESP32 Dev Module.

select esp32 board

Next, go to Tools > Port and select the appropriate port through which your board is connected.

Selecting COM PORT ESP32

Click on the upload button to upload the code into the ESP32 board. After you have uploaded your code to the board press its ENABLE button.

ESP32 enable reset button

Open your Serial Monitor to view the progress of the project. You will be able to view if the ESP32 connection with Wi-Fi and the Broker and the sensor readings published to their respective topics.

ESP32 MQTT Publish and Subsribe Multiple Sensor Serial monitor demo
Serial Monitor

Setting up Node-Red Dashboard as an MQTT Sensors Readings Subscriber

Now let us build the Node-Red Dashboard to view the DHT, BME280, and DS18B20 sensor readings in an interactive manner. Our ESP32 publisher is continuously sending the readings to the specific topics after every 10 seconds. Let us use Node-Red to subscribe to those topics and view them on our laptop.

We will be using Node-Red to subscribe to the topics. However, you can use any other MQTT subscription service as well. In order to get started with Node-Red on Raspberry Pi, refer to the guide:

To access Node-RED, we need the IP address of our Raspberry Pi and the port number on which Node-RED is accessible. By default, it starts on port 1880. Open any web browser and enter the RPI IP address followed by the port number.

192.168.18.8:1880

Creating Flow

This will open the Node-RED interface. You can start creating the flow.

access Node-RED

Make sure the dashboard is already installed. Head over to the extreme right side and find dashboard.

Node-Red Dashboard UI Overview pic1

After you click it, the Dashboard tab appears. The first step is to create the tab. Head over to the Dashboard tab and click +tab to create a new tab. Specify the name and icon and click Update for the changes to take place. Here we are using icons from Angular Material Icons.

We will create one tab named Home.

Node-Red Dashboard UI Overview pic4

Note: You can use any name according to your preference but for the icon you have to use one available at these three links found below:

The next step is to add the widgets. We will add one group to the tab. Click +group in the tab and create the group. We will create three groups, one for each sensor.

DHT Readings

The first group is named ‘DHT Readings.’

ESP32 MQTT Publish and Subscribe Project Set up Node-Red Dashboard 1

We will display the temperature and humidity readings obtained from the DHT sensor on gauges. Therefore we add four nodes to the flow. Head over to the Nodes section found at the far left and scroll down to view the nodes under Dashboard. Drag and drop two gauges and two mqtt in nodes to the flow as shown below:

ESP32 MQTT Publish and Subscribe Project Set up Node-Red Dashboard 2

Now double click the first mqtt node to edit its properties as shown below.

Here we have set the sever (MQTT Broker) to localhost:1883 as we are using Mosquitto Broker on our Raspberry Pi. Specify the topic to be subscribed. This node is being subscribed to the topic ‘esp32/dht/temperature.’ Click the Done button.

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 1

Similarly, double click the second mqtt node and edit its properties as shown below. Notice that this particular node is subscribed to the topic ‘esp32/dht/humidity.’ Click the Done button.

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 2

Now double click the gauges and edit their properties as well. Set the first one for temperature and the second one for humidity.

Finally connect the nodes as shown below:

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 3

BME280 Readings

Now let us create the group for BME280 readings. Click +group in the tab and create a new group as shown below:

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 4

We have named it ‘BME280 Readings.’

ESP32 MQTT BME280 Publish and Subscribe Project Set up Node-Red Dashboard 1

We will display the temperature and humidity readings of BME280 on gauges and the pressure readings of BME280 on a line chart. Therefore we add six nodes to the flow. Head over to the Nodes section found at the far left and scroll down to view the nodes under Dashboard. Drag and drop two gauges, one chart and two mqtt in nodes to the flow as shown below:

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 5

Now double click the first mqtt node to edit its properties as shown below.

Here we have set the sever (MQTT Broker) to localhost:1883 as we are using Mosquitto Broker on our Raspberry Pi. Specify the topic to be subscribed. This node is being subscribed to the topic ‘esp32/bme280/temperature.’ Click the Done button.

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 6

Similarly, double click the second mqtt node and edit its properties as shown below. Notice that this particular node is subscribed to the topic ‘esp32/bme280/humidity.’ Click the Done button.

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 7

Similarly, double click the third mqtt node and edit its properties as shown below. Notice that this particular node is subscribed to the topic ‘esp32/bme280/pressure.’ Click the Done button.

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 8

Now double click the gauges and edit their properties as well. Set the first one for temperature and the second one for humidity. Remember to choose the correct Group.

For the chart, edit the properties as shown below. Remember to choose the correct Group. The line chart will plot pressure readings.

ESP32 MQTT BME280 Publish and Subscribe Project Set up Node-Red Dashboard 4

Finally, join the nodes as shown below:

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 9

DS18B20 Readings

Finally create the group for DS18B20 readings. Click +group in the tab and create a new group. We have named it ‘DS18B20 Readings.’

ESP32 MQTT DS18B20 Publish and Subscribe Project Set up Node-Red Dashboard 1

We will display both the temperature readings from DS18B20 sensor on gauges. Therefore we add four nodes to the flow. Head over to the Nodes section found at the far left and scroll down to view the nodes under Dashboard. Drag and drop two gauges and two mqtt in nodes to the flow as shown below:

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 10

Now double click the first mqtt node to edit its properties as shown below.

Here we have set the sever (MQTT Broker) to localhost:1883 as we are using Mosquitto Broker on our Raspberry Pi. Specify the topic to be subscribed. This node is being subscribed to the topic ‘esp32/ds18b20/temperatureC.’ Click the Done button.

ESP32 MQTT DS18B20 Publish and Subscribe Project Set up Node-Red Dashboard 3

Similarly, double click the second mqtt node and edit its properties as shown below. Notice that this particular node is subscribed to the topic ‘esp32/ds18b20/temperatureF.’ Click the Done button.

ESP32 MQTT DS18B20 Publish and Subscribe Project Set up Node-Red Dashboard 4

Now double click the gauges and edit their properties as well. Set the first one for temperature in Celsius and the second one for temperature in Fahrenheit. Remember to choose the correct Group.

Finally wire the nodes as shown below:

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 11

You can also change the theme of the dashboard. Now deploy the changes by clicking the Deploy button found at the top. The status of the mqtt nodes changes to connected.

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 12

To view the UI, open a new web browser and type: http://Your_RPI_IP_address:1880/ui

The user interface will open up once you press enter.

Here you can view the dashboard consisting of the two gauges with readings from the DHT22 sensor, two gauges and a line chart with readings from the BME280 sensor and two gauges with readings from the DS18B20 sensor.

ESP32 MQTT Publish and Subsribe Multiple Sensor Set up Node-Red Dashboard 13

You may also like to read:

Leave a Comment