DIY IoT: ESP8266 and Raspberry Pi to monitor temperature and humidity via MQTT communication protocol

Introduction

The Internet of Things (IoT) is revolutionizing the way we interact with the world around us. MQTT communication protocol between different devices will be illustrated in this article through the creation of a project using ESP8266 and a Raspberry Pi used to monitor environmental temperature and humidity.
You will learn how to build a temperature and humidity monitoring system that can be easily adapted to meet your specific needs.
You will discover how to configure and program an ESP8266 to collect data from DHT22 sensors and transmit it to a Raspberry Pi, which acts as an MQTT broker. Additionally, you will learn how to subscribe to and manage MQTT messages received by the Raspberry Pi and how to integrate additional functionality into your IoT project.
If you’re interested in exploring the world of IoT, learning how to use the ESP8266 and Raspberry Pi, or simply want to build a custom environmental monitoring system, read on to find out how to get started with this exciting project.

What is MQTT?

MQTT (Message Queuing Telemetry Transport) is a lightweight and flexible messaging protocol designed for communication between devices with bandwidth or computing power restrictions. It is particularly suitable for IoT (Internet of Things) and M2M (Machine-to-Machine) applications where resource conservation is essential. MQTT is based on the publish-subscribe paradigm, where devices can publish messages to specific topics and subscribe to topics to receive relevant messages.

Mosquitto as an MQTT broker

  1. Definition:
    • Mosquitto is an open-source MQTT broker primarily developed by Eclipse Foundation. It is one of the most popular MQTT brokers and is available for a wide range of platforms, including Linux, Windows and MacOS.
  2. Role of the Broker:
    • An MQTT broker acts as an intermediary in communication between devices using MQTT. Accepts messages published by devices and routes them to devices subscribed to the respective topics.
    • Mosquitto is the central component in an MQTT system. MQTT client devices (also called publishers and subscribers) connect to the broker to send and receive messages.
  3. Installation and configuration:
    • Mosquitto is easy to install and configure. It can run on a Raspberry Pi, a Linux server, or any other compatible device.
    • Mosquitto’s main configuration file is mosquitto.conf, where you can specify settings such as the port to listen on, access permissions, and other security options.
  4. Safety:
    • Mosquitto offers security features to protect MQTT communication. It can be configured to require username and password authentication and supports the TLS/SSL protocol for data encryption.
  5. Usage:
    • Mosquitto is widely used in implementing IoT systems, home automation, environmental monitoring and much more. It is the heart of many applications that require reliable communication between distributed devices.
  6. Commands and tools:
    • Mosquitto provides a set of command-line tools for managing and monitoring the MQTT broker, such as mosquitto_pub for publishing messages and mosquitto_sub for subscribing to MQTT topics.
  7. Community and support:
    • Mosquitto has an active community of developers and users and is supported by detailed documentation. It is also included in the repositories of many Linux distributions, making installation and updating easier.

In summary, Mosquitto is a reliable, scalable, open-source MQTT broker that plays a key role in enabling communication between devices in the Internet of Things and other M2M (machine to machine) applications. It is a popular choice for implementing MQTT infrastructures in IoT projects and offers flexibility and security to meet a wide range of communication needs.

Description of IoT environmental monitoring system with MQTT communication protocol

This IoT environmental monitoring system combines different devices and technologies to collect, transmit and display real-time data on ambient temperature and humidity. The system consists of three ESP8266, two DHT22 sensors, a Raspberry Pi acting as an MQTT broker, and a 16×2 LCD display for data visualization. Here’s how it works:

  1. ESP8266 with DHT22 (Sensors):
    • There are two such devices, each equipped with a DHT22 sensor for measuring temperature and humidity. They are placed in different environments to collect relevant data.
    • Each ESP8266 is programmed to read data from its DHT22 sensor at regular intervals.
    • The detected data (temperature and humidity) are published on two different separate MQTT topics, one for each ESP8266. For example, the first ESP8266 can publish data to the temp_hum_sens_1 topic while the second ESP8266 can publish data to the temp_hum_sens_2 topic
  2. Raspberry Pi (Broker MQTT):
    • The Raspberry Pi acts as an MQTT broker and plays a central role in the system.
    • Receives the data published by the two ESP8266 on their respective MQTT topics.
    • It stores the received data in a temporary buffer before transmitting it to the third ESP8266.
    • Maintains a stable connection with the two ESP8266 to ensure continuous data reception.
  3. ESP8266 (LCD Display):
    • This third ESP8266 is programmed to subscribe to two MQTT topics (“temp_hum_sens_1” and “temp_hum_sens_2”) to receive temperature and humidity data from the sensors.
    • Uses a library to control a 16×2 LCD display to display data in real time.
    • It updates the display with temperature and humidity data every time it receives an MQTT message from the corresponding topics.

