mardi 9 mai 2017

Accès à la mémoire SPIFFS du 8266

Un espace de type file system est disponible pour y mettre des fichiers. Cette espace n'est pas très grand, sur le noceMCU que j'utilise il fait 1M. Mais cela suffit pour y stocker des fichiers de configuration, des pages web (html, css, javascript, image ...). Il y a une contrainte sur la taille du  nom du fichier, avec son chemin et son extension, elle ne doit pas dépasser 31 caractères.

Pour pouvoir utiliser cette espace, il faut ajouter un outil dans l'IDE, disponible à l'adresse suivante :
https://github.com/esp8266/Arduino/blob/master/doc/filesystem.rst



Attention à la version de l'ide utilisé, j'avais la version 1.6.2 installé sur ma machine, le téléversement des fichiers ne fonctionnait pas. J'ai donc installé une version plus récente : 1.8.2 ( dernière version au moment de l’écriture de cette page). L'installer de la 1.8.2 sur Ubuntu ne fonctionne pas, il faut le modifier : https://github.com/arduino/Arduino/pull/6110/files


Procédure :

  1. Télécharger L'outil (voir lien plus haut).
  2. Copier le contenu de l'archive dans le dossier tools de l'IDE
  3. Redémarrer l'IDE
  4. Créer un dossier data dans le dossier du sketch utilisé pour tester cette fonctionnalité.
  5. Copier dans le dossier data les fichiers à transférer.
  6. Choisir le port USB de la carte ( à faire à chaque transfert)
  7. Dans L'IDE aller dans Outils/ESP8266 Sketch Data Upload, le transfert se fait, à la fin L'IDE affiche un message de succès.


Exemple d'utilisation :


Voici un exemple d'utilisation pour un serveur web, dans l'espace SPIFFS, on va mettre une feuille de style css (bootstrap minifié) et un formulaire html. Le 8266 se comporte en serveur web.

css :

Récupérer bootstrap : http://getbootstrap.com/getting-started/#download, copier le fichier /css/bootstrap.min.css dans le dossier data/html/css du sketch

html :

Code du formulaire html à mettre dans le dossier data/html/config.html du sketch, la variable $mqtt_host sera remplacer par le serveur web : 
   
<!DOCTYPE html>   
<html lang="fr">   
  <head>   
    <meta charset="utf-8">   
    <title>Configuration</title>    
    <link href="css/bootstrap.min.css" rel="stylesheet">
  </head>  
  <body>  
    <div class="container">
      <div class="row">
        <div class="col-xs-4">
          <form action="/postconfig" method="POST">
            <fieldset> 
              <legend>Mqtt</legend>  
              <div class="form-group form-group-sm col-sm-offset-1">
                <label  for="mqtt_host">Broker</label>
                <input type="text" class="form-control" id="mqtt_host" name="mqtt_host" value="$mqtt_host">
                <p class="help-block">Adresse du Broker mqtt.</p>
              </div>    
            </fieldset> 
            <div class="form-group">  
              <button type="submit" class="btn btn-primary">Sauvegarder</button>
            </div>
          </form>
        </div>
      </div>
    </div>
  </body>  
</html>


Déposez les fichiers sur le 8266, en utilisant la procédure décrite plus haut.


Sketch du serveur web :

/**
* uploadfile to SPIFFS https://github.com/esp8266/Arduino/blob/master/doc/filesystem.md
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h> 
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <FS.h>



const char *host = "serverweb1";
const char *wifi_ssid = "WIFI_SSID"; //replace by your value
const char *wifi_password = "WIFI_PWD"; //replace by your value


const String CONFIG_HTML = "/html/config.html";
const char *configUsername = "admin";
const char *configPwd = "admin";

String mqtt_host = "192.168.0.161";


ESP8266WebServer server(80);


/**
* racine du site.
*/
void handleRoot() {
  server.send(200, "text/html", "Hello !");
}

/**
* Affiche la page de configuration.
*/
void handleConfig() {

    String form = "";
    File f = SPIFFS.open(CONFIG_HTML, "r");
    if (!f) {
      Serial.println("Can't open config html file"); 
    server.send(404, "text/html", "File not found");    
    }
    else {
      char buf[1024];
      int siz = f.size();
      while(siz > 0) {
        size_t len = std::min((int)(sizeof(buf) - 1), siz);
        f.read((uint8_t *)buf, len);
        buf[len] = 0;
        form += buf;
        siz -= sizeof(buf) - 1;
      }
      f.close();

      form.replace("$mqtt_host", mqtt_host);

      Serial.println(form);
      server.send(200, "text/html", form);
    } 

}

/**
* sauvegarde les parametres du formulaire dans le fichier de configuration.
*/
void handlePostConfig() {
  Serial.println("reponse");
  Serial.println("mqtt_host : " + server.arg("mqtt_host"));
  
  mqtt_host = server.arg("mqtt_host");

  String page = "<html><head></head><body>Traitement ...</body></html>";
  server.send(200, "text/html", page);
  
}



/**
* se connecte en client wifi.
*/
bool connectWifiClient() {

  WiFi.mode(WIFI_OFF);  
  delay(200);
  Serial.println("Connecting to...");
  Serial.println(wifi_ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);
  if(WiFi.waitForConnectResult() == WL_CONNECTED){
    Serial.println("WiFi connected");  
    Serial.print("IP address : ");
    Serial.println(WiFi.localIP());
    return true;
  } else {
    Serial.println("WiFi Failed");
    return false;
  }
}

/**
* Demarre le serveur Web.
*/
void initWebserver() {


  server.on("/", handleRoot);
  
  server.on("/config", [&](){
    if(!server.authenticate(configUsername, configPwd)){
      return server.requestAuthentication();
  } else {
    handleConfig();
  }
  });
  
  server.on("/postconfig", [&](){
    if(!server.authenticate(configUsername, configPwd)){
      return server.requestAuthentication();
  } else {
    handlePostConfig();
  }
  });
  
  server.serveStatic("/css", SPIFFS, "/html/css");
  
  server.begin();
  Serial.println("HTTP server started");
  
  
  if (!MDNS.begin(host)) {
    Serial.println("Error setting up MDNS responder!");
    while(1) { 
      delay(1000);
    }
  }
  Serial.println("mDNS responder started");
  // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 80);

}

void setup() {
  delay(1000);
  
  Serial.begin(115200);
  Serial.println("...");
  
  Serial.println("Mounting FS...");

  if (!SPIFFS.begin()) {
    Serial.println("Failed to mount file system");
    return;
  }

  connectWifiClient();
 
  initWebserver();
 
}

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

Test :

Le formulaire web est accessible à l'adresse : http://serverweb1.local/config
Le formulaire de configuration est protégé par un identifiant (admin/admin)