ESP8266 NodeMCU MQTT Publish Subscribe DHT22 Readings with Arduino IDE

In this ESP8266 tutorial, we will learn to use ESP8266 MQTT as a Publisher and Subscriber using Arduino IDE. There will be one ESP8266 MQTT publisher and two subscribers. We will publish DHT11 and DHT22 sensor readings to MQTT with ESP8266 where one ESP8266 will act as a subscriber and Node-Red Dashboard will also subscribe to the MQTT topics and display sensor readings on the Dashboard.

ESP8266 NodeMCU MQTT Publish Subscribe DHT22 Sensor Readings

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 ESP8266 and Node-RED will make connections with the MQTT broker installed on Raspberry Pi. After that, one ESP8266 will publish sensor data to the Node-Red dashboard, and to the ESP8266 subscriber on specified topics. Any appropriate sensor can be used but for this article, we will use a DHT22 and DHT11 sensor which are used to measure temperature and humidity.

ESP8266 MQTT DHT11/DHT22 Project Overview

The diagram below illustrates the process that we will follow in our ESP8266 MQTT Publisher Subscriber project.

ESP8266 MQTT DHT Publish and Subscribe Project Overview
  1. An ESP8266 board connected with DHT22 sensor 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 ESP8266 board publishes the DHT22 temperature readings on the MQTT topic: esp8266/dht/temperature and publishes the DHT22 humidity readings on the MQTT topic: esp8266/dht/humidity.
  3. We have Node-Red and another ESP8266 as subscribers to these two topics. Node-Red receives the sensor data and displays them in an interactive manner in its dashboard. Whereas, the subscriber ESP8266 board, is connected with an OLED and hence displays the readings on the display when it receives them.
ESP8266 MQTT DHT Publish and Subscribe Project

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: 

ESP8266 NodeMCU as an MQTT DHT22 Publisher

Our ESP8266 MQTT Publisher is connected with a DHT22 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 ESP8266 to obtain sensor output reading. They are internally composed of a humidity sensing sensor and a thermistor. These two components measure humidity and temperature. 

DHT22 Pinout 

This following figure shows the pinout diagram of DHT sensors. DHT sensor consists of four pins. But on DHT modules only three pins are exposed to the pinout of the module and10k ohm pull-up resistor is internally connected to pin 2. 

dht11 dht22 pinout diagram

Pin Description

The following lists the pinout of the DHT sensor and their brief description. Pin number starts from left to right when you hold the sensor from the front end. 

DHT22 PinESP8266
1 (Vcc)3.3V 
2 (Data Out)Any GPIO pin of ESP8266 board along with a 10k ohm pull-up resistor
3 (NC)Not used
4 (GND)Ground
  • Vcc is the power supply pin. Apply voltage in a range of 3.3 V to 5.0 V to this pin
  • Data Out is the digital output pin. It sends out the value of measured temperature and humidity in the form of serial data
  • N/C is not connected
  • GND: Connect the GND pin 

Circuit Diagram of ESP8266 with DHT22 sensor

We will need the following components.

Required Components

  1. ESP8266 board
  2. DHT22
  3. 10k ohm resistor (not required if using the DHT22 sensor module)
  4. Bread Board
  5. Jumper wires
  • The first pin the DHT22 sensor is a power supply(VCC) pin. Connect it with the 3.3 volt or Vin pin of ESP8266.
  • Data out is the pin through which we get temperature and humidity samples from the DHT sensor. Connect this pin with GPIO14 of ESP8266 and also connect the data pin with a 10k pull-up resistor. But you can also use any digital pin of ESP8366. 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 ESP8266 board.

Connect ESP8266 with DHT22 as shown in the schematic diagram below:

ESP8266 with DHT sensor circuit diagram
ESP8266 with DHT sensor circuit diagram

Install MQTT and DHT22 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 ESP8266 add-on in Arduino IDE. If your IDE does not have the plugin installed you can visit the link below:

Installing ESP8266 library in Arduino IDE and upload code

For this project, we will have to install libraries for the DHT 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

After installation of the libraries, restart your IDE.

You may also like to read:

Install Async MQTT Client Library and ESPAsyncTCP Library

We will use Async MQTT Client Library by Marvin Roger to use MQTT with ESP8266. ESPAsyncTCP is another library that we will be incorporating as it is required for our ESP8266 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 ESP8266 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 ESPAsync TCP library for free, click here to download. You will download the library as a .zip folder which you will extract and rename as ‘ESPAsyncTCP.’ Then, transfer this folder to the installation 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.

ESP8266 MQTT DHT22 Publisher 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 ESP8266 MQTT publisher by following the steps given below:

  • Connecting the ESP8266 board with the local network
  • Setting up the DHT22 sensor
  • Connecting the ESP8266 to the MQTT broker
  • Publishing the sensor readings to the MQTT topics
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
#include "DHT.h"
 
//replace with your network credentials
#define WIFI_SSID "YOUR_SSID"
#define WIFI_PASSWORD "YOUR_PASSWORD"

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

//MQTT Topics
#define MQTT_PUB_TEMP "esp8266/dht/temperature"
#define MQTT_PUB_HUM  "esp8266/dht/humidity"

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

float temp;
float hum;

AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;

WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker wifiReconnectTimer;

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

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

void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  Serial.println("Connected to Wi-Fi.");
  connectToMqtt();
}

void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  Serial.println("Disconnected from Wi-Fi.");
  mqttReconnectTimer.detach(); 
  wifiReconnectTimer.once(2, connectToWifi);
}

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

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()) {
    mqttReconnectTimer.once(2, connectToMqtt);
  }
}

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

void setup() {
  Serial.begin(115200);
  Serial.println();
  
  dht.begin();
  
  wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
  wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
  

  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;
    hum = dht.readHumidity();
    temp = dht.readTemperature();
    
    if (isnan(temp) || isnan(hum)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }  
    
    // Publish an MQTT message on topic esp8266/dht/temperature
    uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP, packetIdPub1);
    Serial.printf("Message: %.2f \n", temp);

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

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 ESP8266WiFi library as the ESP8266 connects with the internet and Ticker library to generate timers.

#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
#include "DHT.h"

Next, define your network credentials in the WIFI_SSID and WIFI_PASSWORD variables. The ESP8266 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 ESP8266 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

Next we will define two topics which the ESP8266 board will publish to. The temperature readings will be published to esp8266/dht/temperature and the humidity readings will be published to esp8266/dht/humidity.

#define MQTT_PUB_TEMP "esp8266/dht/temperature"
#define MQTT_PUB_HUM  "esp8266/dht/humidity"

We will define the name of the GPIO pin of ESP8266 with which we will connect the DHT22 sensor. It is GPIO pin number 14.

#define DHTPIN 14

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.

#define DHTTYPE 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.

 DHT dht(DHTPIN, DHTTYPE);

Also create two float variables called temp and hum to store the temperature and humidity readings acquired from the sensor.

float temp;
float hum;

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

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

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

AsyncMqttClient mqttClient;

Moreover, we will also be using Ticker timers to reconnect to the Wi-Fi and the broker in case of disconnection. Hence, we will create two objects of Ticker library, one for the MQTT (mqttReconnectTimer) and another for the Wi-Fi (wifiReconnectTimer).

Ticker mqttReconnectTimer;
Ticker 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 ESP8266 board to our Wi-Fi network. The onWifiConnect() function is called when the ESP8266 successfully connects to the Wi-Fi. A relevant message is printed in the serial monitor and the connectToMqtt() function is called to establish connection with the MQTT broker. Similarly, the onWifiDisconnect() function is called when the ESP8266 losses the Wi-Fi connection. It tries to reconnect to Wi-Fi and stops the MQTT reconnection timer.

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

void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  Serial.println("Connected to Wi-Fi.");
  connectToMqtt();
}

void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  Serial.println("Disconnected from Wi-Fi.");
  mqttReconnectTimer.detach(); 
  wifiReconnectTimer.once(2, connectToWifi);
}

