WiFi FTP Client

The project started with a WiFi FTP Server and was later changed to a WiFi FTP Client.

Since end of 2014 there is a very interesting WiFi module with application processor (32 bit) on the market, called ESP8266, at a price of about 3 EUR. The main application is a Serial to WiFi Bridge, named AT. But it can do a lot more, see at WiFiCar-NodeMCU#ESP8266_module.

Since May 2015 there is a very useful, low cost (about $7) WiFi module on the market, NodeMCU (Version 1.0, ESP-12, ESP8266), which allows program development in C under the Arduino IDE (Integrated Develop Environment).

The Arduino IDE has the advantage to work under the 3 major PC Operating Systems Linux, Mac OS X, Windows, and simplifies the embedded SoC (Systerm On Chip) application.

The NodeMCU module has the advantage of an USB interface, which supplies the operating voltage +5 V, and allows to use the Arduino Serial Monitor for debugging.

I needed to send Temperature data every 2 minutes to a FTP Server. Unfortunately I did not found any example for that. The example from Arduino FTP had some difficulties to port to ESP8266WiFi. The now working example is shown in the source listing on this page.

NodeMCU FTP Client

/!\ I made all programming with the Arduino IDE version 1.6.6 and the actual ESP8266 github version.

/!\ A big Thank You for all the genius programmers, who created that.

The program was tested with success with the following FTP Server:

Explanations:

After download (copy & paste) please name the extension to .ino for the Arduino IDE.

