Adafruit IO is a free cloud service made for makers. Your ESP32 sends values to feeds, and you build a dashboard from drag-and-drop blocks: gauges, charts, buttons and switches. The dashboard works in any browser, on your phone or a school computer, wherever you are. In this lesson the ESP32 sends the DHT11's temperature and humidity every 30 seconds, and a toggle on the dashboard switches an LED on the breadboard.
What you'll learn
- What feeds and dashboards are in Adafruit IO
- How to publish and subscribe with the Adafruit MQTT library
- How to stay within a free plan's rate limit
- How to keep a secret key out of sight
What you need
- ESP32 board, expansion board and USB cable (ESP32 IoT Starter Kit)
- DHT11 temperature and humidity sensor (ESP32 IoT Starter Kit)
- 1 LED and 1 resistor, 220 Ω (ESP32 IoT Starter Kit)
- A free Adafruit IO account (ages 13 and up; younger makers ask a parent or teacher)
- A 2.4 GHz Wi-Fi network
- The printed parts from the 3D printing box below (radiation shield), or the cardboard version described there
- Breadboard and jumper wires (ESP32 IoT Starter Kit)
Wiring

| From | To |
|---|---|
| DHT11 S (signal) | ESP32 GPIO 27 |
| DHT11 + and − | 3V3 and GND |
| ESP32 GPIO 25 | 220 Ω resistor, then the LED's long leg |
| LED short leg | GND |
Set up Adafruit IO
- Sign up at io.adafruit.com.
- Open Feeds → New Feed and create three feeds:
temperature,humidityandled. - Open Dashboards → New Dashboard, call it My room, open it and add blocks with the gear icon: a Gauge for temperature (0 to 40), a Line Chart with temperature and humidity, and a Toggle for the led feed (button values ON and OFF).
- Click the yellow key icon (My Key) and copy your username and active key. The key is like a password: never share it or post your sketch with it.
The sketch
Replace YOUR_WIFI_NAME and YOUR_WIFI_PASSWORD with your own network details (2.4 GHz only).
In the Arduino IDE, open Library Manager and install Adafruit MQTT Library and the DHT sensor library by Adafruit.
Put your username and key into AIO_USERNAME and AIO_KEY.
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
#include <DHT.h>
const char* WIFI_NAME = "YOUR_WIFI_NAME";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
#define AIO_USERNAME "YOUR_AIO_USERNAME"
#define AIO_KEY "YOUR_AIO_KEY"
const int LED_PIN = 25;
const unsigned long EVERY = 30000; // 2 values every 30 s: well inside the free limit
WiFiClientSecure net;
Adafruit_MQTT_Client mqtt(&net, "io.adafruit.com", 8883, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Publish temperatureFeed(&mqtt, AIO_USERNAME "/feeds/temperature");
Adafruit_MQTT_Publish humidityFeed(&mqtt, AIO_USERNAME "/feeds/humidity");
Adafruit_MQTT_Subscribe ledFeed(&mqtt, AIO_USERNAME "/feeds/led");
DHT dht(27, DHT11);
unsigned long lastSend = 0;
bool sentOnce = false;
void connectMqtt() {
if (mqtt.connected()) return;
Serial.print("Connecting to Adafruit IO... ");
int8_t result;
while ((result = mqtt.connect()) != 0) {
Serial.println(mqtt.connectErrorString(result));
mqtt.disconnect();
delay(5000);
}
Serial.println("connected");
}
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
dht.begin();
WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" connected");
net.setInsecure();
mqtt.subscribe(&ledFeed);
}
void loop() {
connectMqtt();
// wait up to 1 s for messages from the dashboard
Adafruit_MQTT_Subscribe* message;
while ((message = mqtt.readSubscription(1000))) {
if (message == &ledFeed) {
String value = (char*)ledFeed.lastread;
digitalWrite(LED_PIN, value == "ON");
Serial.println("LED " + value);
}
}
if (!sentOnce || millis() - lastSend > EVERY) {
sentOnce = true;
lastSend = millis();
float t = dht.readTemperature();
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) {
Serial.println("Sensor error");
} else {
temperatureFeed.publish(t);
humidityFeed.publish(h);
Serial.printf("Sent %.1f C, %.0f %%\n", t, h);
}
}
if (!mqtt.ping()) mqtt.disconnect(); // reconnect next time if the link dropped
}
How it works
Adafruit IO speaks MQTT, the same publish/subscribe language as in the MQTT dashboard lesson, but with your own private account. Each feed is a topic named username/feeds/name. The ESP32 publishes to the temperature and humidity feeds and subscribes to the led feed, so when you flip the toggle, Adafruit IO sends "ON" or "OFF" to the ESP32 within a second.
The free plan accepts 30 values a minute and keeps them for 30 days. Two values every 30 seconds is only 4 a minute, so there is room for more sensors. The connection uses port 8883, which is encrypted, so your key doesn't travel over the internet in plain text.
client.setInsecure() keeps the connection encrypted but skips checking the server's certificate. That keeps the sketch short and is fine for a learning project. For a device you leave running for years, load the server's root certificate with client.setCACert() instead.
Try this next
- Add an Action in Adafruit IO that emails you when the temperature goes above 26 °C.
- Add a slider block that sets the LED brightness with PWM.
- Share the dashboard publicly (Dashboard settings → Privacy) and show it on the class screen.
Troubleshooting
- "Connection refused - bad user / password": check the username (case matters) and copy the key again.
-
"Throttle" warnings in Adafruit IO: you are sending too fast. Don't make
EVERYsmaller than 10000. -
The toggle does nothing: its button values must be exactly ON and OFF, and it must use the
ledfeed. - It never connects to Wi-Fi: check the network name and password (both are case-sensitive) and make sure the network is 2.4 GHz.