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

Решено Изменить удаленно размер SPIFFS, чтобы по OTA обновить скетч.

Paul_B

Member
На ESP8266 установлен webServer и крутится довольно объемный проект. Для нужд проекта выделен SPIFFS для web-страниц и рабочих файлов проекта. Раньше было выделено 64 Кб все было замечательно - объема оставшейся памяти хватало, чтобы по OTA обновлять новые версии скетчей.

Потом потребовалось выделить 256 Кб под SPIFFS и оставшейся памяти стало не хватать, чтобы обновить по OTA скетч. Вопрос касается версий ESP8266 с объемом памяти 1МБ (для версии с 4МБ - 1 + 3МБ под SPIFFS все ОК).

Сам вопрос: можно ли как-то удаленно уменьшить объем памяти под SPIFFS (возможно совсем убрать), чтобы обновить скетч, потом опять удаленно выделить нужный размер SPIFFS и закачать файлы.

Пробовал удаленно запускать SPIFFS.end() - не помогает, т.е. внутренне SPIFFS отключается, т.к. web-страницы перестают грузится, а вот эта память не высвобождается для обновления скетча.

Удаленно могу с модулем делать через web-сервер с использованием записи в EEPROM все что угодно. Идеи приветствуются.
 

tretyakov_sa

Moderator
Команда форума
Сначала загрузи маленький скетч загрузчик, затем большой. Затем любую новую систему файловую систему которая определена новым скетчем. Все это проверено при обновлении с сайта. Что подразумевается под ОТА трудно понять.
 

Paul_B

Member
Сначала загрузи маленький скетч загрузчик, затем большой
Пробовал. Мой проект сейчас занимает 490 кб (скетч 5600 строк только моего текста, не считая подключаемых библиотек, необходимых для отправки e-mail, проверки пинга и т.д. и т.п.). Самый минимальный скетч, в котором есть OTA-загрузчик занимает 270 кб. С учетом того, что проект рисует графики с использованием html Highcharts, необходимо выделять минимум 512 кб под SPIFFS, т.к. только два файла с js-скриптами, необходимых для отрисовки графиков HIGHCHARTS занимают 150 кб.
При суммарной памяти в 1МБ на ESP 8266, как видим, такой фокус не пройдет. Просто я думал может как-нибудь удаленно можно отключить SPIFFS, включив его в общую память (можно выполнять какие-нибудь команды, реализовав из выполнение в Web-сервере. Но нет, так нет, буду пользовать 4МБ модули.
 
Последнее редактирование:

Paul_B

Member
А нельзя библиотеки highcharts подкачивать со стороннего ресурса?
Видите ли, проект универсальный, предполагается работать в модулях, которые могут быть связаны между собой сеткой, но выход в интернет может иметь только один из них, удаленный на несколько узлов (аналогичных модулей). Можно управлять ими, через друг друга (причем все настройки, включая передачу условных сообщений от каких-либо событий - уровень аналогового сигнала, значений температуры, влажности, напряжения питания, пинга до любого хоста, просто по таймеру) вводятся через web-страницы, повторюсь, не обязательно через тот модуль, для которого они предназначаются. Так же можно подключаться к каждому модулю через собственную точку доступа, если она в зоне доступа.
Поэтому хранить файлы, необходимые для работы надо внутри каждого модуля.

У меня вот идейка возникла, может файл-прошивку скетча заливать на SPIFFS, предварительно удалив оттуда файлы, прошивать со SPIFFS, а потом заливать заново необходимые файлы. Благо размер SPIFFS (минимум 512 Кб) позволяет это сделать.
 

Paul_B

Member
А если обновление через web или по http это OTA?
Это игра слов. Сформулирую вопрос прямо. Можно ли удаленно прошить bin-файл с прошивкой, который лежит в SPIFFS, при этом сразу "напрямую", т.е. не задействуя внутреннюю память, которой, собственно, нет.
 

Paul_B

Member
Как можно Вам объяснили.
Все эти способы подразумевают подгрузку файла с прошивкой в область памяти меджу уже установленной и SPIFFS. У меня этой памяти не хватает для подгрузки прошивки. Поэтому вопрос-то и состоял - можно ли как-то через Web-сервер, запущенный на ESP8266 либо убрать временно SPIFFS, освободив память для подгрузки прошивки, либо какой-то способ, чтобы записать прошивку сразу из SPIFFS.
 

Paul_B

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

Paul_B

Member
Короче, этот метод хоть и позволяет обновлять прошивку из файла в SPIFFS, но пишет ее в ту же область для OTA-обновлений. Которой если нет, то и не пишет, выдает ERROR[4]: Not Enough Space.
Можно как-то модифицировать Update.write, чтобы писать сразу на место прошивки? Или там на уровне ядра все зашито, что типа область для OTA-обновлений, если она не пустая, встает на место прошивки только при перезагрузке модуля...?
 

Paul_B

Member
Попутно поделюсь опытом как одновременно обновлять прошивку и SPIFFS через bin-файлы, получаемые при компиляции в Arduino IDE.
В bin-файле SPIFFS должно присутствовать "spiffs".
Добавил в файл уважаемого Гуру.

Код:
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";

// Инициализация FFS
void FS_init(void) {
  SPIFFS.begin();
  {
    Dir dir = SPIFFS.openDir("/");
    while (dir.next()) {
      String fileName = dir.fileName();
      size_t fileSize = dir.fileSize();
    }
  }
  //HTTP страницы для работы с FFS
  //list directory
  server.on("/list", HTTP_GET, handleFileList);
  //загрузка редактора editor
  server.on("/edit", HTTP_GET, []() {
    if (!handleFileRead("/editor.htm")) server.send(404, "text/plain", "FileNotFound");
  });
  //Создание файла
  server.on("/edit", HTTP_PUT, handleFileCreate);
  //Удаление файла
  server.on("/edit", HTTP_DELETE, handleFileDelete);
  //first callback is called after the request has ended with all parsed arguments
  //second callback handles file uploads at that location
  server.on("/edit", HTTP_POST, []() {
    server.send(200, "text/plain", "");
  }, handleFileUpload);
  //called when the url is not defined here
  //use it to load content from SPIFFS
   server.onNotFound([]() {
    if (!handleFileRead(server.uri()))
      server.send(404, "text/plain", "FileNotFound");
  });

   server.on("/refit", HTTP_GET, [](){
    server.sendHeader("Connection", "close");
    server.sendHeader("Access-Control-Allow-Origin", "*");
    server.send(200, "text/html", serverIndex);
  });
  server.on("/update", HTTP_POST, [](){
    server.sendHeader("Connection", "close");
    server.sendHeader("Access-Control-Allow-Origin", "*");
    server.send(200, "text/plain", (Update.hasError())?"FAIL":"OK");
    ESP.restart();
  },[](){
    HTTPUpload& upload = server.upload();
    if(upload.status == UPLOAD_FILE_START){
      Serial.setDebugOutput(true);
      WiFiUDP::stopAll();
      Serial.printf("Update: %s\n", upload.filename.c_str());
      uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
      byte cod=0;
      if(upload.filename.indexOf("spiffs")>=0) cod=100; 
      if(!Update.begin(maxSketchSpace,cod)){//start with max available size
              Update.printError(Serial);
            }
   
    } else if(upload.status == UPLOAD_FILE_WRITE){
      if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
        Update.printError(Serial);
      }
    } else if(upload.status == UPLOAD_FILE_END){
      if(Update.end(true)){ //true to set the size to the current progress
        Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
      } else {
        Update.printError(Serial);
      }
      Serial.setDebugOutput(false);
    }
    yield();
  });
}
 

