Server FTP su esp8266 ed esp32
Quando sviluppo una nuova soluzione, vorrei dividere l’applicazione in layer e quindi poter focalizzare la mia attenzione su un solo aspetto alla volta.
In dettaglio separo il livello REST (scritto all’interno del microcontrollore) e il Front-End (scritto in Angular, React / Redux o vanilla JS), quindi vorrei caricare la nuova interfaccia web direttamente sul microcontrollore via FTP.

Per informazioni statiche (pagine Web per esempio), che non cambiano frequentemente, esp8266 o esp32 possono sfruttare lo SPIFFS interno (SPI Flash File System) e puoi caricare dati tramite Arduino IDE come spiegato nell’articolo “WeMos D1 mini (esp8266): sistema operativo integrato SPIFFS” per l’esp8266 “ESP32: FileSystem SPIFFS integrato” per l’esp32 oppure il LittleFS “WeMos D1 mini (esp8266): FileSystem integrato LittleFS” per esp8266 o “ESP32: filesystem integrato LittleFS” per esp32 o FFAT “ESP32: filesystem integrato FFat (Fat/exFAT)” oppure con Arduino per caricare file sull’SD, per operazioni veloci e supporto futuro trovo utile il protocollo FTP.
Ho trovato una semplice libreria che funziona abbastanza bene e non è affamata di risorse, puoi trovarla qui.
Nel tempo questa libreria diventa buggata e con un supporto molto basso quindi l’ho aggiustata e ora puoi recuperare la libreria da qui.
Libreria
La mia nuova libreria è ora disponibile tramite il Library Manager dell’Arduino IDE
Ma anche su GitHub.
Fare clic sul pulsante DOWNLOADS nell’angolo in alto a destra, rinominare la cartella non compressa PCF8574.
Verificare che la cartella SimpleFTPServer contenga FtpServer.cpp, FtpServer.h, FtpServerKey.h e SimpleFTPServer.h .
Collocare la cartella della libreria SimpleFTPServer come / librerie / cartella.
Potrebbe essere necessario creare la sottocartella librerie se è la tua prima libreria.
Riavvia l’IDE.
Selezionare il FS su esp8266
Puoi inoltre abilitare il LittleFS per l’esp8266, andando a modificare nel file FtpServerKey.h la riga
#define DEFAULT_STORAGE_TYPE_ESP8266 STORAGE_SPIFFS
in
#define DEFAULT_STORAGE_TYPE_ESP8266 STORAGE_LITTLEFS
Uso
Ecco un esempio per esp8266
/*
* WeMos D1 mini (esp8266)
* Start FTP server to upload data on SPIFFS
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org/wemos-d1-mini-esp8266-integrated-spiffs-filesistem-part-2/
*
*/
#include "Arduino.h"
#include <ESP8266WiFi.h>
#include <SimpleFtpServer.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial
void setup(void){
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
/////FTP Setup, ensure SPIFFS is started before ftp; /////////
if (SPIFFS.begin()) {
SPIFFS.format();
Serial.println("SPIFFS opened!");
ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV)
}
}
void loop(void){
ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!!
}
Selezionare il FS su esp32
Puoi abilitare il LittleFS per l’esp32, andando a modificare nel file FtpServerKey.h la riga
#define DEFAULT_STORAGE_TYPE_ESP32 STORAGE_SPIFFS
in
#define DEFAULT_STORAGE_TYPE_ESP32 STORAGE_LITTLEFS
or questo per FFAT
#define DEFAULT_STORAGE_TYPE_ESP32 STORAGE_FFAT
Ecco qui la lista completa delle opzioni.
#define STORAGE_SDFAT1 1 // Library SdFat version 1.4.x
#define STORAGE_SDFAT2 2 // Library SdFat version >= 2.0.2
#define STORAGE_SPIFM 3 // Libraries Adafruit_SPIFlash and SdFat-Adafruit-Fork
#define STORAGE_FATFS 4 // Library FatFs
#define STORAGE_SD 5 // Standard SD library (suitable for Arduino esp8266 and esp32
#define STORAGE_SPIFFS 6 // SPIFFS
#define STORAGE_LITTLEFS 7 // LITTLEFS
#define STORAGE_SEEED_SD 8 // Seeed_SD library
#define STORAGE_FFAT 9 // ESP32 FFAT
#define STORAGE_SD_MMC 10 // SD_MMC library
Naturalmente non tutte compatibili con i nostri microcontrollori.
Uso
Qui per esp32
/*
* ESP32 Dev Kit (esp32)
* Start FTP server to upload data on SPIFFS
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org/wemos-d1-mini-esp8266-integrated-spiffs-filesistem-part-2/
*
*/
#include <WiFi.h>
#include "SPIFFS.h"
#include <SimpleFtpServer.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial
void setup(void){
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
/////FTP Setup, ensure SPIFFS is started before ftp; /////////
if (SPIFFS.begin(true)) {
Serial.println("SPIFFS opened!");
ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. set ports in ESP8266FtpServer.h (default 21, 50009 for PASV)
}
}
void loop(void){
ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!!
}
Questa libreria supporta solo la modalità passiva ed è necessario forzare solo una connessione alla volta.
Uso FileZilla come client, puoi scaricarlo qui, è abbastanza semplice sia da usare che configurare.
Per prima cosa devi andare su Manage site --> New site e ora imposta questo parametro:
- Seleziona
FTPcome protocollo; - Seleziona
Use plain FTP (insecure); - Imposta la tua login e password (specificate sullo sketch);
- Ora in
Trasfer settingsselezionaMaximun number of connectionuguale a 1; - Ora connettiti il tuo dispositivo.
Ora puoi gestire il tuo SPIFFS con il drag and drop.
Ricorda che SPIFFS non gestisce le cartelle, quindi tutti i file devono essere piatti.
Test
Per verificare il caricamento è possibile utilizzare il semplice sketch utilizzato nell’articolo SPIFFS sopra lincato:
/*
* WeMos D1 mini (esp8266)
* SPIFFS get info, read dir and show all file uploaded
* add a data folder to use with esp8266 data uploader
* by Mischianti Renzo <https://mischianti.org>
*
* https://mischianti.org/wemos-d1-mini-esp8266-integrated-spiffs-filesistem-part-2/
*
*/
#include "Arduino.h"
#include "FS.h"
void setup()
{
Serial.begin(112500);
delay(500);
Serial.println(F("Inizializing FS..."));
if (SPIFFS.begin()){
Serial.println(F("done."));
}else{
Serial.println(F("fail."));
}
// To format all space in SPIFFS
// SPIFFS.format()
// Get all information of your SPIFFS
FSInfo fs_info;
SPIFFS.info(fs_info);
Serial.println("File sistem info.");
Serial.print("Total space: ");
Serial.print(fs_info.totalBytes);
Serial.println("byte");
Serial.print("Total space used: ");
Serial.print(fs_info.usedBytes);
Serial.println("byte");
Serial.print("Block size: ");
Serial.print(fs_info.blockSize);
Serial.println("byte");
Serial.print("Page size: ");
Serial.print(fs_info.totalBytes);
Serial.println("byte");
Serial.print("Max open files: ");
Serial.println(fs_info.maxOpenFiles);
Serial.print("Max path length: ");
Serial.println(fs_info.maxPathLength);
Serial.println();
// Open dir folder
Dir dir = SPIFFS.openDir("/");
// Cycle all the content
while (dir.next()) {
// get filename
Serial.print(dir.fileName());
Serial.print(" - ");
// If element have a size display It else write 0
if(dir.fileSize()) {
File f = dir.openFile("r");
Serial.println(f.size());
f.close();
}else{
Serial.println("0");
}
}
}
void loop()
{
}
Test con callback
Un’interessante feature che ho aggiunto di recente sono le callback su alcune azioni
/*
* FtpServer esp8266 and esp32 with SPIFFS
*
* AUTHOR: Renzo Mischianti
*
* https://mischianti.org/ftp-server-on-esp8266-and-esp32
*
*/
#ifdef ESP8266
#include <ESP8266WiFi.h>
#elif defined ESP32
#include <WiFi.h>
#include "SPIFFS.h"
#endif
#include <SimpleFTPServer.h>
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASS";
FtpServer ftpSrv; //set #define FTP_DEBUG in ESP8266FtpServer.h to see ftp verbose on serial
void _callback(FtpOperation ftpOperation, unsigned int freeSpace, unsigned int totalSpace){
switch (ftpOperation) {
case FTP_CONNECT:
Serial.println(F("FTP: Connected!"));
break;
case FTP_DISCONNECT:
Serial.println(F("FTP: Disconnected!"));
break;
case FTP_FREE_SPACE_CHANGE:
Serial.printf("FTP: Free space change, free %u of %u!\n", freeSpace, totalSpace);
break;
default:
break;
}
};
void _transferCallback(FtpTransferOperation ftpOperation, const char* name, unsigned int transferredSize){
switch (ftpOperation) {
case FTP_UPLOAD_START:
Serial.println(F("FTP: Upload start!"));
break;
case FTP_UPLOAD:
Serial.printf("FTP: Upload of file %s byte %u\n", name, transferredSize);
break;
case FTP_TRANSFER_STOP:
Serial.println(F("FTP: Finish transfer!"));
break;
case FTP_TRANSFER_ERROR:
Serial.println(F("FTP: Transfer error!"));
break;
default:
break;
}
/* FTP_UPLOAD_START = 0,
* FTP_UPLOAD = 1,
*
* FTP_DOWNLOAD_START = 2,
* FTP_DOWNLOAD = 3,
*
* FTP_TRANSFER_STOP = 4,
* FTP_DOWNLOAD_STOP = 4,
* FTP_UPLOAD_STOP = 4,
*
* FTP_TRANSFER_ERROR = 5,
* FTP_DOWNLOAD_ERROR = 5,
* FTP_UPLOAD_ERROR = 5
*/
};
void setup(void){
Serial.begin(115200);
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
/////FTP Setup, ensure SPIFFS is started before ftp; /////////
/////FTP Setup, ensure SPIFFS is started before ftp; /////////
#ifdef ESP32 //esp32 we send true to format spiffs if cannot mount
if (SPIFFS.begin(true)) {
#elif defined ESP8266
if (SPIFFS.begin()) {
#endif
ftpSrv.setCallback(_callback);
ftpSrv.setTransferCallback(_transferCallback);
Serial.println("SPIFFS opened!");
ftpSrv.begin("esp8266","esp8266"); //username, password for ftp. (default 21, 50009 for PASV)
}
}
void loop(void){
ftpSrv.handleFTP(); //make sure in loop you call handleFTP()!!
// server.handleClient(); //example if running a webserver you still need to call .handleClient();
}
Qui un semplice upload del file README.md
.......
Connected to reef-casa-sopra
IP address: 192.168.1.127
LittleFS opened!
FTP: Connected!
FTP: Upload start!
FTP: Upload of file README.md byte 1072
FTP: Upload of file README.md byte 3120
FTP: Upload of file README.md byte 3559
FTP: Finish transfer!
FTP: Free space change, free 1019904 of 1036288!
Grazie.
- Libreria SimpleFTPServer library: guida esp32 e esp8266
- Libreria SimpleFTPServer: guida WioTerminal
- Server FTP su STM32 con W5500, ENC28J60, scheda SD e memoria flash SPI
- Tutorial libreria MultiFTPServer per ESP32, Raspberry Pi Pico, Arduino, RP2040, ESP8266 e STM32






Ok funziona tutto, 300Kb al secondo di transfer rate con Esp32 Dev Kit V1 e Ili9488 touch screen, librerie TFT_eSPI e LVGL.
Unica cosa che non mi sembra a posto è un warning in fase di compilazione con Arduino Ide:
SimpleFTPServer/FtpServer.h:639:30: warning: ‘packed’ attribute ignored for field of type ‘uint8_t [2048]’ {aka ‘unsigned char [2048]’} [-Wattributes]
… bisogna cambiare la dichiarazione in FtpServerKey?
Grazie e ciao
Oppure quella in FtpServer.h
uint8_t __attribute__((packed, aligned(4))) // need to be aligned to 32bit for Esp8266 SPIClass::transferBytes()
buf[ FTP_BUF_SIZE ]; // data buffer for transfers
Ciao Gabryx,
quello è solo uno warning, per altre architetture è utile, per l’esp32 andrebbe rimosso, ma visto che lo fa in automatico il compilatore l’ho lasciato.
Vedremo nei rilasci futuri.
Ciao Renzo
Buongiorno,
è possibile utilizzare solo la connessione cablata con un w5500 su esp8266 o esp32? ho provato ad adattare gli esempi proposti con la libreria ma non sono riuscito a venirne a capo.
Grazie
Francesco
Ciao Francesco,
devi modificare
EMailSenderKey.hin questo modo:// esp8266 configuration
#ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP8266
#define DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP8266 NETWORK_W5100
#define DEFAULT_STORAGE_TYPE_ESP8266 STORAGE_LITTLEFS
#endif
// esp32 configuration
#ifndef DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32
#define DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32 NETWORK_W5100
#define DEFAULT_STORAGE_TYPE_ESP32 STORAGE_FFAT
#endif
Fammi sapere.
Ciao Renzo
Ciao Renzo,
ho provato a cambiare il file FtpServerKey.h (intendevi questo e non EMailSenderKey.h giusto?) seguendo le tue istruzione ma la compilazione non va mai a buon fine. A dire il vero non va a buon fine qualunque sia il valore che metto in DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP32 o DEFAULT_FTP_SERVER_NETWORK_TYPE_ESP8266.
Sconfortato o anche provato a prendere una ENC28j60 e provare l’esempio ESP32_FFAT_enc28j60.ino ma in questo caso non riesce mai a montare FFat, e se modifico sostituendo FFat con SPIFFS o LittleFS al momento del ftpSrv.begin la scheda va in loop.
Saluti disperati
Francesco
Hehehehe.. diciamo che ho poche informazioni per poterti aiutare..
Apri un Topic sul forum e posta il tuo codice e come hai “configurato” il microcontrollore sull’arduino IDE.
Ciao Renzo
Ciao Renzo,
Sto utilizzando la tua libreria per un mio piccolo esperimento ma sto avendo difficoltà a districarmi con l’utilizzo di client FTP su Android.
Andando con ordine, la mia architettura prevede l’utilizzo dei seguenti elementi (i principali) hardware:
– ESP32 DevKit C V4
– Lettore MicroSD Card su SPI
Per ora sto utilizzando il WiFi per collegarmi alla rete ma ho in programma di integrare anche un ENC28J60 per usare direttamente la connessione via ethernet.
L’obiettivo è quello di ricevere i file video di una IP-CAM che permette l’utilizzo del protocollo FTP ma con qualche limitazione che spiego di seguito.
In primo luogo ho dovuto fare alcune piccole modifiche al codice della libreria, per avere la completa compatibilità con la IP-CAM che utilizza una versione datata del protocollo FTP (in particolare ho dovuto aggiungere la compatibilità di alcuni comandi FTP in osservanza dei vecchi RFC 775 e RFC 1123, che prevedevano che alcuni comandi come
XPWD, XMKD e XRMD fossero considerati sinonimi rispettivamente di PWD, MKD e RMD, tale circostanza è dovuta principalmente a problemi di compatibilità con i vecchi firewall che esigevano che tutti i comandi FTP avessero una lunghezza di esattamente quattro caratteri). Ho fatto anche un altro paio di correzioni credo per un errore nell’utilizzo dei flag del pre-compiler che ho riportato, commentandoli opportunamente, nella copia della libreria che trovi nel mio repository GITHUB https://github.com/robertopapi/esp32/tree/main/personal_ftpserver/MultiFTPServer.
Arrivando al problema, ho provato ad utilizzare alcuni client FTP su Android e tutti hanno dato il medesimo risultato e cioè i nomi dei file e delle directory sono sempre costituiti da giorno del mese, ore, minuti e finalmente il nome file o della directory, quando è eseguito il comando FTP MLSD. Questo accade sistematicamente a prescindere i comandi che lo precedono (un esempio di log lato client è quello disponibilie qui https://github.com/robertopapi/esp32/blob/587e630d40c67c2ef1f819fcd351a06fc47dd77d/personal_ftpserver/x-plore_ftp_log.txt).
Per completezza ho usato senza successo i seguenti client:
– X-plore
– AndFTP
– Total Commander + FTP Plugin for Total Commander
– File Manager
tale fenomeno viceversa NON si manifesta se da PC uso i classici Filezilla, WinSCP o comando ftp da linea di comando.
Ciao Roberto,
Grazie per i dettagli e per le informazioni riguardo alle modifiche per la compatibilità con i vecchi RFC. È interessante vedere come stai adattando la libreria per il tuo progetto con la IP-CAM.
In merito al problema che riscontri con i client Android (nomi file che includono data e ora), ti confermo che ho testato personalmente la versione originale di MultiFtpServer con AndFTP e funziona correttamente: la lista dei file viene visualizzata in modo pulito, senza i prefissi temporali che descrivi.
Purtroppo, in questo periodo non ho il tempo materiale per analizzare il codice che hai modificato o fare debug sulla tua specifica implementazione per capire cosa possa aver innescato questo comportamento anomalo nella risposta al comando MLSD.
Dato che sulla versione standard il problema non si presenta, ti suggerisco di ricontrollare se le modifiche apportate o la configurazione specifica possano aver introdotto qualche formato non standard che confonde il parser dei client Android.
Buona fortuna con il proseguimento del tuo progetto.
Un saluto, Renzo
Ciao Renzo,
grazie per la prontissima risposta.
Purtroppo mi sono rassegnato a scriverti solo dopo aver controllato dettagliatamente il codice, sopratutto in considerazione che le pochissime modifiche che ho apportato alla libreria sono successive al manifestarsi del problema e sono limitate, oltre che alla compatibilità dei comandi FTP indicati, esclusivamente alla risoluzione di due problemi:
– numero dei byte totali e usati della SD nella chiamata alla transfer callback (restituivano sempre 1)
– alla invocazione della funzione generateFileLine(), che invece di utilizzare il contenuto della variabile time utilizzava la stringa fissa “Jan 01 00:00” (prima della modifica il nome file su android conteneva appunto questa stringa e dopo viceversa giorno e ora di scrittura del file su SD)
Per entrambe le situazioni i flag del pre-compilatore STORAGE_SD_MMC e STORAGE_SD erano invertiti.
Ad ogni modo il codice modificato è a disposizione nel mio repository quindi, se lo ritieni importante, lo potrai consultare quando vuoi.
Grazie comunque per il lavoro che fai e per la grrande disponibilità.
A compendio della precedente risposta aggiungo lo screenshot del cell
https://github.com/robertopapi/esp32/blob/b8de17a32c1d5bc793ac2126ed176beb4ce86a54/personal_ftpserver/screenshot%20cell.png
e lo screenshot dei due log (uno per filezilla e l’altro per AndFTP) che dimostrano che lato libreria il comportamento è identico nei due casi (evidenziato da una freccia la riga di debug che ho aggiunto relativa alla invocazione della funzione generateFileLine() con tutti i suoi parametri)
https://github.com/robertopapi/esp32/blob/b8de17a32c1d5bc793ac2126ed176beb4ce86a54/personal_ftpserver/log.png
Risolto!
Il problema della mancata compatibilità con le app Android era dovuto dal fatto che queste richiedono la perfetta aderenza alla direttiva RFC 3659 (https://github.com/robertopapi/esp32/blob/main/personal_ftpserver/rfc3659.txt.pdf), in quanto usano tutte (pare) il comando MLSD che da standard è destinato alla comunicazione machine to machine e non accetta i contenuti UNIX-like della implementazione corrente della libreria.
Come in precedenza ho pubblicato sul mio repository la versione della libreria modificata (https://github.com/robertopapi/esp32/tree/main/personal_ftpserver/MultiFTPServer).
Grazie comunque per la disponibilità.
Ciao Roberto,
grazie per il feedback, come ti dicevo a me funziona correttamente con AndFTP, ma appena posso verifico meglio la casistica.
Grazie ancora Renzo