Às vezes, queremos acompanhar algumas informações dos nossos projetos, seja para debug, ou mesmo para saber tudo o que está acontecendo quando não estamos com o terminal serial aberto. Isso fica muito complicado quando o ESP fica longe do computador, sem acesso ao terminal.
Uma das formas de contornar esse problema, é criar um sistema de log em arquivo, utilizando o SPIFFS (SPI Flash File System). Esse sistema de log em arquivo, poderá guardar tudo o que acontece no ESP e deixar disponível para consulta a qualquer momento, por meio de um webserver.
SPIFFS
O sistema de arquivos do ESP8266 é o SPIFFS, que foi desenhado para sistemas com memória SPI NOR flash, em dispositivos embarcados. O sistema de arquivos tem como principal meta, usar o mínimo possível de memória RAM.
Uma característica importante para ressaltar é que o SPIFFS não suporta pastas, porém o nome do arquivo pode conter “barra”, como por exemplo “/log/arquivo.txt” e subentende-se que o arquivo está dentro da pasta log, por convenção.
Alocação na memória do ESP
O sistema reserva um espaço na memória flash para a criação dos arquivos, que pode variar de acordo com o modelo do módulo ESP que está em uso. Essa alocação pode variar de 64kB até 3MB, sendo configurável em alguns modelos, como mostra a tabela abaixo.
| Board | Flash chip size, bytes | File system size, bytes |
|---|---|---|
| Generic module | 512k | 64k, 128k |
| Generic module | 1M | 64k, 128k, 256k, 512k |
| Generic module | 2M | 1M |
| Generic module | 4M | 3M |
| Adafruit HUZZAH | 4M | 1M, 3M |
| ESPresso Lite 1.0 | 4M | 1M, 3M |
| ESPresso Lite 2.0 | 4M | 1M, 3M |
| NodeMCU 0.9 | 4M | 1M, 3M |
| NodeMCU 1.0 | 4M | 1M, 3M |
| Olimex MOD-WIFI-ESP8266(-DEV) | 2M | 1M |
| SparkFun Thing | 512k | 64k |
| SweetPea ESP-210 | 4M | 1M, 3M |
| WeMos D1 & D1 mini | 4M | 1M, 3M |
| ESPDuino | 4M | 1M, 3M |
A biblioteca SPIFFS já é nativa do ambiente Arduino para o ESP8266. Para utilizar o sistema de arquivo, basta incluir a seguinte biblioteca no seu projeto.
#include <FS.h>
Funções principais da biblioteca
A biblioteca segue o padrão POSIX, com as funções de manipulação de arquivos já conhecidas, tais como:
- open
- close
- read
- write
- seek
- stat
Inicia o sistema de arquivo, equivalente ao mount no Linux:
SPIFFS.begin()
Fecha o sistema de arquivo, equivalente ao unmount:
SPIFFS.end()
Apaga todos os arquivos na região de memória reservada:
SPIFFS.format()
Abre o arquivo no modo de selecionado:
SPIFFS.open(path, mode)
Verifica a existência do arquivo:
SPIFFS.exists(path)
Remove um arquivo:
SPIFFS.remove(path)
Renomeia um arquivo:
SPIFFS.rename(pathFrom, pathTo)
Para a referência completa, acesse o manual da biblioteca no github do projeto ESP8266 Arduino.
WebServer
Para esse projeto, vamos criar um exemplo de como utilizar o sistema de arquivos SPIFFS, fazendo um sistema de armazenamento de log em arquivo, podendo ser consultado por meio de um webserver.
Código fonte
Abaixo segue o código fonte da solução, que trabalha com a criação de um log e a disponibilização dos dados por meio de um webserver.
The MIT License (MIT)
Copyright (c) 2015 Pedro Minatel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "FS.h"
#include <ESP8266WiFi.h>
const char* ssid = "SSID";
const char* password = "PASS";
String buf;
WiFiServer server(80);
void formatFS(void){
SPIFFS.format();
}
void createFile(void){
File wFile;
//Cria o arquivo se ele não existir
if(SPIFFS.exists("/log.txt")){
Serial.println("Arquivo ja existe!");
} else {
Serial.println("Criando o arquivo...");
wFile = SPIFFS.open("/log.txt","w+");
//Verifica a criação do arquivo
if(!wFile){
Serial.println("Erro ao criar arquivo!");
} else {
Serial.println("Arquivo criado com sucesso!");
}
}
wFile.close();
}
void deleteFile(void) {
//Remove o arquivo
if(SPIFFS.remove("/log.txt")){
Serial.println("Erro ao remover arquivo!");
} else {
Serial.println("Arquivo removido com sucesso!");
}
}
void writeFile(String msg) {
//Abre o arquivo para adição (append)
//Inclue sempre a escrita na ultima linha do arquivo
File rFile = SPIFFS.open("/log.txt","a+");
if(!rFile){
Serial.println("Erro ao abrir arquivo!");
} else {
rFile.println("Log: " + msg);
Serial.println(msg);
}
rFile.close();
}
void readFile(void) {
//Faz a leitura do arquivo
File rFile = SPIFFS.open("/log.txt","r");
Serial.println("Reading file...");
while(rFile.available()) {
String line = rFile.readStringUntil('\n');
buf += line;
buf += "<br />";
}
rFile.close();
}
void closeFS(void){
SPIFFS.end();
}
void openFS(void){
//Abre o sistema de arquivos
if(!SPIFFS.begin()){
Serial.println("Erro ao abrir o sistema de arquivos");
} else {
Serial.println("Sistema de arquivos aberto com sucesso!");
}
}
void setup(void){
//Configura a porta serial para 115200bps
Serial.begin(115200);
//Abre o sistema de arquivos (mount)
openFS();
//Cria o arquivo caso o mesmo não exista
createFile();
writeFile("Booting ESP8266...");
writeFile("Connecting to " + (String)ssid);
//Inicia a conexão WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
writeFile("WiFi connected");
Serial.println(WiFi.localIP());
//Inicia o webserver
server.begin();
writeFile("Web Server started");
}
void loop(void){
//Tratamento das requisições http
WiFiClient client = server.available();
if (!client) {
return;
}
Serial.println("new client");
while(!client.available()){
delay(1);
}
String req = client.readStringUntil('\r');
Serial.println(req);
client.flush();
buf = "";
buf += "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n";
buf += "<h3 style=""text-align: center;"">ESP8266 Web Log</h3>";
buf += "<p>";
readFile();
buf += "</p>";
buf += "<h4>Criado por Pedro Minatel</h4>";
buf += "</html>\n";
client.print(buf);
client.flush();
Serial.println("Client disonnected");
}
Para limpar o log, utilize a função formatFS().
Esse projeto pode ser customizado para incluir outros logs ou fazer que o ESP atue em modo AP, facilitando a coleta de dados em ambientes sem WiFi.
Para visualizar os logs, basta acessar o endereço IP do ESP.
Conclusão
Quando um projeto está em teste, é muito importante saber tudo o que aconteceu, mesmo quando não estamos olhando o tempo todo para ele. Esse sistema facilita essa atividade de monitoramento remoto, podendo deixar o projeto por vários dias sem se preocupar com o que está acontecendo, facilitando muito a análise de problemas ou comportamentos inesperados, mesmo de forma off-line.





