ESP32cam系列教程003:ESP32cam实现远程 HTTP_OTA 自动升级

文章目录

  • 1.什么是 OTA
  • 2. ESP32cam HTTP_OTA 本地准备
    • 2.1 HTTP OTA 升级原理
    • 2.2 开发板本地基准程序(程序版本:1_0_0)
    • 2.3 开发板升级程序(程序版本:1_0_1)
    • 2.4 本地 HTTP_OTA 升级测试
      • 2.4.1 本地运行一个 HTTP 服务
      • 2.4.2 替换远程链接并将要升级的程序打包成 `.bin` 文件
      • 2.4.3 替换远程链接并烧录基准程序(版本为:1_0_0 的程序)测试升级是否成功
  • 3. HTTP_OTA 升级展望
    • 3.1 后期版本更新可通过 HTTP_OTA 实现
    • 3.2 借助网络云平台实现远程 HTTP_OTA 升级

本教程是 ESP32cam 的系列教程之三,使用 Arduino IDE 对 ESP32cam 开发板进行开发。
本教程代码同样使用与其他 ESP32 开发板。

1.什么是 OTA

OTA 即空中下载技术(Over-the-Air Technology),其可以安全方便地升级设备的固件或软件。远程升级还可以大大降低成本,节省资源,它已成为物联网设备和产品制造商的关键技术之一。

ESP32 开发板支持 3 种 OTA 方式:

  1. Arduino IDE :主要用于软件开发阶段,实现不接线固件烧录
  2. Web_OTA:通过 Web 浏览器手动提供应用程序更新模块
  3. HTTP_OTA:固件存放到 http 服务器端,设备自动判断是否需要联网下载固件升级

本文主要介绍:HTTP_OTA 的原理与实现。

2. ESP32cam HTTP_OTA 本地准备

2.1 HTTP OTA 升级原理

  1. 本地程序在开机连接 WIFI 后发送 http 请求获取远程服务器中的升级 json 文件。
  2. 通过对比 json 中的远程版本信息与本地的版本信息判断是否一致。
  3. 若远程版本信息与本地版本不一致,则本地需要更新程序。
  4. 通过 json 中的版本信息在远程服务器中拉取需要更新的程序的 .bin 文件。
  5. 依据下载下来的 .bin 自动完成版本的升级,然后自动重启开发板。
  6. 重复第一步获取远程 json 文件判断是否需要更新。

2.2 开发板本地基准程序(程序版本:1_0_0)

本地 1_0_0 版本程序主要内容如下:

  1. 当前版本(非常重要,升级依据)
  2. 远程升级的 json 链接与远程固件的文件夹链接
  3. 获取并解析 json 的函数 httpGETRequest
  4. 依据 json 判断是否需要更新的函数 isOrNotNeedUpdate
  5. 以及其他基础信息组成
#include <WiFi.h>#include <HTTPClient.h>
#include <ESP32httpUpdate.h>
#include <Arduino_JSON.h>/**********根据实际修改**********/
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.binString 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);  //波特率115200Serial.print("Connection WIFI");WiFi.begin(wifi_ssid, wifi_password);    //连接wifiwhile (WiFi.status() != WL_CONNECTED) {  //等待连接wifidelay(500);Serial.print(".");}Serial.println("");// 调用判断是否需要升级函数isOrNotNeedUpdate();
}void loop() {
// 主程序Serial.println(i);i++;delay(2000);
}

2.3 开发板升级程序(程序版本:1_0_1)

本测试升级程序如下,仅仅在程序版本与主程序中做了调整,以便更清楚的看出是否OTA升级成功。

#include <WiFi.h>#include <HTTPClient.h>
#include <ESP32httpUpdate.h>
#include <Arduino_JSON.h>/**********根据实际修改**********/
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.binString 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);  //波特率115200Serial.print("Connection WIFI");WiFi.begin(wifi_ssid, wifi_password);    //连接wifiwhile (WiFi.status() != WL_CONNECTED) {  //等待连接wifidelay(500);Serial.print(".");}Serial.println("");// 调用判断是否需要升级函数isOrNotNeedUpdate();
}void loop() {
// 主程序Serial.println(i);Serial.println("OTA 升级成功");i++;delay(2000);
}

