¿Te imaginas prender la luz del living, mover un servo o ver la temperatura de tu pieza escribiendo una dirección IP en el navegador del celular, sin instalar ninguna app? Eso es exactamente lo que hace un ESP32 cuando lo configuras como servidor web: el propio microcontrolador aloja una página, escucha las peticiones que le llegan por WiFi y responde con HTML o datos en tiempo real.

En esta guía vas a entender qué significa que el ESP32 actúe como servidor web, cómo viaja una petición desde tu navegador hasta el pin físico de la placa, y vas a ver dos proyectos concretos: encender un LED y mover un micro servo, los dos controlados desde una página alojada en la misma placa. Al final encontrarás ideas para extenderlo y la lista de componentes con stock en Chile.

Infografía del ESP32 funcionando como servidor web con panel de control en el navegador

Qué significa que el ESP32 sea un servidor web

La idea es más simple de lo que suena. Cuando conectas el ESP32 a tu red WiFi, el router le asigna una dirección IP local (algo como 192.168.1.6). A partir de ahí, la placa puede hacer dos cosas: pedir información a internet (modo cliente) o quedarse esperando que otros dispositivos le pidan cosas a ella (modo servidor). El modo servidor web es el segundo caso.

Tu celular, tu notebook o tu tablet abren esa IP en el navegador, normalmente por el puerto 80, y el ESP32 responde con una página. Esa página puede ser un tablero con botones para encender dispositivos, un visor de sensores que se actualiza solo, o un formulario para ajustar parámetros. En la práctica, transformas un chip de pocos dólares en el cerebro de un sistema domótico casero, todo dentro de tu red, sin depender de servicios externos.

Las ventajas de hacerlo así son claras:

  • Acceso multiplataforma: cualquier dispositivo con navegador y WiFi sirve. No necesitas desarrollar una app aparte.
  • Personalización total: el HTML, los estilos y la lógica los escribes tú. Desde un botón pelado hasta un dashboard con gráficos.
  • Privacidad: todo corre en tu red local. Los datos de tus sensores no salen a ningún servidor de terceros.
  • Escalabilidad: agregar un sensor o un actuador nuevo es sumar una ruta más en el código.

Cómo viaja una petición: del navegador al pin

Antes de tocar código conviene tener el modelo mental claro, porque casi todos los errores de principiante vienen de no entender este flujo. Un servidor web en el ESP32 funciona asociando rutas (las URLs como /, /on, /off) a funciones que se ejecutan cuando llega una petición a esa ruta.

El ciclo completo es así:

  1. Conexión a la red: en el arranque, el ESP32 se une al WiFi con tu SSID y contraseña, y muestra por el monitor serie la IP que recibió.
  2. Definición de rutas: declaras qué función responde a cada URL. Por ejemplo, / devuelve la página principal y /on enciende el LED.
  3. Recepción: cuando entras a la página o aprietas un botón, el navegador manda una petición HTTP (un GET o un POST) que el ESP32 recibe.
  4. Respuesta: la placa ejecuta la función asociada y devuelve la página HTML actualizada, o datos en JSON si estás armando una API.
  5. Cierre: termina la comunicación y la placa queda lista para la siguiente petición.

Los tres métodos que vas a usar todo el tiempo con la librería estándar de Arduino son server.on() para definir rutas, server.send() para responder, y server.handleClient(), que va dentro del loop() y es el que realmente atiende a los clientes en cada vuelta. Si te olvidas de este último, el servidor "existe" pero nunca contesta: es el error número uno.

Apenas cargues el sketch y abras el monitor serie a 115200 baudios, deberías ver la IP asignada. Esa es tu puerta de entrada.

Monitor serie de Arduino mostrando la dirección IP asignada al ESP32 y el servidor iniciado

Proyecto 1: encender un LED desde la web

Este es el "hola mundo" de los servidores web embebidos, el mismo ejemplo que popularizaron tutoriales como el de TodoMaker. La meta es alojar una página con un botón que prenda y apague un LED, y que el estado se refleje en tiempo real.

