Domotique et objets connectés à faire soi-même

Interface HTML pour ESP8266. Changer de thème Bootstrap avec Bootswatch et bootstrapCDN

Changer le thème Bootstrap par défaut avec Bootswatch et bootstrapCDN

Code source

Bootswatch permet de personnaliser le thème par défaut (remplacer la feuille de style CSS par défaut) du framework Bootstrap. La feuille de style (fichier CSS) de Bootstrap peut facilement être modifiée pour répondre à vos besoins mais le plus facile est encore d’utiliser les nombreux thèmes (pour la plupart gratuits) disponibles en ligne sur bootstrapCDN. 

 

Tutoriel actualisé le 7 août 2020

Nous allons modifier le code de l’interface HTML développé dans le tutoriel précédent.

Comment changer le thème par défaut de Bootstrap avec Bootswatch ?

Il est possible de modifier la feuille de style CSS du framework Bootstrap ou d’ajouter de nouveaux styles en les écrivant soi-même mais c’est un peu dommage de devoir tout faire à la main alors qu’il y a de très nombreux styles de qualité disponibles sur internet (très souvent gratuitement). Impossible de tous les tester. Je vous propose d’essayer les thèmes de BootstrapCND.

Pour modifier le style de notre page, il suffit simplement de pointer vers une autre feuille de style, c’est à dire qu’on va remplacer ce lien dans le code de la page.

link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'

Tout comme Bootstrap, il n’est pas nécessaire de télécharger les fichiers en local, on va simplement pointer vers le CND (serveur de fichier) de BootstrapCND. Ce qui va donner par exemple pour le thème Cosmo le lien suivant.

<link href='https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/cosmo/bootstrap.min.css' rel='stylesheet'>

BootstrapCND met également une clé pour vérifier que le fichier récupéré n’a pas été altéré (il ne contient aucun code malicieux). Je n’ai pas intégré cette vérification dans cet exemple.

BootstrapCDN met à disposition 16 thèmes que l’on trouve dans la section Bootswatch. Si vous en avez besoin, BootstrapCDN met également à disposition un lien pour récupérer les symboles de Font Awesome.

Comment changer le thème par une requête HTTP ?

On va profiter de ce tutoriel pour introduire un nouveau composants proposé par Bootstrap, le bouton drop down (que l’on connait aussi sous le nom combo) qui permet de créer une liste de sélection. Comme d’habitude il existe plusieurs méthodes pour envoyer la sélection faite dans la liste. Comme on ne veut pas forcément embarquer du code javascript, je vous propose de passer par une petite astuce qui consiste à créer un champ invisible dans lequel on va recopier pas possible avant d’appeler la fonction submit().

On va donc créer un formulaire form dans lequel sera placé le bouton drop down ainsi que le champ invisible (un champ de type input). Pour que cela fonctionne, il est important de bien nommer les éléments HTML et leur attribuer un identifiant (id).

Voyons en détail comment ça fonctionne :

Et le code javascript correspondant

<form method='POST' name='selecttheme' id='selecttheme'/> 
  <input class='span' id='choixtheme' name='theme' type='hidden'>
  <div class='btn-group'>
    <button class='btn btn-default'>Choisir un th&eacute;me</button>
    <button data-toggle='dropdown' class='btn btn-default dropdown-toggle'><span class='caret'></span></button>
      <ul class='dropdown-menu'>
        <li onclick='$(\"#choixtheme\").val(\"bootstrap\"); $(\"#selecttheme\").submit()'><a href='#'>Boostrap</a></li>
        <li onclick='$(\"#choixtheme\").val(\"cosmo\"); $(\"#selecttheme\").submit()'><a href='#'>Cosme</a></li> 
      </ul>
  </div>
  </input>     
</form>

Pour voir ce qui se passe, ouvrez les outils de développements sur votre navigateur et sélectionnez un thème pour visualiser la requête envoyée au serveur Web de l’ESP8266.

Comment changer le thème Bootstrap dynamiquement ?

Maintenant il ne reste plus qu’à ajouter un traitement pour actualiser la page à chaque fois que l’utilisateur sélectionne un thème. Pour cela il nous suffit de rajouter un test sur l’argument theme dans la fonction handleRoot().

