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
+54 -55
View File
@@ -15,7 +15,7 @@
// 静态成员初始化
WebSocketManager* WebSocketManager::instance = nullptr;
std::mutex WebSocketManager::instance_mutex;
std::string WebSocketManager::sn = SYS_CONF_JSON().loadSN(); // 获取SN(同时也能初始化文件系统,如果还没有初始化这个文件系统的话)
std::string WebSocketManager::sn = SysConfJson::getInstance()->loadSN(); // 获取SN(同时也能初始化文件系统,如果还没有初始化这个文件系统的话)
// 标签用于日志
static const char* TAG = "WebSocketManager";
@@ -72,15 +72,15 @@ bool WebSocketManager::initialize(const WebSocketConfig& ws_config) {
this, &wifi_instance);
// 启动发送线程
threads_running = true;
ThreadConfig thread_config;
thread_config.name = "WS_Send";
thread_config.stack_size = 4096;
send_thread = ThreadManager::createMemberThread(thread_config, this,
&WebSocketManager::sendThread);
// 只在线程未运行时启动发送线程
if (!send_thread.joinable()) {
threads_running = true;
ThreadConfig thread_config;
thread_config.name = "WS_Send";
thread_config.stack_size = 4096;
send_thread = ThreadManager::createMemberThread(thread_config, this,
&WebSocketManager::sendThread);
}
return true;
}
@@ -118,17 +118,24 @@ bool WebSocketManager::connect() {
}
// 启动重连和心跳线程
ThreadConfig thread_config;
thread_config.name = "WS_Reconnect";
thread_config.stack_size = 3072;
// 只有在线程未运行时才启动新线程
if (!reconnect_thread.joinable()) {
ThreadConfig thread_config;
thread_config.name = "WS_Reconnect";
thread_config.stack_size = 3072;
reconnect_thread = ThreadManager::createMemberThread(thread_config, this,
&WebSocketManager::reconnectThread);
reconnect_thread = ThreadManager::createMemberThread(thread_config, this,
&WebSocketManager::reconnectThread);
}
thread_config.name = "WS_Heartbeat";
heartbeat_thread = ThreadManager::createMemberThread(thread_config, this,
&WebSocketManager::heartbeatThread);
if (!heartbeat_thread.joinable()) {
ThreadConfig thread_config;
thread_config.name = "WS_Heartbeat";
thread_config.stack_size = 3072;
heartbeat_thread = ThreadManager::createMemberThread(thread_config, this,
&WebSocketManager::heartbeatThread);
}
return true;
}
@@ -147,25 +154,21 @@ void WebSocketManager::disconnect() {
}
}
bool WebSocketManager::sendJson(cJSON* json) {
bool WebSocketManager::sendJson(const cppjson::Json& json) {
if (!connected) { // 检查连接状态
ESP_LOGE(TAG, "Not connected, cannot send data");
cJSON_Delete(json);
return false;
}
char* json_str = cJSON_PrintUnformatted(json); // 将JSON对象转换为字符串
cJSON_Delete(json); // 释放JSON对象
if (!json_str) { // 检查转换结果
std::string json_str = json.dump(); // 序列化 JSON
if (json_str.empty() || json_str == "null") { // 检查序列化结果
ESP_LOGE(TAG, "Failed to stringify JSON");
return false;
}
std::lock_guard<std::mutex> lock(queue_mutex); // 锁定队列
send_queue.emplace(json_str); // 添加到队列
free(json_str); // 释放json_str的内存
{ // 临界区
std::lock_guard<std::mutex> lock(queue_mutex);
send_queue.emplace(std::move(json_str)); // 移动进队列,零拷贝
}
queue_cv.notify_one(); // 通知发送线程
return true;
}
@@ -241,7 +244,7 @@ void WebSocketManager::websocketEventHandler(void* handler_args, esp_event_base_
}
break;
case WEBSOCKET_EVENT_ERROR:
case WEBSOCKET_EVENT_ERROR: // 错误事件
ws_instance->connected = false;
ws_instance->connecting = false;
@@ -257,20 +260,13 @@ void WebSocketManager::websocketEventHandler(void* handler_args, esp_event_base_
}
void WebSocketManager::handleReceivedData(const char* data, const int len) const {
// 尝试解析JSON
if (cJSON* json = cJSON_ParseWithLength(data, len)) {
// 成功解析为JSON
if (json_callback) {
json_callback(json);
} else {
cJSON_Delete(json);
}
} else {
// 不是JSON格式,作为原始数据处理
std::string message(data, len);
if (event_callback) {
event_callback(WebSocketEvent::DATA_RECEIVED, message);
}
// 解析JSON
cppjson::Json json = cppjson::Json::parse(std::string(data, len)); // 失败会得到空 Json
if (!json.isNull()) { // 解析成功
if (json_callback) json_callback(json);
} else { // 解析失败,当原始文本处理
if (event_callback)
event_callback(WebSocketEvent::DATA_RECEIVED, std::string(data, len));
}
}
@@ -278,7 +274,7 @@ void WebSocketManager::reconnectThread() {
while (threads_running) {
if (!connected && config.auto_reconnect &&
(config.max_reconnect_attempts == 0 ||
reconnect_attempts < config.max_reconnect_attempts)) {
reconnect_attempts < config.max_reconnect_attempts)) { // 检查重连条件
// 检查WiFi连接
if (!wifi->isWifiConnect()) {
@@ -297,7 +293,7 @@ void WebSocketManager::reconnectThread() {
ESP_LOGE(TAG, "Reconnection attempt failed");
}
}
// sleep
std::this_thread::sleep_for(std::chrono::milliseconds(config.reconnect_interval));
}
}
@@ -306,11 +302,10 @@ void WebSocketManager::heartbeatThread() {
while (threads_running) {
if (connected && config.heartbeat_interval > 0) { // 如果处于连接状态且心跳间隔大于0
// 发送心跳消息
cJSON* heartbeat = cJSON_CreateObject();
cJSON_AddStringToObject(heartbeat, "type", "heartbeat");
cJSON_AddNumberToObject(heartbeat, "timestamp", static_cast<double>(esp_log_timestamp()));
sendJson(heartbeat);
cppjson::Json hb = cppjson::Json::object();
hb.set("type", cppjson::Json("heartbeat"))
.set("timestamp", cppjson::Json(esp_log_timestamp()));
sendJson(hb); // 已经重载好了,直接塞
std::this_thread::sleep_for(std::chrono::milliseconds(config.heartbeat_interval));
} else { // 否则就让出CPU
@@ -364,14 +359,18 @@ bool WebSocketManager::createWebSocketClient() {
// 处理sn码逻辑
// 一般情况下sn码会在开机的时候从flash当中读出,因此此处判断是否为空
sn = SysConfJson::getInstance()->loadSN(); // 再读一次sn码
if (!sn.empty()) { // 如果sn码不为空
// 则在头部加入sn码提交
esp_websocket_client_append_header(client, "sn", sn.c_str());
esp_websocket_client_append_header(client, "X-SN", sn.c_str());
// 同时在头部加入mac码和芯片序列号,方便服务端做验证
esp_websocket_client_append_header(client, "X-MAC", ToolsClass::getChipMAC().c_str());
esp_websocket_client_append_header(client, "X-CHIP-ID", ToolsClass::getChipSerialNumber().c_str());
}
else {
// 否则在头部加入mac码和芯片序列号
esp_websocket_client_append_header(client, "mac", ToolsClass::getChipMAC().c_str());
esp_websocket_client_append_header(client, "chip_id", ToolsClass::getChipSerialNumber().c_str());
// 如果sn码为空,设备可能存在问题
ESP_LOGE(TAG, "SN is empty, please check your device");
return false;
}