Montar un servidor web en el ESP32 con ESPAsyncWebServer y SPIFFS

Hola. Hoy vas a montar un servidor web en el ESP32 con ESPAsyncWebServer y SPIFFS para tener un código más ordenado.

Anteriormente aprendiste a montar un webserver en tu ESP32. Esto era útil para controlar un GPIO del ESP32 desde un equipo remoto, como un teléfono. Como recordarás para mostrar contenido en el navegador insertamos código HTML y CSS en el programa del ESP32.

Insertar ese código en el programa puede ser algo incómodo al inicio. Pero ¿sabías que hay otra alternativa? Podemos subir archivos individuales en formato HTML y CSS en la memoria del ESP32. Esto hará que nuestro código sea más limpio y comprensible.

Para subir los archivos HTML y CSS usaremos SPIFF. Si aún no lo utilizaste te invito a este tutorial en el que aprenderás a instalarlo y utilizarlo.

Programación

Librerías

Además de la librería de SPIFFS usaremos dos librerías más para el manejo del servidor web.

ESPAsyncWebServer

Usaremos esta librería para montar el servidor web en el ESP32 y que pueda ubicar los archivos.

Repositorio: ESPAsyncWebServer: Async Web Server for ESP8266 and ESP32

Descarga directa: Clic aquí.

Async TCP

Esta es una librería necesaria para usar ESPAsyncWebServer en el ESP32.

Repositorio: AsyncTCP: Async TCP Library for ESP32

Descarga directa: clic aquí.

Para instalar las librerías realiza los siguientes pasos:

  1. Ve al repositorio de cada librería y descarga el archivo zip. O usa la descarga directa.
  2. Abre Arduino IDE.
  3. Ve al menú Programa, Incluir Librería, y después Incluir Biblioteca .ZIP.
  4. Ubica el archivo de la librería a instalar en el explorador de archivos.

Verás un mensaje en la parte inferior avisando de que la librería se instaló correctamente.

Código HTML

El contenido del archivo HTML se enviará al cliente que se conecte a la IP del Web Server, en este caso alojado en el ESP32.

Aquí se encuentra el contenido del sitio web desde los textos hasta elementos como los botones.

<!DOCTYPE html>
<html>
<head>
  <title>ESP32 SPIFFS Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
  <h1>ESP32 SPIFFS Web Server</h1>
  <p>GPIO state: <strong> %STATE%</strong></p>
  <p><a href="/on"><button class="button">ENCENDER</button></a></p>
  <p><a href="/off"><button class="button button2">APAGAR</button></a></p>
</body>
</html>

Con esta etiqueta vinculamos el archivo style.css con el archivo index.html. Podríamos añadir los estilos css en el mismo archivo de html, pero tener los archivos separados es una buena práctica, sobre todo cuando tenemos más elementos y la complejidad aumenta.

<link rel="stylesheet" type="text/css" href="style.css">

También se añade el marcador de posición (placeholder) para el estado del led. Este está dentro de una etiqueta de párrafo <p>.

<p>GPIO state: <strong> %STATE%</strong></p>

Se añaden los botones con sus respectivo enlaces (on y off) a los que seremos redirigidos al presionarlos.

<p><a href="/on"><button class="button">ENCENDER</button></a></p>
<p><a href="/off"><button class="button button2">APAGAR</button></a></p>

Código CSS

El archivo css al estar vinculado al archivo html puede seleccionar los elementos del segundo y darles propiedades de estilo. En este caso lo usamos para usar una fuente, ajustar los márgenes y cambiar los colores.

html {
    font-family: Helvetica;
    display: inline-block;
    margin: 0px auto;
    text-align: center;
  }
  h1{
    color: #04009A;
    padding: 2vh;
  }
  p{
    font-size: 1.5rem;
  }
  .button {
    display: inline-block;
    background-color: #06FF00;
    border: none;
    border-radius: 4px;
    color: white;
    padding: 16px 40px;
    text-decoration: none;
    font-size: 30px;
    margin: 2px;
    cursor: pointer;
  }
  .button2 {
    background-color: #FF0000;
  }

Código Arduino

Este es el código habitual subimos al ESP32. Como puedes notar es un código más limpio a comparación de adjuntar el código HTML y CSS en el mismo archivo de Arduino.

// Agregar librerías
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"

//Credenciales WiFi
const char* ssid = "SSID";
const char* password = "Contraseña";

//GPIO del Led
const int ledPin = 2;
// Variable para guardar estado del led
String ledState;

//Crear un servidor AsyncWebServer en el puerto 80
AsyncWebServer server(80);