Алексей.

Active member
Можно как-то модифицировать Update.write, чтобы писать сразу на место прошивки?
Вопросом на вопрос :)
Как должна повести себя прошивка после перезагрузки если обновление не завершено? Одну половину прошивки мы уже затерли, а другая половина осталась от прежней.
 

Paul_B

Member
Как должна повести себя прошивка после перезагрузки если обновление не завершено? Одну половину прошивки мы уже затерли, а другая половина осталась от прежней.
Риск есть, но если файл с прошивкой лежит в SPIFFS, то это практически в той же флэш памяти. И хотелось бы сразу файл из SPIFFS писать не в область OTA-обновлений, а на место прошивки.
 

Алексей.

Active member
Риск есть, но если файл с прошивкой лежит в SPIFFS, то это практически в той же флэш памяти. И хотелось бы сразу файл из SPIFFS писать не в область OTA-обновлений, а на место прошивки.
А какая разница? Ели то, что исполняется загрузилось на половину, как этот битый файл прошивку исполнять теперь, если это скрипт для lua, как его рваного интерпретировать?
 

Paul_B

Member
Вопрос решен.
Файл Updater.cpp модифицирован.
Можно писать bin-файл с прошивкой с адреса расположения SPIFFS (понятно, что SPIFFS затирается), поэтому после перезагрузки модуля сразу же накатывается bin-файл со SPIFFS)
Либо второй вариант - файл с прошивкой сразу писать с 0-го адреса. Какой оставить для себя пока не решил.

Кстати, писать во флеш с адреса расположения SPIFFS это проще (меньше телодвижений) по сравнению с тем, чтобы удалить все файлы из SPIFFS, закачать туда прошивку (т.е. размер SPIFFS в 512Кб практически совпадает с размером прошивки 495Кб)

В файле Updater.cpp меняем строку
Код:
    updateStartAddress = (updateEndAddress > roundedSize)? (updateEndAddress - roundedSize) : 0;
На ту же, что с для обновления SPIFFS:
Код:
updateStartAddress = (uint32_t)&_SPIFFS_start - 0x40200000;
А еще лучше на такую, чтобы запись велась сразу после имеющегося скетча:
Код:
    updateStartAddress = (ESP.getSketchSize() + FLASH_SECTOR_SIZE - 1)& (~(FLASH_SECTOR_SIZE - 1));
Ну и размер обновления выставляем на всю оставшуюся память
Код:
uint32_t maxSketchSpace = (ESP.getFlashChipRealSize()-ESP.getSketchSize()-16)&(~15);
Если обновляемая прошивка умещается между текущей и началом SPIFFS, то обновление пройдет ровно, а если она больше, то надо после будет подгрузить bin-файл SPIFFS
 
Последнее редактирование:

Paul_B

Member
Проверил все работает. Теперь бы еще научиться схранять все нужные фалы из SPIFFS (а не по одному через edit.htm) нажатием одной кнопки перед обновлением и такую же загрузку после обновления...

По кране мере этот способ дает возможность удаленного обновления больших скетчей при мало памяти, не надо доставать и подключать шнурок.
 

Алексей.

Active member
Paul_B,
Вы правите исходники в sdk, что нужно делать, когда выходят обновления sdk?
Например Updater.cpp последний раз обновлялся 2 месяца назад, при выходе обновления в ручную исходники мерджить будем или есть какие нибудь рекомендации по решение проблемы с обновлениями?
 
Сверху Снизу