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.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);
}

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.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);
}

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 (自由转载-非商用-相同方式共享-保持署名)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用Linux部署Jpress博客系统

环境要求 linux系统&#xff1a;我使用的操作系统是CentOS7 数据库&#xff1a;mysql&#xff0c;也可以使用mariadb jdk&#xff1a;与你的Linux操作系统能兼容的版本 tomcat&#xff1a;我使用的是tomcat8版本 如果没有数据库&#xff0c;请先自行下载 如果没有安装jdk…

Agile manifesto principle (敏捷宣言的原则)

Agile在管理中越来越受推崇&#xff0c;最初是由于传统的软件开发管理方式&#xff08;瀑布模型&#xff09;面对日益复杂的需求&#xff0c;无法Delivery令人满意的结果&#xff0c;经过总结探索&#xff0c;2001年&#xff0c;由行业代表在一次聚会中提出Agile敏捷mainfesto&…

RK3588开发板 (armsom-w3) 之 USB摄像头图像预览

硬件准备 RK3588开发板&#xff08;armsom-w3&#xff09;、USB摄像头&#xff08;罗技高清网络摄像机 C93&#xff09;、1000M光纤 、 串口调试工具 v4l2采集画面 v4l2-ctl是一个用于Linux系统的命令行实用程序&#xff0c;用于控制视频4 Linux 2&#xff08;V4L2&#xff0…

P1257 平面上的最接近点对

题目 思路 详见加强加强版 代码 #include<bits/stdc.h> using namespace std; #define int long long const int maxn4e510; pair<int,int> a[maxn]; int n; double d1e16; pair<int,int> vl[maxn],vr[maxn]; void read() { cin>>n;for(int i1;i<…

(一)基于Spring Reactor框架响应式异步编程|道法术器

Spring WebFlux 响应式异步编程|道法术器(一) Spring WeFlux响应式编程整合另一种方案|道法术器(二) R2DBC简介 Spring data R2DBC是更大的Spring data 系列的一部分&#xff0c;它使得实现基于R2DBC的存储库变得容易。R2DBC代表反应式关系数据库连接&#xff0c;这是一种使用…

SpringBoot统一功能处理

我们要实现以下3个目标&#xff1a; 统一用户登录权限统一数据格式返回统一异常处理 1.用户的登录权限校验 1.1Spring AOP用户统一登录验证问题 Aspect Component public class UserAspect {// 定义切点controller包下、子孙包下所有类的所有方法Pointcut("execution(…

浅析大数据时代下的视频技术发展趋势以及AI加持下视频场景应用

视频技术的发展可以追溯到19世纪初期的早期实验。到20世纪初期&#xff0c;电视技术的发明和普及促进了视频技术的进一步发展。 1&#xff09;数字化&#xff1a;数字化技术的发明和发展使得视频技术更加先进。数字电视信号具有更高的清晰度和更大的带宽&#xff0c;可以更快地…

【李宏毅机器学习·学习笔记】Deep Learning General Guidance

本节课可视为机器学习系列课程的一个前期攻略&#xff0c;这节课主要对Machine Learning 的框架进行了简单的介绍&#xff1b;并以training data上的loss大小为切入点&#xff0c;介绍了几种常见的在模型训练的过程中容易出现的情况。 课程视频&#xff1a; Youtube&#xff1…

青少年软件编程(Python六级)等级考试试卷(2022年9月)

青少年软件编程&#xff08;Python六级&#xff09;等级考试试卷&#xff08;2022年9月&#xff09; 第 1 题 单选题 以下关于Python二维数据的描述中&#xff0c;错误的是&#xff1f;&#xff08; &#xff09; A. 表格数据属于二维数据&#xff0c;由整数索引的数据构成 …

Appium+python自动化(二十八)- 高级滑动(超详解)

高级溜冰的滑动 滑动操作一般是两点之间的滑动&#xff0c;这种滑动在这里称其为低级的溜冰滑动&#xff1b;就是上一节给小伙伴们分享的。然而实际使用过程中用户可能要进行一些多点连续滑动操作。如九宫格滑动操作&#xff0c;连续拖动图片移动等场景。那么这种高级绚丽的溜…

