ProtoSem IoT · Viswes Vijayaragavan Sivakumar · 24BCS321

Task 2 — Adafruit IO Dashboard & MQTT

Switching a mains bulb from anywhere through an Adafruit IO dashboard and MQTT.

1Overview

Objective. Control a real bulb from anywhere in the world, not just from inside one Wi-Fi network.

Problem it solves. Task 1 only worked on the local network. Here the control goes through a cloud service: a toggle on an Adafruit IO dashboard publishes ON or OFF to a feed, and the ESP32, which is subscribed to that feed, switches a relay that powers the bulb.

2Concepts

Why Adafruit IO

Adafruit IO is a cloud service built for IoT data. It stores values in feeds, lets you build dashboards (toggles, gauges, charts) on top of them, and runs an MQTT broker the ESP32 can connect to. I didn't have to write or host a server.

MQTT in one paragraph

MQTT is a lightweight publish/subscribe protocol. Devices never talk to each other directly. A publisher sends a message to a topic on a broker, and the broker forwards it to every subscriber of that topic. Messages are tiny, and the device keeps one connection open instead of polling, which suits a microcontroller.

RoleIn this project
PublisherThe Toggle block on my Adafruit IO dashboard
BrokerAdafruit IO (io.adafruit.com)
SubscriberThe ESP32
Topic / feedTringyTrongy/feeds/bulb-relay

Topics and feeds

A feed is Adafruit IO's name for an MQTT topic. Its full topic is username/feeds/feed-key. Anything that writes to bulb-relay (the dashboard now, IFTTT in Task 3) controls the bulb, because the ESP32 only cares about the feed.

3System Design

Task 2 data flowAdafruit IO dashboardToggle blockAdafruit IO brokerfeed: bulb-relayESP32subscriberRelay → bulbGPIO26publish ON / OFFMQTT messagesetRelay()topic: TringyTrongy/feeds/bulb-relay

On boot the ESP32 also asks the feed for its last value (bulbRelay->get()), so after a reset the bulb matches the dashboard.

4Hardware & Software

HardwareSoftware / services
ESP32 DevKit V1Arduino IDE / Arduino Cloud editor
1-channel 5 V relay module (active LOW)Adafruit IO Arduino library (uses Adafruit MQTT)
Bulb, holder and mains cableAdafruit IO account TringyTrongy: feed bulb-relay, dashboard bulb-relay
USB cable, jumper wires

5Wiring / Setup

Task 2 wiringESP32DevKit V1GPIO26Relay IN signalVINRelay VCC 5 VGNDRelay GND
ESP32 pinRelay module
GPIO26IN
VIN (5 V from USB)VCC
GNDGND

The bulb's live wire is cut and passed through the relay's COM and NO (normally open) terminals; neutral goes straight to the bulb. With the relay off, the circuit is open and the bulb is off.

Mains voltage. The relay side carries 230 V AC. Keep the mains side fully insulated, check it before plugging in, and never touch the relay terminals while it is powered.

6Implementation

bulb_v2_adafruitio_relay.inoview on GitHub

Credentials come from arduino_secrets.h, which is not in the repository. Copy arduino_secrets.example.h and fill it in.

/*
  Bulb-V2 — Adafruit IO Relay Control
  ESP32 + single-channel relay module
  Toggles the bulb ON/OFF via an Adafruit IO feed + dashboard toggle switch
*/

#include <WiFi.h>
#include "AdafruitIO_WiFi.h"
#include "arduino_secrets.h"   // auto-generated by the Web Editor's Secret tab

// ---------- Wi-Fi credentials (set these in the Secret tab: SSID, PASS) ----------
#define WIFI_SSID      SECRET_SSID
#define WIFI_PASS      SECRET_PASS

// ---------- Adafruit IO credentials (Secret tab: AIO_USERNAME, AIO_KEY) ----------
#define IO_USERNAME    SECRET_AIO_USERNAME
#define IO_KEY         SECRET_AIO_KEY

// ---------- Relay wiring ----------
#define RELAY_PIN         26     // GPIO wired to the relay's IN/signal pin
#define RELAY_ACTIVE_LOW  true   // most cheap 1-channel relay boards trigger on LOW
                                  // if the bulb turns on when you press "OFF", flip this

AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);
AdafruitIO_Feed *bulbRelay = io.feed("bulb-relay");

void setRelay(bool on) {
  bool pinHigh = RELAY_ACTIVE_LOW ? !on : on;
  digitalWrite(RELAY_PIN, pinHigh ? HIGH : LOW);
  Serial.print("Relay set to: ");
  Serial.println(on ? "ON" : "OFF");
}