In this system, temperature and humidity data are read from the DHT22 sensors on the ESP8266s and transmitted via MQTT to the Raspberry Pi, which acts as an intermediary between the sensors and the display device. The third ESP8266 can display real-time data received from the two DHT22 sensors on a 16×2 LCD display, providing a real-time environmental monitoring interface. This system is highly customizable and can be expanded by adding additional sensors or features based on your specific project needs.

The following image illustrates the complete system:

Operation diagram of the environmental monitoring system based on MQTT communication protocol
Operation diagram of the environmental monitoring system based on MQTT communication protocol

Normally the 16×2 LCD display is not supplied with the connector already soldered so, if you don’t know how to solder it, I refer you to reading the article Yet another tutorial on how to solder.

As usual, we will use the excellent IDE PlatformIO to write the firmware.

What components do we need?

The list of components is not particularly long:

The SD card I used for the experiments is 16GB.

Project implementation

The electrical diagram

Referring to the scheme proposed before, you will have to create two identical circuits composed of an ESP8266 and a DHT22 each which will act as remote sensors and a third circuit composed of an ESP8266 and a 16×2 LCD display which you will use to receive and display the data collected by the remote sensors. You will then have to develop a Raspberry PI following the instructions given in the following paragraphs in order to set up an MQTT broker.

Before creating the actual circuits let’s take a look at the pinouts of the board and the sensors:

The ESP8266 NodeMCU pinout
The ESP8266 NodeMCU pinout

Various GPIOs are used in this project, some to read the sensors, others to control the LCD display.

We will use GPIO D5 to read the DHT22 sensor (ambient temperature and humidity) in both sensor circuits and GPIOs D2, D3, D5, D6, D7, D8 in the receiver circuit to drive the display.

So let’s see the pinouts of the DHT22 sensor and the 16×2 LCD display:

DHT22 pinout
DHT22 pinout
16x2 LCD display pinout

16×2 LCD display pinout

The display is called 16×2 because it has 2 lines of 16 characters each.

Its pins are:

  • 1 VSS (connected to the ground of the circuit GND)
  • 2 VDD connected to the power supply
  • 3 V0/VEE contrast control via potentiometer
  • 4 RS (Register Select) it is a control pin
  • 5 RW (Read/Write) it is a control pin
  • 6 E (Enable) it is a control pin
  • from 7 to 14 (from D0 to D7) data pins
  • 15 A (Anode) It is the internal LED anode for the backlight
  • 16 K (Katode) It is the cathode of the internal LED for the backlight

Let’s now see the construction scheme of the two sensors created with Fritzing:

Construction diagram of the two sensor boards
Construction diagram of the two sensor boards

You will then need to make two of these identical circuits.

The construction diagram of the receiver is below:

Receiver board construction diagram
Receiver board construction diagram

Although the scheme seems complex, it is actually quite simple. For further understanding I attach the display connection table:

DISPLAY LCD 16×2ESP8266
1 – VSSGND
2 – VDD3V3
3 – V0/VEEpotentiometer slider
4 – RSD2
5 – RWGND
6 – ED3
7 – D0not connected
8 – D1not connected
9 – D2not connected
10 – D3not connected
11 – D4D5
12 – D5D6
13 – D6D7
14 – D7D8
15 – AVin
16 – KGND
Display connection table

