• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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 не надо делать никакие запросы.

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