The connectToMqtt() function is responsible for connecting the ESP8266 board to the MQTT broker. The onMqttConnect() function is called when the ESP8266 successfully connects with the broker. On the other hand, the onMqttDisconect() function is called when the ESP8266 disconnects from the broker and if it is connected with Wi-Fi then it tries to reconnect with the MQTT broker. Relevant messages are printed in the serial monitor in each case.

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

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()) {
    mqttReconnectTimer.once(2, connectToMqtt);
  }
}

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 the DHT sensor.

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

Next we will create handlers for Wi-Fi connection and disconnection.

 wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
 wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);

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 ESP8266 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, the ESP8266 board first obtains the DHT sensor readings after every 5 seconds and stores them in the variables ‘hum’ for humidity and ‘temp’ for temperature.

  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    hum = dht.readHumidity();
    temp = dht.readTemperature();
    
    if (isnan(temp) || isnan(hum)) {
      Serial.println(F("Failed to read from DHT sensor!"));
      return;
    }

Then it publishes hum on the topic esp8266/dht/humidity and temp on the topic esp32/dht/temperature. 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 esp8266/dht/temperature
    uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP, 1, true, String(temp).c_str());                            
    Serial.printf("Publishing on topic %s at QoS 1, packetId: %i", MQTT_PUB_TEMP, packetIdPub1);
    Serial.printf("Message: %.2f \n", temp);

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

Demonstration

Choose the correct board and COM port. Go to Tools > Board and select NodeMCU 1.0. Next, go to Tools > Port and select the appropriate port through which your board is connected.

select ESP8266 NodeMCU board

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

ESP8266 NodeMCU reset button

Open your Serial Monitor to view the progress of the project. You will be able to view if the ESP8266 board has successfully connected with the Wi-Fi and the Broker and the status of the publishing.

ESP8266 MQTT DHT Publish and Subscribe serial monitor demo 1
Serial Monitor

Setting up Node-Red Dashboard as an MQTT Subscriber

Now let us build the Node-Red Dashboard to view the DHT sensor readings in an interactive manner. Our ESP8266 publisher is continuously sending temperature and humidity readings to the specific topics. 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:

Add Widgets

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 have named it ‘DHT Readings.’

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

We will display the temperature and humidity readings 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 ‘esp8266/dht/temperature.’ Click the Done button.

ESP8266 MQTT DHT Publish and Subscribe Project 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 ‘esp8266/dht/humidity.’ Click the Done button.

ESP8266 MQTT DHT Publish and Subscribe Project 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 wire the nodes as shown below. You can also change the theme of the dashboard. Now deploy the changes by clicking the Deploy button found at the top.

ESP8266 MQTT DHT Publish and Subscribe Project Set up Node-Red Dashboard 3

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.

ESP8266 MQTT DHT Publish and Subscribe Project Set up Node-Red Dashboard 4

ESP8266 NodeMCU as an MQTT DHT22 Subscriber

In the previous section, we showed you how to publish ESP8266 sensor readings from DHT22 to Node-Red using MQTT. Let us now set up an ESP8266 board connected with an OLED as a subscriber to the esp8266/dht/temperature and esp8266/dht/humidity topics. When this ESP8266 gets connected with the MQTT Broker, it will be able to access the temperature and humidity readings which we will then display on the OLED.

Connecting ESP8266 with OLED

OLED interfacing with ESP8266 hardware

We will need the following components.

Required Components

  1. ESP8266 board
  2. OLED
  3. Bread Board
  4. Jumper wires

The OLED display has 4 terminals which we will connect with the ESP8266 board. As the OLED display requires an operating voltage in the range of 3.3-5V hence we will connect the VCC terminal with 3.3V which will be in common with the ESP8266 board. SCL of the display will be connected with the SCL pin of the module and the SDA of the display will be connected with the SDA of the module. By default, the I2C pin in ESP8266 for SDA is GPIO4 (D2), and for SCL is GPIO5 (D1). The connections between the two devices can be seen below.

ESP8266 boardSSD1306 OLED Display
VCC=3.3VVCC
GPIO4 (D2)SDA
GPIO5 (D1)SCL
GNDGND
Connection of ESP8266 board and SSD1306 OLED Display

The I2C pins stated above are set in default. If you want to use any GPIO pins for I2C, you will have to set it in code using SoftI2C().

