ESP32 OTA升級(jí)之 https ota詳解
1. 前言
本文以 ESP32 官方demo例程 native_ota_example
為例,詳細(xì)闡述如何采用https實(shí)現(xiàn)esp32的ota升級(jí)。
- 第一章節(jié),為本文的前言部分,對(duì)文章內(nèi)容進(jìn)行大體概述;
- 第二章節(jié),主要描述了如何在本地將demo例程跑起來,并附帶了關(guān)于使用demo例程中遇到的相關(guān)報(bào)錯(cuò)的具體解決措施;
- 第三章節(jié),主要描述了ESP32的 flash 扇區(qū)布局;
- 第四章節(jié),主要描述了OTA下載的鏡像文件的頭部數(shù)據(jù)結(jié)構(gòu),并對(duì)其進(jìn)行詳細(xì)分析,鏡像文件的頭部與OTA息息相關(guān);
- 第五、六章節(jié),詳細(xì)描述了OTA升級(jí)過程中應(yīng)用程序的狀態(tài)切換邏輯以及相關(guān)軟件版本的使用;
接下來,讓我們一起研究ESP32的 OTA 升級(jí)是如何實(shí)現(xiàn)的吧!相信你一定有所收獲!
2. 例程體驗(yàn)
例程目錄:
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根證書驗(yàn)證方案
-
進(jìn)入
native_ota_example
工程 -
運(yùn)行
idf.py menuconfig
配置wifi及服務(wù)器地址 -
配置 wifi
-
配置https服務(wù)器地址
如果沒有https服務(wù)器,填寫http服務(wù)器地址也可以,http服務(wù)器搭建參考:ESP32 OTA升級(jí)之HTTP OTA
https服務(wù)器,大家可以嘗試把升級(jí)文件往github、gitee上發(fā)布也可以啦,免費(fèi)的https測試服務(wù)器對(duì)吧 -
運(yùn)行
idf.py build
編譯工程 -
運(yùn)行
idf.py flash monitor
下載工程并開啟監(jiān)控 -
網(wǎng)絡(luò)連接成功之后https下載時(shí)會(huì)報(bào)錯(cuò),提示
mbdtls ssl
握手失敗,錯(cuò)誤碼-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
配置 -
運(yùn)行
idf.py build
編譯工程,之后運(yùn)行idf.py flash monitor
開啟監(jiān)控 -
網(wǎng)絡(luò)連接成功之后https下載時(shí)會(huì)報(bào)錯(cuò),提示
mbdtls
服務(wù)器驗(yàn)證選項(xiàng)esp_tls_cfg_t
結(jié)構(gòu)體配置失敗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
,跳過服務(wù)器證書驗(yàn)證 -
運(yùn)行
idf.py build
編譯工程,之后運(yùn)行idf.py flash monitor
開啟監(jiān)控 -
網(wǎng)絡(luò)連接成功之后https下載成功
2.2 采用mbedtls內(nèi)自帶的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 采用對(duì)應(yīng)服務(wù)器的根證書文件
此方案,首先需要下載對(duì)應(yīng)服務(wù)器的證書文件才可以,下載服務(wù)器的證書可以采用以下方案:
首先使用瀏覽器打開對(duì)應(yīng)的服務(wù)器,之后瀏覽器的地址欄旁邊有一個(gè)??,點(diǎn)擊它
按照上述方式,導(dǎo)出對(duì)應(yīng)服務(wù)器的證書文件 .pem
,之后替換掉工程目錄下 server_certs
目錄下的ca_cert.pem
文件里面的內(nèi)容即可
采用此方案有一個(gè)需要特別注意的地方是:通過此方案下載的證書為此網(wǎng)站的證書,通常有效期為1年,過了一年之后就無效了!?。?/p>
這個(gè)時(shí)間在我們下載證書的時(shí)候其實(shí)就可以看到:
因此使用此方案時(shí),需要注意特別處理,推薦兩種解決方案:
1)采用升級(jí)的手段,定期更新設(shè)備端證書文件;
2)使用發(fā)證機(jī)構(gòu)(注意選擇大品牌的)的根證書文件,通常此類證書的有效期會(huì)比較長,我們上一小節(jié)中 mbedtls里面的證書其實(shí)就是存的一部分發(fā)證機(jī)構(gòu)的ca跟證書
參考文檔:ESP32空中升級(jí) OTA
3. ESP32 flash分區(qū)結(jié)構(gòu)
OTA是基于 Flash 進(jìn)行的,想要弄清楚 ESP32 的 OTA,首先肯定得了解 ESP32 的 flash 布局結(jié)構(gòu),關(guān)于此部分內(nèi)容我整理在了另外一篇博客,請(qǐng)查閱:ESP32 分區(qū)表(點(diǎn)擊跳轉(zhuǎn)),對(duì) ESP32 的 flash 分區(qū)布局有所了解的可以直接跳過。
4. 應(yīng)用程序鏡像段結(jié)構(gòu)
應(yīng)用程序鏡像段結(jié)構(gòu)如下,運(yùn)行命令 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 鏡像文件頭格式
- 鏡像在最后一段之后有一個(gè)校驗(yàn)和字節(jié)(如上述中的
Checksum: e8 (valid)
)。此字節(jié)寫入十六字節(jié)填充邊界,因此應(yīng)用程序鏡像可能需要填充。 - 如果
esp_image_header_t
結(jié)構(gòu)體(見下圖)的hash_appended
字段被設(shè)置,則將附加 SHA256 校驗(yàn)和。SHA256 哈希的值是在從第一個(gè)字節(jié)到該字段的范圍內(nèi)計(jì)算的,該字段的長度為 32 個(gè)字節(jié)。
應(yīng)用程序映像由以下結(jié)構(gòu)組成:
-
首先是 鏡像頭
esp_image_header_t
結(jié)構(gòu)數(shù)據(jù),描述了 SPI 閃存的模式和內(nèi)存段的數(shù)量。 -
之后是 數(shù)據(jù)段頭
esp_image_segment_header_t
結(jié)構(gòu)數(shù)據(jù),此結(jié)構(gòu)數(shù)據(jù)描述了每個(gè)段、其長度及其在 ESP32 內(nèi)存中的位置,后跟長度為data_len
,圖像中每個(gè)片段的數(shù)據(jù)偏移量按以下方式計(jì)算:- 第 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(
-
之后是 應(yīng)用頭
esp_app_desc_t
結(jié)構(gòu)數(shù)據(jù):- 此數(shù)據(jù)結(jié)構(gòu)位于
DORM
段起始位置 - 當(dāng)前應(yīng)用程序可以通過調(diào)用
esp_app_get_description()
獲取應(yīng)用頭結(jié)構(gòu) - 其他應(yīng)用程序可通過調(diào)用
esp_ota_get_partition_description()
獲取其他OTA分區(qū)應(yīng)用頭結(jié)構(gòu) - 此結(jié)構(gòu)的偏移地址計(jì)算為:
offset = sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)
- 此數(shù)據(jù)結(jié)構(gòu)位于
-
再往后是 用戶自定義的應(yīng)用結(jié)構(gòu)頭,如有需要可自行查閱 Adding a Custom Structure to an Application
綜上,一個(gè)應(yīng)用程序鏡像的頭部結(jié)構(gòu)為:
- 首先是
esp_image_header_t
- 其次是
esp_image_segment_header_t
- 之后是
esp_app_desc_t
- 如果有用戶自定義的結(jié)構(gòu)
custom_app_desc
則之后是用戶自定義結(jié)構(gòu)custom_app_desc
- 之后就是實(shí)際的程序了
參考文檔:App Image Format
5. 應(yīng)用程序狀態(tài)切換
應(yīng)用程序通過一個(gè)OTA狀態(tài)對(duì)齊進(jìn)行維護(hù),通過此狀態(tài)決定應(yīng)用程序是否運(yùn)行。
應(yīng)用程序可通過調(diào)用 esp_err_t esp_ota_get_state_partition(const esp_partition_t *partition, esp_ota_img_states_t *ota_state)
獲取對(duì)應(yīng)扇區(qū)應(yīng)用的狀態(tài)。
應(yīng)用程序的狀態(tài)有以下幾大類:
狀態(tài) | 引導(dǎo)加載程序選取啟動(dòng)應(yīng)用程序的限制 |
---|---|
ESP_OTA_IMG_VALID | 沒有限制,可以選取。 |
ESP_OTA_IMG_UNDEFINED | 沒有限制,可以選取。 |
ESP_OTA_IMG_INVALID | 不會(huì)選取。 |
ESP_OTA_IMG_ABORTED | 不會(huì)選取。 |
ESP_OTA_IMG_NEW | 如使能 CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE , 則僅會(huì)選取一次。在引導(dǎo)加載程序中,狀態(tài)立即變?yōu)?ESP_OTA_IMG_PENDING_VERIFY 。 |
ESP_OTA_IMG_PENDING_VERIFY | 如使能 CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE , 則不會(huì)選取,狀態(tài)變?yōu)?code>ESP_OTA_IMG_ABORTED。 |
關(guān)于狀態(tài)的使用,需要注意一個(gè)配置項(xiàng): CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
- 當(dāng)
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
未使能時(shí),應(yīng)用程序狀態(tài)通常只會(huì)使用ESP_OTA_IMG_UNDEFINED
這一個(gè)狀態(tài)- (官方IDF文檔只是說
ESP_OTA_IMG_NEW
和ESP_OTA_IMG_PENDING_VERIFY
不會(huì)使用,但實(shí)測發(fā)現(xiàn)基本只會(huì)使用ESP_OTA_IMG_UNDEFINED
)
- (官方IDF文檔只是說
- 當(dāng)
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
使能時(shí),應(yīng)用程序狀態(tài)通常會(huì)使用除ESP_OTA_IMG_UNDEFINED
狀態(tài)之外的其他所有狀態(tài)
CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
配置項(xiàng)可通過 menuconfig 配置:
當(dāng) CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
未使能時(shí):
當(dāng)CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE
使能時(shí):
Pass: 程序分析小技巧,可以通過python在工程目錄下搭建本地http服務(wù)器,配置升級(jí)地址為服務(wù)器地址,這樣可以循環(huán)升級(jí),并在例程中添加我們需要的打印信息,即可快速分析ota程序!
參考文檔:Over The Air Updates (OTA)
6. 應(yīng)用程序版本修改
應(yīng)用程序版本存儲(chǔ)在 esp_app_desc_t
結(jié)構(gòu)體中。該結(jié)構(gòu)體位于 DROM
扇區(qū),有一個(gè)從二進(jìn)制文件頭部計(jì)算的固定偏移值。該結(jié)構(gòu)體位于 esp_image_header_t
和 esp_image_segment_header_t
結(jié)構(gòu)體之后。字段 Version
類型為字符串,最大長度為 32 字節(jié)。
關(guān)于應(yīng)用程序的版本設(shè)置,總共有以下幾種方案:
- 在
menuconfig
中設(shè)置對(duì)應(yīng)配置項(xiàng)(Application manager
選項(xiàng)內(nèi))
- 在
CMakeLists.txt
文件中設(shè)置PROJECT_VER
變量,注意需要在 包含project.cmake
之前添加,格式如set(PROJECT_VER "0.1.0.1")
- 在工程目錄下新建
version.txt
文檔,在此文檔中輸入對(duì)應(yīng)版本信息
-
使用
git describe
檢索(實(shí)測命令無效) -
若以上均未有設(shè)置,則會(huì)將版本變量
PROJECT_VER
默認(rèn)設(shè)置為1
7. 總結(jié)
以上就是關(guān)于 ESP32 使用 https
進(jìn)行 OTA
升級(jí)的全部內(nèi)容了,歡迎大家一同探討關(guān)于ESP32的更多知識(shí)!
創(chuàng)作不易,轉(zhuǎn)載請(qǐng)注明出處!
關(guān)注、點(diǎn)贊+收藏,可快速查收博主有關(guān)分享!文章來源:http://www.zghlxwxcb.cn/news/detail-632828.html
8. 補(bǔ)充學(xué)習(xí)
??
強(qiáng)烈推薦:文章來源地址http://www.zghlxwxcb.cn/news/detail-632828.html
- 1) ESP32 OTA升級(jí)之HTTP OTA(點(diǎn)擊跳轉(zhuǎn)?。。。?
- 2) ESP32 bin文件生成及多個(gè)bin文件合并指南 (點(diǎn)擊跳轉(zhuǎn)?。。。?
- 3) ESP32 分區(qū)表(點(diǎn)擊跳轉(zhuǎn)!?。。?
- 4) ESP32 專欄(點(diǎn)擊跳轉(zhuǎn)?。。。?
到了這里,關(guān)于ESP32 OTA升級(jí)之https ota詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!