Найти в Дзене
Ilya Engineer

Обновление прошивки esp8266 с ftp сервера. arduino IDE

1. Должен быть ftp сервер с доступом, на который Вы можете закинуть прощивку. 2. Библиотеки: #include <FS.h> 3. Параметры соединения и данные прошивки: char* xhost = "адрес ftp сервера"; // ftp сервер char* xusername = "логин сервера"; // логин ftp char* xpassword = "пароль сервера"; // пароль ftp char* xfolder = "папка с прошивкой на ftp сервере"; // папка с прошивками на ftp char* xfilename = "esp_fw.bin"; // имя файла на сервере Ftp char* xfile = "fw.bin"; // имя файла в файловой системе (с ftp сперва будем копировать на esp во флеш (скачивать)) 4. Переменные и функции: short FTPresult; // пепременная для результатов ftp запросов short doFTP(char* , char* , char* , char*, char* , char* = ""); // функция скачивания файла с ftp на флеш esp8266 short eRcv(WiFiClient aclient, char outBuf[], int size); // обработка ftp запросов 5. Функция закачки файла на флеш с ftp: short doFTP(char* host, char* unam

1. Должен быть ftp сервер с доступом, на который Вы можете закинуть прощивку.

2. Библиотеки:

#include <FS.h>

3. Параметры соединения и данные прошивки:

char* xhost = "адрес ftp сервера"; // ftp сервер
char* xusername = "логин сервера"; // логин ftp
char* xpassword = "пароль сервера"; // пароль ftp
char* xfolder = "папка с прошивкой на ftp сервере"; // папка с прошивками на ftp
char* xfilename = "esp_fw.bin"; // имя файла на сервере Ftp
char* xfile = "fw.bin"; // имя файла в файловой системе (с ftp сперва будем копировать на esp во флеш (скачивать))

4. Переменные и функции:

short FTPresult; // пепременная для результатов ftp запросов
short doFTP(char* , char* , char* , char*, char* , char* = ""); // функция скачивания файла с ftp на флеш esp8266
short eRcv(WiFiClient aclient, char outBuf[], int size); // обработка ftp запросов

5. Функция закачки файла на флеш с ftp:

  • соединение с сервером