2.4 本地 HTTP_OTA 升级测试

2.4.1 本地运行一个 HTTP 服务

这里使用 vscode 进行:

  1. 用 vscode 打开一个空白文件夹
  2. 在文件夹中新建目录 esp32,文件 index.html ,目录下新建文件 esp32_update.json
  3. esp32_update.json 中内容是 {"version":"1_0_1"} ,表明当前远程的版本为 1_0_1
  4. index.html 中为标准html结构文件
  5. index.html 界面中右键>Open with Live Server 打开

  1. 替换 127.0.0.1 为本地 192.168.1.XXX 并拼接 /esp32/esp32_update.json ,如下图所示

2.4.2 替换远程链接并将要升级的程序打包成 .bin 文件

  1. 将 arduino IDE 中的程序的远程链接替换成本地 HTTP 服务器链接

  2. 工具中 开发板和 Partition Scheme 选择如下图:

  3. 项目中选择导出已编译的二进制文件,导出的二进制文件在同级目录下。

  4. 将导出的 .bin 文件重命名为 esp32_1_0_x.bin 样式,并复制到 2.4.1 节中的 esp32目录中,保证使用 http://192.168.1.x/esp32/esp32_1_0_x.bin 能够下载到该文件。

2.4.3 替换远程链接并烧录基准程序(版本为:1_0_0 的程序)测试升级是否成功

  1. 将 arduino IDE 中的程序的远程链接替换成本地 HTTP 服务器链接
  2. 将 2.4.1 节中的 esp32_update.json 内部版本改为 1_0_0 ,保证一开始不升级。
  3. 将程序烧录进 esp32 开发板中。然后打开串口监视器
  4. 串口调试器中显示不需要升级
  5. 将 2.4.1 节中的 esp32_update.json 内部版本改为 1_0_1 ,然后重启开发板。
  6. 由上图可知,开发板自动判断是否需要升级并自动OTA升级成功。

3. HTTP_OTA 升级展望

3.1 后期版本更新可通过 HTTP_OTA 实现

通过第二节可知,可以通过 HTTP_OTA 实现 esp32 开发板的隔空升级,这样可以在一台设备上测试好了程序后,上传 .bin 文件到第 2.4.1 节中的 HTTP 服务器文件夹中,实现其他开发板批量升级。

3.2 借助网络云平台实现远程 HTTP_OTA 升级

第 2.4 节是使用本地 HTTP 服务器进行升级的,我们也可以使用云服务厂商的对象云存储服务,将需要升级的 .bin 文件与 esp32_update.json 放到云服务厂商的对象云存储服务中,使用提供的公网域名替换程序代码中的远程固件连接,真正实现远程 OTA 快速自动升级服务。

注意:

  1. 本地 HTTP_OTA 升级时,本机电脑需要和 esp32 开发板连在同一个网络下,否则 esp32 开发板无法访问固件地址。
  2. 使用云服务厂商的对象云存储服务,对象云存储需要设置禁止缓存,否则可能会获取之前缓存的版本而不是最新版,导致不必要的错误。

本文首发于本人博客:https://blog.gitnote.cn/post/esp32cam_http_ota/
版权信息: CC BY-NC-SA 4.0 (自由转载-非商用-相同方式共享-保持署名)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/19397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ARP协议请求

文章目录 作用请求与应答流程数据包ARP协议以太网帧协议具体应用 作用 通过 IP地址 查找 MAC地址。 请求与应答流程 A&#xff1a;数据发送主机 B&#xff1a;目标主机 目前只知道目标主机IP地址&#xff0c;想把数据发送过去&#xff0c;需要查询到目标主机的MAC地址&#x…

Git使用详细教程