Une variable theme permet de stocker la valeur sélectionnée par l’utilisateur. Ensuite, lorsqu’on créé la page HTML, il suffit de faire un test sur la valeur du thème pour savoir si l’utilisateur souhaite le thème par défaut ou un de BootstrapCDN.

if ( theme == "bootstrap" ) {
  page += "<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>";
} else {
  page += "<link href='https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/";
  page += theme;
  page += "/bootstrap.min.css' rel='stylesheet'>";
}

Code du projet

Nous allons reprendre le code de notre petite station météo développé dans le tutoriel précédent. On récupère la température et l’humidité d’une sonde DHT22 et la pression atmosphérique d’un BMP180.

Wemos D1 Mini (module ESP8266 ESP-12)
Alimentation 5/3A micro-usb

Une alimentation de qualité est recommandée.

Capteur de pression atmosphérique

BMP180

Capteur de température et d’humidité

DHT22 (ou DHT11)

Jumper Dupont
Breadboard

Il reste à changer le ssid ainsi que le mot de passe du réseau WiFi avant de téléverser le code dans l’ESP8266.

#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>

#define ssid      "xxx"       // WiFi SSID
#define password  "xxxxxxxx"  // WiFi password
#define DHTTYPE   DHT22       // DHT type (DHT11, DHT22)
#define DHTPIN    D4          // Broche du DHT / DHT Pin
const uint8_t GPIOPIN[4] = {D5,D6,D7,D8};  // Led
float   t = 0 ;
float   h = 0 ;
float   p = 0;
String  etatGpio[4] = {"OFF","OFF","OFF","OFF"};
String  theme = "bootstrap";

// Création des objets / create Objects
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp;
ESP8266WebServer server ( 80 );

