como-servir-una-pagina-web-con-el-esp8266-desde-spiffs

Cómo servir una página web con ESP32 desde SPIFFS

  • 4 min

SPIFFS permite guardar ficheros en Flash y servirlos desde una placa ESP como si fueran archivos normales.

El ejemplo está orientado a ESP32. En muchos casos también puede adaptarse a ESP8266 cambiando librerías y algunos detalles de pines.

Esto es muy útil para servir contenido estático como index.html, hojas CSS, JavaScript, imágenes pequeñas o cualquier recurso que no queremos meter directamente como cadenas dentro del código.

Por fin podemos empezar a servir ficheros como haríamos en un servidor “convencional”, pero desde nuestro pequeño SoC. No está mal para un chip tan pequeño.

Desde el SPIFFS podemos servir únicamente contenido estático. Es decir, contenido que no varía entre peticiones. Pero eso no significa, ni mucho menos, que sea un simple fichero de texto. De hecho, muchas web modernas son así.

Lo que vamos a hacer va a ser servir ficheros (html, css, js) de forma similar a como hacemos en un servidor “convencional”. Normalmente, el cliente carga este contenido y el funcionamiento dinámico se consigue mediante el código JavaScript servido, y llamadas al Backend.

De momento, vamos a empezar por lo básico.

Nuestro programa principal es similar al de un servidor HTTP sencillo, con la salvedad de que hemos añadido una referencia a FS.h.

#include <WiFi.h>
#include <WebServer.h>
#include <FS.h>   // Include the SPIFFS library

#include "config.h"  // Sustituir con datos de vuestra red
#include "Server.hpp"
#include "ESP32_Utils.hpp"

void setup(void)
{
  Serial.begin(115200);
  SPIFFS.begin();

  ConnectWiFi_STA();

  InitServer();
}

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

Por otro lado, hemos modificado el fichero ‘Server.hpp’ para definir un ruteo cuando la dirección no se encuentra. Como no tenemos ningún otro ruteo a un Endpoint, se dará en todos los casos.

En la función de Callback, en primer lugar, comprobamos si existe un fichero en el SPIFFS que coincida con la petición, con la función ‘HandleFileRead’. Si no existe, devolvemos un error de 404, not found.

WebServer server(80);

#include "ESP32_Utils_Server.hpp"

void handleNotFound() {
  server.send(404, "text/plain", "Not found");
}

void InitServer()
{
   server.onNotFound([]() {                             // If the client requests any URI
     if (!HandleFileRead(server.uri()))                 // send it if it exists
      handleNotFound();                  // otherwise, respond with a 404 (Not Found) error
   });
  
   server.begin();
   Serial.println("HTTP server started");
}
Copied!

Finalmente, hemos incluido el fichero ‘ESP32_Utils_Server’, que contiene la función HandleFileRead, y las funciones necesarias para servir el fichero desde el SPIFFS.

String GetContentType(String filename)
{
  if(filename.endsWith(".htm")) return "text/html";
  else if(filename.endsWith(".html")) return "text/html";
  else if(filename.endsWith(".css")) return "text/css";
  else if(filename.endsWith(".js")) return "application/javascript";
  else if(filename.endsWith(".png")) return "image/png";
  else if(filename.endsWith(".gif")) return "image/gif";
  else if(filename.endsWith(".jpg")) return "image/jpeg";
  else if(filename.endsWith(".ico")) return "image/x-icon";
  else if(filename.endsWith(".xml")) return "text/xml";
  else if(filename.endsWith(".pdf")) return "application/x-pdf";
  else if(filename.endsWith(".zip")) return "application/x-zip";
  else if(filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}

void ServeFile(String path)
{
   File file = SPIFFS.open(path, "r");
   size_t sent = server.streamFile(file, GetContentType(path));
   file.close();
}

void ServeFile(String path, String contentType)
{
   File file = SPIFFS.open(path, "r");
   size_t sent = server.streamFile(file, contentType);
   file.close();
}

bool HandleFileRead(String path) 
{ 
  if (path.endsWith("/")) path += "index.html";
  Serial.println("handleFileRead: " + path);
  
  if (SPIFFS.exists(path)) 
  {
    ServeFile(path);
    return true;
  }
  Serial.println("\tFile Not Found");
  return false;
}
Copied!

Compilamos el código y lo subimos a nuestro ESP8266. Por otro lado, creamos una carpeta llamada ‘data’ dentro de la carpeta donde tengamos alojados los ficheros anteriores.

En esta carpeta, llamamos un fichero llamado ‘index.html’ con el siguiente contenido.

<!DOCTYPE html>
<html class="no-js" lang="">
   <head>
      <meta charset="utf-8">
      <meta http-equiv="x-ua-compatible" content="ie=edge">
      <title>¡Hola mundo!</title>
      <meta name="description" content="">
      <meta name="viewport" content="width=device-width, initial-scale=1">
   </head>
 
   <body>
        <h1>Esta es tu página web. ¡Enhorabuena!</h1>
    </body>
</html>
Copied!

Resultado

Si accedemos desde el navegador al ESP8266 veremos nuestra sencilla (y a la vez que flamante) página web servida desde el SPIFFS del ESP8266. ¡Enhorabuena!

esp8266-servidor-spiffs-hello-world

Mientras que en el puerto serie podemos comprobar que efectivamente hemos recibido la petición.

esp8266-servidor-spiffs-serial-port

Con esto ya podemos servir una página web desde SPIFFS. Para proyectos reales, podemos mejorar aún más el resultado sirviendo ficheros comprimidos en Gzip y reduciendo el tamaño transferido al navegador.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github.

github-full

Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples

Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples