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:
- vsftpd (Linux version 3.0.2) Linux Ubuntu 14.04 32Bit
Explanations:
Constants: SSID and password of your WiFi-Router must be inserted, instead of the dots.
Function connectWifi() - tries to connect to a WiFi router.
Function signalError() - shows with endless blinking of the blue on-board LED a fatal error.
Function setup() - Initialization
- The blue LED is flashed for 100 ms, to show the start of the program.
The blue LED is flashed for 300 ms, to show the connection to the WiFi-Router.
Function loop() - In Arduino Serial Monitor
sending an r to the program, will show the SPIFFS files
sending an u will upload a predefined file from the SPIFFS to the FTP Server.
sending an d will download a predefined file from the FTP Server to the SPIFFS .
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:
NodeMCU = ESP-12E DevKit
- Support STA/AP/STA+AP 3 working modes
- 0~D8, SD1~SD3: used for GPIO, PWM, IIC, ect; the driven ability can be arrived at 15mA
- LED, blue on GPIO16, for debug purpose
- AD0: one-way ADC, 0 to 1.0 V, 10 bit = 0..1023
- Power input: 4.5V~9V(10VMAX), support USB powered and USB debug
- Working current: ≈70mA(200mA MAX, continue), standby<200uA
- Support update firmware remotely (OTA)
- Size: 25.4 x 48.3 x 13 mm
- Firmware supports LUA programming language
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.
- how is the code in the spi flash executed? is it memory mapped? or copied to (D)RAM?
- Copied to DRAM on reset
- The SoC is built around the Tensilica Xtensa LX3 processor (see the compiler info in the library binaries)
- The CPU is clocked at 80 MHz (esp_iot_sdk_v0.6/include/eagle_soc.h, line 58)
hackaday.io info, see Links #23
- how is the code in the spi flash executed? is it memory mapped? or copied to (D)RAM?
Official GCC compiler VM from Espressif
Alternative: github esp-open-sdk
Wireless Througput Tests with netio, about 20 KB/s RX.
Youtube, LUA firmware einrichten (German, 31 min, 2015-01-17)
Links
2WD L293D WiFi RC Smart Car with NodeMCU + Shield for ESP-12E based on ESP8266
Motor Shield Board (L293DD) for NodeMCU from ESP8266 ESP-12E
List of pages in this category:
-- RudolfReuter 2015-12-10 09:59:25
Go back to CategoryAVR or StartSeite ; KontaktEmail (ContactEmail)