ESP32 | OTA更新| spiffs中的配置文件

发布于 2025-02-12 04:39:59 字数 6088 浏览 2 评论 0原文

我正在创建一个项目,我想通过从服务器下载更新数据来进行自动更新(固件和Spiffs Update),我做到了,它有效,但是我有一些问题,因为设备配置(WiFi密码,SSID等) )保存在Spiffs分区中。

但是,您可以猜到,使用.bin映像更新spiffs将从配置中删除文件。我想出了在更新Spiffs之前将配置加载到RAM中的想法,然后在更新后使用先前已加载到RAM的数据覆盖已更新的配置文件。

但是问题在于解决方案是在重新启动板后,配置文件具有更新数据,而不是RAM覆盖。但是,当板启动5-10次时,从RAM读取的实际配置数据突然出现在配置文件中。 这有点有问题,它不应是软件中应包含的解决方案,因为它可能并不总是在所有板上加载。

有人知道您在重新启动板之前可以有效地覆盖更新数据吗?

我会补充说,我使用默认的内存分区布局:

# 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,

是代码:

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();
    }
}

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();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

秋叶绚丽 2025-02-19 04:39:59

我在搜索遇到的类似问题时遇到了这个问题。对我来说,问题是在开始更新之前,我没有在启用SPIFSS图像。

spiffs.end();在启动OTA更新之前,然后spiffs.begin();一旦OTA更新完成。

在我的情况下,用户正在从Spiffs提供的HTML页面启动更新,因此需要在实际启动更新之前加载这些更新,因此将其添加到相关的HTML页面的末尾。

<script>
$(document).ready(function() {
    $.post('/url-to-start-update', {}, function(response) {
        // Ignore the response
    });
});
</script>

I came across this whilst searching a similar issue I was having. For me the problem was that I was not un-mounting the SPIFSS image before commencing the update.

SPIFFS.end(); before starting the OTA update, and then SPIFFS.begin(); once the OTA update is complete.

In my case a user was initiating the update from html pages served from SPIFFS, so needed to allow time for these to load before actually starting the update, so added this to the end of the relevant html page.

<script>
$(document).ready(function() {
    $.post('/url-to-start-update', {}, function(response) {
        // Ignore the response
    });
});
</script>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文