1. cmd面板的常用命令 clear&#xff1a;清屏cd 文件夹名称----进入文件夹cd … 进入上一级目录(两个点)dir 查看当前目录下的文件和文件夹(全拼:directory)Is 查看当前目录下的文件和文件夹touch 文件名----创建文件echo 内容 > 创建文件名----创建文件并写入内容rm 文件名…

vue3.3-TinyMCE:TinyMCE富文本编辑器基础使用

一、TinyMCE官网 GitHub - tinymce/tinymce TinyMCE中文文档中文手册 二、官网介绍 TinyMCE是一款易用、且功能强大的所见即所得的富文本编辑器。同类程序有&#xff1a;UEditor、Kindeditor、Simditor、CKEditor、wangEditor、Suneditor、froala等等。 TinyMCE的优势&…

LabVIEW开发小型减阻试验平台

LabVIEW开发小型减阻试验平台 湍流摩擦在粘性流体的阻力中起着重要作用&#xff0c;减少湍流摩擦是流体力学领域的热门话题之一。在油气管道的长距离流体输送中&#xff0c;泵站提供的几乎所有动力都用于克服流体的胫骨摩擦。在流体输送领域&#xff0c;船舶的蒙皮摩擦阻力占总…

css实现水平居中

代码示例 <div class"box"><div class"box1"></div> </div>1.弹性布局&#xff1a;&#xff08;推荐&#xff09; display:flex&#xff1b; 这些要添加在父级的&#xff0c;是父级的属性 //父级添加display:flex; //父级添加jus…

SpringCloud Gateway 在微服务架构下的最佳实践

作者&#xff1a;徐靖峰&#xff08;岛风&#xff09; 前言 本文整理自云原生技术实践营广州站 Meetup 的分享&#xff0c;其中的经验来自于我们团队开发的阿里云 CSB 2.0 这款产品&#xff0c;其基于开源 SpringCloud Gateway 开发&#xff0c;在完全兼容开源用法的前提下&a…

腾讯云TencentOS Server镜像系统常见问题解答

腾讯云TencentOS Server镜像是腾讯云推出的Linux操作系统&#xff0c;完全兼容CentOS生态和操作方式&#xff0c;TencentOS Server操作系统为云上运行的应用程序提供稳定、安全和高性能的执行环境&#xff0c;TencentOS可以运行在腾讯云CVM全规格实例上&#xff0c;包括黑石物理…

【波浪动态特效】基于jquery实现页面底部波浪动画效果(附完整源码下载)

文章目录 写在前面涉及知识点实现效果1、搭建页面1.1、创建两个片区1.2、创建波浪区域1.3、静态页面源码 2、JS实现波浪效果2.1 动画原理2.2 动画源码 3、源码分享3.1 百度网盘3.2 123云盘3.3 邮箱留言 总结 写在前面 想必搭建过企业官网的大多数对这个效果不陌生吧&#xff0…

Java之Map接口

文章目录 简述Map中key-value特点 Map接口的常用方法Map的主要实现类&#xff1a;HashMapHashMap概述 Map实现类之二&#xff1a;LinkedHashMapMap实现类之三&#xff1a;TreeMapMap实现类之四&#xff1a;Hashtable&#xff08;古老实现类&#xff09;Map实现类之五&#xff1…

AI 3D结构光技术加持,小米引领智能门锁新标准

一直以来&#xff0c;小米智能门锁系列产品让更多家庭走进了安全便捷的智能生活&#xff0c;安全至上的设计让很多家庭都轻松告别了随身钥匙。 7月27日&#xff0c;小米正式推出小米智能门锁M20 Pro&#xff0c;再一次引领智能门锁产品的发展潮流。该款门锁采用AI 3D结构光技术…

2023软件设计师中级备考经验分享(文中有资料链接分享)

先摊结论吧&#xff0c;软考中级设计师备考只是备考半个月&#xff08;期间还摆烂了几天&#xff09;&#xff0c;然而成绩如下&#xff1a; 我自己都没想到会这么好的成绩。。。 上午题&#xff1a;推荐把软考通APP里的历年真题刷3-4遍&#xff0c;直接刷真题&#xff0c;然后…

