ESP32 HttpServer模式下 本地OTA 例程(基于ESP-IDF类似Arduino下OTAWebUpdater例程)
由于項目需要ESP32連接app進行OTA,為了支持AP模式下與STA模式下的本地局域網(wǎng)OTA功能(不需要OTA服務(wù)器)。
咨詢樂鑫技術(shù)支持,ESP-IDF下沒有該模式的官方例程。網(wǎng)上也一直沒有找到相關(guān)例程,翻出來手冊看了看倒也不難。基于esp-idf\examples\system\ota\native_ota_example與esp-idf\examples\http_server\file_serving兩個例程,整理出來了這個demo分享并記錄一下。
demo包含:
工程下載
ESP32 HttpServer模式下 本地OTA 例程(基于ESP-IDF類似Arduino下OTAWebUpdater例程)
https://download.csdn.net/download/l851285812/18808145
分區(qū)表
分區(qū)表相關(guān)配置自行度娘,為節(jié)省flash空間該demo未使用factory工廠分區(qū),使用sta_0分區(qū)作為默認分區(qū)
| nvs | data | nvs | 0x9000 | 16k | |
| otadata | data | ota | 0xd000 | 8k | |
| ota_0 | app | ota_0 | 1000k | ||
| ota_1 | app | ota_1 | 1000k |
部分代碼如下
1. OTA服務(wù)器初始化
首先初始化三個URI并加載到89端口上啟動服務(wù)器,另以防意外將最大連接客戶端數(shù)量設(shè)置為1(config.max_open_sockets = 1)
void HttpOTA_server_init() {httpd_config_t config = HTTPD_DEFAULT_CONFIG();config.max_open_sockets = 1;config.stack_size = 8192;config.server_port = 89;config.ctrl_port = 32779;ESP_LOGI(TAG, "Starting OTA server on port: '%d'", config.server_port);if (httpd_start(&HttpOTA_httpd, &config) == ESP_OK){httpd_uri_t HttpOTA_uri = { //OTA頁面.uri = "/HttpOTAWeb",.method = HTTP_GET,.handler = HttpOTA_handler,.user_ctx = NULL};httpd_register_uri_handler(HttpOTA_httpd, &HttpOTA_uri);httpd_uri_t Now_uri = { //當前固件信息.uri = "/Now",.method = HTTP_GET,.handler = Now_handler,.user_ctx = NULL};httpd_register_uri_handler(HttpOTA_httpd, &Now_uri);/* URI處理程序,用于將文件上傳到服務(wù)器*/httpd_uri_t file_upload = {.uri = "/upload",.method = HTTP_POST,.handler = upload_post_handler,.user_ctx = NULL };httpd_register_uri_handler(HttpOTA_httpd, &file_upload);} }2. 當前固件信息(以json字符串發(fā)送)
//當前固件信息 static esp_err_t Now_handler(httpd_req_t *req) {httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); //跨域傳輸協(xié)議static char json_response[1024];esp_app_desc_t running_app_info;const esp_partition_t *running = esp_ota_get_running_partition();esp_ota_get_partition_description(running, &running_app_info);char * p = json_response;*p++ = '{';p+=sprintf(p, "\"OTAsubtype\":%d,", running->subtype - ESP_PARTITION_SUBTYPE_APP_OTA_MIN); //OTA分區(qū)p+=sprintf(p, "\"address\":%d,", running->address); //地址p+=sprintf(p, "\"version\":\"%s\",", running_app_info.version); //版本號p+=sprintf(p, "\"date\":\"%s\",", running_app_info.date); //日期p+=sprintf(p, "\"time\":\"%s\"", running_app_info.time); //時間*p++ = '}';*p++ = 0;httpd_resp_set_type(req, "application/json"); // 設(shè)置http響應類型return httpd_resp_send(req, json_response, strlen(json_response)); //發(fā)送一個完整的HTTP響應。內(nèi)容在json_response中 }3. 固件上傳頁面
使用Esp32HttpWeb_OTA\main\html\www\compress_pages.sh工具壓縮為.gz網(wǎng)頁燒寫。
注意: html中的中文會被壓縮成亂碼。
注意: 需要在CMakeLfists.txt編譯配置文件下注明該網(wǎng)頁:
固件上傳頁面URI:
//OTA 頁面 static esp_err_t HttpOTA_handler(httpd_req_t *req) {httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); //跨域傳輸協(xié)議extern const unsigned char HttpOTA_html_gz_start[] asm("_binary_HttpOTA_html_gz_start");extern const unsigned char HttpOTA_html_gz_end[] asm("_binary_HttpOTA_html_gz_end");size_t HttpOTA_html_gz_len = HttpOTA_html_gz_end - HttpOTA_html_gz_start;httpd_resp_set_type(req, "text/html");httpd_resp_set_hdr(req, "Content-Encoding", "gzip");return httpd_resp_send(req, (const char *)HttpOTA_html_gz_start, HttpOTA_html_gz_len); }4. 固件接收URI
循環(huán)每次接收1k數(shù)據(jù)到緩沖區(qū)。當接收到完整固件頭部后( 接收包大于 sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) )
則判斷固件是否合法(該固件僅判斷了版本號是否為包含"ESP_"),可自行添加判斷是否與正在運行固件版本號相同等,esp-idf\examples\system\ota\native_ota_example例程中包含相關(guān)代碼。
固件頭校驗完成后,配置新固件燒寫目標分區(qū)并調(diào)用esp_ota_begin( )開始OTA,注意該步驟將擦除目標OTA分區(qū)。
注意: ESP32 OTA必須由esp_ota_begin( )開始并由esp_ota_end( )結(jié)束。
循環(huán)將每次接收到的數(shù)據(jù)寫入目標OTA分區(qū) esp_ota_write( );
/*將固件分塊寫入OTA分區(qū)*/err = esp_ota_write(update_handle, (const void *)OTA_buf, received);if (err != ESP_OK) {char str[25];sprintf(str, "esp_ota_write failed (%s)", esp_err_to_name(err));ESP_LOGE(TAG, "%s", str);httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, str);return ESP_FAIL;}/*跟蹤剩余要上傳的文件的剩余大小*/remaining -= received;}free(OTA_buf);ESP_LOGI(TAG, "文件接收完成: %dByte",L_remaining);整個固件接收完成后調(diào)用esp_ota_end( )結(jié)束OTA并自動校驗固件完整性。
err = esp_ota_end(update_handle);if (err != ESP_OK) {if (err == ESP_ERR_OTA_VALIDATE_FAILED) {ESP_LOGE(TAG, "Image validation failed, image is corrupted");}char str[25];sprintf(str, "esp_ota_end failed (%s)", esp_err_to_name(err));ESP_LOGE(TAG, "%s", str);httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, str);return ESP_FAIL;}ESP_LOGI(TAG, "固件校驗成功!");最后調(diào)用esp_ota_set_boot_partition( )將otadata配置為新OTA分區(qū)(下次上電啟動分區(qū))
并軟件復位 esp_restart();
注意: httpd_resp_sendstr后若無延時,客戶端網(wǎng)頁將接受不到成功回復。
固件上傳網(wǎng)頁
總結(jié)
以上是生活随笔為你收集整理的ESP32 HttpServer模式下 本地OTA 例程(基于ESP-IDF类似Arduino下OTAWebUpdater例程)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: STM32在线升级OTA,看这一篇就够啦
- 下一篇: Android OTA 问题分析