The connections between the two devices can be seen below.

OLED interfacing with ESP8266 Nodemcu

You can read in-depth guide on OLED with ESP8266:

Installing SSD1306 OLED Library in Arduino IDE

To use the OLED display in our project, we have to install the Adafruit SSD1306 OLED library in Arduino IDE. Follow the steps below to successfully install it.

Open Arduino IDE and click on Sketch > Library > Manage Libraries. Type ‘SSD1306’ in the search tab and install the Adafruit SSD1306 OLED library.

Install OLED SSD1306 Library Arduino IDE

We will also require the Adafruit GFX library which is a dependency for SSD1306. Type ‘Adafruit GFX’ in the search tab and install it as well.

install GFX Arduino ide

ESP8266 MQTT DHT22 Subscriber 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 ESP8266 MQTT subscriber by following the steps given below:

  • Connecting the ESP8266 board with the local network
  • Setting up the OLED
  • Connecting the ESP8266 to the MQTT broker
  • Subscribing to the MQTT topics in order to receive them
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
 
//replace with your network credentials
#define WIFI_SSID "YOUR_SSID"
#define WIFI_PASSWORD "YOUR_PASSWORD"

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

//MQTT Topics
#define MQTT_SUB_TEMP "esp8266/dht/temperature"
#define MQTT_SUB_HUM  "esp8266/dht/humidity"

AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;

WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker wifiReconnectTimer;
       

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

void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  Serial.println("Connected to Wi-Fi.");
  connectToMqtt();
}

void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  Serial.println("Disconnected from Wi-Fi.");
  mqttReconnectTimer.detach(); 
  wifiReconnectTimer.once(2, connectToWifi);
}

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

void onMqttConnect(bool sessionPresent) {
  Serial.println("Connected to MQTT.");
  Serial.print("Session present: ");
  Serial.println(sessionPresent);
  uint16_t packetIdSub = mqttClient.subscribe(MQTT_SUB_TEMP, 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);
  packetIdSub = mqttClient.subscribe(MQTT_SUB_HUM, 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  Serial.println("Disconnected from MQTT.");

  if (WiFi.isConnected()) {
    mqttReconnectTimer.once(2, connectToMqtt);
  }
}

void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
  Serial.println("Subscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
  Serial.print("  qos: ");
  Serial.println(qos);
}

void onMqttUnsubscribe(uint16_t packetId) {
  Serial.println("Unsubscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  Serial.println("Publish received.");
  Serial.print("  topic: ");
  Serial.println(topic);
  String messageTemp;
  for (int i = 0; i < len; i++) {
    Serial.print((char)payload[i]);
    messageTemp += (char)payload[i];
  }

  if (String(topic) == "esp8266/dht/temperature"){
  Serial.print("\n Temperature: ");
  Serial.println(messageTemp);
  display.setCursor(0,0);
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("Temperature: ");
  display.setTextSize(2);
  display.setCursor(0,10);
  display.print(messageTemp);
  display.print(" ");
  display.setTextSize(1);
  display.cp437(true);
  display.write(167);
  display.setTextSize(2);
  display.print("C");
  display.display();
  }

   if (String(topic) == "esp8266/dht/humidity"){
  Serial.print("\n Humidity: ");
  Serial.println(messageTemp);

  display.setTextSize(1);
  display.setCursor(0, 35);
  display.print("Humidity: ");
  display.setTextSize(2);
  display.setCursor(0, 45);
  display.print(messageTemp);
  display.print(" %");
  
  display.display();
  }
}

void setup() {
  Serial.begin(115200);
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  //initialize OLED
  delay(2000);         
  display.clearDisplay(); 
  display.setTextSize(1);     
  display.setTextColor(WHITE); 
  display.setCursor(0,0);    
  Serial.println();

  wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
  wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onSubscribe(onMqttSubscribe);
  mqttClient.onUnsubscribe(onMqttUnsubscribe);
  mqttClient.onMessage(onMqttMessage);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);
  connectToWifi();
}

void loop(){
}

How does Code Works?

Most of the code is similar to the previous code which was used to publish to topics via MQTT. In this one we will be subscribing to those topics and display the messages on the OLED connected with the ESP8266 board.

We will start off by including the necessary libraries. This includes all the libraries that we included previously to set up the ESP8266 MQTT Client as well as OLED libraries that we just installed.

#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Define OLED Parameters

We will define the width and height of our OLED display in pixels. We are using a 128×64 display hence the width will be 128 and the height will be 64.

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

Next, we will initialize the display by creating an object of Adafruit_SSD1306 and specifying the width, height, I2C instance (&Wire), and -1 as parameters inside it.’ -1′ specifies that the OLED display which we are using does not have a RESET pin. If you are using the RESET pin then specify the GPIO through which you are connecting it with your development board.

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

Next, define your network credentials in the WIFI_SSID and WIFI_PASSWORD variables. The ESP8266 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 ESP8266 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

Next we will define two topics which the ESP8266 board will subscribe to. The temperature readings were published to esp8266/dht/temperature and the humidity readings were published to esp8266/dht/humidity. Hence, this ESP8266 subscribes to these topics in order to acquire the sensor data.

#define MQTT_SUB_TEMP "esp8266/dht/temperature"
#define MQTT_SUB_HUM  "esp8266/dht/humidity"

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

AsyncMqttClient mqttClient;

Moreover, we will also be using Ticker timers to reconnect to the Wi-Fi and the broker in case of disconnection. Hence, we will create two objects of Ticker library, one for the MQTT (mqttReconnectTimer) and another for the Wi-Fi (wifiReconnectTimer).

Ticker mqttReconnectTimer;
Ticker 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 ESP8266 board to our Wi-Fi network. The onWifiConnect() function is called when the ESP8266 successfully connects to the Wi-Fi. A relevant message is printed in the serial monitor and the connectToMqtt() function is called to establish connection with the MQTT broker. Similarly, the onWifiDisconnect() function is called when the ESP8266 losses the Wi-Fi connection. It tries to reconnect to Wi-Fi and stops the MQTT reconnection timer.

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

void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  Serial.println("Connected to Wi-Fi.");
  connectToMqtt();
}

