Casi todos los proyectos de electrónica empiezan offline: enciendes un LED, lees un sensor, muestras un dato en el monitor serial. El salto interesante viene cuando ese dato sale de tu escritorio y queda disponible en la red, para que cualquier dispositivo del hogar (o del mundo) lo consulte desde un navegador. Eso es exactamente lo que vas a montar acá: un Arduino que actúa como servidor web y entrega lecturas en vivo, primero en tu red local y después desde Internet.

Este tutorial parte del clásico capítulo de Ethernet de John Boxall (tronixstuff.com) y lo reorganiza por bloques: primero entendemos el hardware, luego lo probamos con el ejemplo de fábrica, después lo abrimos a Internet y por último lo convertimos en una estación de temperatura y humedad con un DHT22. Al terminar vas a saber asignar IP y MAC, servir una página HTML básica desde el Arduino, abrir el puerto en tu router y mostrar datos de un sensor real en esa página.

El hardware: qué es un Ethernet shield W5100

El corazón de este proyecto es un Ethernet shield que se monta sobre el Arduino Uno y le agrega un conector RJ45. Casi todos estos shields usan el mismo integrado controlador: el WIZnet W5100, que se encarga de toda la pila TCP/IP por hardware (maneja las conexiones, el armado de paquetes y el handshake), de modo que el Arduino solo le pide datos a alto nivel.

Integrado controlador Ethernet WIZnet W5100, el chip que maneja la pila TCP/IP del shield

Hay tres detalles prácticos que conviene tener claros antes de empezar, porque son los que más dolores de cabeza evitan:

  • Alimentación externa obligatoria. El W5100 consume más corriente de la que entrega el puerto USB, así que tienes que alimentar la placa por el conector DC. Un transformador de 9V con al menos 1A es suficiente. Si dejas el shield solo con USB, vas a ver comportamientos erráticos o que directamente no responde.
  • Se calienta. Tras un rato de uso el W5100 toma temperatura. No lo toques después de tenerlo largo tiempo encendido, es normal pero quema.
  • Pines reservados. El shield usa los pines digitales 10 a 13 para hablar con el Arduino, así que esos no los puedes ocupar para otra cosa. Algunos shields además traen ranura microSD, que se come otro pin digital extra (revisa la documentación de tu modelo para saber cuál).

Primera prueba: el ejemplo WebServer de fábrica

Antes de escribir código propio, lo más inteligente es confirmar que el shield funciona con el ejemplo que ya viene en el IDE de Arduino. Monta el shield sobre el Uno, conecta el cable de red al router y enchufa la alimentación de 9V. En el IDE abre File > Examples > Ethernet > Webserver. Ese sketch sirve una página con los valores de las entradas analógicas, pero no lo subas todavía: necesita un ajuste mínimo.

Tienes que indicarle al shield una dirección IP que calce con tu red. En el sketch busca la línea:

C++
IPAddress ip(192,168,1, 177);

Y cámbiala por una IP libre de tu propia red. Por ejemplo, si en tu casa el router es 10.1.1.1, la impresora 10.1.1.50 y los PC quedan bajo el .50, puedes dejar el shield en 10.1.1.77:

C++
IPAddress ip(10,1,1,77);

También puedes definir la dirección MAC a mano. Cada equipo de red tiene un número de serie único que lo identifica, normalmente grabado en su firmware, pero con Arduino lo decidimos nosotros en esta línea:

C++
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

Si tienes un solo shield, déjala tal cual. Si vas a correr dos o más shields en la misma red, asígnales MAC distintas cambiando esos valores hexadecimales para que no choquen. Guarda, sube el sketch, abre un navegador y entra a la IP que configuraste. Deberías ver algo así:

Navegador mostrando las lecturas de las entradas analógicas servidas por el Arduino en la red local

El Arduino está entregando una página simple con los valores de los pines analógicos. Si refrescas el navegador, los números se actualizan. Funciona porque el sketch solo envía los datos cuando recibe una petición del navegador, no los empuja por su cuenta.

Cómo el Arduino "escribe" la página web

Vale la pena entender el truco, porque después lo vas a reutilizar. Toda la magia de red la maneja la librería Ethernet de Arduino. La parte que nos interesa del ejemplo es este bucle que recorre los seis canales analógicos y arma la respuesta:

