Sending live Temperature & Humidity data to the cloud and controlling a Relay remotely using MQTT
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.
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.
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.
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:
| Component | ESP32 Pin | Purpose |
|---|---|---|
| DHT22 Data Pin | GPIO 27 | Reads temperature & humidity |
| Relay Signal Pin (IN) | GPIO 12 | Switches relay ON/OFF |
| DHT22 VCC | 3.3V | Power |
| Relay VCC | 5V / VIN | Power (check relay module spec) |
| GND (both) | GND | Common 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.
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.
We'll break the sketch down into logical sections, explaining what each block does.
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"
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"
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);
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);
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.
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.
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);
}
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!");
}
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");
}
}
}
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);
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);
}
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.