Before doing a copy of the source code, switch off the line numbers with click on the Link on top of the source listing.

   1 // File: WiWi_FTP_Client.ino for ESP8266 NodeMCU
   2 /*
   3    Original Arduino: FTP passive client 
   4    http://playground.arduino.cc/Code/FTP
   5    Modified 6 June 2015 by SurferTim
   6 
   7    You can pass flash-memory based strings to Serial.print() by wrapping them with F().
   8 
   9    2015-12-09 Rudolf Reuter, adapted to ESP8266 NodeMCU, with the help of Markus.
  10 */
  11 #include <ESP8266WiFi.h>
  12 #include <FS.h>
  13 
  14 // comment out next line to write to SD from FTP server
  15 #define FTPWRITE
  16 
  17 // Set these to your desired softAP credentials. They are not configurable at runtime.
  18 const char *ssid = "FRITZ-7170R";
  19 const char *password = "xxxxxxxx";
  20 
  21 boolean debug = false;  // true = more messages
  22 //boolean debug = true;
  23 
  24 // LED is needed for failure signalling
  25 const short int BUILTIN_LED2 = 16;  //GPIO16 on NodeMCU (ESP-12)
  26 
  27 unsigned long startTime = millis();
  28 
  29 // provide text for the WiFi status
  30 const char *str_status[]= {
  31   "WL_IDLE_STATUS",
  32   "WL_NO_SSID_AVAIL",
  33   "WL_SCAN_COMPLETED",
  34   "WL_CONNECTED",
  35   "WL_CONNECT_FAILED",
  36   "WL_CONNECTION_LOST",
  37   "WL_DISCONNECTED"
  38 };
  39 
  40 // provide text for the WiFi mode
  41 const char *str_mode[]= { "WIFI_OFF", "WIFI_STA", "WIFI_AP", "WIFI_AP_STA" };
  42 
  43 // change to your server
  44 IPAddress server( 192, 168, 17, 72 );
  45 
  46 WiFiClient client;
  47 WiFiClient dclient;
  48 
  49 char outBuf[128];
  50 char outCount;
  51 
  52 // change fileName to your file (8.3 format!)
  53 String fileName = "TimeTemp.txt";
  54 String  path = "/TimeTemp.txt";
  55 
  56 // SPIFFS file handle
  57 File fh;
  58 
  59 void signalError() {  // loop endless with LED blinking in case of error
  60   while(1) {
  61       digitalWrite(BUILTIN_LED2, LOW);
  62       delay(300); // ms
  63       digitalWrite(BUILTIN_LED2, HIGH);
  64       delay(300); // ms
  65   }
  66 }
  67 
  68 //format bytes
  69 String formatBytes(size_t bytes) {
  70   if (bytes < 1024) {
  71     return String(bytes) + "B";
  72   } else if (bytes < (1024 * 1024)) {
  73     return String(bytes / 1024.0) + "KB";
  74   } else if (bytes < (1024 * 1024 * 1024)) {
  75     return String(bytes / 1024.0 / 1024.0) + "MB";
  76   } else {
  77     return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB";
  78   }
  79 }
  80 
  81 //----------------------- WiFi handling
  82 void connectWifi() {
  83   Serial.print("Connecting as wifi client to SSID: ");
  84   Serial.println(ssid);
  85 
  86   // use in case of mode problem
  87   WiFi.disconnect();
  88   // switch to Station mode
  89   if (WiFi.getMode() != WIFI_STA) {
  90     WiFi.mode(WIFI_STA);
  91   }
  92 
  93   WiFi.begin ( ssid, password );
  94 
  95   if (debug ) WiFi.printDiag(Serial);
  96 
  97   // ... Give ESP 10 seconds to connect to station.
  98   unsigned long startTime = millis();
  99   while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000) {
 100     delay(500);
 101     Serial.print(".");
 102   }
 103   Serial.println("");
 104   // Check connection
 105   if (WiFi.status() == WL_CONNECTED) {
 106     Serial.print("WiFi connected; IP address: ");
 107     Serial.println(WiFi.localIP());
 108   } else {
 109     Serial.print("WiFi connect failed to ssid: ");
 110     Serial.println(ssid);
 111     Serial.print("WiFi password <");
 112     Serial.print(password);
 113     Serial.println(">");
 114     Serial.println("Check for wrong typing!");
 115   }
 116 }  // connectWiFi()
 117 
 118 //----------------- FTP fail
 119 void efail() {
 120   byte thisByte = 0;
 121 
 122   client.println(F("QUIT"));
 123 
 124   while (!client.available()) delay(1);
 125 
 126   while (client.available()) {
 127     thisByte = client.read();
 128     Serial.write(thisByte);
 129   }
 130 
 131   client.stop();
 132   Serial.println(F("Command disconnected"));
 133   fh.close();
 134   Serial.println(F("SD closed"));
 135 }  // efail
 136 
 137 //-------------- FTP receive
 138 byte eRcv() {
 139   byte respCode;
 140   byte thisByte;
 141 
 142   while (!client.available()) delay(1);
 143 
 144   respCode = client.peek();
 145 
 146   outCount = 0;
 147 
 148   while (client.available()) {
 149     thisByte = client.read();
 150     Serial.write(thisByte);
 151 
 152     if (outCount < 127) {
 153       outBuf[outCount] = thisByte;
 154       outCount++;
 155       outBuf[outCount] = 0;
 156     }
 157   }
 158 
 159   if (respCode >= '4') {
 160     efail();
 161     return 0;
 162   }
 163   return 1;
 164 }  // eRcv()
 165 
 166 //--------------- FTP handling
 167 byte doFTP(boolean upload) {
 168   
 169   if (upload) {
 170     fh = SPIFFS.open(path, "r");
 171   } else {
 172     SPIFFS.remove(path);
 173     fh = SPIFFS.open(path, "w");
 174   }
 175 
 176   if (!fh) {
 177     Serial.println(F("SPIFFS open fail"));
 178     return 0;
 179   }
 180 
 181   if (upload) {
 182     if (!fh.seek((uint32_t)0, SeekSet)) {
 183       Serial.println(F("Rewind fail"));
 184       fh.close();
 185       return 0;
 186     }
 187   }
 188 
 189   if (debug) Serial.println(F("SPIFFS opened"));
 190 
 191   if (client.connect(server, 21)) {  // 21 = FTP server
 192     Serial.println(F("Command connected"));
 193   } else {
 194     fh.close();
 195     Serial.println(F("Command connection failed"));
 196     return 0;
 197   }
 198 
 199   if (!eRcv()) return 0;
 200   if (debug) Serial.println("Send USER");
 201   client.println(F("USER rudi"));
 202 
 203   if (!eRcv()) return 0;
 204   if (debug) Serial.println("Send PASSWORD");
 205   client.println(F("PASS <password>"));
 206 
 207   if (!eRcv()) return 0;
 208   if (debug) Serial.println("Send SYST");
 209   client.println(F("SYST"));
 210 
 211   if (!eRcv()) return 0;
 212   if (debug) Serial.println("Send Type I");
 213   client.println(F("Type I"));
 214 
 215   if (!eRcv()) return 0;
 216   if (debug) Serial.println("Send PASV");
 217   client.println(F("PASV"));
 218 
 219   if (!eRcv()) return 0;
 220 
 221   char *tStr = strtok(outBuf, "(,");
 222   int array_pasv[6];
 223   for ( int i = 0; i < 6; i++) {
 224     tStr = strtok(NULL, "(,");
 225     array_pasv[i] = atoi(tStr);
 226     if (tStr == NULL) {
 227       Serial.println(F("Bad PASV Answer"));
 228     }
 229   }
 230   unsigned int hiPort, loPort;
 231   hiPort = array_pasv[4] << 8;
 232   loPort = array_pasv[5] & 255;
 233 
 234   if (debug) Serial.print(F("Data port: "));
 235   hiPort = hiPort | loPort;
 236   if (debug) Serial.println(hiPort);
 237 
 238   if (dclient.connect(server, hiPort)) {
 239     Serial.println(F("Data connected"));
 240   }
 241   else {
 242     Serial.println(F("Data connection failed"));
 243     client.stop();
 244     fh.close();
 245     return 0;
 246   }
 247 
 248   if (upload) {
 249     if (debug) Serial.println("Send STOR filename");
 250     client.print(F("STOR "));
 251     client.println(fileName);
 252   } else {
 253     if (debug) Serial.println("Send RETR filename");
 254     client.print(F("RETR "));
 255     client.println(fileName);
 256   }
 257 
 258   if (!eRcv()) {
 259     dclient.stop();
 260     return 0;
 261   }
 262 
 263   if (upload) {
 264     if (debug) Serial.println(F("Writing"));
 265     // for faster upload increase buffer size to 1460
 266 //#define bufSizeFTP 64
 267 #define bufSizeFTP 1460
 268     uint8_t clientBuf[bufSizeFTP];
 269     //unsigned int clientCount = 0;
 270     size_t clientCount = 0;
 271   
 272     while (fh.available()) {
 273       clientBuf[clientCount] = fh.read();
 274       clientCount++;
 275       if (clientCount > (bufSizeFTP - 1)) {
 276         dclient.write((const uint8_t *) &clientBuf[0], bufSizeFTP);
 277         clientCount = 0;
 278         delay(1);
 279       }
 280     }
 281     if (clientCount > 0) dclient.write((const uint8_t *) &clientBuf[0], clientCount);
 282 
 283   } else {
 284     while (dclient.connected()) {
 285       while (dclient.available()) {
 286         char c = dclient.read();
 287         fh.write(c);
 288         if (debug) Serial.write(c);
 289       }
 290     }
 291   }
 292 
 293   dclient.stop();
 294   Serial.println(F("Data disconnected"));
 295 
 296   if (!eRcv()) return 0;
 297 
 298   client.println(F("QUIT"));
 299 
 300   if (!eRcv()) return 0;
 301 
 302   client.stop();
 303   Serial.println(F("Command disconnected"));
 304 
 305   fh.close();
 306   if (debug) Serial.println(F("SPIFS closed"));
 307   return 1;
 308 }  // doFTP()
 309 
 310 
 311 void readSPIFFS() {
 312   fh = SPIFFS.open(fileName, "r");
 313 
 314   if (!fh) {
 315     Serial.println(F("SPIFFS open fail"));
 316     return;
 317   }
 318 
 319   while (fh.available()) {
 320     Serial.write(fh.read());
 321   }
 322 
 323   fh.close();
 324 }  // readSPIFFS()
 325 
 326 
 327 void setup() {
 328   delay(1000);
 329   Serial.begin(115200);
 330   delay(1000);
 331   Serial.println("Sync,Sync,Sync,Sync,Sync");
 332   delay(500);
 333   Serial.println();
 334   // signal start
 335   pinMode(BUILTIN_LED2, OUTPUT);
 336   digitalWrite(BUILTIN_LED2, LOW);
 337   delay(100); // ms
 338   digitalWrite(BUILTIN_LED2, HIGH);
 339   delay(300); // ms
 340 
 341   Serial.print("Chip ID: 0x");
 342   Serial.println(ESP.getChipId(), HEX);
 343 
 344   Serial.println ( "Connect to Router requested" );
 345   connectWifi();
 346   if (WiFi.status() == WL_CONNECTED) {
 347     Serial.print("WiFi mode: ");
 348     Serial.println(str_mode[WiFi.getMode()]);
 349     Serial.print ( "Status: " );
 350     Serial.println (str_status[WiFi.status()]);
 351     // signal WiFi connect
 352     digitalWrite(BUILTIN_LED2, LOW);
 353     delay(300); // ms
 354     digitalWrite(BUILTIN_LED2, HIGH);      
 355   } else {
 356     Serial.println("");
 357     Serial.println("WiFi connect failed, push RESET button.");
 358     signalError();
 359   }
 360 
 361   if (!SPIFFS.begin()) {
 362      Serial.println("SPIFFS failed, needs formatting");
 363      signalError();
 364   }
 365 
 366   fh = SPIFFS.open(path, "r");
 367   if (!fh) {
 368     Serial.println(F("SPIFFS open fail"));
 369     signalError();
 370   } else fh.close();
 371   
 372   Serial.println(F("Ready. Press d, u or r"));
 373 }  // setup()
 374 
 375 
 376 void loop() {
 377   byte inChar;
 378 
 379   if (Serial.available() > 0) {
 380     inChar = Serial.read();
 381   }
 382 
 383 boolean upload = true; // false = download
 384 
 385   if (inChar == 'd') {
 386     upload = false;
 387     if (doFTP(upload)) Serial.println(F("FTP OK"));
 388     else Serial.println(F("FTP FAIL"));
 389   }
 390   
 391   if (inChar == 'u') {
 392     upload = true;
 393     if (doFTP(upload)) Serial.println(F("FTP OK"));
 394     else Serial.println(F("FTP FAIL"));
 395   }  
 396 
 397   if (inChar == 'r') {
 398     String fileNameDir;
 399     Dir dir = SPIFFS.openDir("/");
 400     while (dir.next()) {
 401       fileNameDir = dir.fileName();
 402       size_t fileSize = dir.fileSize();
 403       Serial.printf("FS File: %s, size: %s\n", fileNameDir.c_str(), formatBytes(fileSize).c_str());
 404     }
 405   }
 406   delay(10);  // give time to the WiFi handling in the background
 407 }

