Built-in project · ESP32-C3-DevKitM-1

WiFi: a lamp on a web page, on an ESP32-C3

A WebServer with two buttons and a form. Press one in the Web panel and the LED on the breadboard follows; the network under it is simulated. The whole build, an ESP32-C3 and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Intermediate About 20 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $13.15. On Mokxi they're free.

The circuit runs here once the page has loaded.

What you'll learn

  • How a web server on a microcontroller answers requests
  • Mapping URL paths to handler functions
  • Link requests versus form posts
  • Keeping state in a variable and showing it on a page
  • Difficulty: Intermediate
  • Time: About 20 minutes
  • Board: ESP32-C3-DevKitM-1
  • Parts: 4

How it works

The board joins a simulated Wi-Fi network called Mokxi-Lab and starts a web server on port 80. Only the Web tab in the simulator can reach it. Nothing outside the browser can.

The page says whether the lamp is on or off, with On and Off links and a Toggle button. Each one changes a lampOn flag, writes it to the LED pin, and sends the page back.

The yellow LED is on GPIO 8 through a 220 ohm resistor. Press Run, open the Web tab and press On. The LED follows the page, and each change prints a line to the serial monitor.

Parts list

4 parts, plus the jumper wires. They retail for about $13.15; on Mokxi they're free.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
LED, yellow pin CESP32-C3-DevKitM-1 pin GND
Resistor, 220 Ω pin 1ESP32-C3-DevKitM-1 pin 8
LED, yellow pin AResistor, 220 Ω pin 2

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · ESP32-C3-DevKitM-1
/*
 * WiFi: a lamp on a web page.
 *
 * The server is your code, running on the board's core. The NETWORK under it is
 * SIMULATED: there is no 802.11, no TCP and no listening socket, and the only
 * thing in the world that can reach http://192.168.4.2/ is the Web tab in this
 * page. Nothing outside the browser can, ever.
 *
 * Press Run, open the Web tab, and press On. The LED on GPIO 8 (and any LED
 * you have wired to it) follows the page.
 */
#include <WebServer.h>
#include <WiFi.h>

const char *SSID = "Mokxi-Lab";
const char *PASSWORD = "breadboard";

WebServer server(80);
bool lampOn = false;

void sendPage() {
  String page("<!doctype html><html><head><meta charset=\"utf-8\">");
  page += "<title>Mokxi lamp</title></head><body>";
  page += "<h1>The lamp is ";
  page += lampOn ? "ON" : "OFF";
  page += "</h1><p><a href=\"/on\">On</a> &middot; <a href=\"/off\">Off</a></p>";
  page += "<p><form method=\"post\" action=\"/set\">";
  page += "<button name=\"lamp\" value=\"toggle\">Toggle</button></form></p>";
  page += "<p>Served by the sketch on a simulated network.</p>";
  page += "</body></html>";
  server.send(200, "text/html", page);
}

void applyLamp() {
  digitalWrite(LED_BUILTIN, lampOn ? HIGH : LOW);
  Serial.print("lamp ");
  Serial.println(lampOn ? "on" : "off");
}

void handleRoot() { sendPage(); }

void handleOn() {
  lampOn = true;
  applyLamp();
  sendPage();
}

void handleOff() {
  lampOn = false;
  applyLamp();
  sendPage();
}

void handleSet() {
  if (server.arg("lamp") == "toggle") {
    lampOn = !lampOn;
    applyLamp();
  }
  sendPage();
}

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

  Serial.println("Simulated WiFi: only the Web panel can reach this server.");
  WiFi.begin(SSID, PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(250);
  }
  Serial.println();
  Serial.print("open http://");
  Serial.print(WiFi.localIP());
  Serial.println("/ in the Web tab");

  server.on("/", handleRoot);
  server.on("/on", handleOn);
  server.on("/off", handleOff);
  server.on("/set", handleSet);
  server.begin();
}

void loop() {
  server.handleClient();
  delay(2);
}

Code walkthrough

The key functions of the sketch, and what each one does.

sendPage sketch.ino

Builds the HTML as a String: a heading showing ON or OFF, links to /on and /off, and a form with a Toggle button. Then server.send replies with status 200. Every handler ends by calling this.

void sendPage() {
  String page("<!doctype html><html><head><meta charset=\"utf-8\">");
  page += "<title>Mokxi lamp</title></head><body>";
  page += "<h1>The lamp is ";
  page += lampOn ? "ON" : "OFF";
  page += "</h1><p><a href=\"/on\">On</a> &middot; <a href=\"/off\">Off</a></p>";
  page += "<p><form method=\"post\" action=\"/set\">";
  page += "<button name=\"lamp\" value=\"toggle\">Toggle</button></form></p>";
  page += "<p>Served by the sketch on a simulated network.</p>";
  page += "</body></html>";
  server.send(200, "text/html", page);
}

applyLamp sketch.ino

Writes lampOn to the LED with digitalWrite and prints lamp on or lamp off to the serial monitor. Keeping it in one place means every handler changes the lamp the same way.

void applyLamp() {
  digitalWrite(LED_BUILTIN, lampOn ? HIGH : LOW);
  Serial.print("lamp ");
  Serial.println(lampOn ? "on" : "off");
}

handleSet sketch.ino

Handles the form post at /set. It reads the form field with server.arg, and if it says toggle, it flips lampOn and calls applyLamp. Then it sends the page back.

void handleSet() {
  if (server.arg("lamp") == "toggle") {
    lampOn = !lampOn;
    applyLamp();
  }
  sendPage();
}

setup sketch.ino

Sets the LED pin as an output, joins Wi-Fi with WiFi.begin and waits, printing dots. Then it prints the address and registers each path with server.on: /, /on, /off and /set. server.begin starts listening.

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

  Serial.println("Simulated WiFi: only the Web panel can reach this server.");
  WiFi.begin(SSID, PASSWORD);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(250);
  }
  Serial.println();
  Serial.print("open http://");
  Serial.print(WiFi.localIP());
  Serial.println("/ in the Web tab");

  server.on("/", handleRoot);
  server.on("/on", handleOn);
  server.on("/off", handleOff);
  server.on("/set", handleSet);
  server.begin();
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • The page does not load. This project
    Use the Web tab in the simulator, and wait for the serial monitor to print the address first.
  • The page changes but the LED stays dark. This project
    The code writes to LED_BUILTIN. Check the LED goes through the resistor to GPIO 8, with its cathode on GND.
  • Stuck on dots in the monitor. This project
    SSID and PASSWORD must match the simulated network: Mokxi-Lab and breadboard.
  • The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
    Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure.
  • A pull-up or pull-down resistor is missing, so the input floats and reads random values. Resistor
    Tie the input to 5 V or ground through about 10k. Or use INPUT_PULLUP and wire the switch to ground.
  • The LED does not light, or it lights once and then dies. LED
    LEDs have polarity. The longer leg (anode) goes toward the positive side. Always add a series resistor, about 220 ohms to 1 k ohm on a 5 V pin.
  • A blue or white LED stays dark on 3.3 V. LED
    Blue and white LEDs drop about 3 V, so 3.3 V leaves almost nothing for the resistor. Use a 5 V supply, or a smaller resistor and a red or green LED.
  • Upload fails or the board is not found by the computer. ESP32-C3-DevKitM-1
    Pick the ESP32-C3 board in your tools and the right port. If it still fails, hold BOOT, tap RESET, then release BOOT to enter download mode and try again.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.