El código se apoya en la librería WebServer.h, que ya viene incluida cuando instalas el soporte de placas ESP32 en el IDE de Arduino. Esta es una versión de referencia, mínima y funcional, lista para que cambies el SSID y la clave por los de tu red. Usa el LED integrado de la placa, así que ni siquiera necesitas cablear nada para la primera prueba:

C++
#include <WiFi.h>
#include <WebServer.h>

const char* ssid     = "TU_WIFI";
const char* password = "TU_CLAVE";

WebServer server(80);
const int ledPin = 2;   // LED integrado en la mayoria de las placas ESP32
bool ledEstado = false;

String paginaHTML() {
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
  html += "<meta name='viewport' content='width=device-width, initial-scale=1'>";
  html += "<title>ESP32 Web Server</title></head><body>";
  html += "<h1>WebServer con ESP32</h1>";
  html += "<p>LED: " + String(ledEstado ? "ENCENDIDO" : "APAGADO") + "</p>";
  if (ledEstado) {
    html += "<a href='/off'><button>APAGAR</button></a>";
  } else {
    html += "<a href='/on'><button>ENCENDER</button></a>";
  }
  html += "</body></html>";
  return html;
}

void manejarRaiz()  { server.send(200, "text/html", paginaHTML()); }
void encenderLED()  { ledEstado = true;  digitalWrite(ledPin, HIGH); server.send(200, "text/html", paginaHTML()); }
void apagarLED()    { ledEstado = false; digitalWrite(ledPin, LOW);  server.send(200, "text/html", paginaHTML()); }

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

  WiFi.begin(ssid, password);
  Serial.print("Conectandome");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();
  Serial.print("Conectado, la direccion IP es: ");
  Serial.println(WiFi.localIP());

  server.on("/",    manejarRaiz);
  server.on("/on",  encenderLED);
  server.on("/off", apagarLED);
  server.begin();
  Serial.println("Servidor iniciado");
}

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

Cuando entras a la IP, el navegador te muestra la página con un botón. Al apretarlo, se dispara una petición a /on o /off, el ESP32 cambia el estado del pin físico y te devuelve la página actualizada. Fíjate que la URL en la barra refleja exactamente la acción: ese detalle es clave para depurar.

Interfaz web del servidor ESP32 con el botón para apagar el LED, vista desde el celular

A partir de este esqueleto puedes crecer todo lo que quieras: en vez de un solo botón, arma una grilla de controles, agrega sliders, tablas o gráficos. El frontend y el backend viven en el mismo dispositivo, así que tienes libertad creativa total sobre el HTML y el CSS.

Por qué cuidar la memoria

Acá conviene una explicación que el ejemplo básico no suele dar. El ESP32 es potente, pero cuando construyes el HTML concatenando texto en variables String como en el código de arriba, cada concatenación reserva memoria nueva en el heap. Si tu página crece a cientos de líneas o incrustas imágenes pesadas en base64, te puedes quedar sin RAM y la placa se reinicia sola en mitad de una petición. Para páginas grandes, la práctica recomendada es guardar el HTML en memoria de programa con PROGMEM o servir los archivos desde el sistema de archivos LittleFS, en lugar de armarlos a mano en cada llamada.

Proyecto 2: controlar un servomotor por WiFi

El salto interesante viene cuando en vez de un LED controlas un actuador con movimiento, como un micro servo SG90. El concepto es el mismo, pero ahora la página manda un ángulo y el ESP32 traduce ese número en una señal PWM. Roboticoss tiene un ejemplo muy claro de esto, con un slider en el celular que mueve el servo en vivo.

ESP32 en protoboard controlando un servomotor SG90 desde una página web con slider de ángulo en el celular

El montaje del servo usa tres cables:

  • Alimentación (rojo): al pin 5V del ESP32 si el servo es pequeño como el SG90. Para servos más grandes conviene una fuente externa de 5V, porque el regulador de la placa no da abasto.
  • Tierra (café o negro): a GND.
  • Señal (naranjo o amarillo): a un GPIO digital, por ejemplo GPIO4.

Una protoboard ayuda mucho a ordenar estas conexiones mientras pruebas. Del lado del código, la idea es leer el ángulo que viene en la petición y aplicarlo con la librería de servo:

C++
#include <WiFi.h>
#include <WebServer.h>
#include <ESP32Servo.h>

const char* ssid     = "TU_WIFI";
const char* password = "TU_CLAVE";

WebServer server(80);
Servo miServo;
const int servoPin = 4;   // señal del servo en GPIO4

void moverServo() {
  if (server.hasArg("angulo")) {
    int angulo = server.arg("angulo").toInt();
    angulo = constrain(angulo, 0, 180);
    miServo.write(angulo);
  }
  server.send(200, "text/plain", "OK");
}

void setup() {
  Serial.begin(115200);
  miServo.attach(servoPin);

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) { delay(500); }
  Serial.println(WiFi.localIP());

  server.on("/servo", moverServo);   // ejemplo: /servo?angulo=90
  server.begin();
}

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

Con esta base ya puedes pensar en cosas mucho más grandes: brazos robóticos, automatismos para abrir una ventana, o domótica más seria. La librería ESP32Servo es la versión para ESP32 de la clásica Servo de Arduino, porque el ESP32 maneja el PWM de forma distinta.

El reto de salir de tu red local

Hay un punto que frustra a mucha gente la primera vez: el servidor web del ESP32 solo es accesible mientras estás conectado a la misma red WiFi. Si te vas de la casa, esa IP 192.168.x.x deja de servir, porque es una dirección privada. Para controlar tus dispositivos desde la calle tienes tres caminos, cada uno con su costo:

  • Reenvío de puertos (port forwarding): abres un puerto en el router y rediriges el tráfico al ESP32. Funciona, pero expone tu placa a internet y suele necesitar IP pública fija o DNS dinámico. Solo para pruebas y con autenticación, nunca para algo crítico.
  • Plataformas IoT en la nube: Blynk, Arduino Cloud o Firebase te dan acceso remoto cómodo, a cambio de ceder parte de la personalización de tu HTML.
  • VPN y túneles: WireGuard, OpenVPN o servicios tipo Ngrok son la opción más profesional y segura, pero piden conocimientos extra.

La decisión es un intercambio: control total y libertad creativa con el servidor embebido, o accesibilidad desde cualquier parte sacrificando un poco de personalización.

Variantes y mejoras

Una vez que tengas el servidor básico andando, estas son tres extensiones concretas para subir el nivel del proyecto:

  • Actualización en tiempo real sin recargar: en lugar de recargar toda la página en cada clic, usa AJAX (o mejor, WebSockets con la librería ESPAsyncWebServer). El navegador pide solo el dato nuevo cada cierto tiempo y refresca el valor del sensor en pantalla. Es lo que hace que un dashboard se vea fluido.
  • Lectura de un sensor real: combina este servidor con un sensor DHT22 o un DS18B20 y muestra temperatura y humedad en la misma página. Con eso pasas de un simple interruptor a una mini estación de monitoreo.
  • Autenticación simple: aunque estés en tu red local, cualquiera con tu WiFi puede mover tus dispositivos. Agrega una autenticación básica con server.authenticate() para que el panel pida usuario y contraseña antes de dejar pasar.

Personalización para Chile

En Chile puedes conseguir todo lo necesario para estos dos proyectos en MechatronicStore, con stock local:

  • ESP32 ESP WROOM-32 con WiFi y Bluetooth (SKU 3688) por $7.990: la placa que aloja el servidor. Trae el LED integrado para la primera prueba.
  • Micro Servo SG90 180° (SKU X7-2) por $2.490: el actuador del segundo proyecto, ideal por su consumo bajo.
  • Protoboard 830 puntos GL-12 (SKU C-320) por $3.790: para ordenar las conexiones del servo sin soldar nada.
  • Cables macho hembra 30cm (SKU C-418) por $1.990: los tres cables que van del ESP32 al servo.

Si en algún tutorial en inglés ves un "Adafruit Feather" o un "Sparkfun ESP32 Thing", el ESP32 DevKit del catálogo cumple exactamente la misma función a una fracción del precio: el código es idéntico, porque todas usan el mismo chip de Espressif.

Recursos

Versión chilena inspirada en el artículo de Ardumania, con componentes en stock local en MechatronicStore.