简介
OTA全称“Over-The-Air”,即空中下载技术(或者空中升级),早期被广泛应用在手机行业中,终结了手机软件升级需要连接电脑、下载软件、再安装更新的繁复操作。OTA在ESP32上,就是空中上传固件,你可以不用通过USB线对ESP上传固件,只要ESP32和你的电脑处于同一网络,或者蓝牙网络,甚至可以通过互联网在网页端进行固件更新。
OTA是相当实用的技术,除了方便,有时候对于上传有点问题ESP32来说,是相当方便的,之前文章有讨论过《ESP32自动烧录超时的解决方法(Timed out waiting for packet header)》,上传点问题的esp32很常见,因为各个厂家用料和设计不尽相同,经常会有各种各样的问题,如果OTA固件在一开始就写入了,即使使用过程中不能使用usb接口写入固件,也可以通过OTA进行更新。
本文讨论在Arduino环境下,ESP32在Wifi网络下通过UDP进行远程更新的操作。
原理
OTA 升级机制可以让设备在固件正常运行时根据接收数据(如通过 Wi-Fi 或蓝牙)进行自我更新。要运行 OTA 机制,需配置设备的分区表,该分区表至少包括两个 OTA 应用程序分区(即 ota_0 和 ota_1)和一个 OTA 数据分区。OTA 功能启动后,向当前未用于启动的 OTA 应用分区写入新的应用固件镜像。镜像验证后,OTA 数据分区更新,指定在下一次启动时使用该镜像。
下图说明了在不同阶段下,esp32使用分区的情况。
通过UDP OTA进行更新
Basic OTA使用了ArduinoOTA的框架来支持OTA操作,支持了Basic OTA的ESP32通过向网络发送UDP包,让电脑可以发现支持OTA的设备。
在Arduino选择了网络中的设备作为端口以后,就能在Arduino中空中升级固件。
如果使用的是PlatformIO,只要把原来写入端口的位置改成IP,也能进行空中升级固件。
你可以修改或增加plaformio.ini中一下upload_port配置,
upload_port = 192.168.31.143
也可以运行pio命令是指定upload_port
pio run -t upload --upload-port 192.168.31.143
同理,上传文件到ESP32的SPIFFS或者LittleFS也可以用同样方法。
代码例子
要写一个支持OTA的程序,只需要加入少量代码并进行配置,就能实现OTA功能。
第一步,加入头文件
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
第二步,配置SSID和密码的信息
const char* ssid = "<你的网络名称>";
const char* password = "<你的WIFI>";
第三步,先连接WIFI
void setup() {
Serial.begin(115200);
Serial.println("Booting");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
第四步,设置hostname,这样能辨认出哪个esp32
ArduinoOTA.setHostname("esp32_ota_test");
第五步,增加OTA的调回处理程序,和开始OTA的服务
这段程序主要是处理OTA的onStart,onEnd,onProgress和onError几个事件的调回。
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
else // U_SPIFFS
type = "filesystem";
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
})
.onEnd([]() {
Serial.println("\nEnd");
})
.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
})
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
第六步,在loop方法中加入OTA处理
ArduinoOTA.handle();
常见问题
问题1:OTA过程中意外断电或者中断,是否后影响原来的程序?
回答:不会影响原来程序。一般ESP程序会划分一个OTA 数据分区,当OTA成功后才会指定下次程序启动时使用OTA的数据分区,因此,OTA过程意外中断并不会影响原来的程序。
问题2:是否所有ESP32都支持OTA?
回答:不是的,在写入ESP32时,如果配置了No OTA的配置,你就不能使用OTA的功能,ESP32为你准备一个APP的数据区,和OTA的数据区,也就是说如果支持OTA,你的程序空间需要占用双倍的空间才能支持OTA功能,因此,并不是所有开发人员原因牺牲双倍的空间来支持OTA。