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

Решено Как отправить от HTTP сервера (Web server на ESP8266) html-ответ в браузер компьютера файлом?

Paul_B

Member
Есть HTTP сервер на ESP8266, который по запросам с компьютера отправляет html-ответы в виде интернет-страничек. Размер их может достигать до 10кб. Отправку осуществляю командой
Код:
server.send(200,"text/html", str)
где сформированная html-страничка находится в строковой переменной str.
Иногда она формируется нулевой длины, что связываю с возникновением глюков из-за большого размера (до 10 тыс знаков) и нехватки памяти.
Можно ли как-то формировать файл в SPIFFS, записывая в него кусочками (по 100-200 знаков) всю страницу, а потом отправить сразу весь записанный файл, минуя его предварительное чтение и преобразование через строковую переменную?
 
Последнее редактирование:

Юрий Ботов

Moderator
Команда форума
помнится мне там кроме .send( есть еще и .send_P( для непосредственной адресации к флэшу. Не к файлу, а просто к строке во флэше.
 

Paul_B

Member
помнится мне там кроме .send( есть еще и .send_P( для непосредственной адресации к флэшу. Не к файлу, а просто к строке во флэше.
Говорят, на сайте есть пример от Гуру, но я не нашел. Т.е. проблема понятна - как отправить большую html страницу минуя ее преобразование в строковую переменную. ну, или как ее отправить частями. но во втором случае не обойтись без java
 

Paul_B

Member
Вот как получилось:
Код:
File file = SPIFFS.open("/index.html", "w");
 file.print(.....);
........
file.print(.....);
file.close();
 
file = SPIFFS.open("/index.html", "r");
size_t sent = server.streamFile(file, "text/html");
file.close();
Т.е. я формирую html- файлы в теле скетча, поскольку они зависят от многих параметров, т.к. я реализую сеть из ESP8266 произвольного числа, которые сами объединяются так, чтобы все модули были в одной сети и возможно было с любого управлять любым, включая изменять настройки.
 
Последнее редактирование:

Сергей_Ф

Moderator
Команда форума
@Paul_B и сколько у вас так Флэш проживет? Не лучше отправлять из флеш-памяти только неизменяемые части, а подставлять параметры "на лету"?
 

Paul_B

Member
@Paul_B и сколько у вас так Флэш проживет? Не лучше отправлять из флеш-памяти только неизменяемые части, а подставлять параметры "на лету"?
Кстати, SPIFFS - энергонезависим? Т.е., при отключении питания там файлы сохраняются?
Пусть возможен 100 000 режимов записи. Если входить через HTTP даже 10 раз в день, то это хватит на 30 лет. Я столько не проживу. Это раз.
А если подставлять "на лету", это значит я должен опять считать в строковую переменную, это не пойдет. Или есть способ отправить HTML станицу двумя кусками? Способ, что сначала написать код страницы, а потом подсасывать в нее параметры не подойдет, потому что связан с изучением всяких java. Создать целиком страницу и целиком ее передать в браузер я еще освоил, освоил передачу параметров от браузера в ESP, а вот как разбирать параметры от ESP внутри HTML для меня темный лес.
 
Последнее редактирование:

Сергей_Ф

Moderator
Команда форума
@Paul_B конечно энергонезависимый, но довольно медленный на запись. Вы уверены что это вас устроит? Страницу можно отдавать хоть 10-ю частями. А лучше потратить немного времени и изучить AJAX - будет потом проще и удобнее.
 

Сергей_Ф

Moderator
Команда форума
@Paul_B , честно говоря, не знаю даже что сказать. Просто берете и посылаете двумя частями. Или тремя. Или 10-ю. Да хоть по одному символу посылайте. Html-заканчива там, где он закончится. Извините за каламбур.

Посмотрите простейший проект https://esp8266.ru/forum/threads/prostye-wifi-chasy.1209/
 

Paul_B

Member
Просто берете и посылаете двумя частями. Или тремя. Или 10-ю. Да хоть по одному символу посылайте.
А мне всегда казалось, что в браузере функция приема аналогична записи в файл с опцией "w", т.е. каждая новая посылка сбрасывает указатель на ноль, т.е. затирает переданные до нее в браузере. А вы утверждаете, что посылать можно как при опции записи "a", т.е. с продолжением. Надо попробовать.
 

Paul_B

Member
Говорят, на сайте есть пример от Гуру, но я не нашел. Т.е. проблема понятна - как отправить большую html страницу минуя ее преобразование в строковую переменную. ну, или как ее отправить частями. но во втором случае не обойтись без java

Код:
size_t server_sendfile(const String& fn)
{
File f=SPIFFS.open(fn, "r");
if(f)
    {
      char buf[1024];
      size_t sent = 0;
      int siz = f.size();
      Serial.println("\nSend file "+fn+" size="+String(siz));
      while(siz > 0) {
        size_t len = std::min((int)(sizeof(buf) - 1), siz);
        f.read((uint8_t *)buf, len);
      //  Serial.println(buf);
        server.client().write((const char*)buf, len);
        siz -= len;
        sent+=len;
      }
     f.close();  
     Serial.println(" sended "+String(sent));
     return(sent);  
    }
else Serial.println("Bad open file "+fn);  
return(0);  
}
 

Алексей.

Active member
Paul_B,
Всю статику прям в коде (в прошивке) держу, в виде массива байтов, к счастью есп поддерживает режим progmem и данные мапятся прямо на флеш. Скрипты, стили страницы - пережаты gzip-ом, картинки нет смысла жать, поэтому так лежат.
В прошивку положил потому что загружается прошивка в модуль быстро, а загрузка файлов на spiffs кажется вечностью.
Отгружаю контент броузеру или одним куском, если данных не много
Код:
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(code, dataType);
server.sendContent_P(content, size);
или частями (бутстрап и джи-квери хоть и пережал, но всё равно тяжелые)
Код:
#define CONTENT_BLOCK_MAX 2048

server.sendHeader("Content-Encoding", "gzip");
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(200, dataType, "");
size_t offset;
for (offset = 0; offset < size; ) {
  size_t bytes = (size - offset) >= CONTENT_BLOCK_MAX ? CONTENT_BLOCK_MAX : size - offset;
  server.sendContent_P(content + offset, bytes);
  offset += bytes;
}
 
Последнее редактирование:

Paul_B

Member
Вот окончательно сделал замену вечно лагающему .streamFile
Код:
size_t server_sendfile(String fn)
{
if(!fn.startsWith("/")) fn="/"+fn;
File f=SPIFFS.open(fn, "r");
if(f)
    {
      char buf[2048];
      size_t sent = 0;
      int siz = f.size();
      String S="HTTP/1.1 200\r\nContent-Type: "+ getContentType(fn) +"\r\nContent-Length: "+ String(siz)+"\r\nConnection: close\r\n\r\n";
      server.client().write(S.c_str(), S.length());
      Serial.println("\nSend file "+fn+" size="+String(siz));
      while(siz > 0) {
        size_t len = std::min((int)(sizeof(buf) - 1), siz);
        f.read((uint8_t *)buf, len);
        server.client().write((const char*)buf, len);
        siz -= len;
        sent+=len;
      }
     f.close();  
     Serial.println(" sended "+String(sent));
     return(sent);  
    }
else {
  server.send(404, "text/plain", "FileNotFound");
  Serial.println("Bad open file "+fn);
}
return(0);  
}
 

Legion12

New member
Paul_B,
Всю статику прям в коде (в прошивке) держу, в виде массива байтов, к счастью есп поддерживает режим progmem и данные мапятся прямо на флеш. Скрипты, стили страницы - пережаты gzip-ом, картинки нет смысла жать, поэтому так лежат.
В прошивку положил потому что загружается прошивка в модуль быстро, а загрузка файлов на spiffs кажется вечностью.
Отгружаю контент броузеру или одним куском, если данных не много
Код:
server.setContentLength(CONTENT_LENGTH_UNKNOWN);
server.send(code, dataType);
server.sendContent_P(content, size);
Черт возьми, всего Вам доброго и хорошего ))))))))))))) Вы просто спасли меня!
 

