Casi todos los proyectos de electronica 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 aca: un Arduino que actua como servidor web y entrega lecturas en vivo, primero en tu red local y despues desde Internet.

Este tutorial parte del clasico capitulo de Ethernet de John Boxall (tronixstuff.com) y lo reorganiza por bloques: primero entendemos el hardware, luego lo probamos con el ejemplo de fabrica, despues lo abrimos a Internet y por ultimo lo convertimos en una estacion de temperatura y humedad con un DHT22. Al terminar vas a saber asignar IP y MAC, servir una pagina HTML basica desde el Arduino, abrir el puerto en tu router y mostrar datos de un sensor real en esa pagina.

El hardware: que es un Ethernet shield W5100

El corazon 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 practicos que conviene tener claros antes de empezar, porque son los que mas dolores de cabeza evitan:

  • Alimentacion externa obligatoria. El W5100 consume mas corriente de la que entrega el puerto USB, asi 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 erraticos o que directamente no responde.
  • Se calienta. Tras un rato de uso el W5100 toma temperatura. No lo toques despues 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, asi que esos no los puedes ocupar para otra cosa. Algunos shields ademas traen ranura microSD, que se come otro pin digital extra (revisa la documentacion de tu modelo para saber cual).

Primera prueba: el ejemplo WebServer de fabrica

Antes de escribir codigo propio, lo mas 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 alimentacion de 9V. En el IDE abre File > Examples > Ethernet > Webserver. Ese sketch sirve una pagina con los valores de las entradas analogicas, pero no lo subas todavia: necesita un ajuste minimo.

Tienes que indicarle al shield una direccion IP que calce con tu red. En el sketch busca la linea:

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

Y cambiala 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);

Tambien puedes definir la direccion MAC a mano. Cada equipo de red tiene un numero de serie unico que lo identifica, normalmente grabado en su firmware, pero con Arduino lo decidimos nosotros en esta linea:

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

Si tienes un solo shield, dejala tal cual. Si vas a correr dos o mas shields en la misma red, asignales MAC distintas cambiando esos valores hexadecimales para que no choquen. Guarda, sube el sketch, abre un navegador y entra a la IP que configuraste. Deberias ver algo asi:

Navegador mostrando las lecturas de las entradas analogicas servidas por el Arduino en la red local

El Arduino esta entregando una pagina simple con los valores de los pines analogicos. Si refrescas el navegador, los numeros se actualizan. Funciona porque el sketch solo envia los datos cuando recibe una peticion del navegador, no los empuja por su cuenta.

Como el Arduino "escribe" la pagina web

Vale la pena entender el truco, porque despues lo vas a reutilizar. Toda la magia de red la maneja la libreria Ethernet de Arduino. La parte que nos interesa del ejemplo es este bucle que recorre los seis canales analogicos 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 practica estas construyendo una pagina web muy basica linea por linea.

La unica pieza nueva es el formato HTML. Con client.println("<br />") le mandas al navegador la etiqueta <br />, que en HTML significa salto de linea. Si quieres paginas mas 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 peticion. No esta gastando ciclos generando la pagina en vano. Por eso, aunque el loop() corre todo el tiempo, el costo real ocurre recien cuando alguien abre la URL.

Abrir el Arduino a Internet

Hasta aca el servidor solo vive dentro de tu red local. Para llegar a el desde afuera hay dos requisitos.

1. Una IP publica accesible. Lo ideal es una IP fija que tu proveedor te asigne y no cambie. Si no tienes IP fija, mientras dejes el modem siempre encendido la IP suele mantenerse, aunque no es lo optimo. Si tu proveedor no ofrece IP fija de ninguna forma, igual puedes avanzar usando un servicio de DNS dinamico (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 modem necesita soportar (tener cliente para) ese DDNS. Hay varios proveedores conocidos de este tipo de servicio.

Para encontrar tu IP publica entra a la pagina de administracion del router (suele ser 192.168.0.1 o 192.168.1.1) y busca el dato que dice WAN IP.

2. Redireccion de puertos (port forwarding). Esto le dice al router a donde mandar las peticiones que llegan desde afuera. En el sketch, la linea EthernetServer server(125); fijo 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 configuracion de port forwarding del router, redirigiendo el puerto 125 a la IP del shield

Con eso, la direccion externa de tu shield queda formada por tu IP publica mas el puerto, escrita como WAN:125. Es decir, desde cualquier dispositivo con Internet escribes tu IP publica seguida de :125 y llegas a tu Arduino. Es posible que ademas tengas que abrir el puerto 125 en el firewall del modem para permitir el trafico entrante; revisa la documentacion de tu equipo.

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

Las mismas lecturas analogicas del Arduino vistas desde un telefono conectado por datos moviles

Proyecto final: temperatura y humedad en una pagina web con DHT22

Ahora que sabemos servir una pagina y llegar a ella desde fuera, reemplacemos los valores analogicos genericos por datos utiles. Vamos a usar el DHT22, un sensor de temperatura y humedad barato y muy popular.

Primero instala la libreria del DHT22 (la encuentras desde el gestor de librerias del IDE). Si es tu primera vez con este sensor, prueba antes el sketch de ejemplo que trae la libreria para entender como 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 modificacion del ejemplo WebServer que ya usamos. La idea es la misma, con dos cambios clave: la pagina se refresca sola cada 30 segundos (con la linea client.println("Refresh: 30");) y el HTML personalizado de nuestra pagina empieza despues del comentario // from here we can enter our own HTML code to create the web page. Ahi armamos un titulo y dos parrafos con la temperatura y la humedad leidas 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 pagina con la temperatura y la humedad en vivo, que se actualiza sola cada medio minuto:

Pagina 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:

  • Mas sensores en la misma pagina. El DHT22 ya entrega temperatura y humedad, pero puedes sumar un sensor de luz (LDR) o un sensor de gas en las entradas analogicas libres y agregarlos como filas extra de HTML. Tu Arduino pasa a ser un pequeno panel ambiental.
  • Refresco mas inteligente. En vez de recargar la pagina completa cada 30 segundos con Refresh: 30, podrias servir los datos como JSON y pedirlos con JavaScript desde el navegador (fetch). Asi actualizas solo los numeros sin parpadeo. Es un paso mas avanzado, pero abre la puerta a graficos 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 codigo cambia de libreria, pero la logica de armar la pagina con client.print() es practicamente la misma.
  • Seguridad basica. Exponer un Arduino directo a Internet por port forwarding es comodo para aprender, pero deja el puerto abierto al mundo. Para algo permanente, considera ponerlo detras de un servicio intermedio o una VPN en lugar de abrir el puerto al exterior.

Personalizacion 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 alimentacion 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 unico componente que no esta en el catalogo es el Ethernet shield W5100 en si, asi que ese tendras 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.
  • Documentacion: libreria Ethernet oficial de Arduino (incluida en el IDE) y la libreria DHT para el sensor DHT22.

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