In this ESP32 and ESP8266 tutorial, we will learn to use ESP MQTT as a Publisher using MicroPython and subscribe through Node-Red. There will be one ESP32/ESP8266 MQTT publisher and Node-Red subscriber. We will publish BME280 sensor readings to MQTT with ESP32/ESP8266 and Node-Red Dashboard will subscribe to the MQTT topics and display sensor readings on the Dashboard in an interactive manner.
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.
The Publisher ESP board and Node-RED will make connections with the MQTT broker installed on Raspberry Pi. After that, the ESP32/ESP8266 will publish sensor data to the Node-Red dashboard on the specified topics. Any appropriate sensor can be used but for this article, we will use a BME280 sensor which is used to measure ambient temperature, barometric pressure, and relative humidity.
Before continuing with this project, make sure you have the latest version of MicroPython and Thonny IDE installed in you PC. Your ESP32/ESP8266 board should be already flashed with the firmware.
We will be using the same Thonny IDE as we have done previously when we learned how to blink and chase LEDs in micropython. If you have not followed our previous tutorial, you check here:
If you are using uPyCraft IDE, you can check this getting started guide:
Additionally we will be using Mosquitto broker to send and receive messages. So make sure your broker is installed on the Raspberry Pi.
ESP32/ESP8266 Micropython MQTT BME280 Project Overview
The diagram below illustrates the process that we will follow in our ESP32/ESP8266 MQTT project with BME280 sensor.
- An ESP32 or ESP8266 board connected with BME280 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.
- This ESP board publishes the BME280 temperature readings on the topic: esp/bme280/temperature. It publishes the BME280 humidity readings on the topic: esp/bme280/humidity. Likewise, it publishes the BME280 pressure readings on the topic: esp/bme280/pressure.
- Node-Red will subscribe to these three 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.
For a detailed tutorial regarding MQTT, its main components, MQTT broker and working follow the link:
ESP32/ESP8266 as an MQTT BME280 Publisher
Our ESP32/ESP8266 MQTT Publisher is connected with a BME280 sensor.
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.
I2C means Inter-Integrated Circuit and works on the principle of the synchronous, multi-master multi-slave system. With BME280 and the ESP boards, the ESP32/ESP8266 acts as a master, and the BME280 sensor as a slave because it is an external device, acts as a slave. The ESP development boards communicate with the BME280 sensor through the I2C protocol to get temperature, barometric pressure, and relative humidity.
The figure below shows the BME280 sensor and its pinout.
- VCC: connected with 3.3V
- SCL: used to generate the clock signal
- SDA: used in sending and receiving data
Interfacing BME280 sensor with ESP32 and ESP8266
The connection of BME280 with the ESP 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 ESP modules.
The I2C pin in ESP32 for SDA is GPIO21 and for SCL is GPIO22. Whereas, in ESP8266 the default I2C pins for SDA are GPIO4 and for SCL are GPIO5.
The connections between the two devices can be seen below.
|GPIO21(I2C SDA)||GPIO4 (D2)||SDA|
|GPIO22 (I2C SCL)||GPIO5 (D1)||SCL|
We will need the following components to connect our ESP board with the BME280 sensor.
- BME280 Sensor
- Connecting Wires
Follow the schematic diagrams below for both the ESP modules and connect them accordingly. If you are using ESP32 for this project, connect the ESP32 device with BME280 as shown in the schematic diagram below:
Similarly, you are using ESP8266 NodeMCU for this project, connect the ESP8266 device with BME280 as shown in the schematic diagram below:
In some BME280 sensors as seen in the above connection diagram, the SCK terminal means the SCL pin and is connected with its respective GPIO pin on the ESP board. Likewise, the SDI terminal means the SDA pin and is connected with its respective GPIO pin on the board. Vin is connected with a 3.3V pin on the module and both the ESP board and the sensor is commonly grounded.
Install MQTT and BME280 Libraries for MicroPython
We will have to install the BME280 library for MicroPython to continue with our project.
To successfully do that, open your Thonny IDE with your ESP board plugged in your system. Go to Tools > Manage Packages. This will open up the Thonny Package Manager.
Search for “bme280” in the search bar by typing its name and clicking the button ‘Search on PyPI.’ From the following search results click on the one highlighted below: micropython-bme280. Install this library.
After a few moments this library will get successfully installed.
The next step is to install the umqttsimple library in MicroPython because we have to use the MQTT with our ESP32/ESP8266 board.
Open Thonny IDE and create a new file. Copy the code given here save it your MicroPython device.
Save the new file by the name umqttsimple.py. This library will be used while programming the ESP MQTT publisher.
Now we are ready to program our ESP board with BME280 sensor for MQTT protocol in MicroPython.
ESP32/ESP8266 MQTT Publisher BME280 Sensor Readings MicroPython Script
After installing the umqttsimple library, click File > Open and open the boot.py file from the MicroPython device. If the file is not present, then create one by going to File > New to open a new file. Copy the code given below in that file and save it as boot.py in your MicroPython device. You need to enter your network credentials and your Raspberry Pi IP address.
import time from umqttsimple import MQTTClient import ubinascii import machine import micropython import network import esp from machine import Pin, I2C import bme280 #importing BME280 library esp.osdebug(None) import gc gc.collect() ssid = 'YOUR_SSID' password = 'YOUR_PASSWORD' mqtt_server = '192.168.10.8' #Replace with your MQTT Broker IP client_id = ubinascii.hexlify(machine.unique_id()) TOPIC_PUB_TEMP = b'esp/bme280/temperature' TOPIC_PUB_HUM = b'esp/bme280/humidity' TOPIC_PUB_PRES = b'esp/bme280/pressure' last_message = 0 message_interval = 5 i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000) #initializing the I2C method for ESP32 #i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000) #initializing the I2C method for ESP8266 station = network.WLAN(network.STA_IF) station.active(True) station.connect(ssid, password) while station.isconnected() == False: pass print('Connection successful') print(station.ifconfig())
How the Code Works?
We start off by importing all the necessary libraries which would be required including time ,umqttsimple, MQTTClient, ubinascii, machine, micropython, network, esp, bme280 and Pin and I2C classes from the machine module.
import time from umqttsimple import MQTTClient import ubinascii import machine import micropython import network import esp from machine import Pin, I2C import bme280
Then we activate the garbage collector and set the debug to ‘None.’
esp.osdebug(None) import gc gc.collect()
Next, we will enter our network Wi-fi, its password and the IP of our MQTT broker. You will have to specify your own figures in order for the network to connect with the MQTT and ESP32/ESP8266 board.
ssid = 'YOUR_SSID' #write your own wi-fi name password = 'YOUR_PASSWORD' #write your own password mqtt_server = '192.168.10.8' #Replace with your MQTT Broker IP
We will initialize the I2C method by giving it three arguments. The first argument specifies the GPIO pin for SCL. This is given as GPIO22 for ESP32 and GPIO5 for ESP8266. The second parameter specifies the GPIO pin for the SDA. This is given as GPIO21 for ESP32 and GPIO4 for ESP8266. Keep in mind, these are the default I2C pins for SCL and SDA which we have used for both the ESP boards respectively. The third parameter specifies the maximum frequency for SCL to be used.
If you are using ESP8266, uncomment the I2C method for ESP8266 and comment the I2C method of ESP32.
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=10000) #initializing the I2C method for ESP32 #i2c = I2C(scl=Pin(5), sda=Pin(4), freq=10000) #initializing the I2C method for ESP8266
Then we will create a client_id variable which saves the ESP unique ID. This is required to form a MQTT client.
client_id = ubinascii.hexlify(machine.unique_id())
Next we will define three topics which the ESP32/ESP8266 board will publish to. The temperature readings will be published to esp/bme280/temperature. The humidity readings will be published to esp/bme280/humidity. Likewise, the pressure readings will be published to esp/bme280/pressure.
TOPIC_PUB_TEMP = b'esp/bme280/temperature' TOPIC_PUB_HUM = b'esp/bme280/humidity' TOPIC_PUB_PRES = b'esp/bme280/pressure'
We will obtain the sensor readings after every 5 seconds. The variables below will monitor the time interval between the readings.
last_message = 0 message_interval = 5
MicroPython: Connecting to a Wi-Fi Network
Next, we will connect the ESP32/ESP8266 board to the Wi-Fi network. The network.WLAN() is used to create a WLAN network interface object.
Supported interfaces are:
- network.STA_IF (station mode)
- network.AP_IF (Soft access point mode)
After that, activate the station by passing the “True” argument to the sta_if.active() method. The connect() method is used to connect to the specified wireless network using the specified Wi-Fi name (SSID) and password.
station = network.WLAN(network.STA_IF) station.active(True) station.connect(ssid, password)
In station mode, isconnected() method returns “True” if ESP32/ESP8266 successfully connects to a Wi-Fi network and a device also assigned a valid IP address. Otherwise, it returns “False”. This statement checks if the ESP device connects to the Wi-Fi or not. The code does not move to the next step till the ESP board is not connected to the Wi-Fi network.
while station.isconnected() == False: pass
After a Wi-Fi connection is established on the ESP board, an IP address gets assigned to the ESP device. The ifconfig() method provides an IP address assigned to the ESP32/ESP8266 device. In this statement, we print the IP address using the ifconfig() method on the station object which we created previously.
print('Connection successful') print(station.ifconfig())
The next step is to create the main.py file for the ESP32/ESP8266 Publisher. Create a new file and name it as main.py. Save it to the MicroPython device. Copy the code given below in that file.
def connect_mqtt(): global client_id, mqtt_server client = MQTTClient(client_id, mqtt_server) client.connect() print('Connected to %s MQTT broker' % (mqtt_server)) return client def restart_and_reconnect(): print('Failed to connect to MQTT broker. Reconnecting...') time.sleep(10) machine.reset() try: client = connect_mqtt() except OSError as e: restart_and_reconnect() while True: try: if (time.time() - last_message) > message_interval: bme = bme280.BME280(i2c=i2c) temperature = bme.values humidity = bme.values pressure = bme.values print('Temperature: %s' %temperature, 'Humidity: %s' %humidity, 'Pressure: %s' %pressure) client.publish(TOPIC_PUB_TEMP, temperature) print('Published message %s to topic %s' %(temperature,TOPIC_PUB_TEMP)) client.publish(TOPIC_PUB_HUM, humidity) print('Published message %s to topic %s' %(humidity,TOPIC_PUB_HUM)) client.publish(TOPIC_PUB_PRES, pressure) print('Published message %s to topic %s' %(pressure,TOPIC_PUB_PRES)) print() last_message = time.time() except OSError as e: restart_and_reconnect()
How the Code Works?
First, we will define the connect_mqtt() function. This is used to connect the ESP32/ESP8266 board with the MQTT broker. We will initialize global variables for client_id and mqtt_server. This way we will be able to use them anywhere in the program code.
The next step is to initialize the MQTTClient() method with two parameters. The first parameter is the ID of the client named as: ‘client_id’ and the second parameter is the mqtt_server which is the IP address of the broker which was already configured in the boot.py file. This method will be assigned to the object ‘client.’ Then we will connecting the client with the broker. This would be done by using the connect() method on the object which we created previously: ‘client.’
def connect_mqtt(): global client_id, mqtt_server client = MQTTClient(client_id, mqtt_server) client.connect() print('Connected to %s MQTT broker' % (mqtt_server)) return client
In case of failure of connecting with the ESP32/ESP8266 board, we will also create a restart_and_reconnect() function which would display a failure message on the screen. The ESP development board will restart after 10 seconds.
def restart_and_reconnect(): print('Failed to connect to MQTT broker. Reconnecting...') time.sleep(10) machine.reset()
The next step is to learn how to connect our ESP32/ESP8266 board to the MQTT broker. This is accomplished by forming a client. We will create a client through the connect() function which we defined previously. Moreover, we have to keep track of a failure in connection as well. In case it happens, the ESP32/ESP8266 board will restart.
try: client = connect_mqtt() except OSError as e: restart_and_reconnect()
Publish MQTT Message to Topic
After that, we will set up a while loop which continues endlessly by acquiring the BME280 sensor data and publishing it at the specific topics. After every 5 seconds, the ESP32/ESP8266 obtains the temperature, humidity and pressure readings and saves them in the variables ‘temperature’, ‘humidity’ and ‘pressure’ respectively. We create an object of BME280 named bme and access the temperature, humidity and pressure values through it.
The temperature reading is published to the topic esp/bme280/temperature. The humidity reading is published to the topic esp/bme280/humidity. The pressure reading is published to the topic esp/bme280/pressure.
To publish the messages we use the publish() method. This method has two arguments. The first argument is the publishing topic which we already configured in our boot.py file. The second argument is the MQTT message which is the BME280 sensor reading in our case.
In case of a failure during the process, we will call the restart_and _reconnect() function which restarts the ESP32/ESP8266 board.
while True: try: if (time.time() - last_message) > message_interval: bme = bme280.BME280(i2c=i2c) temperature = bme.values #reading the value of temperature humidity = bme.values #reading the value of humidity pressure = bme.values #reading the value of pressure print('Temperature: %s' %temperature, 'Humidity: %s' %humidity, 'Pressure: %s' %pressure) client.publish(TOPIC_PUB_TEMP, temperature) print('Published message %s to topic %s' %(temperature,TOPIC_PUB_TEMP)) client.publish(TOPIC_PUB_HUM, humidity) print('Published message %s to topic %s' %(humidity,TOPIC_PUB_HUM)) client.publish(TOPIC_PUB_PRES, pressure) print('Published message %s to topic %s' %(pressure,TOPIC_PUB_PRES)) print() last_message = time.time() except OSError as e: restart_and_reconnect()
Uploading MicroPython Script
To upload this MicroPython script to your ESP32/ESP8266 publisher device, go to Files and click on ‘Save as’ or click the Save icon. Save the file to the MicroPython device as main.py and click ok.
Now press the Run current script icon.
This would upload the code onto our ESP32/ESP8266 board. After the code is uploaded, press the Enable/RESET button on your ESP32/ESP8266.
Open the Thonny Shell. The ESP board will first connect to the Wi-Fi and the MQTT broker. After every 5 seconds, it will publish temperature reading to the esp/bme280/temperature topic, the humidity reading to the esp/bme280/humidity topic and pressure reading to the esp/bme280/pressure topic.
Setting up Node-Red Dashboard as an MQTT BME280 Subscriber
Now let us build the Node-Red Dashboard to view the BME280 sensor readings in an interactive manner. Our ESP32 publisher is continuously sending temperature, humidity, and pressure readings to 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: Install Node-RED on Raspberry Pi (32-bit and 64-bit RPI OS)
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.
This will open the Node-RED interface. You can start creating the flow.
Make sure the dashboard is already installed. Head over to the extreme right side and find dashboard.
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.
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 have named it ‘BME280 Readings.’
We will display the temperature and humidity readings on gauges and the pressure readings 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:
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 ‘esp/bme280/temperature.’ Click the Done button.
Similarly, double click the second mqtt node and edit its properties as shown below. Notice that this particular node is subscribed to the topic ‘esp/bme280/humidity.’ Click the Done button.
Similarly, double click the third mqtt node and edit its properties as shown below. Notice that this particular node is subscribed to the topic ‘esp/bme280/pressure.’ Click the Done button.
Now double click the gauges and edit their properties as well. Set the first one for temperature and the second one for humidity.
For the chart, edit the properties as shown below. The line chart will plot pressure readings.
Finally, join the nodes as shown below and click the Deploy button found at the top. The status of the MQTT nodes changes to connected.
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 and a line chart with readings from the BME280 sensor.
You may also like to read: