2

I am creating a project where I want to do auto update by downloading update data from the server (FIRMWARE and SPIFFS update), I did it and it works, but I have a little problem because the device configuration (wifi password, ssid etc.) is saved on the SPIFFS partition.

But as you can guess, updating SPIFFS with a .bin image will remove the file from the configuration. I came up with the idea to load the configuration into RAM before updating SPIFFS and then overwrite the already updated configuration file with the data previously loaded into RAM after the update.

But the problem is with the solution that after restarting the board, the configuration file has the update data, not the RAM overwritten. But when the board is booted 5-10 times, the actual configuration data read from RAM suddenly appears in the configuration file. It is a bit problematic and it shouldn't be a solution that should be included in the software, because it may not always be loaded on all board.

Does anyone know how effectively you can overwrite the update data before restarting the board?

I will add that I use the default memory partitioning layout:

# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x140000,
app1,     app,  ota_1,   0x150000,0x140000,
spiffs,   data, spiffs,  0x290000,0x170000,

This is code:

void makeUpdate(String host, String bin, int command = 0)
{
    WiFiClientSecure client;
    client.setCACert(github_cert);

    long contentLength = 0;
    bool isValidContentType = false;

    Serial.println("Connecting to: " + String(host));
    if (client.connect(host.c_str(), PORT)){
        Serial.println("Fetching Bin: " + String(bin));

        client.print(String("GET ") + bin + " HTTP/1.1\r\n" +
                     "Host: " + host + "\r\n" +
                     "Cache-Control: no-cache\r\n" +
                     "Connection: close\r\n\r\n");

        unsigned long timeout = millis();
        while (client.available() == 0){
            if (millis() - timeout > 5000){
                Serial.println("Client Timeout !");
                client.stop();
                return;
            }
        }

        while (client.available()){
            String line = client.readStringUntil('\n');
            line.trim();

            if (!line.length()) break;
            if (line.startsWith("HTTP/1.1")){
                if (line.indexOf("200") < 0){
                    Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
                    break;
                }
            }
            if (line.startsWith("Content-Length: ")){
                contentLength = atol((this->getHeaderValue(line, "Content-Length: ")).c_str());
                Serial.println("Got " + String(contentLength) + " bytes from server");
            }
            if (line.startsWith("Content-Type: ")){
                String contentType = this->getHeaderValue(line, "Content-Type: ");
                Serial.println("Got " + contentType + " payload.");
                if (contentType == "application/octet-stream") isValidContentType = true;
            }
        }
    }
    else Serial.println("Connection to " + String(host) + " failed. Please check your setup");

    Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType));

    String configFileSave = "";
    if (contentLength && isValidContentType){

//*************** This is read config file **************************

        if (command == U_SPIFFS){
            Serial.printf("Reading config file: %s\r\n", CONFIG_FILE);

            File file = SPIFFS.open(CONFIG_FILE);
            if (!file || file.isDirectory()){
                Serial.println("======Failed to open config file======");
                return;
            }
            configFileSave = file.readString();

            file.close();
            Serial.println("--Configuration file reading complete--");
        }

//*************** This is read config file **************************

        bool canBegin = Update.begin(contentLength, command, LED_BUILTIN, HIGH);

        if (canBegin){
            Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!");
            size_t written = Update.writeStream(client);

            if (written == contentLength) Serial.println("Written : " + String(written) + " successfully");
            else Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?");

            if (Update.end()){
                Serial.println("OTA done!");
                if (Update.isFinished()){

//*************** This is write config file **************************

                    if (command == U_SPIFFS){
                        Serial.printf("Writing config file: %s\r\n", CONFIG_FILE);

                        File file = SPIFFS.open(CONFIG_FILE, FILE_WRITE);
                        if (!file || file.isDirectory()){
                            Serial.println("======Failed to open config file======");
                            return;
                        }
                        if (!file.println(configFileSave)){
                            Serial.println("======Failed to write data to config file======");
                            return;
                        }

                        file.close();
                        Serial.println("--Completed writing data to the configuration file");

                        File f = SPIFFS.open(CONFIG_FILE, FILE_READ);
                        if (!f || f.isDirectory()){
                            Serial.println("======Failed to open config file======");
                            return;
                        }
                        String configFile = f.readString();
                        Serial.print("===Config File: ");
                        Serial.println(configFile);
                        f.close();
                    }

//*************** This is write config file **************************


                    Serial.println("Update successfully completed. Rebooting.");
                    // ESP.restart();
                }
                else Serial.println("Update not finished? Something went wrong!");
            }
            else Serial.println("Error Occurred. Error #: " + String(Update.getError()));
        }
        else{
            Serial.println("Not enough space to begin OTA");
            client.flush();
        }
    }
    else{
        Serial.println("There was no content in the response");
        client.flush();
    }
}
Marak123
  • 21
  • 1
  • 3
  • 1
    Do you need to update the firmware/spiffs at the same time? Maybe you could separate the firmware and spiffs; do an update. Restart. And download the changed spiff, before you restart initialize the needed parameters? – RemyHx Jul 01 '22 at 14:38
  • Good idea, I also came up with it, but it does not change my problem, I did as you wrote, i.e. updated spiffs, restarted and updated the firmware (why is the firmware updated second, because in the future I do not know what software I will introduce and whether it will update spiffs after starting ). The configuration file is replaced with the update data anyway. – Marak123 Jul 01 '22 at 14:56
  • you could use the EEPROM emulation library for configuration data if you must update the whole SPIFFS – Juraj Jul 01 '22 at 16:35
  • You could also introduce a custom partition for the config data, separate from spiffs and firmware. Like here: https://esp32.com/viewtopic.php?t=6694 – RemyHx Jul 01 '22 at 21:50
  • In the esp32 examples folder there is an partitions write and read example. I think it could be useful. – RemyHx Jul 02 '22 at 08:58
  • Have you found a solution for this? – Mendes Mar 10 '23 at 11:52
  • Unfortunately not, for now I decided to hold off and focus on another project. – Marak123 Mar 11 '23 at 13:04

0 Answers0