void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  Serial.println("Disconnected from Wi-Fi.");
  mqttReconnectTimer.detach(); 
  wifiReconnectTimer.once(2, connectToWifi);
}

The connectToMqtt() function is responsible for connecting the ESP8266 board to the MQTT broker. The onMqttConnect() function is called when the ESP8266 successfully connects with the broker. On the other hand, the onMqttDisconect() function is called when the ESP8266 disconnects from the broker and if it is connected with Wi-Fi then it tries to reconnect with the MQTT broker. Relevant messages are printed in the serial monitor in each case.

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

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()) {
    mqttReconnectTimer.once(2, connectToMqtt);
  }
}
Subscribing to Topics

The onMqttConnect() function is called when the ESP8266 successfully connects with the broker. Then it subscribes to the topic using the subscribe() method on the AsyncMqttClient object. It takes in two parameters. The first parameter is the topic which is to be subscribed to and the second parameter is the QoS. This returns the packet id which is displayed in the serial monitor.

On the other hand, the onMqttDisconect() function is called when the ESP8266 disconnects from the broker. If it is connected with Wi-Fi then it tries to establish a connection with the MQTT broker again. 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);
  uint16_t packetIdSub = mqttClient.subscribe(MQTT_SUB_TEMP, 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);
  packetIdSub = mqttClient.subscribe(MQTT_SUB_HUM, 2);
  Serial.print("Subscribing at QoS 2, packetId: ");
  Serial.println(packetIdSub);
}

void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
  Serial.println("Disconnected from MQTT.");

  if (WiFi.isConnected()) {
    mqttReconnectTimer.once(2, connectToMqtt);
  }
}

The onMqttSubscribe() prints the packet id and the QoS in the serial monitor, along with ‘Subscribe acknowledged.’ The onMqttUnsubscribe() prints the packet id along with ‘Unsubscribe acknowledged.’ These functions are called in the case of a successful subscription or un-subscription of a topic respectively.

void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
  Serial.println("Subscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
  Serial.print("  qos: ");
  Serial.println(qos);
}