The potentiometer is used to adjust the contrast of the display.

The sketches

Let’s create the PlatformIO project for the two transmitter-sensors

We have already seen the procedure for creating a PlatformIO project in the How to create a project for NodeMCU ESP8266 with PlatformIO article.

Of the libraries indicated, install only the libraryDHT sensor library for ESPx by Bernd Giesecke.

Then install the PubSubClient by Nick O’Leary library as shown in the following photo:

Install the PubSubClient library
Install the PubSubClient library

Now edit the platformio.ini file to add these two lines:

monitor_speed = 115200
upload_speed = 921600

so that it looks like this:

[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps = 
	knolleary/PubSubClient@^2.8
	beegee-tokyo/DHT sensor library for ESPx@^1.19

Obviously you can download the project from the following link:

Replace the main.cpp file of the project you created with the one present in the zip file.

You will use this same sketch for the two sensor devices (i.e. the two with the DHT22) and for this reason you will have to adapt it slightly.

In particular, you will have to adapt the topic and client name for each one.

Assuming we number the two sensor devices with 1 and 2 respectively:

  • for device 1 the topic (on line 16) will be temp_hum_sens_1 while the client (on line 65) will be ESP8266Client_1
  • for device 2 the topic (on line 16) will be temp_hum_sens_2 while the client (on line 65) will be ESP8266Client_2

Then upload the firmware to Device 1 and Device 2 with the changes above.

Now let’s see how the sketch works.

Initially the necessary libraries are included:

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "DHTesp.h"

Next we set the credentials for our WiFi network:

// Set up your Wi-Fi credentials
const char* ssid = "my_wifi_SSID";
const char* password = "my_wifi_password";

Then replace the strings my_wifi_SSID and my_wifi_password with, respectively, the SSID and password of your wifi network.

At this point the parameters for the MQTT connection are set:

// Set up your MQTT information
const char* mqtt_server = "192.168.1.190";      // set the IP address of the Raspberry 
const int mqtt_port = 1883;
const char* mqtt_user = "pippo";                // set the user of the mqtt server 
const char* mqtt_password = "pluto";            // set the password of the mqtt server 
const char* mqtt_topic = "temp_hum_sens_1";     // set the topic

The first parameter, mqtt_server, is the IP address of the MQTT broker running on the Raspberry. We will see in the paragraphs on Raspberry how to set this parameter.

The second, mqtt_port, is the communication port where the MQTT broker “listens” to messages.

The third and fourth parameters, mqtt_user and mqtt_password, are the MQTT login credentials. If a device does not have these exact credentials, it cannot register with the MQTT broker and will be denied access. We will see in the paragraph regarding the Raspberry how to set these access parameters on the MQTT broker.

The last parameter, mqtt_topic, is the topic to which the device registers and will be, as mentioned above, temp_hum_sens_1 for device 1 and temp_hum_sens_2 for device 2.

In the following lines, the dht object that manages the DHT22 is defined, the communication GPIO for the DHT22 is defined and the clients for the WiFi connection and for the connection to the MQTT are defined. Then follows the prototype of the setup_wifi() function:

// Set the DHT22 sensor pin
DHTesp dht;
#define  DHT22_PIN 14 

WiFiClient espClient;
PubSubClient client(espClient);

void setup_wifi();

We then encounter a function that removes the last character of a given string and which we use here to eliminate the second decimal place in the temperature and humidity values:

String removeLastCharacter(String input) {
  // Checks whether the string has at least one character
  if (input.length() > 0) {
    // Use substring() to get a substring excluding the last character
    return input.substring(0, input.length() - 1);
  } else {
    // The string is empty, return an empty string
    return "";
  }
}

We then find the setup function which initializes the serial port, activates WiFi by calling the setup_wifi() function, connects the MQTT client to the server and connects the DHT22 sensor to GPIO 14:

void setup() {
  Serial.begin(115200);
  delay(2000);  
  setup_wifi();
  client.setServer(mqtt_server, mqtt_port);  
  dht.setup(DHT22_PIN, DHTesp::DHT22); // Connect DHT sensor to GPIO 14 
}

Then follows the aforementioned setup_wifi() function which manages the connection to the wireless network:

void setup_wifi() {
  delay(10);
  // Connect to Wi-Fi
  Serial.println();
  Serial.print("Connection to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
}

The next function checks whether the MQTT connection is up and running and, if not, tries to re-establish it. If the MQTT connection cannot be established, it returns an error message. Note that, as an argument to the if block, there is the client name which, as already mentioned above, will be ESP8266Client_1 for device 1 and ESP8266Client_2 for device 2.

void reconnect() {
  while (!client.connected()) {
    Serial.print("Connecting to MQTT...");
    if (client.connect("ESP8266Client_1", mqtt_user, mqtt_password)) {
      Serial.println("connected");
    } else {
      Serial.print("error, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

The sketch concludes with the loop function which we examine in detail.

Initially, the status of the MQTT connection is checked and, if applicable, reset:

if (!client.connected()) {
    reconnect();
 }
 client.loop();

The temperature and humidity values ​​are then read from the DHT22 and checked that they are valid:

// Read data from DHT22
float temperature = dht.getTemperature();
float humidity = dht.getHumidity();

// Check if the reading is valid
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Error reading the DHT22 sensor!");
return;
}

The second decimal place is eliminated from the values ​​just read:

String temperature_mod = removeLastCharacter(String(temperature));
String humidity_mod = removeLastCharacter(String(humidity));

Finally, the message to be sent (payload) is created by concatenating the two temperature and humidity values ​​with a comma, it is printed on the Serial Monitor (for debugging purposes only) and is then sent to the server. There is a 5 second pause before starting the loop again.

By changing the value of this pause you can adjust the timing of sending the message. However, this value cannot be less than 2 seconds (which is the time needed for the DHT22 to make a detection):

String payload = temperature_mod + "," + humidity_mod;
Serial.println(payload);
client.publish(mqtt_topic, payload.c_str());

// Please wait before reading again
delay(5000);  // Please wait 5 seconds before your next reading

Let’s create the PlatformIO project for the receiver device

Create a PlatformIO project as described in the article How to create a project for NodeMCU ESP8266 with PlatformIO.

Install the PubSubClient by Nick O’Leary library as done previously.

Then install the LiquidCrystal by Arduino library as shown in the following photo:

Install the LiquidCrystal library
Install the LiquidCrystal library

Now edit the platformio.ini file to add these two lines:

monitor_speed = 115200
upload_speed = 921600

so that it looks like this:

[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps = 
	knolleary/PubSubClient@^2.8
	arduino-libraries/LiquidCrystal@^1.0.7

Obviously you can download the project from the following link:

Replace the main.cpp file of the project you created with the one present in the zip file.

Now let’s see how the sketch works.

Initially the necessary libraries are included:

#include <Arduino.h>

#include <LiquidCrystal.h>

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

The next part performs the same settings as the other sketch:

// Set up your Wi-Fi credentials
const char* ssid = "my_wifi_SSID";
const char* password = "my_wifi_password";

// Set up your MQTT information
const char* mqtt_server = "192.168.1.190";
const int mqtt_port = 1883;
const char* mqtt_user = "pippo";
const char* mqtt_password = "pluto";

The variables that will contain the received data are then defined:

String temperature_topic_1 = "";
String humidity_topic_1 = "";
String temperature_topic_2 = "";
String humidity_topic_2 = "";

The two topics to which the receiver will register are defined:

#define TOPIC1 "temp_hum_sens_1"
#define TOPIC2 "temp_hum_sens_2"

In fact, the receiver, having to receive the data sent by both sensors, will have to register to both topics.

The display is then connected to the ESP8266 and the lcd object that manages it is created. Subsequently, the clients for managing WiFi and MQTT are created:

const int RS = D2, EN = D3, d4 = D5, d5 = D6, d6 = D7, d7 = D8;   
LiquidCrystal lcd(RS, EN, d4, d5, d6, d7);

WiFiClient espClient;
PubSubClient client(espClient);

The thermometer and water drop icons that will appear on the display are then defined:

byte temp[8] = 						//icon for thermometer
{
    B00100,
    B01010,
    B01010,
    B01110,
    B01110,
    B11111,
    B11111,
    B01110
};

byte drop[8] = 						//icon for water droplet
{
    B00100,
    B00100,
    B01010,
    B01010,
    B10001,
    B10001,
    B10001,
    B01110,
};

A function is then implemented that is used to split a given string on a separator character (we will need it to split the message received using the “,” as a character to separate the temperature value from that of humidity):

void splitString(const String &input, char delimiter, String *output, int &outputSize) {
  outputSize = 0; // Initialize the size of the output array to zero

  int start = 0; // Starting index of each substring

  // Scan the input string
  for (int i = 0; i < input.length(); i++) {
    if (input.charAt(i) == delimiter) {
      // Once you find a delimiter character, add the substring to the output array
      output[outputSize++] = input.substring(start, i);
      start = i + 1; // Sets the starting index for the next substring
    }
  }

  // Add last substring (or whole string if there is no delimiter at the end)
  if (start < input.length()) {
    output[outputSize++] = input.substring(start);
  }
}

Then there is the setup_wifi function which manages the WiFi connection:

void setup_wifi() {
  delay(10);
  // Connect to Wi-Fi
  Serial.println();
  Serial.print("Connection to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  lcd.print("Connecting WiFi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
}

and the reconnect function which takes care of the connection or reconnection to the MQTT broker and the subscription to the two topics:

void reconnect() {
  while (!client.connected()) {
    Serial.print("I try to connect to MQTT...");
    if (client.connect("ESP8266Client_3", mqtt_user, mqtt_password)) {
      Serial.println("connected");
      client.subscribe(TOPIC1);
      client.subscribe(TOPIC2);
    } else {
      Serial.print("error, rc=");
      Serial.print(client.state());
      Serial.println(" I'll try again in 5 seconds");
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("MQTT not");
      lcd.setCursor(0, 1);
      lcd.print("connected...");
      delay(5000);
    }
  }
}

Then follows the callback function which is set in the setup function and which is automatically called by the functions of the PubSubClient library every time a message arrives from one of the two topics. This function extracts the messages (payload) coming from the two topics and splits them to fill the variables temperature_topic_1, humidity_topic_1, temperature_topic_2 and humidity_topic_2 which will then be shown on the display:

void callback(char* topic, byte* payload, unsigned int length) {
  if (strcmp(topic, TOPIC1) == 0) {
      String message_topic_1 = "";
      for (unsigned int i = 0; i < length; i++) {
        message_topic_1 += (char)payload[i];
      }

      String outputArray[2]; 
      int outputSize = 0;
      char delimiter = ',';
      splitString(message_topic_1, delimiter, outputArray, outputSize);
      temperature_topic_1 = outputArray[0];
      humidity_topic_1 = outputArray[1];

  } else if (strcmp(topic, TOPIC2) == 0) {
    String message_topic_2 = "";
    for (unsigned int i = 0; i < length; i++) {
      message_topic_2 += (char)payload[i];
    }

    String outputArray[2]; 
    int outputSize = 0;
    char delimiter = ',';
    splitString(message_topic_2, delimiter, outputArray, outputSize);
    temperature_topic_2 = outputArray[0];
    humidity_topic_2 = outputArray[1];

  }   
}

The setup function initializes the serial port, thermometer and water drop icons, display, and calls the setup_wifi function to connect to Wifi. It also connects the client to the server and registers (as already mentioned) the callback function. Then print a message on the display:

void setup() {
  Serial.begin(115200);
  delay(2000); 
  lcd.createChar(1,temp);				// create a new character labeled 1
  lcd.createChar(2,drop);				// create a new character labeled 2
  lcd.begin(16, 2);
  setup_wifi();

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(callback);

  // Print a message to the LCD.
  lcd.clear();
  lcd.print("Device connected");
  delay(5000); 
  lcd.clear();
}

The sketch ends with the loop function that we see in particular.

Initially checks if the board is connected to the MQTT and, if not, try to reconnect it:

if (!client.connected()) {
    reconnect();
 }
 client.loop();

Then points the display cursor to the position (0,0) i.e. in the top left corner and start writing the data and symbols relating to sensor 1:

lcd.setCursor(0, 0);

lcd.print("1");
lcd.print(" ");
lcd.write(1);
lcd.print(temperature_topic_1);
lcd.print((char)223);
lcd.print("C ");
lcd.write(2);						// Print the new character labeled 2
lcd.print(humidity_topic_1);
lcd.print("%");

Finally, points the display cursor at position (0,1) i.e. in the lower left corner and start writing the data and symbols relating to sensor 2:

lcd.setCursor(0, 1);

lcd.print("2");
lcd.print(" ");
lcd.write(1);
lcd.print(temperature_topic_2);
lcd.print((char)223);
lcd.print("C ");
lcd.write(2);						// Print the new character labeled 2
lcd.print(humidity_topic_2);
lcd.print("%");

Let’s see in the next photo an overview of the devices:

Device overview
Device overview

On the left we can see the Raspberry with the WiFi dongle equipped with an antenna (a camera is also connected but is not used in this project), in the center we see, starting from the top, the two transmitting devices equipped with the DHT22 sensor and the receiving device equipped with 16×2 LCD display and potentiometer for contrast adjustment.

Before moving on to Raspberry, upload the sketches to the 3 boards with ESP8266 and keep them powered (perhaps with power banks). If everything goes well, the three devices will connect to the WiFi network and try to register with the MQTT broker which, however, does not yet exist. So for the moment they won’t be able to communicate yet. This fact will also be reported to us on the display of the receiver device with a message telling us that the MQTT is not connected.

Preparing the Raspberry

In order to use the Raspberry it is necessary to take some preliminary steps and install some software.

Let’s start immediately with the installation of the operating system.

The operating system chosen is a distribution made specifically to run on all types of Raspberry, even the older ones. The tests were done on a Raspberry Pi 1 Model B and a Raspberry PI 3 Model B.

If the Raspberry does not have a native wireless connection you can use a WiFi dongle to insert into one of its USB sockets.

Let’s download and install the operating system on the SD card

You can download the image I used from the link below:

Otherwise, if you want the latest version, go to https://www.raspberrypi.com/software/operating-systems/

and take you to the Raspberry Pi OS (Legacy) section. You will download a version that has no graphical environment so that it is as lightweight as possible:

The chosen distribution
The chosen distribution

The downloaded file will be compressed in xz format. To unzip it on Linux you will first need to install the tool:

sudo dnf install xz           su CentOS/RHEL/Fedora Linux.
sudo apt install xz-utils     su Ubuntu/Debian

and then give the command line:

xz -d -v filename.xz

where filename.xz is the name of the file you just downloaded containing the operating system.

On Windows it will be sufficient to use one of these tools: 7-Zip, winRAR, WinZip.

The result will be a file with img extension which is the image to flash on the Raspberry SD card.

To flash the image on the SD card you can use the Balena Etcher tool which works on both Linux, Windows and MACOS.

Its use is very simple: simply select the image to flash, the destination SD card and press the Flash button.

This is what its interface looks like:

The interface of the Balena Etcher tool
The interface of the Balena Etcher tool

The image to be flashed is set on the left, the SD card to be flashed in the centre, and the button to start the flashing operation on the right.

At the end of the operation the SD card will contain two partitions: boot and rootfs. In the device manager on Linux a menu like this appears:

Device menu on Linux
Device menu on Linux

Windows will also show a menu like this: from your file explorer, under This computer you will see the 2 partitions.

Now, with a text editor, create a file on your computer that you will call wpa_supplicant.conf and which you will edit like this:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=«your_ISO-3166-1_two-letter_country_code»
network={
     ssid="«your_SSID»"
     psk="«your_PSK»"
     key_mgmt=WPA-PSK
}

You will need to replace the following items:

  • «your_ISO-3166-1_two-letter_country_code» with the identifier of your country (for example for Italy it is IT)
  • «your_SSID» with the SSID name of your WiFi network
  • «your_PSK» with the WiFi network password

At this point, you will need to create an empty file that you will call ssh (without any extension).

Now open the boot partition on the SD card and copy the two files wpa_supplicant.conf and ssh into it. Safely remove the SD card from the computer and insert it into the Raspberry.

Turn on the Raspberry, wait a few minutes. To be able to log in to the Raspberry via ssh, you will need to find out what its IP is (the one that the router assigned to it via DHCP).

To do this, simply issue the command from a PC shell:

ping raspberrypi.local 

valid on both Linux and Windows(after installing Putty on Windows).

On my PC the Raspberry responds like this:

Raspberry response to ping
Raspberry response to ping

This makes me understand that the assigned IP is 192.168.43.27.

Alternatively you can use the tool Angry IP Scanner or you can access your router settings to see the devices connected via WiFi and find out what IP the Raspberry has.

To be able to log in to the Raspberry via ssh, issue the shell command (obviously in your case the IP will be different from this):

with raspberry password. On Windows you need Putty.

Once inside the Raspberry, issue the following commands to update the software:

sudo apt update
sudo apt upgrade

The password is always raspberry.

Let’s configure the timezone

To configure the timezone, issue the command:

sudo raspi-config

to the Raspberry shell. Suppose you want to set the time zone of Rome (here I will give the example of the time zone of Rome since I live in Italy, you will have to use the time zone of your country).

A screen like this will appear:

Initial screen of the sudo raspi-config command
Initial screen of the sudo raspi-config command

Select the localization option and click OK:

Selected the localization option
Selected the localization option

Then select the timezone option and click OK:

Selected timezone option
Selected timezone option

Now select the geographical area and click OK:

Selected geographic area
Selected geographic area

Finally select the city and click OK:

Selected city
Selected city

Done!

Restart the Raspberry by issuing the command:

sudo reboot

and, after a few minutes, log back into ssh as you did before.

Give the command

date

The Raspberry should now show the correct date and time.

Let’s set the static IP

To ensure that the Raspberry always has the same IP address, we need to set it to be static. In my tests I set it to 192.168.1.190. If we didn’t do this, the router would assign it a different IP at each reboot which would force us to change the IP address of the MQTT server in the ESP8266 sketches each time.

We will proceed in two steps:

  • we will set the fixed IP in the Raspberry
  • we will set the router to reserve that address for our Raspberry

For the first point, issue the command:

nano /etc/dhcpcd.conf

to open the dhcpcd.conf file and edit it.

At the end of the file you will need to add a block like this:

interface [INTERFACE]
static_routers=[ROUTER IP]
static domain_name_servers=[DNS IP]
static ip_address=[STATIC IP ADDRESS YOU WANT]/24

where:

  • [INTERFACE] is the name of the WiFi interface (in our case it will be wlan0)
  • [ROUTER IP] is the address of our router (usually it’s something like 192.168.0.1 or 192.168.1.1). You can find it by entering the administration interface of your modem/router
  • [DNS IP] is the address of the DNS server, which generally coincides with the [ROUTER IP] parameter of the modem/router
  • [STATIC IP ADDRESS YOU WANT] it is the IP address that we want to assign as a fixed IP to the Raspberry

So, assuming that [ROUTER IP] = [DNS IP] = 192.168.1.1 and that [STATIC IP ADDRESS YOU WANT] = 192.168.1.190, the block will look like this:

interface wlan0
static_routers=192.168.1.1
static domain_name_servers=192.168.1.1
static ip_address=192.168.1.190/24

Now restart the Raspberry with the command

sudo reboot

and then log in via ssh again, this time with IP 192.168.1.190.

As a second step we will set the router so that it reserves the address 192.168.1.190 for our Raspberry. Each modem/router is different from the others but they are more or less similar. I’ll show here what mine looks like.

To enter I type the address 192.168.1.1 (because my modem has this IP) on the browser and, after giving the administrator password, I arrive at the main screen. From here I have to look for the access control screen.

Adding a static IP for the Raspberry
Adding a static IP for the Raspberry

There will be a button to add a static IP: add the chosen IP combined with the MAC address of the Raspberry WiFi card. However, I recommend that you consult the instruction manual of your modem/router for this operation.

Now check that the Raspberry connects to the network by issuing the command:

ping www.google.com

If you get the response to the ping the network is connected. If you get a message like “Network is unreachable” issue the command

sudo route add default gw [ROUTER IP]  

where [ROUTER IP] is the gateway which in our case is the router IP, i.e. 192.168.1.1

Let’s install the MQTT broker

First we install a very common MQTT broker called Mosquitto:

sudo apt-get update
sudo apt-get install mosquitto mosquitto-clients

and then we enable and start the service:

sudo systemctl enable mosquitto
sudo systemctl start mosquitto

By default, the Mosquitto broker allows anonymous connections. The Mosquitto broker can be configured to require a username and password when the client connects to the broker. This paragraph shows how to set up username and password authentication for the Mosquitto broker on Raspberry Pi. For example we will use the word pippo as the username and the word pluto as the password.

We can create the password file using the mosquitto_passwd tool.

First of all we change our user from pi to root by giving the command to the shell:

sudo su

and, when asked, we type the password (which is raspberry if it has not been changed).

Once you have root privileges, type the following command:

mosquitto_passwd -c /etc/mosquitto/credentials pippo

You will be asked twice for the password to be associated with the user pippo which, in our case, is pluto.

The command created a file called credentials containing the username (pippo) and the encrypted password (pluto) in the /etc/mosquitto/ folder. At this point you need to edit the Mosquitto configuration file like this. Give the command:

nano /etc/mosquitto/mosquitto.conf

and add these three lines at the end:

listener 1883
allow_anonymous false
password_file /etc/mosquitto/credentials

For the changes to take effect, issue the command:

systemctl restart mosquitto

This will restart the Mosquitto service.

Now return to user pi by issuing the command:

exit

To see MQTT messages transmitted from one of the ESP8266s (to the temp_hum_sens_1 topic or the temp_hum_sens_2 topic) on your Raspberry Pi, you can use the mosquitto_sub MQTT client provided with the Mosquitto broker. Here’s how to do it:

  1. Open a terminal window on your Raspberry Pi.
  2. Use the following command to subscribe to a specific MQTT topic and view incoming messages:
mosquitto_sub -h IP_ADDRESS_RASPBERRY_PI -t temp_hum_sens_1 -u mqtt_user -P mqtt_password

where

  • IP_ADDRESS_RASPBERRY_PI: replace it with the IP address of your Raspberry Pi.
  • temp_hum_sens_1: is the name of the MQTT topic to which your ESP8266 is publishing data (one of the two ESP8266s).
  • mqtt_user e mqtt_password: replace them with your broker’s MQTT credentials if they are needed for subscription.

Once you run the command, you should see MQTT messages arriving in the terminal every time your ESP8266 publishes data to the specified topic. Messages displayed will include the temperature and humidity sent by the ESP8266.

If you try to issue the command without entering mqtt_user and/or mqtt_password or by entering them incorrectly, Mosquitto responds with the message “Connection Refused: not authorised.”

Let’s see the project in operation: here is a video of the receiver in operation

We have practically reached the end. The three ESP8266 are connected to the WiFi network and try to register on the MQTT broker that runs on the Raspberry. As soon as the broker starts working, the three devices will register and start transmitting and receiving data.

The following video will show you my receiver device in operation:

In the experiment, sensor 1 was located in the backyard of the house while sensor 2 was located inside.

Newsletter

If you want to be informed about the release of new articles, subscribe to the newsletter. Before subscribing to the newsletter read the page Privacy Policy (UE)

If you want to unsubscribe from the newsletter, click on the link that you will find in the newsletter email.

Enter your name
Enter your email
Scroll to Top