Server FTP su esp8266 ed esp32

Spread the love

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.

FTP file transfer on esp8266 or esp32

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

SimpleFTPServer sull'Arduino library manager
SimpleFTPServer sull’Arduino library manager

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.

Filezilla configuration for access esp8266, select plain FTP on Manage Site

Per prima cosa devi andare su Manage site --> New site e ora imposta questo parametro:

  • Seleziona FTP come protocollo;
  • Seleziona Use plain FTP (insecure);
  • Imposta la tua login e password (specificate sullo sketch);
  • Ora in Trasfer settings seleziona Maximun number of connection uguale a 1;
  • Ora connettiti il tuo dispositivo.
Filezilla configuration for access esp8266, select max num connections

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.

  1. Libreria SimpleFTPServer library: guida esp32 e esp8266
  2. Libreria SimpleFTPServer: guida WioTerminal
  3. Server FTP su STM32 con W5500, ENC28J60, scheda SD e memoria flash SPI
  4. Tutorial libreria MultiFTPServer per ESP32, Raspberry Pi Pico, Arduino, RP2040, ESP8266 e STM32

Spread the love

13 Risposte

  1. Gabryx ha detto:

    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

  2. Gabryx ha detto:

    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

    • Renzo Mischianti ha detto:

      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

  3. Francesco ha detto:

    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

    • Renzo Mischianti ha detto:

      Ciao Francesco,
      devi modificare EMailSenderKey.h in 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

      • Francesco ha detto:

        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

        • Renzo Mischianti ha detto:

          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

  4. Roberto ha detto:

    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.

    • Renzo Mischianti ha detto:

      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

Rispondi a Roberto Annulla risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *