Maj: 01/08/2020 – le système SPIFFS étant passé en « dépréciation » il faut envisager LittleFS , voir article sur LittleFS
Dans cet article , je vais expliquer comment utiliser la mémoire SPIFFS de votre module ESP8266.
A la suite de cet article vous saurez comment :
- importer des fichiers dans la mémoire SPIFFS
- Manipuler les fichiers en lecture et en écriture
- Comment monter rapidement une interface WEB dynamique
- Monter un serveur FTP
- Formater la mémoire.
Chapitre 1 : Utilisation de la mémoire SPIFFS ( cet article )
Chapitre 2 : EEPROM ou SPIFFS
La structure mémoire des modules ESP8266
Lors de mes différents articles , nous avons eu l’occasion de travailler sur la mémoire où est stocké notre sketch. (cette mémoire est lue à chaque démarrage , les variables sont donc réinitialiser avec les valeurs par défaut).
L’espace OTA est un dossier temporaire pour les mises à jour via OTA
EEPROM : Permet de stocker des infos, qui pourront être lues après redémarrage. Nous sommes sur une mémoire plus lente (que la mémoire dédiée au sketch et qui dispose d’une durée de vie limitée en écriture . Ne pas en abuser).
File system : ou mémoire SPIFFS , ce que nous allons étudier, aujourd’hui , est un espace de stockage (que l’on pourrait assimiler à une SDcard ).
Selon les modules utilisés, la taille du fichier systéme peut varier de 64ko à 3Mo.
Comment transférer un fichier dans la mémoire SPIFFS
Pour cela , il suffit d’utiliser la bibliothèque : FS.h
Tous les détails de cette bibliothèque ici.
Il existe un outil qui permet d’uploader automatiquement , tous les fichiers dans la mémoire SPIFFS depuis l’interface Arduino.
Lien vers outils de téléchargement SPIFFS ( outil FS )
Pour l’installer il faut :
- dans votre dossier arduino , créér un dossier tools
- décompresser l’outil téléchargé dans le dossier tools . Vous devriez avoir une arborescence sous la forme suivante : <home_dir>/Arduino/tools/ESP8266FS/tool/esp8266fs.jar
Re-démarrer l’interface Arduino.
Dans le dossier de votre sketch , créér un dossier data .
Les fichiers déposés dans ce dossier , seront transférés dans la mémoire SPIFFS.
Par exemple :
Une fois votre sketch ouvert , dans l’interface Arduino , sélectionner dans le menu outil : ESP8266 Sketch data upload.
Le contenu du dossier data sera transféré dans la mémoire SPIFFS. Ici le fichier test.txt.
Cela peut être plus ou moins long , en fonction de la vitesse d’upload sélectionnée , penser à régler la vitesse d’upload à son maximum . Pour le transfert de vos sketchs , vous la redescendrez. Puis effectuer le transfert de votre sketch de façon habituelle.
Comment accéder à ce fichier
Apres avoir créé un fichier text de test , déposez le dans le dossier data , de notre sketch .
par exemple le fichier texte : « ceci est un fichier test SPIFFS »
Je vais écrire un sketch , me permettant d’afficher le contenu de ce fichier , dans la console .
/* * SPIFFS test */ #include//Include File System Headers void setup() { Serial.begin(115200); Serial.println(); //demarrage file system SPIFFS.begin(); Serial.println("Demarrage file System"); File dataFile = SPIFFS.open("/test.txt", "r"); //Ouverture fichier pour le lire Serial.println("Lecture du fichier en cours:"); //Affichage des données du fichier for(int i=0;i<dataFile.size();i++) { Serial.print((char)dataFile.read()); //Read file } dataFile.close(); } void loop() { }
Une fois le sketch uploader , j’ouvre la console et j’obtiens le résultat suivant :
Comment écrire dans un fichier avec SPIFFS
l’écriture est tout aussi simple , que la lecture , il suffit d’ouvrir le fichier en mode écriture avec l’option w.
File f = SPIFFS.open(« /test.txt », « w »);
pour écrire du texte , il suffit d’utiliser la fonction : f.print(« mon nouveau texte »);
Attention toute nouvelle écriture dans le fichier supprime les anciennes données du fichiers.Il faut penser à sauvegarder dans une variable les données du fichier avant d’écrire la nouvelle info.
par exemple par la fonction suivante :
fileTxt = f.readString();
Ci-dessous exemple sketch :
/*
*** SPIFFS test
*/
#include “FS.h” //Include File System Headers
String fileTxt;
void setup() {
Serial.begin(115200);
Serial.println(); //demarrage file system
SPIFFS.begin();
Serial.println("Demarrage file System");
File f = SPIFFS.open("/test.txt", "r"); //Ouverture fichier pour le lire
Serial.println("Lecture du fichier en cours:"); //Affichage des données du fichier
fileTxt = f.readString(); // on recupere le contenu entier du ficher
Serial.println(fileTxt);
f.close();
Serial.println("");
}
void loop() {
// écrire dans fichier test.txt
File f = SPIFFS.open("/test.txt", "w");
f.println(fileTxt); // on réécrit l'ancien contenu sauvegardé au préalable
f.print("Ecriture nouvelle info dupuis sketch :"); // puis les nouvelles infos.
f.println(millis()); f.close(); // on ferme le fichier une fois les enregistrements terminés
// on ouvre de nouveau pour lecture
f = SPIFFS.open("/test.txt", "r");
fileTxt = f.readString();
//Affichage des données du fichier
Serial.println("affichage de la nouvelle chaine de caractére :");
Serial.println(fileTxt);
f.close(); //pause de 80 secondes , afin d'éviter de remplir la mémoire trop vite.Pensez à débrancher votre ESP ou d'uploader un nouveau sketch avant de saturer votre mémoire.
delay(80000);
}
Voila ce que l’on observe dans la console :
Pensez a débrancher votre ESP, ou uploader un sketch différent avant de saturer votre mémoire !! Car ce programme écrit en permanence dans le fichier txt .
SPIFFS pour quel usage
Au quotidien , à quoi peut servir d’enregistrer des fichiers dans la mémoire SPIFFS.
- Garder un historique des températures ou d’autres données , par exemple.
- Lire et sauvegarder un fichier de configuration
- stocker , les fichiers d’un site WEB ( par exemple , feuille de style , fichier javascript …. )
- et bien d’autres possibilités encore.
Pour illustrer un de ces usages , voici comment mettre en place une interface WEB , pour allumer ou éteindre la led interne.
Une interface Web dynamique
Pour cela , je vais récupérer le fichier jquery.mini.js chez Jquery et le déposer dans le dossier data de mon sketch.
A l’aide d’un éditeur de texte , j’écris mon fichier index.html .
<!DOCTYPE html>
<html>
<head>
<cript src="jquery.min.js"></script>
</head>
<body>
<center>
<h1>Tuto SPIFFS + jquery - Byfeel</h1>
<p>Demo jquery , pour on/off led interne</p>
<div>Temperature : <span id="Temp"></span> </div>
<form action='/setLED' method='POST' id='FormLED'>
<fieldset>
<legend>LED interne 2 :</legend>
<INPUT type='radio' name='LED' value='on' id='on' checked><label for='on'>ON</label>
<INPUT type='radio' name='LED' value='off' id='off'><label for='off'>OFF</label>
</fieldset>
<INPUT type='submit' value='Envoyer' id='bouton_LED'/>
</form>
<a href="https://byfeel.info">byfeel.info</a><br>
<div id="info"></div>
<script>
$("#FormLED").submit(function(){
$.ajax({
url: '/setLED',
type: 'post',
data: $("#FormLED").serialize(),
success: function(data) {
$("#info").html("<p> Commende LED : "+data+"</p>");
}
});
return false;
});
function loadInfo(){
$( "#Temp" ).load( "/getInfo");
}
loadInfo(); // premiere execution
setInterval(function(){
loadInfo() // rappel toutes les 10 secondes
}, 10000);
</script>
</body>
</html>
que je dépose aussi , dans mon fichier data. Ce fichier index , sera ma page de démarrage de mon nouveau serveur WEB. Cette page affiche un simple formulaire , composé de deux boutons radio ( on et off ) et d’un bouton envoyer. Le script Javascript , permet lors de l’appui sur le bouton d’envoyer l’info on ou off à la page : http://ip_module/setLED .
Afin que cette page soit gérée par mon module , je modifie mon sketch en conséquence.
Script sketch ( pensez à renseigner vos codes WIFI )
/* * SPIFFS test */ #include#include #include //Include SPIFFS //WiFi Connection configuration const char *ssid = "Mon-point-WIFI"; const char *password = "Mon-mot-de-passe-wifi"; #define led 2 //*********************************** //************* Gestion du serveur WEB //*********************************** ESP8266WebServer server(80); void handleRoot(){ server.sendHeader("Location", "/index.html",true); //Redirige vers page index.html sur SPIFFS server.send(302, "text/plane",""); } // fonction de traitement SETLED void handleLED(){ String SetLED = server.arg("LED"); Serial.println(SetLED); if (SetLED=="on") digitalWrite(led, LOW); else digitalWrite(led, HIGH); server.send(200, "text/plane",SetLED); } // fonction permettant de gérer les pages "not found" void handleWebRequests(){ if(loadFromSpiffs(server.uri())) return; String message = "File Not Detected\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET)?"GET":"POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i=0; i<server.args(); i++){ message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n"; } server.send(404, "text/plain", message); Serial.println(message); } //********** fin serveur web void setup() { Serial.begin(115200); Serial.println(); //démarrage file system SPIFFS.begin(); Serial.println("Demarrage file System"); // Conexion WIFI WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } //Si connexion affichage info dans console Serial.println(""); Serial.print("Connection ok sur le reseau : "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); //Initialize Webserver server.on("/",handleRoot); server.on("/setLED",handleLED); //pour gerer led server.onNotFound(handleWebRequests); //Pour page not found - redirige vers index.html server.begin(); pinMode(led, OUTPUT); } void loop() { server.handleClient(); } // gestion du not found. bool loadFromSpiffs(String path){ String dataType = "text/plain"; if(path.endsWith("/")) path += "index.htm"; if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf(".")); else if(path.endsWith(".html")) dataType = "text/html"; else if(path.endsWith(".htm")) dataType = "text/html"; else if(path.endsWith(".css")) dataType = "text/css"; else if(path.endsWith(".js")) dataType = "application/javascript"; else if(path.endsWith(".png")) dataType = "image/png"; else if(path.endsWith(".gif")) dataType = "image/gif"; else if(path.endsWith(".jpg")) dataType = "image/jpeg"; else if(path.endsWith(".ico")) dataType = "image/x-icon"; else if(path.endsWith(".xml")) dataType = "text/xml"; else if(path.endsWith(".pdf")) dataType = "application/pdf"; else if(path.endsWith(".zip")) dataType = "application/zip"; File dataFile = SPIFFS.open(path.c_str(), "r"); if (server.hasArg("download")) dataType = "application/octet-stream"; if (server.streamFile(dataFile, dataType) != dataFile.size()) { } dataFile.close(); return true; }
La fonction setLED ressemble à ça :
// fonction de traitement SETLED
void handleLED(){ // on répond à l’appel de la page
String SetLED = server.arg(« LED »); // on recupére l’argument
Serial.println(SetLED); // info de debug pour la console
if (SetLED== »on ») digitalWrite(led, LOW); // si On, on allume si Off on éteint
else digitalWrite(led, HIGH);
server.send(200, « text/plane »,SetLED); // on renvoie la valeur
}
A vous de tester :
la structure de votre dossier ressemble à ça :
Il faut maintenant dans l’ordre :
- uploader le contenu data , par le menu outil : ESP8266 sketch data upload
- uploader votre sketch
- ouvrir la console , pour récupérer l’adresse ip de votre module
- lancer l’interface WEB , pour obtenir la page ci dessous :
Ce petit exemple a pour but de monter comment mettre en place une interface WEB dynamique , pour s’interfacer avec vos modules.
Le but d’aujourd’hui n’est pas de détailler ce script , mais de montrer comment utiliser la mémoire SPIFFS , pour stocker les pages WEB.
Un serveur FTP
Selon la vitesse sélectionnée , l’upload du dossier data , peut être plus ou moins long . A chaque Upload , l’intégralité de la mémoire est écrite , même pour un petit fichier de quelques Ko. Si mémoire de 3Mo , les 3 Mo seront envoyés.
Par contre lors d’un développement , il devient vite fastidieux de recharger la config complète pour une toute petite modification.
Il existe pour cela , une bibliothèque , qui permet d’émuler un serveur FTP , sur le SPIFFS.
ESP8266FTPServer de nailbuster .
Télécharger cette bibliothèque , et insérez la dans votre bibliothèque Arduino.
Ce serveur FTP est encore en développement , mais il permet un accès rapide à la mémoire SPIFFS pour des petites modifications sur les fichiers. Il y a encore pas mal de bug , mais cela fonctionne très bien pour le transfert des fichiers.
Ci-dessous le sketch , pour utilisation du serveur FTP.
/* * SPIFFS test */ #include#include #include //Include SPIFFS // FTPserver #include "ESP8266FtpServer.h" //WiFi Connection configuration const char *ssid = "MON-AP-WIFI"; const char *password = "MOT-de-Passe"; #define led 2 // on crée l'instance FTP FtpServer ftpSrv; //*********************************** //************* Gestion du serveur WEB //*********************************** ESP8266WebServer server(80); void handleRoot(){ server.sendHeader("Location", "/index.html",true); //Redirige vers page index.html sur SPIFFS server.send(302, "text/plane",""); } // fonction de traitement SETLED void handleLED(){ String SetLED = server.arg("LED"); Serial.println(SetLED); if (SetLED=="on") digitalWrite(led, LOW); else digitalWrite(led, HIGH); server.send(200, "text/plane",SetLED); } void handleWebRequests(){ if(loadFromSpiffs(server.uri())) return; String message = "File Not Detected\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET)?"GET":"POST"; message += "\nArguments: "; message += server.args(); message += "\n"; for (uint8_t i=0; i<server.args(); i++){ message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n"; } server.send(404, "text/plain", message); Serial.println(message); } //********** fin serveur web void setup() { Serial.begin(115200); Serial.println(); // Conexion WIFI WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } //démarrage file system if (SPIFFS.begin()) { Serial.println("Demarrage file System"); ftpSrv.begin("esp8266","pass"); // demarrage serveur ftp avec user = esp8266 et mdp = password } else Serial.println("Erreur file System"); //Si connexion affichage info dans console Serial.println(""); Serial.print("Connection ok sur le reseau : "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); //Initialize Webserver server.on("/",handleRoot); server.on("/setLED",handleLED); //Rpour gerer led server.onNotFound(handleWebRequests); //Set setver all paths server.begin(); pinMode(led, OUTPUT); } void loop() { server.handleClient(); ftpSrv.handleFTP(); } // gestion du not found. bool loadFromSpiffs(String path){ String dataType = "text/plain"; if(path.endsWith("/")) path += "index.htm"; if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf(".")); else if(path.endsWith(".html")) dataType = "text/html"; else if(path.endsWith(".htm")) dataType = "text/html"; else if(path.endsWith(".css")) dataType = "text/css"; else if(path.endsWith(".js")) dataType = "application/javascript"; else if(path.endsWith(".png")) dataType = "image/png"; else if(path.endsWith(".gif")) dataType = "image/gif"; else if(path.endsWith(".jpg")) dataType = "image/jpeg"; else if(path.endsWith(".ico")) dataType = "image/x-icon"; else if(path.endsWith(".xml")) dataType = "text/xml"; else if(path.endsWith(".pdf")) dataType = "application/pdf"; else if(path.endsWith(".zip")) dataType = "application/zip"; File dataFile = SPIFFS.open(path.c_str(), "r"); if (server.hasArg("download")) dataType = "application/octet-stream"; if (server.streamFile(dataFile, dataType) != dataFile.size()) { } dataFile.close(); return true; }
il y a quatre lignes qui ont été rajoutées :
- #include « ESP8266FtpServer.h »
- FtpServer ftpSrv; ( pour créer l’instance ftp )
- ftpSrv.begin(« esp8266″, »pass »); Dans fonction setup() , pour démarrer le serveur avec utilisateur esp8266 et mdp : pass
- ftpSrv.handleFTP(); dans la boucle loop , pour écouter les requêtes FTP.
Le serveur FTP n’est pas compatible avec tous les clients FTP . J’ai testé avec filezilla , cela fonctionne , mais il faut faire attention aux paramètres suivants :
Pas de mode sécurisé , ni support d’aucun cryptage et une connexion simultanée uniquement.
Ce n’est pas indispensable , mais lors des phases de développement , c’est quand même plus pratique. Cela permet d’apporter rapidement des retouches aux fichier index.html , pour les test .
Formater l’espace SPIFFS
Tous les fichiers envoyés dans l’espace SPIFFS , reste présent . Pour effacer complètement la partie SPIFFS , il existe une commande .
SPIFFS.format();
à utiliser aprés la commande SPIFFS.begin();
8 commentaires sur “Utilisation de la mémoire SPIFFS sur ESP8266”
Bonjour,
Dans tes codes, il manque des choses derrière les include : (dans tous les codes)
/*
* SPIFFS test
*/
#include //Include File System Headers
void setup() {
Il faut avoir :
/*
* SPIFFS test
*/
#include « FS.h » //Include File System Headers
void setup() {
….
Problème de mon navigateur ? (mozilla)
Sinon, ça marche ! le reste est clair 🙂
Merci , pour la remontée …
je regarde pour corriger tout ca.
Bonjour,
Bien le tuto !
Je me suis beaucoup inspiré surtout de la partie mise en mémoire SPIFFS et reste aussi essayant de faire de la domotique avec des ESP12E.
Mais je me heurte à un détails, celui de récupérer les valeurs écrites en mémoire dans le même ordre d’écriture !
En écrivant des valeurs issues de variables (int) par
f.println (heures);
f.println (minutes);
f.close();
f = SPIFFS.open(« /test.txt », « r »);
fileTxt = f.readString();
me donne toutes les valeurs en mémoires et je souhaiterais récupérer les valeurs l’une après l’autre dans le but de mettre ces valeurs dans d’autres variables ou les mêmes, ceux-ci devraient être des valeurs horaires à récupérer lors d’une coupure d’alimentation !
Après un certains nombre d’essais, je ne trou pas la syntaxe.
Auriez vous une idée ?
Merci d’avance.
La mémoire spiffs est une mémoire plutôt destinée à stocker des fichiers que des données seule.
Quand j’Ecris des données dans un fichier txt , celle ci s inscrivent à la suite de l autre.
Pour les récupérer il faut donc découper la chaîne de caractère lu selon un caractère comme une virgule par exemple.
Pour stocker mes variables de config dans mon notifheure , j utilise le format JSON qui permet de retrouver une info facilement en fonction d un index. Plus simple a utiliser il existe une bibliothèque dédié à ça
De quelle version de notifheure s’agît t’il ou à quelle bibliothèque Json pensez vous ?
J utilise la bibliothèque JSON Arduino , qui est très bien documenté.
https://arduinojson.org