• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Нужна помощь Передача файлов (двоичных) между двумя ESP8266

Paul_B

Member
Есть сеть ESP8266. Часть подключены к домашней сети, часть подключены к другим ESP через точки доступа. Умею пересылать сообщения (строковые данные) по всему кусту сообщения с учетом любой вложенности подключений.
С ESP, которые подключены к домашней сети через браузер могу закачивать файлы в SPIFFS, включая файлы прошивки (через браузер!) и обновлять прошивку. Могу скачивать файлы через браузер из SPIFFS на компьютер.
Но что-то не могу понять как соорудить запрос, чтобы передать файл из SPIFFS с одной ESP на другую ESP, чтобы та этот файл сохранила в SPIFFS (ну, а далее легко реализуется передача файлов по кусту с любой степенью вложенности).
 

Paul_B

Member
Файлы в ESP я передаю по форме:
Код:
<form method='POST' action='/up' enctype='multipart/form-data'>
<input type='file' name='up' >
New name:<input name='newname' size='14' >
<input type='submit' value='Upload'></form>
В самой ESP это организовано так:
Код:
ESP8266WebServer server(80);
//внешняя переменная под имя файла
String FS_Filename;

//обработка команды /up

 server.on("/up", HTTP_POST, [](){
      String S=server.arg("newname");
// сверяю имя переданного файла с тем в который надо переименовать     
      if(S!="" && FS_Filename!=S)
        {
         if (!S.startsWith("/")) S = "/" + S;
         SPIFFS.rename(String(FS_Filename),S);
        }
 // после окончания процедуры закачки файла запускаю стартовую страницу в браузере
      Start_ESP();   
  },[](){    
         handleFileUpload();
        });

// процедура загрузки файла в ESP8266 с компьютера
void handleFileUpload() {
  static File fsUploadFile;

  HTTPUpload& upload = server.upload();
 
  if (upload.status == UPLOAD_FILE_START) {
    String filename=upload.filename;
  
    if (!filename.startsWith("/")) filename = "/" + filename;
//сохраняю имя файла во внешней переменной для последующего переименования при необходимости
    FS_Filename=filename;

  
    fsUploadFile = SPIFFS.open(filename, "w");
    filename = String();
  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (fsUploadFile)
      fsUploadFile.write(upload.buf, upload.currentSize);
  } else if (upload.status == UPLOAD_FILE_END) {
    if (fsUploadFile)  fsUploadFile.close();
  }
}
 

Paul_B

Member
Передача файла с ESP в компьютер делаю так:
Код:
http://IP-адрес-ESP/имя_файла
В самой ESP передача организована:
Код:
//естественно, имя файла не совпадает ни с одним сервер-запросом-обработчиком
 
server.onNotFound([]() {
     handleFileRead(server.uri());
  });


size_t handleFileRead(String fn)
{

if(!fn.startsWith("/")) fn="/"+fn;
if(!SPIFFS.exists(fn)) return(0);

String contentType = "application/octet-stream";

     File f=SPIFFS.open(fn, "r");
     if(f)
        {
         char buf[1025];
          size_t len, sent = 0;
          int siz = f.size();
         
          server.setContentLength(siz);
          server.send(200, contentType, "");

          while(siz > 0) {
            len = std::min((int)(sizeof(buf) - 1), siz);
            f.read((uint8_t *)buf, len);
            server.sendContent_P((const char*)buf, len);
            siz -= len;
            sent+= len;
          }
         f.close();
         return(sent);
        }
 
  server.send(404, "text/plain", "FileNotFound "+fn);
  return(0);
}
А вот какой запрос сформировать с одной ESP на другую, чтобы передаваемый файл правильно принялся - пока не получается.
 

nikolz

Well-known member
Передача файла с ESP в компьютер делаю так:
Код:
http://IP-адрес-ESP/имя_файла
В самой ESP передача организована:
Код:
//естественно, имя файла не совпадает ни с одним сервер-запросом-обработчиком
 
server.onNotFound([]() {
     handleFileRead(server.uri());
  });


