创客出手

目录

ESP32 Wi-Fi OTA上传固件详解

esp32 ota

简介

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使用分区的情况。
file

通过UDP OTA进行更新

Basic OTA使用了ArduinoOTA的框架来支持OTA操作,支持了Basic OTA的ESP32通过向网络发送UDP包,让电脑可以发现支持OTA的设备。
在Arduino选择了网络中的设备作为端口以后,就能在Arduino中空中升级固件。
file

如果使用的是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。
file

更多关于 的文章
关注创客出手公众号

关注创客出手