ESP32 + Adafruit IO Dashboard

Sending live Temperature & Humidity data to the cloud and controlling a Relay remotely using MQTT

1. Project Overview

In this lesson, we take the Adafruit IO dashboard we previously built and connect it to a real ESP32 microcontroller. The ESP32 will read live data from a DHT22 temperature & humidity sensor and publish those readings to the dashboard over the internet using the MQTT protocol. At the same time, the ESP32 will subscribe to a "relay" feed on the dashboard, allowing you to switch a relay (and anything connected to it — a lamp, a fan, a pump) ON or OFF directly from the web dashboard.

DHT22 Sensor
ESP32
Wi-Fi Router
Adafruit IO Cloud
Dashboard (Browser)
Relay Module
ESP32
Adafruit IO Cloud
Dashboard Toggle Switch

This creates a full two-way communication loop: sensor data flows up to the dashboard, and control commands flow down from the dashboard to the hardware.

2. Getting Your Adafruit IO Credentials

Before writing any code, you need two pieces of information from your Adafruit IO account: your Username and your Active Key (AIO Key). This key acts as your password/authentication token that allows the ESP32 to securely publish and subscribe to your feeds.

  1. Log in to io.adafruit.com
  2. Click on your profile icon (top-right corner)
  3. Select "My Key"
  4. Copy the Username shown
  5. Copy the Active Key (AIO Key) shown
Security Tip: Your AIO Key is like a password. Never share it publicly or commit it to a public GitHub repository.

3. Circuit Diagram

The hardware setup consists of a DHT22 sensor for reading temperature and humidity, and a relay module to control an external device. Pin connections used in this example:

ComponentESP32 PinPurpose
DHT22 Data PinGPIO 27Reads temperature & humidity
Relay Signal Pin (IN)GPIO 12Switches relay ON/OFF
DHT22 VCC3.3VPower
Relay VCC5V / VINPower (check relay module spec)
GND (both)GNDCommon ground
        ┌───────────────────────┐
        │         ESP32         │
        │                       │
        │  GPIO27 ●─────────────┼────►  DHT22 (DATA)
        │                       │
        │  GPIO12 ●─────────────┼────►  Relay (IN / Signal)
        │                       │
        │   3.3V  ●─────────────┼────►  DHT22 (VCC)
        │   5V    ●─────────────┼────►  Relay (VCC)
        │   GND   ●─────────────┼────►  Common Ground
        └───────────────────────┘
            

You can expand this circuit by adding more sensors or more relays — simply repeat the same pattern with new GPIO pins and matching Adafruit IO feeds.

4. Installing the Required Library

This project relies on the Adafruit MQTT Library to communicate with Adafruit IO. It is free and open-source — although built by Adafruit for their own IO platform, it can be used with any generic MQTT broker as well.

  1. Open Arduino IDE
  2. Go to Sketch
  3. Click Include Library
  4. Click Manage Libraries
  5. Search for "Adafruit MQTT Library"
  6. Click Install
Version Note: This example was tested with version 1.3.0. If you encounter compatibility issues, try rolling back to version 1.0.3 and compare results.

5. Code Walkthrough

We'll break the sketch down into logical sections, explaining what each block does.

5.1 Library Includes

The sketch begins by including the WiFi library (for ESP32 connectivity), the DHT sensor library, and the Adafruit MQTT libraries needed to talk to Adafruit IO.

#include <WiFi.h>
#include <DHT.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

5.2 Wi-Fi and Adafruit IO Credentials

Next come your Wi-Fi network credentials and Adafruit IO account details. The AIO_SERVER and AIO_SERVERPORT values stay the same for everyone — only your username and AIO key (copied earlier) need to be changed.

#define WLAN_SSID       "YourWiFiName"
#define WLAN_PASS       "YourWiFiPassword"

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME    "your_username"
#define AIO_KEY         "your_aio_key"

5.3 Sensor and Relay Pin Setup

The DHT sensor pin, sensor type (DHT22), and relay pin are declared, and a DHT object instance is created.

#define DHTPIN 27
#define DHTTYPE DHT22
#define RELAYPIN 12

DHT dht(DHTPIN, DHTTYPE);

5.4 WiFi Client and MQTT Setup

A WiFiClient object handles the raw network connection, while the Adafruit_MQTT_Client object wraps it with MQTT protocol support, using the server, port, username, and key defined earlier.

WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

5.5 Defining Feeds (Publish & Subscribe Topics)

Each value you send to or receive from the dashboard needs a "feed" object. The first parameter is simply a friendly name (used only in your code), while the second — the actual feed path — is what matters. It always follows the pattern username/feeds/feedname.

Tip: You can find the exact feed path on your Adafruit IO dashboard by hovering over a feed block — it appears in the bottom-left corner of the page.
Adafruit_MQTT_Publish temperatureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperature");
Adafruit_MQTT_Publish humidityFeed    = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/humidity");
Adafruit_MQTT_Subscribe relaySub      = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/relay");

If you add more sensors or relays later, simply create additional feed instances following the same pattern.

5.6 The setup() Function