String getPage(){
  String page = "<html charset=UTF-8><head><meta http-equiv='refresh' content='60' name='viewport' content='width=device-width, initial-scale=1'/>";
  page += "<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js'></script><script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'></script>";
  if ( theme == "bootstrap" ) {
    page += "<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css'>";
  } else {
    page += "<link href='https://maxcdn.bootstrapcdn.com/bootswatch/3.3.7/";
    page += theme;
    page += "/bootstrap.min.css' rel='stylesheet'>";
  }
  page += "<title>ESP8266 Demo - www.projetsdiy.fr</title></head><body>";
  page += "<div class='container-fluid'>";
  page +=   "<div class='row'>";
  page +=     "<div class='col-md-12'>";
  page +=       "<h1>Demo Webserver ESP8266 + Bootstrap</h1>";
  page +=       "<h3>Mini station m&eacute;t&eacute;o</h3>";
  page +=       "<ul class='nav nav-pills'>";
  page +=         "<li class='active'>";
  page +=           "<a href='#'> <span class='badge pull-right'>";
  page +=           t;
  page +=           "</span> Temp&eacute;rature</a>";
  page +=         "</li><li>";
  page +=           "<a href='#'> <span class='badge pull-right'>";
  page +=           h;
  page +=           "</span> Humidit&eacute;</a>";
  page +=         "</li><li>";
  page +=           "<a href='#'> <span class='badge pull-right'>";
  page +=           p;
  page +=           "</span> Pression atmosph&eacute;rique</a></li>";
  page +=       "</ul>";
  page +=       "<table class='table'>";  // Tableau des relevés
  page +=         "<thead><tr><th>Capteur</th><th>Mesure</th><th>Valeur</th><th>Valeur pr&eacute;c&eacute;dente</th></tr></thead>"; //Entête
  page +=         "<tbody>";  // Contenu du tableau
  page +=           "<tr><td>DHT22</td><td>Temp&eacute;rature</td><td>"; // Première ligne : température
  page +=             t;
  page +=             "&deg;C</td><td>";
  page +=             "-</td></tr>";
  page +=           "<tr class='active'><td>DHT22</td><td>Humidit&eacute;</td><td>"; // 2nd ligne : Humidité
  page +=             h;
  page +=             "%</td><td>";
  page +=             "-</td></tr>";
  page +=           "<tr><td>BMP180</td><td>Pression atmosph&eacute;rique</td><td>"; // 3ème ligne : PA (BMP180)
  page +=             p;
  page +=             "mbar</td><td>";
  page +=             "-</td></tr>";
  page +=       "</tbody></table>";
  page +=       "<h3>GPIO</h3>";
  page +=       "<div class='row'>";
  page +=         "<div class='col-md-4'><h4 class ='text-left'>D5 ";
  page +=           "<span class='badge'>";
  page +=           etatGpio[0];
  page +=         "</span></h4></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D5' value='1' class='btn btn-success btn-lg'>ON</button></form></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D5' value='0' class='btn btn-danger btn-lg'>OFF</button></form></div>";
  page +=         "<div class='col-md-4'><h4 class ='text-left'>D6 ";
  page +=           "<span class='badge'>";
  page +=           etatGpio[1];
  page +=         "</span></h4></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D6' value='1' class='btn btn-success btn-lg'>ON</button></form></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D6' value='0' class='btn btn-danger btn-lg'>OFF</button></form></div>";
  page +=         "<div class='col-md-4'><h4 class ='text-left'>D7 ";
  page +=           "<span class='badge'>";
  page +=           etatGpio[2];
  page +=         "</span></h4></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D7' value='1' class='btn btn-success btn-lg'>ON</button></form></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D7' value='0' class='btn btn-danger btn-lg'>OFF</button></form></div>";
  page +=         "<div class='col-md-4'><h4 class ='text-left'>D8 ";
  page +=           "<span class='badge'>";
  page +=           etatGpio[3];
  page +=         "</span></h4></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D8' value='1' class='btn btn-success btn-lg'>ON</button></form></div>";
  page +=         "<div class='col-md-4'><form action='/' method='POST'><button type='button submit' name='D8' value='0' class='btn btn-danger btn-lg'>OFF</button></form></div>";
  page +=       "</div>";
  page +=   "<div class='row'>";
  page +=     "<div class='col-md-4'>";
  page +=       "<form method='POST' name='selecttheme' id='selecttheme'/>"; 
  page +=       "<input class='span' id='choixtheme' name='theme' type='hidden'>";
  page +=       "<div class='btn-group'>";
  page +=         "<button class='btn btn-default'>Choisir un th&eacute;me</button>";
  page +=         "<button data-toggle='dropdown' class='btn btn-default dropdown-toggle'><span class='caret'></span></button>";
  page +=         "<ul class='dropdown-menu'>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"bootstrap\"); $(\"#selecttheme\").submit()'><a href='#'>Boostrap</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"cerulean\"); $(\"#selecttheme\").submit()'><a href='#'>Cerulean</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"cosmo\"); $(\"#selecttheme\").submit()'><a href='#'>Cosmo</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"cyborg\"); $(\"#selecttheme\").submit()'><a href='#'>Cyborg</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"darkly\"); $(\"#selecttheme\").submit()'><a href='#'>Darkly</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"flatly\"); $(\"#selecttheme\").submit()'><a href='#'>Flatly</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"journal\"); $(\"#selecttheme\").submit()'><a href='#'>Journal</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"lumen\"); $(\"#selecttheme\").submit()'><a href='#'>Lumen</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"paper\"); $(\"#selecttheme\").submit()'><a href='#'>Paper</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"readable\"); $(\"#selecttheme\").submit()'><a href='#'>Readable</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"sandstone\"); $(\"#selecttheme\").submit()'><a href='#'>Sandstone</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"simplex\"); $(\"#selecttheme\").submit()'><a href='#'>Simplex</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"slate\"); $(\"#selecttheme\").submit()'><a href='#'>Slate</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"spacelab\"); $(\"#selecttheme\").submit()'><a href='#'>Spacelab</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"superhero\"); $(\"#selecttheme\").submit()'><a href='#'>Superhero</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"united\"); $(\"#selecttheme\").submit()'><a href='#'>United</a></li>";
  page +=           "<li onclick='$(\"#choixtheme\").val(\"yeti\"); $(\"#selecttheme\").submit()'><a href='#'>Yeti</a></li>";
  page +=         "</ul>";
  page +=       "</div>";
  page +=       "</form></div>";
  page +=       "<div class='col-md-8'>";
  page +=         "<p><a href='http://www.projetsdiy.fr'>Version francaise : www.projetsdiy.fr</p>";
  page +=         "<p><a href='http://www.diyprojects.io'>English version : www.diyprojects.io</p>";
  page +=       "</div>";
  page +=   "</div>"; 
  page += "</div></div></div>";
  page += "</body></html>";
  return page;
}
void handleRoot(){ 
  if ( server.hasArg("theme") ) {
    handleTheme();
  } else if ( server.hasArg("D5") ) {
    handleD5();
  } else if ( server.hasArg("D6") ) {
    handleD6();
  } else if ( server.hasArg("D7") ) {
    handleD7();
  } else if ( server.hasArg("D8") ) {
    handleD8();
  } else {
    server.send ( 200, "text/html", getPage() );
  }  
}