void onMqttUnsubscribe(uint16_t packetId) {
  Serial.println("Unsubscribe acknowledged.");
  Serial.print("  packetId: ");
  Serial.println(packetId);
}

The onMqttMessage() is responsible for obtaining the MQTT message from the subscribed topic and displaying it on the OLED. The string variable ‘messageTemp’ holds the MQTT message. To display the sensor readings on the OLED, we will first check the topic and then display the readings accordingly. We will set the cursor, clear the display, set the text size and then print the readings along with the units on the OLED. Finally, we will call the display() function on the display object so that the text displays on the OLED.


void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) {
  Serial.println("Publish received.");
  Serial.print("  topic: ");
  Serial.println(topic);
  String messageTemp;
  for (int i = 0; i < len; i++) {
    Serial.print((char)payload[i]);
    messageTemp += (char)payload[i];
  }

  if (String(topic) == "esp8266/dht/temperature"){
  Serial.print("\n Temperature: ");
  Serial.println(messageTemp);
  display.setCursor(0,0);
  display.clearDisplay();
  display.setTextSize(1);
  display.print("Temperature");
  display.setTextSize(2);
  display.setCursor(0,45);
  display.print(messageTemp);
  display.print(" ");
  display.setTextSize(1);
  display.cp437(true);
  display.write(167);
  display.setTextSize(2);
  display.print("C");
  display.display();
  }

   if (String(topic) == "esp8266/dht/humidity"){
  Serial.print("\n Humidity: ");
  Serial.println(messageTemp);
  display.setTextSize(1);
  display.setCursor(0, 35);
  display.print("Temperature");
  display.setTextSize(2);
  display.setCursor(0,10);
  display.print(messageTemp);
  display.print(" ");
  display.setTextSize(1);
  display.cp437(true);
  display.write(167);
  display.setTextSize(2);
  display.print("F");
  display.display();
  }
}

setup()

Inside the setup() function, we will open a serial connection at a baud rate of 115200. Moreover, we will also initialize the OLED display by using display.begin(). Make sure you specify the correct address of your display. In our case, it is 0X3C.

Serial.begin(115200);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  //initialize OLED

Next we create the W-Fi handlers for the connection and disconnection of network .

   wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
  wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);

Moreover, call the rest of the callback functions that we previously described as well. These include onConnect(), onDisconnect(), onSubscribe(), onUnSubscribe() and onMessage(). 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 ESP8266 to the Wi-Fi network by calling connectToWifi() function.

  mqttClient.onConnect(onMqttConnect);
  mqttClient.onDisconnect(onMqttDisconnect);
  mqttClient.onSubscribe(onMqttSubscribe);
  mqttClient.onUnsubscribe(onMqttUnsubscribe);
  mqttClient.onMessage(onMqttMessage);
  mqttClient.setServer(MQTT_HOST, MQTT_PORT);

  connectToWifi();

Demonstration

To see the demonstration of the above code, upload the code to the ESP8266 connected with the OLED. Choose the correct board and COM port. Go to Tools > Board and select NodeMCU 1.0. Next, go to Tools > Port and select the appropriate port through which your board is connected.

select ESP8266 NodeMCU board

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

ESP8266 NodeMCU reset button

Make sure the ESP8266 that is publishing DHT readings is powered on.

Once the code is uploaded to ESP8266, the OLED Display will start displaying the sensor readings on its screen. You can have a look at it in the picture given below.

ESP8266 MQTT DHT Subscriber

Open the serial monitor and you will be able to see the following messages indicating a successful connection to Wi-Fi, MQTT Broker and subscription.

ESP8266 MQTT DHT Publish and Subscribe serial monitor demo 2
Serial Monitor

You may also like to read:

1 thought on “ESP8266 NodeMCU MQTT Publish Subscribe DHT22 Readings with Arduino IDE”

  1. Great project! I noticed the temperature reports an outlandish number below 0 Degrees (~6000 degrees). The DHT22 says it can go to -50. Can you please help?
    I tried 2 different 8266 and 3 different DHT22s
    Thanks,
    Cav

    Reply

Leave a Comment