size_t handleFileRead(String fn)
{

if(!fn.startsWith("/")) fn="/"+fn;
if(!SPIFFS.exists(fn)) return(0);

String contentType = "application/octet-stream";

     File f=SPIFFS.open(fn, "r");
     if(f)
        {
         char buf[1025];
          size_t len, sent = 0;
          int siz = f.size();
        
          server.setContentLength(siz);
          server.send(200, contentType, "");

          while(siz > 0) {
            len = std::min((int)(sizeof(buf) - 1), siz);
            f.read((uint8_t *)buf, len);
            server.sendContent_P((const char*)buf, len);
            siz -= len;
            sent+= len;
          }
         f.close();
         return(sent);
        }
 
  server.send(404, "text/plain", "FileNotFound "+fn);
  return(0);
}
А вот какой запрос сформировать с одной ESP на другую, чтобы передаваемый файл правильно принялся - пока не получается.
правильно ли я вас понял.
Вы умеете передавать текстовые файлы (это ASCIIZ формат) и не умеете двоичные?
 

Paul_B

Member
Вы умеете передавать текстовые файлы (это ASCIIZ формат) и не умеете двоичные?
Я умею передавать любые файлы с компьютера на ESP и обратно. Между ESP я могу передавать только текстовые сообщения (строковые). Хочу научиться передавать файл составной пересылкой, но не понимаю какой запрос отправить, чтобы была аналогия с формой
Код:
<script>function f(f) {document.getElementById('newname').value=f}</script>
Upload File to SPIFFS: <br><br>
<form method='POST' action='/up' enctype='multipart/form-data'>
<input type='file' name='up' id='up' onchange='f(this.files[0].name)'>
<small>New name:</small><input name='newname' id='newname' size='14' >
<input type='submit' value='Upload'></form>
Ее упрощенный вид я привел в первом сообщении.
 

Paul_B

Member
Если с одной ESP на другую передавать такой запрос (как сохранение на компьютер):
Код:
http://IP-адрес-ESP/имя_файла
То на той ESP на которую передали этот запрос проходит передача файла, но он не принимается на той ESP, которая передала данный запрос.
Если передать данный запрос с компьютера на ESP, то проходит передача файла и после ее окончания возникает диалоговое окно на сохранение ("Сохранить как").
 

Paul_B

Member
Сегодня поэкспериментирую посмотрю что происходит на обоих ESP через com-порт. Вчера смотрел только на одну, картина не совсем понятная.
 

Paul_B

Member
Между ESP я передаю сообщения по их IP (с учетом вложенности подключения)
Код:
bool Send_Client(IPAddress ip, const String& Subj, int id)
{
  bool rez=false;
  WiFiClient* myclient=new WiFiClient;

  myclient->setTimeout(3000);
   if (myclient->connect(ip, 80))
     {
      myclient->print("POST " + Subj + (Subj.indexOf("?") < 0 ? "?id=" + String(id):"&id=" + String(id))+ " HTTP/1.1\r\nHost: " + IP_to_String(ip) + "\r\nConnection: close\r\n\r\n");

      myclient->stop();
      rez=true; 
     }    
   delete myclient;
   myclient=NULL; 
    return(rez);
}
 

Paul_B

Member
По запросу на ESP dn?ip=IP_адрес&filename=имя_файла
будет отправлен файл на указанный адрес и на том конце файл будет сохранен по одной из указанных выше процедур (конкретно - "up" - именно эта процедура указывается в multipart/form-data запросе)