Paul_B

Member
void ESP8266WebServer::sendContent_P ( PGM_P content, size_t size )

Извините, а что такое PGM_P и что выступает в роли content?
 

Paul_B

Member
void ESP8266WebServer::sendContent_P ( PGM_P content, size_t size )

Извините, а что такое PGM_P и что выступает в роли content?
 

Paul_B

Member
В Spiffs есть куча файликов. Можно как-то из скетча запустить exe-архиватор (тоже лежит в Spiffs), а потом созданный архив одним файлом скачать на диск (это я умею). Вопрос - как средствами Arduino ide запустить exe файл в Spiffs?
 

Алексей.

Active member
Можно как-то из скетча запустить exe-архиватор
Из скетча?? Это код выполняется на модуле, что он запустить должен?
Вопрос - как средствами Arduino ide запустить exe файл
Хуками, определяйте в platform.local.txt что выполнять, например recipe.hooks.sketch.prebuild.0.pattern и каждый раз при сборке (когда нажимаете в ардуино-иде кнопку "Проверить") будет выполняться ваш код (то что определите в хуке). Подробно тут.

П.С.
Для пережатия файлов gzip-ом, не требуются дополнительное ПО. Достаточно средств в ОС, на виндовс powershell-ом (скриптом) замечательно архивируется.
 
Сверху Снизу