Projects
Communication
WiFi and MQTT

Overview

This project demonstrates how to send data from the serial input of an ESP32 board to AWS IoT via MQTT communication. Additionally, it includes functionality to handle messages received on a subscribed MQTT topic, making the communication bidirectional.

⚠️

This project requires a pre-requiste of making a thing on AWS and downloading the certificates. A file named "Secrets" holds all the sensitive data like WiFi name and password, thing name, AWS IoT endpoints and all the certificates required to connect to AWS.

This will be explained in more detail to subscribers.

You can follow this project to only establish a WiFi connection and connect to a simpler MQTT platform or an API platform.

Components

We will use an ESP32 board with built-in support for WiFi.

espressif_esp32

Circuit Diagram

There is no circuit diagram for this project, it only requires the board connected to the computer USB port using the appropriate cable.

Assembly

Connect the board to the computer using the appropriate cable.

Code

/*
  Project: Bi directional communication with AWS via MQTT communication. 
  Project Description:
  This sketch writes data from serial input to AWS IoT via MQTT communication and handles messages received on a topic.
 
  Author: STEMVentor Educonsulting
  
  This code is copyrighted. Please do not reuse or share for any purpose other than for learning with subscribed STEMVentor programs.
  This code is for educational purposes only and is not for production use.
*/
 
// LIBRARIES
 
// Libraries For MQTT communication 
#include "Secrets.h"
// wifi library
#include <WiFiClientSecure.h>
#include <WiFi.h>
// main MQTT library
#include <PubSubClient.h>
//Arduino Json library
#include <ArduinoJson.h>
#include <WiFi.h>
 
// PIN DEFINITIONS
 
// GLOBAL VARIABLES
// Define the display size
#define AWS_IOT_PUBLISH_TOPIC   "STEMVentorMicrocircuitsPublish"
#define AWS_IOT_SUBSCRIBE_TOPIC "STEMVentorMicrocircuitsSubscribe"
 
// Used for reading a string.
String receivedString;
bool readCheck = false; //variable check if string has been entered  
// Packet to be sent
char packet[500];
 
/* INITIALIZE OBJECTS
 * Libraries usually follow an object-oriented approach that requires
 * an instance of the class to call its methods.
 */
WiFiClientSecure net; // WiFi client
PubSubClient client(net); // MQTT client
 
/* LOCAL FUNCTIONS */
 
void readString(){
  // Serial.println("Enter a data string to be sent via MQTT:");
  if (Serial.available()) {     // if data available
  receivedString = Serial.readString(); // Read until timeout
  receivedString.trim();   // Remove any \r \n whitespace at the end of the String
  readCheck = true;
  }             
}
 
void wifiSetup()
{
  WiFi.mode(WIFI_STA); // Station mode, where the device connects to an external WiFi network
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD); // Gets the SSID and password from the Secrets.h file
 
  Serial.println("Connecting to Wi-Fi");
 
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
}
 
void messageHandler(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived on topic: ");
  Serial.println(topic);
  Serial.print("Message: ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
  // Process the payload as needed
}
 
void AWSSetup()
{
  // Configure WiFiClientSecure to use the AWS IoT device credentials
  net.setCACert(AWS_CERT_CA);
  net.setCertificate(AWS_CERT_CRT);
  net.setPrivateKey(AWS_CERT_PRIVATE);
 
  // Connect to the MQTT broker on the AWS endpoint we defined in secrets file
  client.setServer(AWS_IOT_ENDPOINT, 8883);
 
  // Create a message handler
  client.setCallback(messageHandler);
 
  Serial.println("Connecting to AWS IoT");
 
  while (!client.connected())
  {
    Serial.print(".");
    if (client.connect(THINGNAME))
    {
      Serial.println("Connected to AWS IoT");
      client.subscribe(AWS_IOT_SUBSCRIBE_TOPIC); //sucscribe to topic here
    }
    else
    {
      Serial.println("AWS IoT Connection Failed! Retrying...");
      int errorCode = client.state(); //error code
      Serial.print("Error code: ");
      Serial.println(errorCode);
      delay(1000);
    }
  }
}
 
void JSONFormatter()
{
  StaticJsonDocument<200> doc;
 
  doc["message"] = receivedString;  //make json  
  serializeJson(doc, packet); //serialise json
}
 
// Function to publish message to MQTT topic 
void publishMessage(char message[500])
{
  bool publish_check = false; // Variable to indicate if MQTT publish has happened successfully or not
  int publish_counter = 0; // Variable to store number of times MQTT publish has been tried
  while (publish_check == false)
  {
    if (!client.publish(AWS_IOT_PUBLISH_TOPIC, message))  //publishes message to topic
    {
      Serial.println("Failed to publish message");
      Serial.println("Checking connection with AWS IoT...");
      checkAWS();
      delay(1000);
      if (publish_counter > 3) // If publish is not successful for 3 times then restart the ESP.
      {
        Serial.println("Restarting the ESP");
        ESP.restart();  //restarts the esp
      }
    }
    else 
    {
      Serial.println("Message published successfully");
      publish_check = true;
    }
    publish_counter++;
  }
}
 
// Function to check WiFi connection
void checkWIFI()
{
  if (WiFi.status() != WL_CONNECTED) 
  {
    Serial.println("Wi-Fi not connected, reconnecting...");
    wifiSetup();
  }
} 
 
// Function to check AWS connection
void checkAWS()
{
  if (!client.connected()) 
  {
    Serial.println("AWS IoT not connected, reconnecting...");
    AWSSetup();
  }
}
 
/* SETUP CODE: runs once when the board starts up or resets */ 
void setup() {
  // Start the serial communication with baud rate suitable for your components.
  Serial.begin(9600);
  wifiSetup();
  AWSSetup();
  Serial.println("Setup done successfully");
}
 
/* MAIN LOOP: runs repeatedly at a very high frequency (1000s of times a second) */
void loop() {
  checkWIFI();
  checkAWS();
  client.loop(); // This keeps the MQTT connection alive and processes incoming messages
  readString();
 
  if (readCheck == true)
  {
  JSONFormatter();
  publishMessage(packet);
  readCheck = false;
  }
}