// // Created by misaki on 2025/9/4. // #include "app_ota.h" #include "esp_log.h" #include "esp_ota_ops.h" #include "esp_http_client.h" #include "esp_https_ota.h" #include "freertos/task.h" static const char *TAG = "app_ota"; #define DEFAULT_VERSION "0.0.1" /* 本地版本号,编译时可由构建系统注入 */ #ifndef APP_FW_VERSION #define APP_FW_VERSION DEFAULT_VERSION #endif static const char s_version[] = APP_FW_VERSION; const char *app_ota_current_version(void) { return s_version; } /* 简单版本号比较:a.b.c 字符串比较即可 */ static bool need_update(const char *server_ver) { if (!server_ver) return false; return strcmp(server_ver, s_version) > 0; } /* HTTP 事件回调,仅打印进度 */ static esp_err_t http_evt(esp_http_client_event_t *evt) { switch (evt->event_id) { case HTTP_EVENT_ON_DATA: /* 数据流直接走 OTA,这里不打印 */ break; default: break; } return ESP_OK; } static void ota_task(void *pv) { char url[256]; strncpy(url, (const char *)pv, sizeof(url) - 1); url[sizeof(url) - 1] = '\0'; ESP_LOGI(TAG, "开始 OTA,URL=%s", url); esp_http_client_config_t http_cfg = { .url = url, .event_handler = http_evt, .keep_alive_enable = true, // 如用 https,把 cert_pem 打开即可 // .cert_pem = (const char *)server_cert_pem_start, }; esp_https_ota_config_t ota_cfg = { .http_config = &http_cfg, }; /* 执行升级 */ esp_err_t ret = esp_https_ota(&ota_cfg); if (ret == ESP_OK) { ESP_LOGI(TAG, "OTA 完成,准备重启"); esp_restart(); } else { ESP_LOGE(TAG, "OTA 失败,err=%s", esp_err_to_name(ret)); } vTaskDelete(NULL); } esp_err_t app_ota_start(const char *url) { if (!url) return ESP_ERR_INVALID_ARG; /* 内部建 Task,栈 8 KB */ BaseType_t ok = xTaskCreate(ota_task, "ota_task", 8192, (void *)url, 5, NULL); return ok == pdPASS ? ESP_OK : ESP_FAIL; }