[lll-main-image] Continuamos con las entradas del ESP8266 y el ESP32 viendo cómo servir una página con estética Material Design gracias a la librería Material Design Lite.
Haremos referencia al ESP8266, pero el mismo código es compatible para el ESP32, ajustando el nombre de las librerías. Al final tenéis el código tanto para el ESP8266 como para el ESP32.
Hemos dedicado varias entradas a ver cómo servir páginas web desde el ESP8266, y como conectar el frontend con el backend a través de llamadas AJAX o Websockets.
Pero, reconozcámoslo, las páginas web que hemos servido hasta ahora son bastante feas. ¡Eso está a punto de cambiar! y empezaremos con la sencilla librería Material Design Lite que ya vimos en esta entrada.
¡Así que manos a la obra! En cuanto a la parte del backend, es decir, el código del ESP8266, es idéntico al que hemos venido usando. Esto es,
#include <ESP8266WiFi.h>
#include <ESPAsyncWebServer.h>
#include <FS.h>
#include "config.h" // Sustituir con datos de vuestra red
#include "Server.hpp"
#include "ESP8266_Utils.hpp"
void setup(void)
{
Serial.begin(115200);
SPIFFS.begin();
ConnectWiFi_STA();
InitServer();
}
void loop(void)
{
}
AsyncWebServer server(80);
void InitServer()
{
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");
server.onNotFound([](AsyncWebServerRequest *request) {
request->send(400, "text/plain", "Not found");
});
server.begin();
Serial.println("HTTP server started");
}
La diferencia de verdad en este ejemplo está en el fichero ‘index.html’ y en los ficheros que subiremos a la memoria SPIFFS. Hasta ahora nuestro código html hubiera sido así,
<!doctype html>
<html class="no-js" lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div>
<div>
<form action="#">
<div>
<input type="text" id="sample3">
<label for="sample3">Text...</label>
</div>
</form>
</div>
</div>
<div>
<div>
<button>
<i class="material-icons">add</i>
</button>
</div>
<div>
<button>Button</button>
</div>
</div>
<div>
<div>
<input type="range" min="0" max="100" value="25" tabindex="0">
</div>
</div>
<div >
<div>
<label or="checkbox-1">
<input type="checkbox" id="checkbox-1" checked>
<span>Checkbox</span>
</label>
<label for="checkbox-2">
<input type="checkbox" id="checkbox-2">
<span>Checkbox2</span>
</label>
<label for="checkbox-3">
<input type="checkbox" id="checkbox-3">
<span>Checkbox3</span>
</label>
</div>
</div>
<div>
<div>
<label for="option-1">
<input type="radio" id="option-1" name="options" value="1" checked>
<span>First</span>
</label>
<label for="option-2">
<input type="radio" id="option-2" name="options" value="2">
<span>Second</span>
</label>
<label for="option-3">
<input type="radio" id="option-3" name="options" value="3">
<span>Third</span>
</label>
</div>
</div>
<div>
<div>
<label or="switch-1">
<input type="checkbox" id="switch-1" checked>
<span>Switch</span>
</label>
</div>
</div>
</body>
</html>
Que daría este terriblemente feo resultado.
Y ahora ahora va a pasar a ser
<!doctype html>
<html class="no-js" lang="">
<head>
<title>ESP8266 Material Lite</title>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<link rel="stylesheet" href="vendor/google-fonts.css">
<link rel="stylesheet" href="vendor/material.css">
<!--<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/material-design-lite@1.3.0/dist/material.indigo-pink.min.css">-->
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<form action="#">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="sample3">
<label class="mdl-textfield__label" for="sample3">Text...</label>
</div>
</form>
</div>
</div>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--1-col">
<button class="mdl-button mdl-js-button mdl-button--fab mdl-js-ripple-effect mdl-button--colored">
<i class="material-icons">add</i>
</button>
</div>
<div class="mdl-cell mdl-cell--1-col">
<button class="mdl-button mdl-js-button mdl-button--raised mdl-js-ripple-effect mdl-button--colored">Button</button>
</div>
</div>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<input class="mdl-slider mdl-js-slider" type="range" min="0" max="100" value="25" tabindex="0">
</div>
</div>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-1">
<input type="checkbox" id="checkbox-1" class="mdl-checkbox__input" checked>
<span class="mdl-checkbox__label">Checkbox</span>
</label>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-2">
<input type="checkbox" id="checkbox-2" class="mdl-checkbox__input">
<span class="mdl-checkbox__label">Checkbox2</span>
</label>
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" for="checkbox-3">
<input type="checkbox" id="checkbox-3" class="mdl-checkbox__input">
<span class="mdl-checkbox__label">Checkbox3</span>
</label>
</div>
</div>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-1">
<input type="radio" id="option-1" class="mdl-radio__button" name="options" value="1" checked>
<span class="mdl-radio__label">First</span>
</label>
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-2">
<input type="radio" id="option-2" class="mdl-radio__button" name="options" value="2">
<span class="mdl-radio__label">Second</span>
</label>
<label class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="option-3">
<input type="radio" id="option-3" class="mdl-radio__button" name="options" value="3">
<span class="mdl-radio__label">Third</span>
</label>
</div>
</div>
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col">
<label class="mdl-switch mdl-js-switch mdl-js-ripple-effect" for="switch-1">
<input type="checkbox" id="switch-1" class="mdl-switch__input" checked>
<span class="mdl-switch__label">Switch</span>
</label>
</div>
</div>
<script src="vendor/material.js"></script>
<!--<script src="https://cdn.jsdelivr.net/combine/npm/vue@2.6.10,npm/material-design-lite@1.3.0"></script>-->
</body>
</html>
Con el que conseguiremos esta estética.
Respecto a los ficheros empleados por el framework Material Design Lite (JS y CSS) podemos o bien cargarlos desde una CDN, o bien subirlos comprimidos a la memoria del ESP8266.
En el ejemplo tenéis ambas opciones, estando comentada la opción de CDN
En principio preferiremos la CDN siempre que sea posible, es decir, cuando el cliente final disponga de conexión a Internet para bajar los ficheros. De esta forma liberamos al ESP8266 del trabajo de tener que servir los ficheros.
Pero no siempre va a ser posible. Por ejemplo, tendremos que servirlos nosotros cuando el ESP8266 esté actuando como en modo AP porque el cliente no va a tener acceso a Internet para descargarse los ficheros por desde el CDN.
¡Así de sencillo ha sido!. Por supuesto, estamos usando el framework Material Design Lite pero podéis usar cualquier otro framework o template que queráis para servir las páginas web siguiendo el procedimiento que hemos visto para cargar los ficheros.
Se acabaron las excusas para servir páginas “feas” desde vuestro ESP8266. En la siguiente entrada de la serie volveremos a meternos en comunicación frontend backend intercambiando información codificada en Json en llamadas Ajax. ¡Hasta pronto!
Descarga el código
Todo el código de esta entrada está disponible para su descarga en Github.
Versión para el ESP8266: https://github.com/luisllamasbinaburo/ESP8266-Examples
Versión para el ESP32: https://github.com/luisllamasbinaburo/ESP32-Examples