// called whenever the dashboard toggle publishes a new value
void handleMessage(AdafruitIO_Data *data) {
  String val = data->value();
  Serial.print("Feed message received: ");
  Serial.println(val);

  bool on = (val == "1" || val.equalsIgnoreCase("ON"));
  setRelay(on);
}

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

  pinMode(RELAY_PIN, OUTPUT);
  setRelay(false); // start with bulb OFF

  Serial.print("Connecting to Adafruit IO");
  io.connect();

  // subscribe to the feed
  bulbRelay->onMessage(handleMessage);

  while (io.status() < AIO_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.println(io.statusText());

  // pull the last known state from the dashboard on boot
  bulbRelay->get();
}

void loop() {
  io.run(); // keeps the MQTT connection alive — must be called every loop, unblocked
}

Key sections

  • Connecting — AdafruitIO_WiFi io(...) holds the Wi-Fi and Adafruit IO credentials; io.connect() joins Wi-Fi and opens the MQTT connection.
  • Subscribing — io.feed("bulb-relay") picks the topic and bulbRelay->onMessage(handleMessage) registers the function that runs for every new value.
  • Acting on a message — handleMessage() accepts "1" or "ON" as on and anything else as off, then calls setRelay().
  • Active-LOW relay — RELAY_ACTIVE_LOW inverts the pin, because this relay board closes its contact when IN is pulled LOW.
  • Keeping the connection alive — io.run() must run on every loop; it processes incoming messages and sends MQTT keep-alive pings.

7Configuration

  1. Signed up at io.adafruit.com (username TringyTrongy).
  2. Feeds → New Feed → bulb-relay.
  3. Dashboards → New Dashboard → bulb-relay → New Block → Toggle, linked to the bulb-relay feed (button values ON / OFF).
  4. Copied the username and Active Key from the key icon into the sketch's secrets.
  5. Flashed the ESP32 and opened the Serial Monitor to watch messages arrive.
Feed page: privacy, history settings and the dashboard it appears on
Feed page: privacy, history settings and the dashboard it appears on

8Evidence

9Challenges & Fixes

Problem. The bulb turned on when the dashboard said OFF.

Why. Most cheap relay boards are active LOW: the contact closes when IN is pulled to ground, so the pin value is the opposite of the bulb.

Fix. Added RELAY_ACTIVE_LOW; setRelay() inverts the pin when it is true. Only one line changes if a different board is used.

Problem. The relay did not always release fully when switched off.

Why. The relay module expects 5 V logic but the ESP32 drives 3.3 V. Driving the pin HIGH to switch off can still leak enough current through the module's input to keep it half-on.

Fix. In my later LCU-1 firmware (and in the Task 4 firmware when it is set for an active-LOW board) the pin is set to INPUT (high impedance) for OFF instead of HIGH, which leaves the input floating at the module's own pull-up.

Problem. After a reset the bulb did not match the dashboard.

Why. The ESP32 only hears new messages, so it missed the value set while it was off.

Fix. bulbRelay->get() at the end of setup() asks the broker for the last value, which runs handleMessage() once.

10Reflection

MQTT changed how I think about devices. The ESP32 doesn't know or care who is controlling it; it just listens to a topic. That makes adding a second controller almost free, which is exactly what Task 3 does with a voice assistant. I also learned to check what voltage a module expects before trusting a GPIO pin to drive it.

11Repository Link

All code for this task: https://github.com/TringyTrongy/protosem-iot/tree/main/task2-adafruit-io-mqtt

✓Checklist coverage

Every item from the IoT Portfolio Guide for this task, and where it is on this page.

Guide itemWhere
Purpose of Adafruit IO in an IoT system2. Concepts
Basic concept of MQTT2. Concepts
Publisher, subscriber and broker identified2. Concepts
Role of an MQTT topic / feed2. Concepts
Hardware and software used4. Hardware & Software
Adafruit IO account created and documented7. Configuration
Dashboard and feed configuration documented7. Configuration
Communication flow between ESP32, MQTT and Adafruit IO3. System Design
MQTT topic / feed structure used2. Concepts
Complete ESP32 source code6. Implementation
Explanation of important code sections6. Implementation
Photographs of the hardware setup8. Evidence
Screenshots of the Adafruit IO dashboard7. Configuration
LED / bulb control through the cloud dashboard demonstrated8. Evidence
Problems during MQTT / cloud setup9. Challenges & Fixes
Solutions implemented9. Challenges & Fixes
Learning reflection10. Reflection
All files in the repository11. Repository Link