C++
for (int analogChannel = 0; analogChannel < 6; analogChannel++)
          {
            int sensorReading = analogRead(analogChannel);
            client.print("analog input ");
            client.print(analogChannel);
            client.print(" is ");
            client.print(sensorReading);
            client.println("<br />");
          }
          client.println("</html>");

Si ya usaste Serial.print() para mandar datos al monitor serial, esto te va a sonar familiar: client.print() funciona igual, pero en vez de ir al monitor serial, el texto viaja de vuelta al navegador. En la práctica estás construyendo una página web muy básica línea por línea.

La única pieza nueva es el formato HTML. Con client.println("<br />") le mandas al navegador la etiqueta <br />, que en HTML significa salto de línea. Si quieres páginas más elaboradas, basta con intercalar otras etiquetas HTML dentro de los client.print(). No necesitas ser desarrollador web: con un par de etiquetas ya tienes una salida legible.

Un detalle importante de eficiencia, que el tutorial original no profundiza: el Arduino solo responde cuando llega una petición. No está gastando ciclos generando la página en vano. Por eso, aunque el loop() corre todo el tiempo, el costo real ocurre recién cuando alguien abre la URL.

Abrir el Arduino a Internet

Hasta acá el servidor solo vive dentro de tu red local. Para llegar a él desde afuera hay dos requisitos.

1. Una IP pública accesible. Lo ideal es una IP fija que tu proveedor te asigne y no cambie. Si no tienes IP fija, mientras dejes el módem siempre encendido la IP suele mantenerse, aunque no es lo óptimo. Si tu proveedor no ofrece IP fija de ninguna forma, igual puedes avanzar usando un servicio de DNS dinámico (DDNS): te dan un nombre de host estable (por ejemplo, miarduino.ejemplo.com) y el servicio se encarga de seguir tu IP cambiante y mantener el nombre apuntando a ella. Tu módem necesita soportar (tener cliente para) ese DDNS. Hay varios proveedores conocidos de este tipo de servicio.

Para encontrar tu IP pública entra a la página de administración del router (suele ser 192.168.0.1 o 192.168.1.1) y busca el dato que dice WAN IP.

2. Redirección de puertos (port forwarding). Esto le dice al router a dónde mandar las peticiones que llegan desde afuera. En el sketch, la línea EthernetServer server(125); fijó el puerto del shield en el 125. Entonces en el router configuras una regla que redirija el puerto entrante 125 hacia la IP local del shield (10.1.1.77 en nuestro caso):

Pantalla de configuración de port forwarding del router, redirigiendo el puerto 125 a la IP del shield

Con eso, la dirección externa de tu shield queda formada por tu IP pública más el puerto, escrita como WAN:125. Es decir, desde cualquier dispositivo con Internet escribes tu IP pública seguida de :125 y llegas a tu Arduino. Es posible que además tengas que abrir el puerto 125 en el firewall del módem para permitir el tráfico entrante; revisa la documentación de tu equipo.

Una vez listo, lo puedes probar desde el celular usando datos móviles (sin WiFi de la casa) para confirmar que el acceso viene de verdad desde Internet y no de tu red local:

Las mismas lecturas analógicas del Arduino vistas desde un teléfono conectado por datos móviles

Proyecto final: temperatura y humedad en una página web con DHT22

Ahora que sabemos servir una página y llegar a ella desde fuera, reemplacemos los valores analógicos genéricos por datos útiles. Vamos a usar el DHT22, un sensor de temperatura y humedad barato y muy popular.

Primero instala la librería del DHT22 (la encuentras desde el gestor de librerías del IDE). Si es tu primera vez con este sensor, prueba antes el sketch de ejemplo que trae la librería para entender cómo entrega los datos. El conexionado es directo: el pin de datos del DHT22 va a D2 del Arduino, Vin al pin 5V y GND a GND.

El sketch de abajo es una modificación del ejemplo WebServer que ya usamos. La idea es la misma, con dos cambios clave: la página se refresca sola cada 30 segundos (con la línea client.println("Refresh: 30");) y el HTML personalizado de nuestra página empieza después del comentario // from here we can enter our own HTML code to create the web page. Ahí armamos un título y dos párrafos con la temperatura y la humedad leídas del sensor:

C++
#include <SPI.h>
#include <Ethernet.h>

