À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.