Скрыть объявление
На нашем форуме недоступен просмотр изображений для неавторизованных пользователей. Если Вы уже зарегистрированы на нашем форуме, то можете войти. Если у Вас еще нет аккаунта, мы будем рады, если Вы к нам присоединитесь. Зарегистрироваться Вы можете здесь.

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

Тема в разделе "Общие вопросы по esp8266", создана пользователем Paul_B, 3 сен 2019.

  1. Paul_B

    Paul_B Новичок

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

    Paul_B Новичок

    Сообщения:
    149
    Симпатии:
    3
    Файлы в ESP я передаю по форме:
    Код (Text):
    1. <form method='POST' action='/up' enctype='multipart/form-data'>
    2. <input type='file' name='up' >
    3. New name:<input name='newname' size='14' >
    4. <input type='submit' value='Upload'></form>
    В самой ESP это организовано так:
    Код (Text):
    1.  
    2. ESP8266WebServer server(80);
    3. //внешняя переменная под имя файла
    4. String FS_Filename;
    5.  
    6. //обработка команды /up
    7.  
    8.  server.on("/up", HTTP_POST, [](){
    9.       String S=server.arg("newname");
    10. // сверяю имя переданного файла с тем в который надо переименовать    
    11.       if(S!="" && FS_Filename!=S)
    12.         {
    13.          if (!S.startsWith("/")) S = "/" + S;
    14.          SPIFFS.rename(String(FS_Filename),S);
    15.         }
    16.  // после окончания процедуры закачки файла запускаю стартовую страницу в браузере
    17.       Start_ESP();  
    18.   },[](){    
    19.          handleFileUpload();
    20.         });
    21.  
    22. // процедура загрузки файла в ESP8266 с компьютера
    23. void handleFileUpload() {
    24.   static File fsUploadFile;
    25.  
    26.   HTTPUpload& upload = server.upload();
    27.  
    28.   if (upload.status == UPLOAD_FILE_START) {
    29.     String filename=upload.filename;
    30.  
    31.     if (!filename.startsWith("/")) filename = "/" + filename;
    32. //сохраняю имя файла во внешней переменной для последующего переименования при необходимости
    33.     FS_Filename=filename;
    34.  
    35.  
    36.     fsUploadFile = SPIFFS.open(filename, "w");
    37.     filename = String();
    38.   } else if (upload.status == UPLOAD_FILE_WRITE) {
    39.     if (fsUploadFile)
    40.       fsUploadFile.write(upload.buf, upload.currentSize);
    41.   } else if (upload.status == UPLOAD_FILE_END) {
    42.     if (fsUploadFile)  fsUploadFile.close();
    43.   }
    44. }
    45.  
     
  3. Paul_B

    Paul_B Новичок

    Сообщения:
    149
    Симпатии:
    3
    Передача файла с ESP в компьютер делаю так:
    Код (Text):
    1. http://IP-адрес-ESP/имя_файла
    В самой ESP передача организована:
    Код (Text):
    1. //естественно, имя файла не совпадает ни с одним сервер-запросом-обработчиком
    2.  
    3. server.onNotFound([]() {
    4.      handleFileRead(server.uri());
    5.   });
    6.  
    7.  
    8. size_t handleFileRead(String fn)
    9. {
    10.  
    11. if(!fn.startsWith("/")) fn="/"+fn;
    12. if(!SPIFFS.exists(fn)) return(0);
    13.  
    14. String contentType = "application/octet-stream";
    15.  
    16.      File f=SPIFFS.open(fn, "r");
    17.      if(f)
    18.         {
    19.          char buf[1025];
    20.           size_t len, sent = 0;
    21.           int siz = f.size();
    22.          
    23.           server.setContentLength(siz);
    24.           server.send(200, contentType, "");
    25.  
    26.           while(siz > 0) {
    27.             len = std::min((int)(sizeof(buf) - 1), siz);
    28.             f.read((uint8_t *)buf, len);
    29.             server.sendContent_P((const char*)buf, len);
    30.             siz -= len;
    31.             sent+= len;
    32.           }
    33.          f.close();
    34.          return(sent);
    35.         }
    36.  
    37.   server.send(404, "text/plain", "FileNotFound "+fn);
    38.   return(0);
    39. }
    40.  
    А вот какой запрос сформировать с одной ESP на другую, чтобы передаваемый файл правильно принялся - пока не получается.
     
  4. Paul_B

    Paul_B Новичок

    Сообщения:
    149
    Симпатии:
    3
  5. Paul_B

    Paul_B Новичок

    Сообщения:
    149
    Симпатии:
    3
  6. nikolz

    nikolz Гуру

    Сообщения:
    4.698
    Симпатии:
    452
    правильно ли я вас понял.
    Вы умеете передавать текстовые файлы (это ASCIIZ формат) и не умеете двоичные?
     
  7. Paul_B

    Paul_B Новичок

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

    Paul_B Новичок

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

    Paul_B Новичок

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

    Paul_B Новичок

    Сообщения:
    149
    Симпатии:
    3
    Между ESP я передаю сообщения по их IP (с учетом вложенности подключения)
    Код (Text):
    1. bool Send_Client(IPAddress ip, const String& Subj, int id)
    2. {
    3.   bool rez=false;
    4.   WiFiClient* myclient=new WiFiClient;
    5.  
    6.   myclient->setTimeout(3000);
    7.    if (myclient->connect(ip, 80))
    8.      {
    9.       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");
    10.  
    11.       myclient->stop();
    12.       rez=true;
    13.      }    
    14.    delete myclient;
    15.    myclient=NULL;
    16.     return(rez);
    17. }
    18.  
     
  11. Paul_B

    Paul_B Новичок

    Сообщения:
    149
    Симпатии:
    3
    Задача решена!
     
  12. Paul_B

    Paul_B Новичок

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

    Код (Text):
    1.     server.on("/dn", [](){
    2.       handleSendFile(String_to_IP(server.arg("ip")), server.arg("filename"));
    3.    
    4. });
    Код (Text):
    1. size_t handleSendFile(IPAddress ip1, String fn)
    2. {
    3.  
    4. if(!fn.startsWith("/")) fn="/"+fn;
    5. if(!SPIFFS.exists(fn)) return(0);
    6. String contentType = getContentType(fn);
    7. //случайная строка-разделитель
    8. String boundary="----Myboundary51VPCLa3iwBN";
    9. WiFiClient myclient;
    10. myclient.setTimeout(3000);
    11. byte i=0;
    12. while(!myclient.connect(ip1, 80) && i<30) {delay(10);i++;}
    13. if(i>=30) return(0);
    14. size_t len, sent = 0;
    15. File f=SPIFFS.open(fn, "r");
    16. if(f)
    17.     {
    18.       char buf[10];
    19.       int siz = f.size();
    20.       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");  
    21.       myclient.print("Content-Length: "+String(siz)+"\r\n\r\n");
    22.       myclient.print("--"+boundary+"\r\n");
    23.       myclient.print("Content-Disposition: form-data; name=\"up\"; filename=\""+fn.substring(1)+"\"\r\nContent-Type: "+contentType+"\r\n\r\n");
    24.  
    25.       while(siz > 0) {
    26.         len = std::min((int)(sizeof(buf) - 1), siz);
    27.         f.read((uint8_t *)buf, len);
    28.         myclient.write((const char*)buf, len);
    29.         siz -= len;
    30.         sent+= len;
    31.       }
    32.      f.close();
    33.      myclient.print("\r\n--"+boundary+"--\r\n");
    34.      myclient.stop();
    35.     }
    36.    return(sent);
    37. }
    38.  
    Код (Text):
    1. String getContentType(String filename) {
    2.   if (server.hasArg("download")) return "application/octet-stream";
    3.   else if (filename.endsWith(".htm")) return "text/html";
    4.   else if (filename.endsWith(".html")) return "text/html";
    5.   else if (filename.endsWith(".json")) return "application/json";
    6.   else if (filename.endsWith(".css")) return "text/css";
    7.   else if (filename.endsWith(".js")) return "application/javascript";
    8.   else if (filename.endsWith(".png")) return "image/png";
    9.   else if (filename.endsWith(".gif")) return "image/gif";
    10.   else if (filename.endsWith(".jpg")) return "image/jpeg";
    11.   else if (filename.endsWith(".ico")) return "image/x-icon";
    12.   else if (filename.endsWith(".xml")) return "text/xml";
    13.   else if (filename.endsWith(".pdf")) return "application/x-pdf";
    14.   else if (filename.endsWith(".zip")) return "application/x-zip";
    15.   else if (filename.endsWith(".gz")) return "application/x-gzip";
    16.   return "text/plain";
    17. }
    18.  
     
  13. Paul_B

    Paul_B Новичок

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

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

    nikolz Гуру

    Сообщения:
    4.698
    Симпатии:
    452
    Что означает "без согласия"? если ESP не соединилась и не запрашивает данные то вы насильно в нее ничего не засунете.
     
  15. Paul_B

    Paul_B Новичок

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

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

Поделиться этой страницей