ESP32 OTA升级之 https ota详解
1. 前言
本文以 ESP32 官方demo例程 native_ota_example
为例,详细阐述如何采用https实现esp32的ota升级。
- 第一章节,为本文的前言部分,对文章内容进行大体概述;
- 第二章节,主要描述了如何在本地将demo例程跑起来,并附带了关于使用demo例程中遇到的相关报错的具体解决措施;
- 第三章节,主要描述了ESP32的 flash 扇区布局;
- 第四章节,主要描述了OTA下载的镜像文件的头部数据结构,并对其进行详细分析,镜像文件的头部与OTA息息相关;
- 第五、六章节,详细描述了OTA升级过程中应用程序的状态切换逻辑以及相关软件版本的使用;
接下来,让我们一起研究ESP32的 OTA 升级是如何实现的吧!相信你一定有所收获!
2. 例程体验
例程目录:
esp-idf/examples/system/ota/native_ota_example/
工程地址:https://github.com/espressif/esp-idf/tree/release/v5.1/examples/system/ota/native_ota_example
IDF版本: v5.1
2.1 采用直接跳过ca根证书验证方案
-
进入
native_ota_example
工程 -
运行
idf.py menuconfig
配置wifi及服务器地址 -
配置 wifi
-
配置https服务器地址
如果没有https服务器,填写http服务器地址也可以,http服务器搭建参考:ESP32 OTA升级之HTTP OTA
https服务器,大家可以尝试把升级文件往github、gitee上发布也可以啦,免费的https测试服务器对吧 -
运行
idf.py build
编译工程 -
运行
idf.py flash monitor
下载工程并开启监控 -
网络连接成功之后https下载时会报错,提示
mbdtls ssl
握手失败,错误码-0x2700
I (5888) native_ota_example: Starting OTA example task I (5888) native_ota_example: Running partition type 0 subtype 0 (offset 0x00010000) E (6808) esp-tls-mbedtls: mbedtls_ssl_handshake returned -0x2700 I (6808) esp-tls-mbedtls: Failed to verify peer certificate! E (6808) esp-tls: Failed to open new connection E (6818) transport_base: Failed to open a new connection E (6828) HTTP_CLIENT: Connection failed, sock < 0 E (6828) native_ota_example: Failed to open HTTP connection: ESP_ERR_HTTP_CONNECT E (6838) native_ota_example: Exiting task due to fatal error...
-
打开
native_ota_example.c
文件,屏蔽.cert_pem
配置 -
运行
idf.py build
编译工程,之后运行idf.py flash monitor
开启监控 -
网络连接成功之后https下载时会报错,提示
mbdtls
服务器验证选项esp_tls_cfg_t
结构体配置失败I (5888) native_ota_example: Starting OTA example task I (5888) native_ota_example: Running partition type 0 subtype 0 (offset 0x00010000) E (6368) esp-tls-mbedtls: No server verification option set in esp_tls_cfg_t structure. Check esp_tls API reference E (6368) esp-tls-mbedtls: Failed to set client configurations, returned [0x8017] (ESP_ERR_MBEDTLS_SSL_SETUP_FAILED) E (6378) esp-tls: create_ssl_handle failed E (6388) esp-tls: Failed to open new connection E (6388) transport_base: Failed to open a new connection E (6398) HTTP_CLIENT: Connection failed, sock < 0 E (6398) native_ota_example: Failed to open HTTP connection: ESP_ERR_HTTP_CONNECT E (6408) native_ota_example: Exiting task due to fatal error...
-
修改
menuconfig
,跳过服务器证书验证 -
运行
idf.py build
编译工程,之后运行idf.py flash monitor
开启监控 -
网络连接成功之后https下载成功
2.2 采用mbedtls内自带的ca根证书方案
- 修改
native_ota_example.c
文件中.cert_pem
配置
esp_http_client_config_t config = {
.url = CONFIG_EXAMPLE_FIRMWARE_UPG_URL,
// .cert_pem = (char *)server_cert_pem_start,
.crt_bundle_attach = esp_crt_bundle_attach,
.timeout_ms = CONFIG_EXAMPLE_OTA_RECV_TIMEOUT,
.keep_alive_enable = true,
};
2.3 采用对应服务器的根证书文件
此方案,首先需要下载对应服务器的证书文件才可以,下载服务器的证书可以采用以下方案:
首先使用浏览器打开对应的服务器,之后浏览器的地址栏旁边有一个🔒,点击它
按照上述方式,导出对应服务器的证书文件 .pem
,之后替换掉工程目录下 server_certs
目录下的ca_cert.pem
文件里面的内容即可
采用此方案有一个需要特别注意的地方是:通过此方案下载的证书为此网站的证书,通常有效期为1年,过了一年之后就无效了!!!
这个时间在我们下载证书的时候其实就可以看到:
因此使用此方案时,需要注意特别处理,推荐两种解决方案:
1)采用升级的手段,定期更新设备端证书文件;
2)使用发证机构(注意选择大品牌的)的根证书文件,通常此类证书的有效期会比较长,我们上一小节中 mbedtls里面的证书其实就是存的一部分发证机构的ca跟证书
参考文档:ESP32空中升级 OTA
3. ESP32 flash分区结构
OTA是基于 Flash 进行的,想要弄清楚 ESP32 的 OTA,首先肯定得了解 ESP32 的 flash 布局结构,关于此部分内容我整理在了另外一篇博客,请查阅:ESP32 分区表(点击跳转),对 ESP32 的 flash 分区布局有所了解的可以直接跳过。
4. 应用程序镜像段结构
应用程序镜像段结构如下,运行命令 esptool.py --chip esp32 image_info build/app.bin
esptool.py v2.3.1
Image version: 1
Entry point: 40080ea4
13 segments
Segment 1: len 0x13ce0 load 0x3f400020 file_offs 0x00000018 SOC_DROM
Segment 2: len 0x00000 load 0x3ff80000 file_offs 0x00013d00 SOC_RTC_DRAM
Segment 3: len 0x00000 load 0x3ff80000 file_offs 0x00013d08 SOC_RTC_DRAM
Segment 4: len 0x028e0 load 0x3ffb0000 file_offs 0x00013d10 DRAM
Segment 5: len 0x00000 load 0x3ffb28e0 file_offs 0x000165f8 DRAM
Segment 6: len 0x00400 load 0x40080000 file_offs 0x00016600 SOC_IRAM
Segment 7: len 0x09600 load 0x40080400 file_offs 0x00016a08 SOC_IRAM
Segment 8: len 0x62e4c load 0x400d0018 file_offs 0x00020010 SOC_IROM
Segment 9: len 0x06cec load 0x40089a00 file_offs 0x00082e64 SOC_IROM
Segment 10: len 0x00000 load 0x400c0000 file_offs 0x00089b58 SOC_RTC_IRAM
Segment 11: len 0x00004 load 0x50000000 file_offs 0x00089b60 SOC_RTC_DATA
Segment 12: len 0x00000 load 0x50000004 file_offs 0x00089b6c SOC_RTC_DATA
Segment 13: len 0x00000 load 0x50000004 file_offs 0x00089b74 SOC_RTC_DATA
Checksum: e8 (valid)
Validation Hash: 407089ca0eae2bbf83b4120979d3354b1c938a49cb7a0c997f240474ef2ec76b (valid)
4.1 镜像文件头格式
- 镜像在最后一段之后有一个校验和字节(如上述中的
Checksum: e8 (valid)
)。此字节写入十六字节填充边界,因此应用程序镜像可能需要填充。 - 如果
esp_image_header_t
结构体(见下图)的hash_appended
字段被设置,则将附加 SHA256 校验和。SHA256 哈希的值是在从第一个字节到该字段的范围内计算的,该字段的长度为 32 个字节。
应用程序映像由以下结构组成:
-
首先是 镜像头
esp_image_header_t
结构数据,描述了 SPI 闪存的模式和内存段的数量。 -
之后是 数据段头
esp_image_segment_header_t
结构数据,此结构数据描述了每个段、其长度及其在 ESP32 内存中的位置,后跟长度为data_len
,图像中每个片段的数据偏移量按以下方式计算:- 第 0 段的偏移量 = sizeof(
esp_image_header_t
) + sizeof(esp_image_segment_header_t
))。 - 第 1 Segment 的偏移量 = 0 Segment 的偏移量 + 0 Segment 的长度 + sizeof(
esp_image_segment_header_t
)。 - 第 2 Segment 的偏移量 = 1 Segment 的偏移量 + 1 Segment 的长度 + sizeof(
esp_image_segment_header_t
)。
- 第 0 段的偏移量 = sizeof(
-
之后是 应用头
esp_app_desc_t
结构数据:- 此数据结构位于
DORM
段起始位置 - 当前应用程序可以通过调用
esp_app_get_description()
获取应用头结构 - 其他应用程序可通过调用
esp_ota_get_partition_description()
获取其他OTA分区应用头结构 - 此结构的偏移地址计算为:
offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)
- 此数据结构位于
-
再往后是 用户自定义的应用结构头,如有需要可自行查阅 Adding a Custom Structure to an Application
综上,一个应用程序镜像的头部结构为:
- 首先是
esp_image_header_t
- 其次是
esp_image_segment_header_t
- 之后是
esp_app_desc_t
- 如果有用户自定义的结构
custom_app_desc
则之后是用户自定义结构custom_app_desc
- 之后就是实际的程序了
参考文档:App Image Format
5. 应用程序状态切换
应用程序通过一个OTA状态对齐进行维护,通过此状态决定应用程序是否运行。
应用程序可通过调用 esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_img_states_t *ota_state)
获取对应扇区应用的状态。
应用程序的状态有以下几大类:
状态 | 引导加载程序选取启动应用程序的限制 |
---|---|
ESP_OTA_IMG_VALID | 没有限制,可以选取。 |
ESP_OTA_IMG_UNDEFINED | 没有限制,可以选取。 |
ESP_OTA_IMG_INVALID | 不会选取。 |
ESP_OTA_IMG_ABORTED | 不会选取。 |
ESP_OTA_IMG_NEW | 如使能 CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE , 则仅会选取一次。在引导加载程序中,状态立即变为 ESP_OTA_IMG_PENDING_VERIFY 。 |
ESP_OTA_IMG_PENDING_VERIFY | 如使能 CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE , 则不会选取,状态变为ESP_OTA_IMG_ABORTED 。 |
关于状态的使用,需要注意一个配置项: CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
- 当
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
未使能时,应用程序状态通常只会使用ESP_OTA_IMG_UNDEFINED
这一个状态- (官方IDF文档只是说
ESP_OTA_IMG_NEW
和ESP_OTA_IMG_PENDING_VERIFY
不会使用,但实测发现基本只会使用ESP_OTA_IMG_UNDEFINED
)
- (官方IDF文档只是说
- 当
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
使能时,应用程序状态通常会使用除ESP_OTA_IMG_UNDEFINED
状态之外的其他所有状态
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
配置项可通过 menuconfig 配置:
当 CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
未使能时:
当CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
使能时:
Pass: 程序分析小技巧,可以通过python在工程目录下搭建本地http服务器,配置升级地址为服务器地址,这样可以循环升级,并在例程中添加我们需要的打印信息,即可快速分析ota程序!
参考文档:Over The Air Updates (OTA)
6. 应用程序版本修改
应用程序版本存储在 esp_app_desc_t
结构体中。该结构体位于 DROM
扇区,有一个从二进制文件头部计算的固定偏移值。该结构体位于 esp_image_header_t
和 esp_image_segment_header_t
结构体之后。字段 Version
类型为字符串,最大长度为 32 字节。
关于应用程序的版本设置,总共有以下几种方案:
- 在
menuconfig
中设置对应配置项(Application manager
选项内)
- 在
CMakeLists.txt
文件中设置PROJECT_VER
变量,注意需要在 包含project.cmake
之前添加,格式如set(PROJECT_VER "0.1.0.1")
- 在工程目录下新建
version.txt
文档,在此文档中输入对应版本信息
-
使用
git describe
检索(实测命令无效) -
若以上均未有设置,则会将版本变量
PROJECT_VER
默认设置为1
7. 总结
以上就是关于 ESP32 使用 https
进行 OTA
升级的全部内容了,欢迎大家一同探讨关于ESP32的更多知识!
创作不易,转载请注明出处!
关注、点赞+收藏,可快速查收博主有关分享!文章来源:https://www.toymoban.com/news/detail-632828.html
8. 补充学习
强烈推荐:文章来源地址https://www.toymoban.com/news/detail-632828.html
- 1) ESP32 OTA升级之HTTP OTA(点击跳转!!!)
- 2) ESP32 bin文件生成及多个bin文件合并指南 (点击跳转!!!)
- 3) ESP32 分区表(点击跳转!!!)
- 4) ESP32 专栏(点击跳转!!!)
到了这里,关于ESP32 OTA升级之https ota详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!