本教程是 ESP32cam 的系列教程之三,使用 Arduino IDE 对 ESP32cam 开发板进行开发。
本教程代码同样使用与其他 ESP32 开发板。
OTA 即空中下载技术(Over-the-Air Technology),其可以安全方便地升级设备的固件或软件。远程升级还可以大大降低成本,节省资源,它已成为物联网设备和产品制造商的关键技术之一。
ESP32 开发板支持 3 种 OTA 方式:
本文主要介绍:HTTP_OTA 的原理与实现。
.bin
文件。.bin
自动完成版本的升级,然后自动重启开发板。本地 1_0_0 版本程序主要内容如下:
#include
#include
#include
#include
/**********根据实际修改**********/
const char* wifi_ssid = "TP-LINK_1760"; // WIFI名称,区分大小写,不要写错
const char* wifi_password = "987654321"; // WIFI密码
// 特别重要,升级依据!!!
// 设置当前代码版本 格式 1_0_0
char* version = "1_0_0";
//远程固件链接,只支持http
const char* baseUpdateUrl = "http://example.cn/esp32/";
const char* updateJson = "http://example.cn/esp32/esp32_update.json";
// esp32_update.json
// {
// "version":"1_0_1"
// }
/**********根据实际修改**********/
int need_ota_update = 0;
int i = 0;
String jsonBuffer;
// 获取远程 json 升级文件
String httpGETRequest(const char* serverName) {
WiFiClient client;
HTTPClient http;
String payload = "";
//连接目标网址
http.begin(client, serverName);
//发送HTTP站点请求
int httpCode = http.GET();
if (httpCode > 0) {
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
payload = http.getString();
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end(); //关闭连接
//返回获得的数据用于Json处理
return payload;
}
// 依据json文件中版本号与本地版本号,判断是否需要进行更新
void isOrNotNeedUpdate(){
// 获取远程的升级 json ,判断内部版本与本地是否相同,判断是否需要升级
jsonBuffer = httpGETRequest(updateJson);
Serial.println(jsonBuffer);
//将解析的Json对象值储存在Jsonu缓冲区中
JSONVar myObject = JSON.parse(jsonBuffer);
Serial.println(myObject);
// Serial.println(myObject["version"]);
const char* ota_version = myObject["version"];
// Serial.println(ota_version);
Serial.println("---");
Serial.print("远程版本: ");
Serial.println(ota_version);
Serial.print("本地版本: ");
Serial.println(version);
// char * 与 const char * 比较
// 判断远程版本与本地版本是否相同
if (String(version) == String(ota_version)) {
need_ota_update = 0;
Serial.println("无需升级。。。");
} else {
need_ota_update = 1;
Serial.println("需要升级。。。");
Serial.print("OTA 升级地址为:");
// 升级的完整链接, 例如:http://example.cn/esp32/esp32_1_0_1.bin
String fullUpdateUrl = String(baseUpdateUrl) + "esp32_" + ota_version + ".bin";
Serial.println(String(fullUpdateUrl));
// 获取远程 bin 文件进行升级
t_httpUpdate_return ret = ESPhttpUpdate.update(fullUpdateUrl);
Serial.println(ret);
switch (ret) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
Serial.println("HTTP_UPDATE_OK");
break;
default:
Serial.println(ret);
}
// version=(char *)ota_version;
}
need_ota_update = 0;
}
void setup() {
Serial.begin(115200); //波特率115200
Serial.print("Connection WIFI");
WiFi.begin(wifi_ssid, wifi_password); //连接wifi
while (WiFi.status() != WL_CONNECTED) { //等待连接wifi
delay(500);
Serial.print(".");
}
Serial.println("");
// 调用判断是否需要升级函数
isOrNotNeedUpdate();
}
void loop() {
// 主程序
Serial.println(i);
i++;
delay(2000);
}
本测试升级程序如下,仅仅在程序版本与主程序中做了调整,以便更清楚的看出是否OTA升级成功。
#include
#include
#include
#include
/**********根据实际修改**********/
const char* wifi_ssid = "TP-LINK_1760"; // WIFI名称,区分大小写,不要写错
const char* wifi_password = "987654321"; // WIFI密码
// 特别重要,升级依据!!!
// 设置当前代码版本 格式 1_0_0
char* version = "1_0_1";
//远程固件链接,只支持http
const char* baseUpdateUrl = "http://example.cn/esp32/";
const char* updateJson = "http://example.cn/esp32/esp32_update.json";
// esp32_update.json
// {
// "version":"1_0_1"
// }
/**********根据实际修改**********/
int need_ota_update = 0;
int i = 0;
String jsonBuffer;
// 获取远程 json 升级文件
String httpGETRequest(const char* serverName) {
WiFiClient client;
HTTPClient http;
String payload = "";
//连接目标网址
http.begin(client, serverName);
//发送HTTP站点请求
int httpCode = http.GET();
if (httpCode > 0) {
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
payload = http.getString();
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end(); //关闭连接
//返回获得的数据用于Json处理
return payload;
}
// 依据json文件中版本号与本地版本号,判断是否需要进行更新
void isOrNotNeedUpdate(){
// 获取远程的升级 json ,判断内部版本与本地是否相同,判断是否需要升级
jsonBuffer = httpGETRequest(updateJson);
Serial.println(jsonBuffer);
//将解析的Json对象值储存在Jsonu缓冲区中
JSONVar myObject = JSON.parse(jsonBuffer);
Serial.println(myObject);
// Serial.println(myObject["version"]);
const char* ota_version = myObject["version"];
// Serial.println(ota_version);
Serial.println("---");
Serial.print("远程版本: ");
Serial.println(ota_version);
Serial.print("本地版本: ");
Serial.println(version);
// char * 与 const char * 比较
// 判断远程版本与本地版本是否相同
if (String(version) == String(ota_version)) {
need_ota_update = 0;
Serial.println("无需升级。。。");
} else {
need_ota_update = 1;
Serial.println("需要升级。。。");
Serial.print("OTA 升级地址为:");
// 升级的完整链接, 例如:http://example.cn/esp32/esp32_1_0_1.bin
String fullUpdateUrl = String(baseUpdateUrl) + "esp32_" + ota_version + ".bin";
Serial.println(String(fullUpdateUrl));
// 获取远程 bin 文件进行升级
t_httpUpdate_return ret = ESPhttpUpdate.update(fullUpdateUrl);
Serial.println(ret);
switch (ret) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;
case HTTP_UPDATE_OK:
Serial.println("HTTP_UPDATE_OK");
break;
default:
Serial.println(ret);
}
// version=(char *)ota_version;
}
need_ota_update = 0;
}
void setup() {
Serial.begin(115200); //波特率115200
Serial.print("Connection WIFI");
WiFi.begin(wifi_ssid, wifi_password); //连接wifi
while (WiFi.status() != WL_CONNECTED) { //等待连接wifi
delay(500);
Serial.print(".");
}
Serial.println("");
// 调用判断是否需要升级函数
isOrNotNeedUpdate();
}
void loop() {
// 主程序
Serial.println(i);
Serial.println("OTA 升级成功");
i++;
delay(2000);
}
这里使用 vscode 进行:
esp32
,文件 index.html
,目录下新建文件 esp32_update.json
esp32_update.json
中内容是 {"version":"1_0_1"}
,表明当前远程的版本为 1_0_1
index.html
中为标准html结构文件index.html
界面中右键>Open with Live Server 打开127.0.0.1
为本地 192.168.1.XXX
并拼接 /esp32/esp32_update.json
,如下图所示.bin
文件将导出的 .bin
文件重命名为 esp32_1_0_x.bin
样式,并复制到 2.4.1 节中的 esp32目录中,保证使用 http://192.168.1.x/esp32/esp32_1_0_x.bin
能够下载到该文件。
esp32_update.json
内部版本改为 1_0_0 ,保证一开始不升级。esp32_update.json
内部版本改为 1_0_1 ,然后重启开发板。通过第二节可知,可以通过 HTTP_OTA 实现 esp32 开发板的隔空升级,这样可以在一台设备上测试好了程序后,上传 .bin
文件到第 2.4.1 节中的 HTTP 服务器文件夹中,实现其他开发板批量升级。
第 2.4 节是使用本地 HTTP 服务器进行升级的,我们也可以使用云服务厂商的对象云存储服务,将需要升级的 .bin
文件与 esp32_update.json
放到云服务厂商的对象云存储服务中,使用提供的公网域名替换程序代码中的远程固件连接,真正实现远程 OTA 快速自动升级服务。
注意:
- 本地 HTTP_OTA 升级时,本机电脑需要和 esp32 开发板连在同一个网络下,否则 esp32 开发板无法访问固件地址。
- 使用云服务厂商的对象云存储服务,对象云存储需要设置禁止缓存,否则可能会获取之前缓存的版本而不是最新版,导致不必要的错误。
本文首发于本人博客:https://blog.gitnote.cn/post/esp32cam_http_ota/
版权信息: CC BY-NC-SA 4.0 (自由转载-非商用-相同方式共享-保持署名)