In setup(), we start the serial monitor, initialize the DHT sensor, configure the relay pin as an output (defaulting to LOW/off), connect to Wi-Fi, and finally subscribe to the relay feed so we can listen for incoming commands.

void setup() {
  Serial.begin(115200);
  dht.begin();

  pinMode(RELAYPIN, OUTPUT);
  digitalWrite(RELAYPIN, LOW);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected!");

  mqtt.subscribe(&relaySub);
}

5.7 The MQTT_connect() Helper Function

This function checks whether the MQTT connection is alive. If it's already connected, it simply returns; if not, it attempts to reconnect. It must be called repeatedly inside loop() to keep the connection healthy — do not modify its internal logic.

void MQTT_connect() {
  if (mqtt.connected()) {
    return;
  }
  Serial.println("Connecting to MQTT...");
  while (mqtt.connect() != 0) {
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);
  }
  Serial.println("MQTT Connected!");
}

5.8 Handling the Relay Subscription

This block waits briefly for any incoming subscription messages. If a message has arrived on the relay feed, it compares the received text to "ON" or "OFF" and switches the relay pin accordingly. If you add more subscriptions later, duplicate this if block for each one.

Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(5000))) {
  if (subscription == &relaySub) {
    Serial.print("Relay: ");
    Serial.println((char *)relaySub.lastread);

    if (strcmp((char *)relaySub.lastread, "ON") == 0) {
      digitalWrite(RELAYPIN, HIGH);
      Serial.println("Relay turned ON");
    } else if (strcmp((char *)relaySub.lastread, "OFF") == 0) {
      digitalWrite(RELAYPIN, LOW);
      Serial.println("Relay turned OFF");
    }
  }
}

5.9 Reading and Publishing Sensor Data

Finally, we read the temperature and humidity from the DHT22 sensor and publish each value to its respective feed. The publish() function returns a non-zero value on success, which we can check and print to the Serial Monitor for confirmation.

float temperature = dht.readTemperature();
float humidity    = dht.readHumidity();

if (temperatureFeed.publish(temperature)) {
  Serial.println("Temperature published!");
} else {
  Serial.println("Temperature publish failed.");
}

if (humidityFeed.publish(humidity)) {
  Serial.println("Humidity published!");
} else {
  Serial.println("Humidity publish failed.");
}

Serial.println("********************");
delay(5000);

6. Full Example Sketch

Putting all the pieces together, here is the complete sketch:

#include <WiFi.h>
#include <DHT.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#define WLAN_SSID       "YourWiFiName"
#define WLAN_PASS       "YourWiFiPassword"

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME    "your_username"
#define AIO_KEY         "your_aio_key"

#define DHTPIN 27
#define DHTTYPE DHT22
#define RELAYPIN 12

DHT dht(DHTPIN, DHTTYPE);
WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

Adafruit_MQTT_Publish temperatureFeed = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/temperature");
Adafruit_MQTT_Publish humidityFeed    = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/humidity");
Adafruit_MQTT_Subscribe relaySub      = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/relay");

void MQTT_connect() {
  if (mqtt.connected()) return;
  Serial.println("Connecting to MQTT...");
  while (mqtt.connect() != 0) {
    Serial.println("Retrying MQTT connection in 5 seconds...");
    mqtt.disconnect();
    delay(5000);
  }
  Serial.println("MQTT Connected!");
}

void setup() {
  Serial.begin(115200);
  dht.begin();
  pinMode(RELAYPIN, OUTPUT);
  digitalWrite(RELAYPIN, LOW);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected!");

  mqtt.subscribe(&relaySub);
}

void loop() {
  MQTT_connect();

  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(5000))) {
    if (subscription == &relaySub) {
      Serial.print("Relay: ");
      Serial.println((char *)relaySub.lastread);

      if (strcmp((char *)relaySub.lastread, "ON") == 0) {
        digitalWrite(RELAYPIN, HIGH);
      } else if (strcmp((char *)relaySub.lastread, "OFF") == 0) {
        digitalWrite(RELAYPIN, LOW);
      }
    }
  }

  float temperature = dht.readTemperature();
  float humidity    = dht.readHumidity();

  if (temperatureFeed.publish(temperature)) {
    Serial.println("Temperature published!");
  }
  if (humidityFeed.publish(humidity)) {
    Serial.println("Humidity published!");
  }

  Serial.println("********************");
  delay(5000);
}

7. Uploading and Testing

  1. Connect your ESP32 board via USB
  2. Select the correct Board and Port in Arduino IDE
  3. Click Upload
  4. Open the Serial Monitor at 115200 baud
  5. Verify WiFi connection message appears
  6. Verify MQTT Connected message appears
  7. Check the Adafruit IO dashboard for live temperature and humidity data
  8. Toggle the relay switch on the dashboard to test the relay feed

Once uploaded, your ESP32 will continuously read the DHT22 sensor, publish temperature and humidity readings every few seconds, and listen for relay ON/OFF commands from your dashboard — completing a fully functional two-way IoT system.

Next Steps Try adding a second relay, an additional sensor (like light or motion), or setting up dashboard alerts based on threshold values.