short doFTP(char* host, char* uname, char* pwd, char* fileName, char* fNameMem, char* folder)
{
WiFiClient ftpclient;
WiFiClient ftpdclient;
const short FTPerrcode = 400; //error codes are > 400
const byte Bufsize = 128;
char outBuf[Bufsize];
short FTPretcode = 0;
const byte port = 21; //21 is the standard connection port
WiFiClient dataClient;
// попытка подключения к серверу
if (ftpclient.connect(host,port)) {
Serial.println(F("Connected to FTP server"));
}
else {
Serial.println(F("Failed to connect to FTP server"));
return 910;
}
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
// авторизация на сервере ftp
ftpclient.print("USER ");
ftpclient.println(uname);
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
/* PASS - Authentication password
* After sending the USER command, send this command to complete
* the login process. (Note, however, that an ACCT command may have to be
* used on some systems, not needed with synology diskstation)
*/
ftpclient.print("PASS ");
ftpclient.println(pwd);
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
//CWD - Change the working folder on the FTP server
// переход в заданную папку
if(!(folder == "")) {
ftpclient.print("CWD ");
ftpclient.println(folder);
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) {return FTPretcode;}
}
// определение кодировки обмане данными
/* SYST - Returns a word identifying the system, the word "Type:",
* and the default transfer type (as would be set by the
* TYPE command). For example: UNIX Type: L8 - this is what
* the diskstation returns
*/
/*ftpclient.println("SYST");
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;*/
// определение типа данных на ftp
/* TYPE - sets the transfer mode
* A - ASCII text
* E - EBCDIC text
* I - image (binary data)
* L - local format
* for A & E, second char is:
* N - Non-print (not destined for printing). This is the default if
* second-type-character is omitted
* Telnet format control (<CR>, <FF>, etc.)
* C - ASA Carriage Control
*/
ftpclient.println("Type I");
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
// пассивный режим обмена данными с ftp. В ответ получаем адрес/порт
ftpclient.println("PASV");
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
if(FTPretcode >= 400) return FTPretcode;
char *tStr = strtok(outBuf,"(,"); //chop the output buffer into tokens based on the delimiters
int array_pasv[6];
for ( int i = 0; i < 6; i++) { //there are 6 elements in the address to decode
tStr = strtok(NULL,"(,"); //1st time in loop 1st token, 2nd time 2nd token, etc.
array_pasv[i] = atoi(tStr); //convert to int, why atoi - because it ignores any non-numeric chars
//after the number
if(tStr == NULL) {Serial.println(F("Bad PASV Answer"));}
}
//extract data port number
unsigned int hiPort,loPort;
hiPort=array_pasv[4]<<8; //bit shift left by 8
loPort=array_pasv[5]&255;//bitwise AND
Serial.print(F("Data port: "));
hiPort = hiPort|loPort; //bitwise OR
Serial.println(hiPort);
//first instance of dftp
if(ftpdclient.connect(host, 21)){Serial.println(F("Data port connected"));}
else {
Serial.println(F("Data connection failed"));
ftpclient.stop();
// ftx.close();
}
// получение размера файла на ftp сервере
if (dataClient.connect(host,hiPort)) {
Serial.println("Data connection established");
ftpclient.println("SIZE " + String(fileName));
FTPretcode = eRcv(ftpclient,outBuf,Bufsize);
Serial.println(FTPretcode);
char *tStr = strtok(outBuf," ");
Serial.print("code:");Serial.println(tStr);
tStr = strtok(NULL," ");
Serial.print("sizelong:");Serial.println(atol(tStr));
long s_ = atol(tStr);
// чтение файла и перенос данных на esp
ftpclient.println("RETR " + String(fileName));
String response = ftpclient.readStringUntil('\n');
Serial.println("RETR Response: " + response);
Serial.println("File content:");
// открываем файл для записи и переносим в него данные с ftp
// данные переносятся по 100 байт, концовка по 1 байту
File fsUploadFile = SPIFFS.open(fNameMem, "w");
byte size_max_buffer = 100;
char buffer_[size_max_buffer];//[21];
char buffer_1[1];
long t = 0;
s_ = s_/size_max_buffer;
Serial.println(s_);
long percent = 0;
long percent_prev = 0;
while (dataClient.connected() || dataClient.available()) {
if (dataClient.available()) {
// запись в файл участков по 100 байт
if (t < s_)
{
size_t bytes_read = dataClient.readBytes(buffer_, size_max_buffer);
t++;
percent = t * 100/s_;
if (percent > percent_prev)
{
Serial.print(percent); Serial.println("%");
tft.fillRect(keyb_panel_left, 50, 480-keyb_panel_left - 1, 100, TFT_WHITE);
tft.setTextColor(TFT_BLACK, TFT_WHITE);
tft.setCursor(keyb_panel_left + 3, 50 + 3, 2);
tft.print("download: ");
tft.print(percent);
tft.print("%");
}
percent_prev = percent;
fsUploadFile.write(buffer_, bytes_read);
}
else // запись в файл остатка по 1 байту
{
size_t bytes_read = dataClient.readBytes(buffer_1, 1);
//buffer_[bytes_read] = '\0';
t++;
fsUploadFile.write(buffer_1, bytes_read);
}
}
delay(1);
}
if(fsUploadFile) fsUploadFile.close();
dataClient.stop();
// выводим данные о файлах на флеш и их размере (справочно можно убрать)
String str = "";
Dir dir = SPIFFS.openDir("");
while (dir.next()) {
str += dir.fileName();
str += " / ";
str += dir.fileSize();
str += "\r\n";}
Serial.print(str);
Serial.println("--------------------------------");
Serial.println("\nData connection closed");
} else {
Serial.println("Data connection failed");
}
//разрыв соединения, завершение сессии
ftpclient.println("QUIT");
ftpclient.stop();
Serial.println(F("Disconnected from FTP server"));
Serial.println(F("File closed"));
return FTPretcode;
} // end function doFTP

Далее создаем ффункцию обновления прошивки esp, в начале которой вызывается функция загрузки файла с ftp на flash память esp

void update_esp()
{
// загрузка прошивки с ftp на esp
  FTPresult = doFTP(xhost,xusername,xpassword,xfilename, xfile, xfolder); 
  Serial.print("Return code = ");
  Serial.println(FTPresult);
  if (FTPresult == 213)
  {
 // Обновление прошивки
   File file = SPIFFS.open(xfile, "r");
   uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
   if (!Update.begin(maxSketchSpace, U_FLASH)) { //start with max available size
    Update.printError(Serial);
    Serial.println("ERROR");
   }
   else
   {
    Serial.println("start");
   }
   if (file.available())
   {
    Serial.println("file ok");
    long size_ = file.size();
    long size_wr = 0;
    long percent, percent_prev = 0;
    while (file.available()) {
     size_wr += 128;
     percent = size_wr * 100 / size_;
     if (percent > percent_prev)
     { Serial.print(percent); Serial.println("%");
        tft.fillRect(keyb_panel_left, 70, 480-keyb_panel_left - 1, 100, TFT_WHITE);
        tft.setTextColor(TFT_BLACK, TFT_WHITE);
        tft.setCursor(keyb_panel_left + 3, 70 + 3, 2);
        tft.print("update: ");
        tft.print(percent);
        tft.print("%");
     }
     percent_prev = percent;
     uint8_t ibuffer[128];
     file.read((uint8_t *)ibuffer, 128);
     Update.write(ibuffer, sizeof(ibuffer));
    }
    file.close();
    Serial.print(Update.end(true));
    delay(1);
    ESP.restart(); // перезагрузка esp после обновления прошивки
   }
  }  
}

Вот и всё. Данный код позволит обеспечить обновление прошивки с ftp сервера...