Код:
    server.on("/dn", [](){
      handleSendFile(String_to_IP(server.arg("ip")), server.arg("filename"));
   
});
Код:
size_t handleSendFile(IPAddress ip1, String fn)
{
 
if(!fn.startsWith("/")) fn="/"+fn;
if(!SPIFFS.exists(fn)) return(0);
String contentType = getContentType(fn);
//случайная строка-разделитель
String boundary="----Myboundary51VPCLa3iwBN";
WiFiClient myclient;
myclient.setTimeout(3000);
byte i=0;
while(!myclient.connect(ip1, 80) && i<30) {delay(10);i++;}
if(i>=30) return(0);
size_t len, sent = 0;
File f=SPIFFS.open(fn, "r");
if(f)
    {
      char buf[10];
      int siz = f.size();
      myclient.print("POST /up?filemame="+fn.substring(1)+" HTTP/1.1\r\nHost: "+IP_to_String(ip1)+"\r\nContent-Type: multipart/form-data; boundary="+boundary+"\r\n");   
      myclient.print("Content-Length: "+String(siz)+"\r\n\r\n");
      myclient.print("--"+boundary+"\r\n");
      myclient.print("Content-Disposition: form-data; name=\"up\"; filename=\""+fn.substring(1)+"\"\r\nContent-Type: "+contentType+"\r\n\r\n");
  
      while(siz > 0) {
        len = std::min((int)(sizeof(buf) - 1), siz);
        f.read((uint8_t *)buf, len);
        myclient.write((const char*)buf, len);
        siz -= len;
        sent+= len;
      }
     f.close();
     myclient.print("\r\n--"+boundary+"--\r\n");
     myclient.stop();
    }
   return(sent);
}
Код:
String getContentType(String filename) {
  if (server.hasArg("download")) return "application/octet-stream";
  else if (filename.endsWith(".htm")) return "text/html";
  else if (filename.endsWith(".html")) return "text/html";
  else if (filename.endsWith(".json")) return "application/json";
  else if (filename.endsWith(".css")) return "text/css";
  else if (filename.endsWith(".js")) return "application/javascript";
  else if (filename.endsWith(".png")) return "image/png";
  else if (filename.endsWith(".gif")) return "image/gif";
  else if (filename.endsWith(".jpg")) return "image/jpeg";
  else if (filename.endsWith(".ico")) return "image/x-icon";
  else if (filename.endsWith(".xml")) return "text/xml";
  else if (filename.endsWith(".pdf")) return "application/x-pdf";
  else if (filename.endsWith(".zip")) return "application/x-zip";
  else if (filename.endsWith(".gz")) return "application/x-gzip";
  return "text/plain";
}
 

Paul_B

Member
Причем что замечательно, приведенным выше способом можно передавать и ПОДМЕНЯТЬ файлы на любой ESP без ее согласия, т.е. с нее не должен исходить запрос на прием файла.
Пример. В сети две ESP: ESP1 и ESP2.
Я сначала копирую на ESP1 с компьютера файл через браузер, потом с браузера даю команду переслать этот файл на ESP2 и файл пересылается на ESP2 и записывается с заменой.
Причем с учетом всего скетча я могу передать файл на TSP, которая находится в 3-м поколении и более от домашней сети, то есть:

Home-WiFi-LAN <-ESP1<-ESP2<-ESP3<-...<-ESPn
Причем ESPn может находиться за сотни метров, главное, чтобы любые две ESP находились в зоне WIFi-видимости друг друга.
 

nikolz

Well-known member
Причем что замечательно, приведенным выше способом можно передавать и ПОДМЕНЯТЬ файлы на любой ESP без ее согласия, т.е. с нее не должен исходить запрос на прием файла.
Пример. В сети две ESP: ESP1 и ESP2.
Я сначала копирую на ESP1 с компьютера файл через браузер, потом с браузера даю команду переслать этот файл на ESP2 и файл пересылается на ESP2 и записывается с заменой.
Причем с учетом всего скетча я могу передать файл на TSP, которая находится в 3-м поколении и более от домашней сети, то есть:

Home-WiFi-LAN <-ESP1<-ESP2<-ESP3<-...<-ESPn
Причем ESPn может находиться за сотни метров, главное, чтобы любые две ESP находились в зоне WIFi-видимости друг друга.
Что означает "без согласия"? если ESP не соединилась и не запрашивает данные то вы насильно в нее ничего не засунете.
 

Paul_B

Member
ESP не соединилась и не запрашивает данные то вы насильно в нее ничего не засунете
ЕSP работает как сервер, естественно, другая ESP, подключаясь к ней, отправляет на нее файлы по вышеприведенным процедурам. Я в тому, что принимающей ESP не надо делать никакие запросы.

ЗЫ. Вы бы лучше по делу что-либо когда-нибудь ответили, а то либо обвинения в некомпетентности, либо сплошное бла-бла-бла.
 
Сверху Снизу