关于 Ubuntu 长按 shift 无效, 按 Esc 直接进入 grub 改密码的解决方法

本次长按shift没有反应&#xff0c;直接进入了系统界面&#xff0c;所以改用长按Esc键&#xff0c;步骤如下&#xff1a; 1. 长按esc&#xff0c;进入grub>提示 2.输入grub>normal &#xff0c;回车 3.上一步回车后&#xff0c;继续敲击Esc &#xff0c;出现grub界面 …

无法加载 DLL“xxxx.dll”: 找不到指定的模块。 (异常来自 HRESULT:0x8007007E)。

目录 1、DLL引用的问题 1、DLL引用的问题 这两篇文章说的很好&#xff0c;C# DllImport用法和路径问题和无法加载 DLL“xxxx.dll”: 找不到指定的模块 但我折腾了2天&#xff0c;还是没有解决。后来请同事帮忙&#xff0c;发现&#xff0c;服务器上少装东西了…下图的红框这个…

java学习路程之篇四、进阶知识、石头迷阵游戏、绘制界面、打乱石头方块、移动业务、游戏判定胜利、统计步数、重新游戏

文章目录 1、绘制界面2、打乱石头方块3、移动业务4、游戏判定胜利5、统计步数6、重新游戏7、完整代码 1、绘制界面 2、打乱石头方块 3、移动业务 4、游戏判定胜利 5、统计步数 6、重新游戏 7、完整代码 java之石头迷阵单击游戏、继承、接口、窗体、事件、组件、按钮、图片

深度学习——常见注意力机制

1.SENet SENet属于通道注意力机制。2017年提出&#xff0c;是imageNet最后的冠军 SENet采用的方法是对于特征层赋予权值。 重点在于如何赋权 1.将输入信息的所有通道平均池化。 2.平均池化后进行两次全连接&#xff0c;第一次全连接链接的神经元较少&#xff0c;第二次全连…

【HarmonyOS】键盘遮挡输入框时,实现输入框显示在键盘上方

【关键字】 harmonyOS、键盘遮挡input&#xff0c;键盘高度监听 【写在前面】 在使用API6、API7开发HarmonyOS应用时&#xff0c;常出现页面中需要输入input&#xff0c;但是若input位置在页面下方&#xff0c;在input获取焦点的时候&#xff0c;会出现软键盘挡住input情况&a…

数字图像处理-彩色图像处理

文章目录 一、彩色模型1.1RGB彩色模型1.2CMY和CMYK彩色模型1.3HSI彩色模型 二、伪彩色图像处理2.1灰度分层2.2灰度到彩色的变换 三、彩色图像的分割3.1RGB中的彩色图像分割3.2彩色边缘检测 一、彩色模型 1.1RGB彩色模型 RGB空间是生活中最常用的一个模型&#xff0c;电视机、…

手写自定义的spring-boot-start

需求&#xff1a;手写一个加密的spring-boot-start&#xff0c;按着用户定义的加密算法&#xff08;可选&#xff1a;MD5、SHA&#xff09;去加密内容 新建一个maven项目 新建好的项目结构和pom.xml如图 添加pom.xml 完整的pom.xml文件 <?xml version"1.0" …

25.6 matlab里面的10中优化方法介绍——模拟退火算法(matlab程序)

1.简述 相信没有相关物理知识背景的小伙伴看到“退火”二字是一脸懵逼的...固体的退火过程指的是将固体加热至足够高的温度&#xff0c;再使其慢慢冷却的过程。在加热过程中&#xff0c;原本有序排列的内部粒子开始无序运动&#xff0c;此时固体的内能不断增大&#xff1b;而在…

大数据面试题:HBase的RegionServer宕机以后怎么恢复的?

面试题来源&#xff1a; 《大数据面试题 V4.0》 大数据面试题V3.0&#xff0c;523道题&#xff0c;679页&#xff0c;46w字 可回答&#xff1a;1&#xff09;HBase一个节点宕机了怎么办&#xff1b;2&#xff09;HBase故障恢复 参考答案&#xff1a; 1、HBase常见故障 导…