Desenvolvimento

24 fev, 2017

Webserver log no ESP8266 com SPIFFS

Publicidade

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