1. 优化了cpp_json的内容,使其更modern

2. 稍微优化了一下系统配置类
3. 增加了系统版本号,便于区分系统版本,方便OTA
4. 重写OTA的逻辑,完成了Cpp的OTA封装,测试通过
This commit is contained in:
Misaki
2025-09-24 04:01:23 +08:00
parent 6c4749ba0c
commit a47e20cb64
18 changed files with 908 additions and 458 deletions
+250 -2
View File
@@ -202,10 +202,258 @@ void testMIC() {
}
#include "ToolsClass.h"
#include "WifiConnectors.h"
#include "CommClass.h"
#include "sys_conf_singleton.h"
#include "HttpOtaUpdater.h"
using namespace std::chrono;
const auto sleep_time = seconds{
5
};
// 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); // 仅用于测试
}
// JSON 数据回调函数
/** 交互所使用的json内容
{
"type": "xxx", // 消息类型
"xxx":"xxx", // 其他数据
......
}
*/
void onJsonData(const cppjson::Json& json)
{
// 打印收到的 JSON
ESP_LOGI("JSON_CALLBACK", "收到JSON数据: %s", json.dump().c_str());
// 解析消息类型
const cppjson::Json& type = json["type"];
if (!type.isString()) return;
std::string typeStr = type.asString();
if (typeStr == "greeting") {
ESP_LOGI("JSON_CALLBACK", "收到服务器问候消息");
} else if (typeStr == "heartbeat") {
ESP_LOGI("JSON_CALLBACK", "收到心跳响应");
} else if (typeStr == "response") {
ESP_LOGI("JSON_CALLBACK", "收到服务器响应");
} else if (typeStr == "echo") {
ESP_LOGI("JSON_CALLBACK", "收到回显消息");
} else if (typeStr == "broadcast") {
ESP_LOGI("JSON_CALLBACK", "收到广播消息");
} else if (typeStr == "ota") {
ESP_LOGI("JSON_CALLBACK", "收到OTA消息");
// 进一步处理OTA消息
// 获取OTA中的版本信息
const cppjson::Json& version = json["version"];
if (!version.isString()) return;
std::string versionStr = version.asString();
// 获取OTA中的HTTP URL
const cppjson::Json& url = json["url"];
if (!url.isString()) return;
std::string urlStr = url.asString();
// 告诉服务端,升级开始
cppjson::Json response = cppjson::Json::object();
response.set("type", cppjson::Json("ota_start"));
WebSocketManager::getInstance()->sendJson(response);
otaUpdater.start(urlStr);
}
}
// WebSocket事件回调函数
void onWebSocketEvent(WebSocketEvent event, const std::string& message) {
switch (event) {
case WebSocketEvent::CONNECTED:
ESP_LOGI("EVENT_CALLBACK", "WebSocket已连接: %s", message.c_str());
break;
case WebSocketEvent::DISCONNECTED:
ESP_LOGI("EVENT_CALLBACK", "WebSocket已断开: %s", message.c_str());
break;
case WebSocketEvent::DATA_RECEIVED:
ESP_LOGI("EVENT_CALLBACK", "收到原始数据: %s", message.c_str());
break;
case WebSocketEvent::ERROR:
ESP_LOGE("EVENT_CALLBACK", "WebSocket错误: %s", message.c_str());
break;
}
}
// 发送状态信息函数
void sendStatus()
{
cppjson::Json status = cppjson::Json::object();
status.set("type", cppjson::Json("status"));
cppjson::Json data = cppjson::Json::object();
data.set("free_heap", cppjson::Json(esp_get_free_heap_size()))
.set("uptime", cppjson::Json(xTaskGetTickCount() * portTICK_PERIOD_MS / 1000));
status.set("data", data); // 嵌套对象
if (WebSocketManager::getInstance()->sendJson(status)) {
ESP_LOGI("SEND", "已发送状态信息");
} else {
ESP_LOGE("SEND", "发送状态信息失败");
}
}
// 发送问候消息函数
void sendGreeting()
{
cppjson::Json greeting = cppjson::Json::object();
greeting.set("type", cppjson::Json("greeting"))
.set("message", cppjson::Json("Hello from ESP32-S3"))
.set("timestamp", cppjson::Json(xTaskGetTickCount() * portTICK_PERIOD_MS / 1000));
if (WebSocketManager::getInstance()->sendJson(greeting)) {
ESP_LOGI("SEND", "已发送问候消息");
} else {
ESP_LOGE("SEND", "发送问候消息失败");
}
}
void websocket_task() {
TickType_t lastStatusTime = 0;
TickType_t lastHeartbeatTime = 0;
TickType_t lastGreetingTime = 0;
while (true) {
TickType_t currentTime = xTaskGetTickCount();
// 检查连接状态
if (!WebSocketManager::getInstance()->isConnected()) {
ESP_LOGI("APP_TASK", "WebSocket未连接,尝试重新连接...");
// 确保WiFi已连接
if (!WifiConnectors::getInstance()->isWifiConnect()) {
ESP_LOGI("APP_TASK", "WiFi未连接,等待WiFi连接...");
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
if (WebSocketManager::getInstance()->connect()) {
ESP_LOGI("APP_TASK", "重新连接成功");
} else {
ESP_LOGI("APP_TASK", "重新连接失败");
}
vTaskDelay(5000 / portTICK_PERIOD_MS);
continue;
}
// 每10秒发送状态信息
if (currentTime - lastStatusTime > (10000 / portTICK_PERIOD_MS)) {
sendStatus();
lastStatusTime = currentTime;
}
// 每60秒发送问候
if (currentTime - lastGreetingTime > (60000 / portTICK_PERIOD_MS)) {
sendGreeting();
lastGreetingTime = currentTime;
}
vTaskDelay(100 / portTICK_PERIOD_MS);
}
}
void createWebSocket() {
// 等待WiFi连接成功后再连接WebSocket
ESP_LOGI("APP_TASK", "等待WiFi连接...");
while (!WifiConnectors::getInstance()->isWifiConnect()) {
ESP_LOGI("APP_TASK", "WiFi未连接,等待中...");
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
// 保存SN
SysConfJson::getInstance()->saveSN(ToolsClass::GenerateSN(ToolsClass::getChipMAC(), ToolsClass::getChipSerialNumber()));
// 读取SN
std::string sn = SysConfJson::getInstance()->loadSN();
ESP_LOGI("conf", "loaded sn = %s", sn.c_str());
// 配置WebSocket
WebSocketConfig config;
config.uri = "ws://" + std::string("192.168.1.11") + ":" + std::to_string(8080) + "/ws";
config.auto_reconnect = true; // 自动重连
config.reconnect_interval = 5000; // 重连间隔(毫秒)
config.heartbeat_interval = 30000; // 心跳间隔(毫秒)
config.max_reconnect_attempts = 10; // 最大重连尝试次数
// TODO: 此处通信类存在线程重复创建bug,似乎是来自esp-idf的bug,待查证
// 初始化WebSocket管理器
if (!WebSocketManager::getInstance()->initialize(config)) {
ESP_LOGE("APP_TASK", "WebSocket管理器初始化失败");
vTaskDelete(NULL);
return;
}
// 设置回调函数
WebSocketManager::getInstance()->setJsonCallback(onJsonData);
WebSocketManager::getInstance()->setEventCallback(onWebSocketEvent);
// 连接WebSocket服务器
ESP_LOGI("APP_TASK", "正在连接WebSocket服务器: %s", config.uri.c_str());
if (!WebSocketManager::getInstance()->connect()) {
ESP_LOGE("APP_TASK", "WebSocket连接失败");
}
// 创建WebSocket任务
ThreadConfig websocket_config;
websocket_config.core_id = 0;
websocket_config.inherit_cfg = true;
websocket_config.name = "websocket_task";
websocket_config.priority = 5;
websocket_config.stack_size = 4096;
std::thread websocket_thread = ThreadManager::createThread(websocket_config, websocket_task);
websocket_thread.detach();
}
void Cpp_Hand() {
// testMIC();
// testPetSystem();
OTAClass oc;
oc.Init();
ESP_LOGI("CppHandle::Cpp_Hand", "当前固件版本 %s:", ToolsClass::getDeviceVersion().c_str());
ESP_LOGI("CppHandle::Cpp_Hand", "当前设备MAC地址 %s:", ToolsClass::getChipMAC().c_str());
ESP_LOGI("CppHandle::Cpp_Hand", "当前设备固件序列号 %s:", ToolsClass::getChipSerialNumber().c_str());
// 连接wifi
WifiConnectors::getInstance()->connectWifi("Misaki-2.4G", "88888888", 5);
// 创建WebSocket
createWebSocket();
// 设置OTA回调
setupOtaCallbacks();
while (true) { // 主线程线程循环
// ThreadManager::print_sys_memory(); // 打印系统内存使用情况
// ThreadManager::stats_task(); // 打印任务统计信息
std::this_thread::sleep_for(sleep_time); // 休眠5秒
}
}