NodeMCU

NodeMCU is an ESP-12E module mounted on a carrier board, together with an USB to serial converter. Have a look to the user manual, see Links #12. In short some details:

Wikipedia has some information, at Links #13.

Community Forum and Wiki

There is a ESP8266 Community Forum and wiki at Links #22. I will mention important postings.

  1. 2WD L293D WiFi RC Smart Car with NodeMCU + Shield for ESP-12E based on ESP8266

  2. wikipedia.de - ESP8266 (German)

  3. www.mikrocontroller.net - ESP8266 Info (German)

  4. wikipedia.org - ESP8266 modules

  5. NodeMCU, pinout, schematic

  6. NodeMCU firmware API 0.95

  7. Motor Shield Board (L293DD) for NodeMCU from ESP8266 ESP-12E

  8. Shenzhen Doctors of Intelligence & Technology

  9. Doit WiFi car manual

  10. ESP-12E module documentation

  11. Adafruit.com, ESP-12E specification

  12. NodeMCU manual (ESP-12E)

  13. wikipedia.com, NodeMCU

  14. ESP-12E motor shield, user manual

  15. WiFi-Car control with smart phone orientation

  16. AJAX programming

  17. Arduino ESP8266 plugin

  18. ESP8266 Arduino Core Reference API

  19. Mozilla Developer Network, DeviceMotionEvent.acceleration

  20. W3C, DeviceOrientation Event Specification

  21. html5rocks.com, This End Up: Using Device Orientation

  22. ESP8266 Community Forum and wiki

  23. hackaday.io ESP8266 WiFi Module Library

  24. 2. Get ESP8266 source code

  25. ESP8266 Documents, Firmware

  26. Forum of company espressif for ESP8266

  27. ESP8266 WiFi Module Quick Start Guide

  28. electrodragon, ESP8266 wiki, ESP8266 IC pinout

  29. ESP8266 flashing LUA firmware

  30. LUA nodemcu ESP8266 firmware

  31. Wlan2Serial Modul für 5 euro (German Forum

  32. msxfaq.de, many Links for NodeMCU and LUA (German)

List of pages in this category:

-- RudolfReuter 2015-12-10 09:59:25


Go back to CategoryAVR or StartSeite ; KontaktEmail (ContactEmail)

WiFiFTPServer (last edited 2018-04-20 20:38:19 by RudolfReuter)