// for DHT22 sensor
#include "DHT.h"
#define DHTPIN 2
#define DHTTYPE DHT22

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {   0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(10,1,1,77);

// Initialize the Ethernet server library
// with the IP address and port you want to use 
// (port 80 is default for HTTP):
EthernetServer server(125);
DHT dht(DHTPIN, DHTTYPE);

void setup() 
{
  dht.begin();
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

void loop() 
{
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) 
        {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
	  client.println("Refresh: 30");  // refresh the page automatically every 30 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");

          // get data from DHT22 sensor
          float h = dht.readHumidity();
          float t = dht.readTemperature();
          Serial.println(t);
          Serial.println(h);

          // from here we can enter our own HTML code to create the web page
          client.print("<head><title>Office Weather</title></head><body><h1>Office Temperature</h1><p>Temperature - ");
          client.print(t);
          client.print(" degrees Celsius</p>");
          client.print("<p>Humidity - ");
          client.print(h);
          client.print(" percent</p>");
          client.print("<p><em>Page refreshes every 30 seconds.</em></p></body></html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } 
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

Sube el sketch y entra a la IP del shield (o a tu WAN:125 desde afuera). Vas a ver tu propia página con la temperatura y la humedad en vivo, que se actualiza sola cada medio minuto:

Página Office Temperature servida por el Arduino mostrando temperatura y humedad del DHT22 en un celular

Con esto ya tienes el esqueleto para publicar cualquier dato que procese tu Arduino: cambia el bloque HTML por los client.print() que necesites e inserta las variables de tus propios sensores.

Variantes y mejoras

Una vez que el servidor base funciona, hay varias formas de subirle el nivel que el tutorial original no cubre:

  • Más sensores en la misma página. El DHT22 ya entrega temperatura y humedad, pero puedes sumar un sensor de luz (LDR) o un sensor de gas en las entradas analógicas libres y agregarlos como filas extra de HTML. Tu Arduino pasa a ser un pequeño panel ambiental.
  • Refresco más inteligente. En vez de recargar la página completa cada 30 segundos con Refresh: 30, podrías servir los datos como JSON y pedirlos con JavaScript desde el navegador (fetch). Así actualizas solo los números sin parpadeo. Es un paso más avanzado, pero abre la puerta a gráficos en tiempo real.
  • Salto a WiFi. Si el cable de red te limita, el mismo concepto de "Arduino como servidor web" se puede portar a un ESP32, que trae WiFi integrado y no necesita shield ni router cableado. El código cambia de librería, pero la lógica de armar la página con client.print() es prácticamente la misma.
  • Seguridad básica. Exponer un Arduino directo a Internet por port forwarding es cómodo para aprender, pero deja el puerto abierto al mundo. Para algo permanente, considera ponerlo detrás de un servicio intermedio o una VPN en lugar de abrir el puerto al exterior.

Personalización para Chile

En Chile puedes conseguir el grueso de los componentes en MechatronicStore:

  • Arduino Uno R3 (SKU X4-8): $9.990. La placa base del proyecto.
  • Sensor DHT22 (SKU GP1-7): $4.100. El sensor de temperatura y humedad del proyecto final.
  • Transformador 9V 1A para Arduino (SKU X1-2): $3.490. Imprescindible: el W5100 necesita esta alimentación externa porque el USB no le basta.
  • Cables DuPont hembra a hembra (SKU 712212): desde $690. Para conectar el DHT22 a los pines del Arduino.

El único componente que no está en el catálogo es el Ethernet shield W5100 en sí, así que ese tendrás que conseguirlo aparte. Como referencia: en la tienda hay placas ESP32 (por ejemplo el ESP32 DOIT 38 pines) que permiten armar el mismo proyecto de servidor web pero por WiFi y sin shield, si prefieres ir por esa ruta en lugar del Ethernet cableado.

Recursos

  • Tutorial original: Tutorial Ethernet Shields and Arduino por John Boxall, en tronixstuff.com.
  • Documentación: librería Ethernet oficial de Arduino (incluida en el IDE) y la librería DHT para el sensor DHT22.

Versión chilena con componentes en stock local en MechatronicStore. Tutorial basado en el trabajo de John Boxall (tronixstuff.com), reescrito y ampliado con contexto local.