void handleTheme(){
  theme = server.arg("theme");
  Serial.println("Update theme : "); Serial.print(theme);  
  server.send ( 200, "text/html", getPage() );
}

void handleD5() {
  String D5Value; 
  updateGPIO(0,server.arg("D5")); 
}

void handleD6() {
  String D6Value; 
  updateGPIO(1,server.arg("D6")); 
}

void handleD7() {
  String D7Value; 
  updateGPIO(2,server.arg("D7")); 
}

void handleD8() {
  String D8Value; 
  updateGPIO(3,server.arg("D8")); 
}

void updateGPIO(int gpio, String DxValue) {
  Serial.println("");
  Serial.println("Update GPIO "); Serial.print(GPIOPIN[gpio]); Serial.print(" -> "); Serial.println(DxValue);
  
  if ( DxValue == "1" ) {
    digitalWrite(GPIOPIN[gpio], HIGH);
    etatGpio[gpio] = "On";
    server.send ( 200, "text/html", getPage() );
  } else if ( DxValue == "0" ) {
    digitalWrite(GPIOPIN[gpio], LOW);
    etatGpio[gpio] = "Off";
    server.send ( 200, "text/html", getPage() );
  } else {
    Serial.println("Err Led Value");
  }  
}

void setup() {
  for ( int x = 0 ; x < 5 ; x++ ) { 
    pinMode(GPIOPIN[x],OUTPUT);
  }  
  Serial.begin ( 115200 );
  // Initialisation du BMP180 / Init BMP180
  if ( !bmp.begin() ) {
    Serial.println("BMP180 KO!");
    while(1);
  } else {
    Serial.println("BMP180 OK");
  }
  
  WiFi.begin ( ssid, password );
  // Attente de la connexion au réseau WiFi / Wait for connection
  while ( WiFi.status() != WL_CONNECTED ) {
    delay ( 500 ); Serial.print ( "." );
  }
  // Connexion WiFi établie / WiFi connexion is OK
  Serial.println ( "" ); 
  Serial.print ( "Connected to " ); Serial.println ( ssid );
  Serial.print ( "IP address: " ); Serial.println ( WiFi.localIP() );

  // On branche la fonction qui gère la premiere page / link to the function that manage launch page 
  server.on ( "/", handleRoot );

  server.begin();
  Serial.println ( "HTTP server started" );
  
}

void loop() {
  // put your main code here, to run repeatedly:
  server.handleClient();
  t = dht.readTemperature();
  h = dht.readHumidity();
  p = bmp.readPressure() / 100.0F;

  delay(1000);
}

Test de quelques thèmes proposés par bootstrapCDN

Le programme démarre avec le thème Bootstrap. La liste de sélection se trouve en bas de page. A chaque changement de thème, celui-ci est téléchargé (sauf s’il est déjà en cache sur l’ESP8266) et la page est reconstruite avec la nouvelle feuille de style.

Voici quelques exemples. Je vous laisse découvrir les autres thèmes par vous-même en testant directement depuis votre projet ESP8266.

Thème Bootstrap 3.3.7 par défaut

 

Thème Bootswatch Darkly

 

Thème Bootswatch Readable

 

Thème Bootswatch Superhero

 

Thème Bootswatch United

De quoi donner un aspect très pro et très bien fini à tous vos projets DIY ESP8266 !

 

Avez-vous aimé cet article ?
[Total: 1 Moyenne: 5]
Quitter la version mobile