DIY ELECTRONICSTR

← All projects

LED Control from Your Phone (ESP32 Wi-Fi)

Beginner20 min

The ESP32 joins your home Wi-Fi and serves a small web page; with the ON and OFF buttons on the page you open in your phone's browser, you switch the LED from afar. No app to install: any phone or computer on the same network can open the page. The first step of smart-home projects: a relay, a motor or any other device is controlled the same way.

Build it step by step in the app

What you need

Wiring steps

  1. 1

    Put the LED and the resistor on the breadboard

    Put the LED and the resistor on the breadboard

    The LED's long leg is plus (+), the short one minus (−). Put the short leg in column 13 and the long one in column 14, both in row E; the LED's head sits over the gap in the middle. Put one end of the 220 Ω resistor in column 10 and the other in column 14, the long leg's column (row C). The resistor works either way round. The five holes of a column are connected, which is how the resistor and the LED meet.

    • red LED long leg (+) → column 14, bottom half
    • red LED short leg (−) → column 13, bottom half
    • 220 Ω resistor → columns 10 and 14, bottom half
  2. 2

    Connect the ESP32 with two wires

    Connect the ESP32 with two wires

    The ESP32 does not go on the breadboard; it lies on the table. Push the female ends of two male-female jumper wires onto the ESP32's pins and the male ends into the breadboard: D2 to column 10 (the resistor's free end), and the GND on the board's right edge, just above 3V3, to column 13 (the LED's short leg). D2 also drives the board's own blue LED: it blinks even without the LED. Before you upload the code, write your home Wi-Fi network's name and password into WIFI_NAME and WIFI_PASSWORD; the ESP32 only joins 2.4 GHz networks.

    • ESP32 D2 → column 10, bottom half (green wire)
    • ESP32 GND (next to 3V3) → column 13, bottom half (black wire)

Arduino sketch

// Board: "ESP32 Dev Module"
#include <WiFi.h>
#include <WebServer.h>

// Your Wi-Fi network's name and password
const char* WIFI_NAME = "Network_Name";
const char* WIFI_PASSWORD = "Password";
// The LED's pin; the board's blue LED too
const int LED_PIN = 2;
// Ask about the password after this (ms)
const unsigned long WIFI_HINT_AFTER = 15000;

// The web server the phone opens, port 80
WebServer server(80);
bool ledOn = false;

// The page the phone shows: the state and
// two big buttons
String page() {
  String html =
      "<!DOCTYPE html><html><head><meta charset='utf-8'>"
      "<meta name='viewport' content='width=device-width'>"
      "<title>ESP32 LED</title><style>"
      "body{font-family:sans-serif;text-align:center;"
      "background:#111;color:#eee;padding-top:40px}"
      "a{display:block;margin:16px auto;width:220px;"
      "padding:18px;font-size:24px;color:#111;"
      "text-decoration:none;border-radius:8px}"
      ".on{background:#4aff8c}.off{background:#ff5c5c}"
      "</style></head><body><h1>LED: ";
  html += ledOn ? "ON" : "OFF";
  html += "</h1><a class='on' href='/on'>ON</a>";
  html += "<a class='off' href='/off'>OFF</a>";
  html += "</body></html>";
  return html;
}

void showPage() {
  server.send(200, "text/html", page());
}

void setLed(bool on) {
  ledOn = on;
  digitalWrite(LED_PIN, on ? HIGH : LOW);
  Serial.println(on ? "LED on" : "LED off");
  // Back to the page: reloading won't tap
  server.sendHeader("Location", "/");
  server.send(303);
}

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

  Serial.print("Connecting to ");
  Serial.println(WIFI_NAME);
  WiFi.begin(WIFI_NAME, WIFI_PASSWORD);
  unsigned long start = millis();
  bool hinted = false;
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (!hinted && millis() - start > WIFI_HINT_AFTER) {
      // No luck: check name, password
      Serial.println();
      Serial.println("Check the network's name and password.");
      hinted = true;
    }
  }
  Serial.println();
  Serial.print("Open on your phone: http://");
  Serial.println(WiFi.localIP());

  server.on("/", showPage);
  server.on("/on", [] { setLed(true); });
  server.on("/off", [] { setLed(false); });
  server.begin();
}

void loop() {
  // Answers every request that comes in
  server.handleClient();
}

What the Serial Monitor shows

SERIAL MONITOR · 115200 BAUD
Connecting to HomeNet
.....
Open on your phone: http://192.168.1.42
LED on
LED off

If a wire is loose

SERIAL MONITOR · 115200 BAUD
Connecting to HomeNet
..............................
Check the network's name and password.
..........

What you will see

If the ESP32 is not set up in the Arduino IDE yet, once: in File → Preferences write https://espressif.github.io/arduino-esp32/package_esp32_index.json into "Additional boards manager URLs", install "esp32 by Espressif Systems" from Tools → Board → Boards Manager and pick "ESP32 Dev Module" as the board. No library is needed for this project. Upload the code and open the Serial Monitor at 115200 baud. Within a few seconds it prints a line like "Open on your phone: http://192.168.1.42"; yours will be another address. Put your phone on the same Wi-Fi network (not mobile data) and type that address into its browser: a page saying "LED: OFF" opens, with ON and OFF buttons. Tapping ON lights the LED and the board's blue LED and the page says "LED: ON"; OFF switches them off. The Serial Monitor prints each tap. If the page does not open, make sure the phone is on the same network as the ESP32; guest networks and some routers' "client isolation" keep devices from seeing each other. The address may change when the ESP32 restarts; look in the Serial Monitor again. The page opens only from inside your home network, not from outside. If the dots never end and it says "Check the network's name and password", check the network's name, password and that it is 2.4 GHz. If uploading says "Connecting..." and fails, hold the ESP32's BOOT button down while it uploads.

In the app, tick off every wire, match the parts to your inventory and pick up where you left off.

Build it step by step in the app