Files
Misaki a47e20cb64 1. 优化了cpp_json的内容,使其更modern
2. 稍微优化了一下系统配置类
3. 增加了系统版本号,便于区分系统版本,方便OTA
4. 重写OTA的逻辑,完成了Cpp的OTA封装,测试通过
2025-09-24 04:01:23 +08:00

218 lines
5.9 KiB
C++

//
// Created by misaki on 2025/9/24.
//
#pragma once
#include <esp_https_ota.h>
#include <esp_ota_ops.h>
#include <esp_log.h>
#include <string>
#include <functional>
#include "ThreadManager.h"
class HttpOtaUpdater {
public:
// OTA状态枚举
enum class OtaState {
IDLE, // 空闲状态
CONNECTING, // 连接中
DOWNLOADING, // 下载中
VERIFYING, // 验证中
SUCCESS, // 成功
FAILED // 失败
};
// 进度回调函数类型
using ProgressCallback = std::function<void(int progress, int total)>;
// 状态回调函数类型
using StateCallback = std::function<void(OtaState state, const std::string& message)>;
// 完成回调函数类型
using FinishCallback = std::function<void(bool success, const std::string& message)>;
/**
* @brief 构造函数
*/
HttpOtaUpdater();
/**
* @brief 析构函数
*/
~HttpOtaUpdater();
/**
* @brief 开始OTA升级
* @param url HTTP下载链接
* @return true-成功开始升级,false-失败
*/
bool start(const std::string& url);
/**
* @brief 停止OTA升级
*/
void stop();
/**
* @brief 检查是否正在升级
* @return true-正在升级,false-空闲
*/
[[nodiscard]] bool isUpdating() const;
/**
* @brief 设置进度回调
* @param callback 回调函数
*/
void setProgressCallback(const ProgressCallback &callback);
/**
* @brief 设置状态回调
* @param callback 回调函数
*/
void setStateCallback(const StateCallback &callback);
/**
* @brief 设置完成回调
* @param callback 回调函数
*/
void setFinishCallback(const FinishCallback &callback);
/**
* @brief 设置CA证书(用于HTTPS,保留供后期使用)
* @param cert_pem PEM格式的证书内容
*/
void setCACert(const char* cert_pem);
/**
* @brief 跳过证书通用名检查(仅用于测试,保留供后期使用)
* @param skip true-跳过检查,false-不跳过
*/
void skipCertCommonNameCheck(bool skip);
/**
* @brief 获取当前状态
* @return 当前OTA状态
*/
[[nodiscard]] OtaState getCurrentState() const;
/**
* @brief 获取错误信息
* @return 错误信息字符串
*/
[[nodiscard]] std::string getErrorMessage() const;
// 禁止拷贝和赋值
HttpOtaUpdater(const HttpOtaUpdater&) = delete;
HttpOtaUpdater& operator=(const HttpOtaUpdater&) = delete;
private:
/**
* @brief OTA任务主函数
*/
void otaTask();
/**
* @brief 执行OTA升级
* @param url 下载链接
*/
void performOta(const std::string& url);
/**
* @brief 更新状态
* @param state 新状态
* @param message 状态信息
*/
void updateState(OtaState state, const std::string& message = "");
/**
* @brief HTTPS OTA事件处理函数
* @param event 事件
*/
static esp_err_t httpEventHandle(esp_http_client_event_t* event);
// 成员变量
std::string m_url; ///<! 下载链接
OtaState m_currentState; ///<! 当前状态
std::string m_errorMessage; ///<! 错误信息
bool m_isUpdating; ///<! 是否正在升级
std::thread m_otaThread; ///<! OTA线程
// HTTP配置(保留供后期使用)
const char* m_cert_pem; ///<! CA证书
bool m_skip_cert_common_name_check; ///<! 跳过证书通用名检查
// 回调函数
ProgressCallback m_progressCallback;///<! 进度回调
StateCallback m_stateCallback; ///<! 状态回调
FinishCallback m_finishCallback; ///<! 完成回调
// 进度相关变量
int m_totalSize; ///<! 总大小
int m_downloadedSize; ///<! 已下载大小
// 日志标签
static constexpr auto TAG = "HttpOtaUpdater";
};
/** 使用示例
// 创建全局OTA更新器实例
HttpOtaUpdater otaUpdater;
void setupOtaCallbacks() {
// 设置进度回调
otaUpdater.setProgressCallback([](int progress, int total) {
ESP_LOGI("OTA", "Progress: %d%%", progress);
});
// 设置状态回调
otaUpdater.setStateCallback([](HttpOtaUpdater::OtaState state, const std::string& message) {
const char* stateNames[] = {
"IDLE", "CONNECTING", "DOWNLOADING", "VERIFYING", "SUCCESS", "FAILED"
};
ESP_LOGI("OTA", "State: %s - %s", stateNames[static_cast<int>(state)], message.c_str());
});
// 设置完成回调
otaUpdater.setFinishCallback([](bool success, const std::string& message) {
if (success) {
ESP_LOGI("OTA", "Completed successfully: %s", message.c_str());
} else {
ESP_LOGE("OTA", "Failed: %s", message.c_str());
}
});
// 如果需要HTTPS,可以在这里设置证书(保留供后期使用)
// otaUpdater.setCACert(my_ca_cert_pem);
// otaUpdater.skipCertCommonNameCheck(true); // 仅用于测试
}
// 在websocket消息处理函数中调用
void onOtaUrlReceived(const std::string& otaUrl) {
ESP_LOGI("OTA", "Received OTA URL: %s", otaUrl.c_str());
if (otaUpdater.isUpdating()) {
ESP_LOGW("OTA", "OTA update is already in progress");
return;
}
if (otaUpdater.start(otaUrl)) {
ESP_LOGI("OTA", "OTA update started successfully");
} else {
ESP_LOGE("OTA", "Failed to start OTA update");
}
}
// 检查OTA状态
void checkOtaStatus() {
if (otaUpdater.isUpdating()) {
ESP_LOGI("OTA", "OTA update in progress, state: %d",
static_cast<int>(otaUpdater.getCurrentState()));
} else {
ESP_LOGI("OTA", "No OTA update in progress");
}
std::string error = otaUpdater.getErrorMessage();
if (!error.empty()) {
ESP_LOGE("OTA", "Last error: %s", error.c_str());
}
}
*/