ESP32 MQTT Home Automation (Hands-on Project)

Connect your ESP32 NodeMCU to a public MQTT broker, publish sensor readings, and subscribe to control an LED.

Welcome to the ESP32 MQTT Hands-on Project! Now that we have covered the theory of MQTT, let's put it into action by building a real IoT project.

In this tutorial, we will:

  1. Connect an ESP32 to a local Wi-Fi network.
  2. Establish a connection to a free, public MQTT broker (broker.hivemq.com).
  3. Publish simulated temperature values from the ESP32 every 5 seconds.
  4. Subscribe to a command topic on the ESP32 to remotely turn the onboard LED ON or OFF.

🛠️ Requirements & Parts List

Here is what you will need for this project:

  • ESP32 NodeMCU Board (Any standard ESP32 development board).
  • Micro-USB Cable (To connect the ESP32 to your computer).
  • Arduino IDE (Installed on your computer).
  • Onboard LED (Usually pre-connected to GPIO 2).

Installing the MQTT Library:

To handle MQTT communications in Arduino IDE, we need to install the PubSubClient library:

  1. Open Arduino IDE.
  2. Navigate to Sketch ➡️ Include Library ➡️ Manage Libraries.
  3. In the Library Manager search bar, type PubSubClient (by Nick O'Leary).
  4. Click Install.

Note: The PubSubClient library is one of the most stable and popular MQTT client libraries for Arduino-compatible microcontrollers.


🔌 Connection & Circuit Setup

To keep things simple for testing, we will use the onboard blue LED pre-wired on the ESP32 board.

  • Onboard LED Pin: GPIO 2 (labeled as 2 or D2 on most ESP32 boards).

If you want to control a physical appliance instead, connect a 5V relay module as follows:

  • Relay VCC ➡️ ESP32 Vin (5V Supply)
  • Relay GND ➡️ ESP32 GND
  • Relay IN ➡️ ESP32 GPIO 2

💻 Arduino Source Code

Copy the code below into your Arduino IDE.

Make sure to update:

  • ssid and password with your Wi-Fi credentials.
  • client_id (on Line 74) to a unique string to avoid server conflicts.
esp32_mqtt_project.ino
#include <WiFi.h>
#include <PubSubClient.h>

// --- WiFi Configuration ---
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";

// --- MQTT Broker Configuration ---
// We are using HiveMQ's free public sandbox broker
const char* mqtt_broker = "broker.hivemq.com"; 
const int mqtt_port = 1883;

// --- MQTT Topics ---
const char* publish_topic = "sparkovation/esp32/temp";
const char* subscribe_topic = "sparkovation/esp32/led";

// ESP32 Client Instances
WiFiClient espClient;
PubSubClient client(espClient);

const int ledPin = 2; // Onboard LED Pin
unsigned long lastMsg = 0;
float temperature = 24.0;

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

// Callback Function: Triggered when a new message arrives on a subscribed topic
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("]: ");
  
  String message = "";
  for (int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  Serial.println(message);

  // Switch LED control logic
  if (String(topic) == subscribe_topic) {
    if (message == "ON") {
      digitalWrite(ledPin, HIGH);
      Serial.println("LED turned ON!");
    } else if (message == "OFF") {
      digitalWrite(ledPin, LOW);
      Serial.println("LED turned OFF!");
    }
  }
}

// Reconnect Function: Reconnects to the broker if connection drops
void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    
    // Create a unique client ID to prevent connection collisions
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);
    
    if (client.connect(clientId.c_str())) {
      Serial.println("connected!");
      // Re-subscribe to control topic
      client.subscribe(subscribe_topic);
      Serial.print("Subscribed to: ");
      Serial.println(subscribe_topic);
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" trying again in 5 seconds");
      delay(5000);
    }
  }
}

void setup() {
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  Serial.begin(115200);
  setup_wifi();
  
  client.setServer(mqtt_broker, mqtt_port);
  client.setCallback(callback);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop(); // Keeps the MQTT client running and handles keep-alives

  unsigned long now = millis();
  // Publish simulated temperature reading every 5 seconds
  if (now - lastMsg > 5000) {
    lastMsg = now;
    
    // Simulate slight temperature changes (+/- 0.5 degrees)
    temperature += random(-5, 6) / 10.0;
    
    // Convert float value to a string
    char tempString[8];
    dtostrf(temperature, 1, 2, tempString);
    
    Serial.print("Publishing temperature: ");
    Serial.println(tempString);
    client.publish(publish_topic, tempString);
  }
}

🔍 Testing the Setup

Once the code is uploaded to your ESP32, you can test publishing and subscribing using one of the following methods:

Method 1: HiveMQ Web Client (No Installation)

  1. Open the HiveMQ Websocket Client Demo in your web browser.
  2. Leave the default settings and click Connect.
  3. Under the Subscriptions panel, click Add New Topic Subscription and subscribe to: sparkovation/esp32/temp. You should start seeing the ESP32's temperature values appear here every 5 seconds!
  4. Under the Publish panel, enter the topic sparkovation/esp32/led and write ON (case-sensitive) in the message box. Click Publish and watch the ESP32 onboard blue LED turn ON.
  5. Publish OFF to turn the LED OFF.

Method 2: MQTT Explorer (Desktop Client)

For a comprehensive desktop testing tool, download MQTT Explorer.

  • Host: broker.hivemq.com
  • Port: 1883
  • Click Connect. This tool lets you view the entire topic tree hierarchically, watch live published changes, and publish control values instantly.

🛠️ Common Troubleshooting

  • Serial Monitor shows rc=-2 (Connection Failed):
    • Cause: The broker is unreachable. Make sure your local router is connected to the internet. Since this is a public broker sandbox, the broker itself might occasionally be down.
  • Serial Monitor shows rc=-4 (Connection Timeout):
    • Cause: Your router or firewall may be blocking outgoing traffic on Port 1883. Try connecting the ESP32 and computer to a mobile hotspot.
  • ESP32 is stuck printing dots (....) and not connecting to Wi-Fi:
    • Cause: Double-check your SSID and Password. Remember that ESP32 only supports 2.4GHz Wi-Fi bands; it cannot connect to a 5GHz network.

🎉 Congratulations!

You have successfully built and tested a real-time MQTT home automation node! You can now expand this setup by connecting DHT22 sensors, active relays, and linking them to your favorite home automation dashboards.