//Cambiar el valor del estado del led
String processor(const String& var) {
  Serial.println(var);
  if (var == "STATE") {
    if (digitalRead(ledPin)) {
      ledState = "ON";
    }
    else {
      ledState = "OFF";
    }
    Serial.print(ledState);
    return ledState;
  }
  return String();
}

void setup() {
  //Iniciar monitor serial
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);

  //Iniciar SPIFFS
  if (!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

  //Conectar a red WiFi
  Serial.println("Conectando a la red WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("Conectado");

  //Imprimir IP local en el Monitor Serie
  Serial.println(WiFi.localIP());

  //Seleccionando archivo index.html
  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

  //Seleccionando archivo style.css
  server.on("/style.css", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/style.css", "text/css");
  });

  //Dirección cuando se presiona el botón ENCENDER
  server.on("/on", HTTP_GET, [](AsyncWebServerRequest * request) {
    digitalWrite(ledPin, HIGH);
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

  //Dirección cuando se presiona el botón ENCENDER
  server.on("/off", HTTP_GET, [](AsyncWebServerRequest * request) {
    digitalWrite(ledPin, LOW);
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

  //Iniciar servidor
  server.begin();
}

void loop() {

}

Explicación del código

Configuraciones iniciales

Se incluyen las librerías para conectar el ESP32 a la red WiFi, manejar el servidor y usar el sistema de archivos SPIFFS.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"

Aquí reemplaza con los datos de tu red.

const char* ssid = "SSID";
const char* password = "Contraseña";

Declara el pin que se usará para controlar el LED y crea una variable para guardar su estado.

const int ledPin = 2;
String ledState;

Crea el servidor, el cual es un objeto llamado server, que será ejecutado en el puerto 80.

AsyncWebServer server(80);

Comunicación entre el ESP32 y los archivos

La función processor servirá para cambiar el estado del led que se mostrará en el archivo index.html.

Empieza verificando que se encuentre la variable STATE. Después lee el pin que usamos para el led y si está en un estado alto (HIGH), lo que para la condición sería como 1 o verdadero, la variable ledState tendrá el valor ON. Caso contrario se le atribuye el valor de OFF.

String processor(const String& var) {
  Serial.println(var);
  if (var == "STATE") {
    if (digitalRead(ledPin)) {
      ledState = "ON";
    }
    else {
      ledState = "OFF";
    }
    Serial.print(ledState);
    return ledState;
  }
  return String();
}

Dentro de setup se inicia el Monitor Serie a una velocidad de 115200 baudios y se establece el pin del led como salida.

  Serial.begin(115200);
  pinMode(ledPin, OUTPUT);

Inicia el sistema de archivos SPIFFS y en caso de no activarse imprime un mensaje de error en el Monitor Serie.

  if (!SPIFFS.begin(true)) {
    Serial.println("An Error has occurred while mounting SPIFFS");
    return;
  }

Conexión a la red

Conecta el ESP32 a la red WiFi cuyos datos se agregaron en las primeras líneas del programa. Imprime una línea de puntos como indicador visual mientras se conecta y al realizar la conexión imprime la IP local.

A esa IP es a la que se debe entrar desde otros dispositivos en la red.

  Serial.println("Conectando a la red WiFi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("Conectado");

  Serial.println(WiFi.localIP());

Montando servidor web con AsyncWebServerRequest

Cuando se detecte una petición de un cliente se le enviará el archivo html. Además se incluye la función processor para mostrar el estado actual del led.

Se hace lo mismo para enviar el archivo css pero sin añadir la función processor.

  server.on("/", HTTP_GET, [](AsyncWebServerRequest * request) {
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

En el código HTML se indica que al presiona run botón se irá a una dirección diferente. Cuando esto sea reconocido por el servidor se procederá a encenderá a encender o apagar el led según sea el caso.

Posteriormente se vuelve a enviar el archivo html pero con el placeholder actualizado a el nuevo estado correspondiente.

  server.on("/on", HTTP_GET, [](AsyncWebServerRequest * request) {
    digitalWrite(ledPin, HIGH);
    request->send(SPIFFS, "/index.html", String(), false, processor);
  });

Se da inicio al servidor desde el que se ejecutarán las operaciones mencionadas anteriormente.

server.begin();

Demostración

Empieza subiendo los archivos index.html y style.css mediante SPIFFS. Si aún no lo instalas mira este tutorial que hicimos referente a esta herramienta.

Ahora sube el programa del ESP32 y abre el Monitor Serie. Después de que te haya mostrado la IP escríbela en la barra de direcciones del navegador en tu teléfono u otra computadora que estén en la misma red.

También te puedes guiar de nuestro video:

Gracias por leernos. Comparte esta publicación a tus contactos.

Te invitamos a tomar el curso de Introducción al ESP32: Introducción al ESP32 | TodoMaker’s School

Previous Post
Next Post