我正在创建一个项目,我想通过从服务器下载更新数据(固件和 SPIFFS 更新)来进行自动更新,我做到了并且它有效,但我有一个小问题,因为设备配置(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();
}
}
我在搜索我遇到的类似问题时遇到了这个。对我来说,问题是我在开始更新之前没有卸载 SPIFSS 映像。
开始 OTA 更新之前SPIFFS.end();
,OTA 更新完成后SPIFFS.begin();
。
在我的例子中,用户从 SPIFFS 提供的 html 页面启动更新,因此需要在实际开始更新之前留出时间加载这些页面,因此将其添加到相关 html 页面的末尾。
<script>
$(document).ready(function() {
$.post('/url-to-start-update', {}, function(response) {
// Ignore the response
});
});
</script>