银河麒麟V10 飞腾 Qt环境搭建

采用在线安装方式&#xff1a; 1、在线安装qt组件 sudo apt-get install qt5-* 2、在线安装qt creator sudo apt-get install qtcreator 以上简单两步安装完成后&#xff0c;新建项目已经可以编译过&#xff0c;但ClangCodeModel会报错如下图 the code model could not parse …

docker—springboot服务通信

文章目录 docker—springboot服务通信一、方式1、host 二、坑点末、参考资料 docker—springboot服务通信 一、方式 1、host 步骤&#xff1a; host文件增加域名解析&#xff1a; 127.0.0.1 rabbitmqapplication.yml&#xff1a; application.yml中&#xff0c;连接方式使用…

matlab使用教程(7)—基本画图函数

1.创建绘图 plot 函数具有不同的形式&#xff0c;具体取决于输入参数。 • 如果 y 是向量&#xff0c; plot(y) 会生成 y 元素与 y 元素索引的分段线图。 • 如果有两个向量被指定为参数&#xff0c; plot(x,y) 会生成 y 对 x 的图形。 使用冒号运算符创建从 0 至 2…

python-网络爬虫.BS4

BS4 Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库&#xff0c; 它能够通过你喜欢的转换器实现惯用的文档导航、查找、修改文档的方 式。 Beautiful Soup 4 官方文档&#xff1a;https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/ 帮助手册&…

devops(前端)

1.前言 前端的打包流程和后端的流程是一样的&#xff0c;只是打包的环境和制作的镜像有所不同&#xff0c;前端需要使用nodejs环境打包&#xff0c;镜像也是使用nginx镜像&#xff0c;因为用的是k8s的pod运行镜像&#xff0c;还需要使用configmap挂载nginx的配置&#xff0c;一…

CDH基于Kerberos开启身份验证实践总结

CDH基于Kerberos开启身份验证实践总结 前言简介Kerberos是什么Kerberos解决什么问题 Kerberos基本概念Kerberos认证流程Kerberos基本配置principalkeytabkrb5.confkdc.confkadm5.aclkerberos数据库 访问示例数据库访问信息 其他kerberos常用命令[Git Bash支持make命令](https:/…

【计算机网络】11、网络连通性:ping、traceroute、nslookup

文章目录 一、ping1.1 禁 ping 二、traceroute三、nslookup3.1 非交互模式3.2 交互模式 注意&#xff0c;测试网络连通性时&#xff0c;有的机器无法 ping 通&#xff0c;但可能 telnet 能通。不要因为无法 ping 通就放弃尝试。 一、ping 1.1 禁 ping 禁 ping 是通过忽略 IC…

SpringBoot 统⼀功能处理

目录 前言 1.⽤户登录权限效验 1.1、最初⽤户登录效验 1.2、Spring AOP ⽤户统⼀登录验证的问题 1.3、Spring 拦截器 了解 创建一个 Spring 拦截器 的流程 1、 创建自定义拦截器&#xff0c;实现 HandlerInterceptor 接⼝的preHandle&#xff08;执⾏具体⽅法之前的预处理…

day17 | 654.最大的二叉树 617.合并二叉树 700.二叉搜索树中的搜索 98.验证二叉搜索树

文章目录 一、最大的二叉树二、合并二叉树三、二叉搜索树中的搜索四、验证二叉搜索树 一、最大的二叉树 654.最大的二叉树 构建二叉树的题目&#xff0c;都用前序遍历。 因为我们一定要先构建根节点&#xff0c;才能继续向后构建。 递归函数的参数和返回值&#xff1a; Tree…

【MyBatis】MyBatis把空字符串转换成0的问题处理方案(96)

先看问题: Postman入参: MyBatis采用map循环插入: // Mapper接口层void addPar(Param(value "question") Map<String, Object> paramMap);<!-- 新增&#xff1a;参数 --><insert id"addPar" parameterType"map">INSERT IGNO…