From 1e295aeeb3d283d7557bd78a3ce703dc62dddc59 Mon Sep 17 00:00:00 2001 From: zhaojingkui <1553836110@qq.com> Date: Thu, 27 Feb 2025 22:37:21 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E5=AE=9E=E7=8E=B0,?= =?UTF-8?q?=E9=87=87=E7=94=A8websocket?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 +- bin/pPowerManger.moos | 3 +- bin/static/script.js | 149 +++++++++---------- data/msg/uPower_currentState_st.json | 2 +- data/msg/uPower_disSysState_st.json | 6 +- data/msg/uPower_fcsState_st.json | 32 ++-- data/msg/uPower_liBatState_st.json | 18 +-- src/appPowerMangerWebUI/CMakeLists.txt | 8 +- src/appPowerMangerWebUI/main.cpp | 197 ++++++++++++------------- 9 files changed, 204 insertions(+), 213 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 068914a..7f7a91c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -103,4 +103,4 @@ ENDIF( ${WIN32} ) # Add Subdirectories #======================================================================= ADD_SUBDIRECTORY( src ) -ADD_SUBDIRECTORY( test ) +# ADD_SUBDIRECTORY( test ) diff --git a/bin/pPowerManger.moos b/bin/pPowerManger.moos index e4e89c1..b68ca3e 100644 --- a/bin/pPowerManger.moos +++ b/bin/pPowerManger.moos @@ -5,5 +5,4 @@ ProcessConfig = pPowerManger { AppTick = 5 CommsTick = 4 -} - +} \ No newline at end of file diff --git a/bin/static/script.js b/bin/static/script.js index 3642eee..4775382 100644 --- a/bin/static/script.js +++ b/bin/static/script.js @@ -24,82 +24,86 @@ document.getElementById('download-db').addEventListener('click', function() { }); }); -// 更新页面数据的函数 -function updateData() { - // 获取状态机数据 - fetch('/api/state') - .then(response => response.json()) - .then(stateData => { - // 更新状态机面板 - const stateInfo = ` -更新时间 ${stateData.time} -状态ID ${stateData.state_id} -状态名称 ${stateData.state_name} -事件 ${stateData.event} -事件ID ${stateData.event_id} -故障代码 ${stateData.fault_code} -备注 ${stateData.note} -`; - document.getElementById('state-machine-state').innerHTML = stateInfo; - }) - .catch(error => console.error('Error fetching state data:', error)); +// WebSocket连接 +let ws = null; +let reconnectAttempts = 0; +const maxReconnectAttempts = 5; +const reconnectDelay = 5000; - // 获取其他系统状态 - fetch('/api/status') - .then(response => response.json()) - .then(data => { - // 更新DIS系统状态 - document.getElementById('dis-sys-state').textContent = JSON.stringify(data.disSys, null, 2); - - // 更新CCU状态 - document.getElementById('ccu-state').textContent = JSON.stringify(data.ccuState, null, 2); - - // 更新运行日志 - document.getElementById('log-data').textContent = data.logs.join('\n'); - }) - .catch(error => console.error('Error fetching system data:', error)); +// 初始化WebSocket连接 +function initWebSocket() { + ws = new WebSocket('ws://' + window.location.host + '/ws/state'); + + ws.onopen = () => { + console.log('WebSocket连接已建立'); + reconnectAttempts = 0; + }; + + ws.onmessage = (event) => { + const data = JSON.parse(event.data); + updateUI(data); + }; + + ws.onclose = () => { + console.log('WebSocket连接已关闭'); + if (reconnectAttempts < maxReconnectAttempts) { + setTimeout(() => { + reconnectAttempts++; + console.log(`尝试重新连接 (${reconnectAttempts}/${maxReconnectAttempts})`); + initWebSocket(); + }, reconnectDelay); + } + }; + + ws.onerror = (error) => { + console.error('WebSocket错误:', error); + ws.close(); + }; } -// 检查MOOS数据库连接状态 -function checkMoosDbConnection() { - fetch('/api/moos-db') - .then(response => response.json()) - .then(data => { + // 更新UI + function updateUI(data) { + // 更新数据库状态 + if (data.db_status) { + const dbStatus = document.getElementById('db-status'); + if (dbStatus) { + dbStatus.className = data.db_status.connected ? 'db-status connected' : 'db-status disconnected'; + dbStatus.innerHTML = `已连接到数据库:${data.db_status.database}`; + } + } + + // 更新MOOS数据库状态 + if (data.moos_db_status) { const moosDbStatus = document.getElementById('moos-db-status'); - if (data.connected) { + if (data.moos_db_status.connected) { moosDbStatus.className = 'db-status connected'; - moosDbStatus.innerHTML = `已连接到MOOS数据库:${data.host}:${data.port}`; + moosDbStatus.innerHTML = `已连接到MOOS数据库:${data.moos_db_status.host}:${data.moos_db_status.port}`; } else { moosDbStatus.className = 'db-status disconnected'; moosDbStatus.innerHTML = `MOOS数据库连接失败`; } - }) - .catch(error => { - const moosDbStatus = document.getElementById('moos-db-status'); - moosDbStatus.className = 'db-status disconnected'; - moosDbStatus.innerHTML = `MOOS数据库连接错误`; - }); -} + } -// 检查本地数据库连接状态 -function checkDbConnection() { - fetch('/api/db-status') - .then(response => response.json()) - .then(data => { - const dbStatus = document.getElementById('db-status'); - if (data.connected) { - dbStatus.className = 'db-status connected'; - dbStatus.innerHTML = `已连接到数据库:${data.database}`; - } else { - dbStatus.className = 'db-status disconnected'; - dbStatus.innerHTML = `数据库连接失败`; - } - }) - .catch(error => { - const dbStatus = document.getElementById('db-status'); - dbStatus.className = 'db-status disconnected'; - dbStatus.innerHTML = `数据库连接错误`; - }); + // 更新状态机面板 + const stateInfo = ` +更新时间 ${data.state.time} +状态ID ${data.state.state_id} +状态名称 ${data.state.state_name} +事件 ${data.state.event} +事件ID ${data.state.event_id} +故障代码 ${data.state.fault_code} +备注 ${data.state.note} +`; + document.getElementById('state-machine-state').innerHTML = stateInfo; + + // 更新DIS系统状态 + document.getElementById('dis-sys-state').textContent = JSON.stringify(data.status.disSys, null, 2); + + // 更新CCU状态 + document.getElementById('ccu-state').textContent = JSON.stringify(data.status.ccuState, null, 2); + + // 更新运行日志 + document.getElementById('log-data').textContent = data.status.logs.join('\n'); } // MOOS通知功能 @@ -140,14 +144,7 @@ function sendMoosNotify() { document.getElementById('moos-send-btn').addEventListener('click', sendMoosNotify); -// 每1秒更新一次数据 -setInterval(updateData, 1000); -updateData(); // 初始加载 +// 初始化WebSocket连接 +initWebSocket(); -// 每10秒检查一次数据库连接状态 -setInterval(() => { - checkDbConnection(); - checkMoosDbConnection(); -}, 10000); -checkDbConnection(); // 初始检查 -checkMoosDbConnection(); // 初始检查 +// 删除旧的定时检查,现在通过WebSocket实时更新 diff --git a/data/msg/uPower_currentState_st.json b/data/msg/uPower_currentState_st.json index a8a0701..41648bf 100644 --- a/data/msg/uPower_currentState_st.json +++ b/data/msg/uPower_currentState_st.json @@ -6,7 +6,7 @@ "HVABbusBVol_uint16": 0, "HVABmastSteGeaCur_uint16": 0, "HVABopenWaterCur_uint16": 0, - "HVABxczCur_uint16": 1, + "HVABxczCur_uint16": 0, "HVBBCCUCur_uint16": 0, "HVBBFCSSecurSysCur_uint16": 0, "HVBBbatInsCur_uint16": 0, diff --git a/data/msg/uPower_disSysState_st.json b/data/msg/uPower_disSysState_st.json index 90bc4ac..ed8e1bf 100644 --- a/data/msg/uPower_disSysState_st.json +++ b/data/msg/uPower_disSysState_st.json @@ -1,8 +1,8 @@ { "HVolABusBreaker_unit16": 0, - "HVolBBusBreaker_unit16": 79, - "HVolBusBreaker_uint16": 58, - "LVolBusBreaker_uint16": 159, + "HVolBBusBreaker_unit16": 0, + "HVolBusBreaker_uint16": 0, + "LVolBusBreaker_uint16": 0, "faultCode_array": [ 0 diff --git a/data/msg/uPower_fcsState_st.json b/data/msg/uPower_fcsState_st.json index 8c925cc..31141fb 100644 --- a/data/msg/uPower_fcsState_st.json +++ b/data/msg/uPower_fcsState_st.json @@ -1,30 +1,30 @@ { - "backpressure1_fp32": 3.0, - "backpressure2_fp32": 8.0, - "ch4oConcent1_fp32": 13.0, - "ch4oConcent2_fp32": 57.0, + "backpressure1_fp32": 0.0, + "backpressure2_fp32": 0.0, + "ch4oConcent1_fp32": 0.0, + "ch4oConcent2_fp32": 0.0, "ch4o_fp32": 0.0, - "excTemp_fp32": 64.0, + "excTemp_fp32": 0.0, "faultCode1_uint16": 0, "faultCode2_uint16": 0, "faultCode3_uint16": 0, "fcuCurIns_fp32": 0.0, "fcuCurPower_fp32": 0.0, - "fcuCur_fp32": 74.0, + "fcuCur_fp32": 0.0, "fcuFaultLeve_uint8": 0, - "fcuOutIns_fp32": 81.0, - "fcuOutPower_fp32": 848.0, + "fcuOutIns_fp32": 0.0, + "fcuOutPower_fp32": 0.0, "fcuState_uint8": 0, "fcuVolIns_fp32": 0.0, "fcuVolPower_fp32": 0.0, - "fcuVol_fp32": 384.0, - "flameDet_uint8": 1, - "h2Concent1_fp32": 55.0, - "h2Concent2_fp32": 34.0, - "o2Concent1_fp32": 67.0, - "o2Concent2_fp32": 53.0, + "fcuVol_fp32": 0.0, + "flameDet_uint8": 0, + "h2Concent1_fp32": 0.0, + "h2Concent2_fp32": 0.0, + "o2Concent1_fp32": 0.0, + "o2Concent2_fp32": 0.0, "o2Level_fp32": 0.0, "o2_fp32": 0.0, - "powLimit_fp32": 23.0, - "powerGen_fp32": 539.0 + "powLimit_fp32": 0.0, + "powerGen_fp32": 0.0 } \ No newline at end of file diff --git a/data/msg/uPower_liBatState_st.json b/data/msg/uPower_liBatState_st.json index 8be04ea..b3e9fd4 100644 --- a/data/msg/uPower_liBatState_st.json +++ b/data/msg/uPower_liBatState_st.json @@ -2,14 +2,14 @@ "fcuCurToInsLimit1_uint8": 0, "fcuCurToinsLimit2_uint8": 0, "insBatCurElect_uint16": 0, - "insBatLimit_uint16": 86, - "insBatSoc_uint8": 95, - "insBatTotalElect_uint16": 741, + "insBatLimit_uint16": 0, + "insBatSoc_uint8": 0, + "insBatTotalElect_uint16": 0, "insChargeState_uint8": 0, "insCurSocHold1_uint8": 0, "insCurSocHold2_uint8": 0, "insCurSocHold3_uint8": 0, - "insCurrent_uint16": 9, + "insCurrent_uint16": 0, "insLinkVol_uint16": 0, "insNegRelayState_uint8": 0, "insNegRes_uint16": 0, @@ -18,21 +18,21 @@ "insPosRes_uint16": 0, "insfaultCode_uint8": 0, "powBatCurElect_uint16": 0, - "powBatSoc_uint8": 47, - "powBatTotalElect_uint16": 860, + "powBatSoc_uint8": 0, + "powBatTotalElect_uint16": 0, "powChargeState_uint8": 0, "powCurSocHold1_uint8": 0, "powCurSocHold2_uint8": 0, "powCurSocHold3_uint8": 0, "powCurToInsLimit1_uint8": 0, "powCurToinsLimit2_uint8": 0, - "powCur_uint16": 34, + "powCur_uint16": 0, "powLinkVol_uint16": 0, "powNegRelayState_uint8": 0, "powNegRes_uint16": 0, - "powPosRelayState_uint8": 1, + "powPosRelayState_uint8": 0, "powPosRes_uint16": 0, - "powerBatLimit_uint16": 65, + "powerBatLimit_uint16": 0, "powerPackVol_uint16": 0, "powfaultCode_uint8": 0 } \ No newline at end of file diff --git a/src/appPowerMangerWebUI/CMakeLists.txt b/src/appPowerMangerWebUI/CMakeLists.txt index 23f8a6b..2e25378 100644 --- a/src/appPowerMangerWebUI/CMakeLists.txt +++ b/src/appPowerMangerWebUI/CMakeLists.txt @@ -8,6 +8,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # 设置 vcpkg 工具链文件路径 set(CMAKE_TOOLCHAIN_FILE "/home/zjk/project/lib/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") +# 查找Boost库 +find_package(Boost REQUIRED COMPONENTS system thread) + #find crow库 find_package(Crow CONFIG REQUIRED) # Find SQLite3 package @@ -28,5 +31,6 @@ TARGET_LINK_LIBRARIES(appPowerMangerWebUI asio::asio jsoncpp SQLiteDB - sqlite3) - + sqlite3 + Boost::system + Boost::thread) diff --git a/src/appPowerMangerWebUI/main.cpp b/src/appPowerMangerWebUI/main.cpp index 63ad493..8dc35ae 100644 --- a/src/appPowerMangerWebUI/main.cpp +++ b/src/appPowerMangerWebUI/main.cpp @@ -9,139 +9,130 @@ #include #include #include +#include #include "../pPowerManger/SQLiteDB.h" #include "../pPowerManger/pmSysvariable.h" #include using namespace std; -// 定义一个全局变量,用于存储状态信息 +// 定义全局变量 ccuState ccustate; StateData stateData; +mutex wsMutex; +vector wsConnections; +shared_ptr db; +shared_ptr moosClient; + + +// WebSocket消息处理 +void sendStateUpdate() { + crow::json::wvalue msg; + string time; + { + lock_guard lock(wsMutex); + db->getStateData(stateData, time); + } + + msg["state"] = { + {"time", time}, + {"state_id", stateData.state_id}, + {"state_name", stateData.state_name}, + {"event", stateData.event}, + {"event_id", stateData.event_id}, + {"fault_code", stateData.fault_code}, + {"note", stateData.note} + }; + + // 添加数据库状态信息 + msg["db_status"] = { + {"connected", db->isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/data", "power_data.db")}, + {"database", db->getDBPatch()} + }; + + // 添加MOOS数据库状态信息 + msg["moos_db_status"] = { + {"connected", moosClient->IsConnected()}, + {"host", "localhost"}, + {"port", 9000} + }; + + { + lock_guard lock(wsMutex); + for(auto conn : wsConnections) { + conn->send_text(msg.dump()); + } + } +} int main() { crow::SimpleApp app; - SQLiteDB db("/home/zjk/project/H100/H100PowerManger/data/power_data.db"); - MOOS::MOOSAsyncCommClient moosClient; - moosClient.Run("localhost", 9000, "appPowerMangerWebUI"); + db = make_shared("/home/zjk/project/H100/H100PowerManger/data/power_data.db"); + moosClient = make_shared(); + moosClient->Run("localhost", 9000, "appPowerMangerWebUI"); - std::cout << " Current Path -> " << std::system("pwd") << std::endl; + // WebSocket路由 + CROW_WEBSOCKET_ROUTE(app, "/ws/state") + .onopen([&](crow::websocket::connection& conn){ + lock_guard lock(wsMutex); + wsConnections.push_back(&conn); + cout << "New WebSocket connection" << endl; + }) + .onclose([&](crow::websocket::connection& conn, const string& /*reason*/, uint16_t /*code*/){ + lock_guard lock(wsMutex); + wsConnections.erase( + remove(wsConnections.begin(), wsConnections.end(), &conn), + wsConnections.end()); + cout << "WebSocket connection closed" << endl; + }) + .onmessage([&](crow::websocket::connection& conn, const string& data, bool is_binary){ + // 处理收到的WebSocket消息 + cout << "Received WebSocket message: " << data << endl; + }); - // 定义路由,处理根路径的请求 + // 状态更新定时器 + thread([](){ + while(true) { + sendStateUpdate(); + this_thread::sleep_for(chrono::seconds(1)); + } + }).detach(); + + // 绑定主页路由 CROW_ROUTE(app, "/")([]() { auto page = crow::mustache::load_text("index.html"); return page; }); - // 定义路由,处理 /api/power-data 的请求 - CROW_ROUTE(app, "/api/db-status") - ([&db]() { - crow::json::wvalue response; - if (db.isDatabaseConnected("/home/zjk/project/H100/H100PowerManger/data", "power_data.db")) { - response["connected"] = true; - response["database"] = db.getDBPatch(); - } else { - response["connected"] = false; - } - return response; - }); - CROW_ROUTE(app, "/api/state") - ([&db]() { - crow::json::wvalue response; - string time; - db.getStateData(stateData,time);//状态机的状态 - response["state_id"] = stateData.state_id; - response["state_name"] = stateData.state_name; - response["event"] = stateData.event; - response["event_id"] = stateData.event_id; - response["fault_code"] = stateData.fault_code; - response["note"] = stateData.note; - response["time"] = time; - return response; - }); - // 定义路由,处理 /api/power-data 的请求 - CROW_ROUTE(app, "/api/download-db") - ([&db]() { - std::ifstream file("/home/zjk/project/H100/H100PowerManger/src/appPowerMangerWebUI/index.html", std::ios::binary); - if (!file) { - return crow::response(404, "Database file not found"); - } - - // 获取文件大小 - file.seekg(0, std::ios::end); - size_t fileSize = file.tellg(); - file.seekg(0, std::ios::beg); - - // 创建响应对象 - crow::response response; - response.code = 200; - response.set_header("Content-Type", "application/octet-stream"); - response.set_header("Content-Disposition", "attachment; filename=power_data.db"); - response.set_header("Content-Length", std::to_string(fileSize)); - - // 直接返回文件流 - response.body = std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - file.close(); - - return response; - }); - // 定义路由,处理 /api/moos-db 的请求 - CROW_ROUTE(app, "/api/moos-db") - ([&moosClient]() -> crow::json::wvalue { - crow::json::wvalue response; - if (moosClient.IsConnected()) { - response["connected"] = true; - response["host"] = moosClient.GetDBHostname(); - response["port"] = std::to_string(moosClient.GetDBHostPort()); - } - else { - response["connected"] = false; - } - return response; - }); - - // 定义路由,处理 /api/moos-notify 的请求(POST) - CROW_ROUTE(app, "/api/moos-notify").methods("POST"_method) - ([&moosClient](const crow::request& req) { + // MOOS通知API + CROW_ROUTE(app, "/api/moos-notify") + .methods("POST"_method) + ([](const crow::request& req) { auto json = crow::json::load(req.body); if (!json) { return crow::response(400, "Invalid JSON"); } - std::string var = json["var"].s(); - std::string key = json["key"].s(); - - // 发送MOOS消息 - bool notifyResult = moosClient.Notify(var, key); - std::cout << "MOOS Notify: var=" << var << ", key=" << key - << ", result=" << (notifyResult ? "success" : "failed") << std::endl; + string var = json["var"].s(); + string key = json["key"].s(); - crow::response res; - if (notifyResult) - { - res.body = crow::json::wvalue({ - {"success", true}, - {"message", key + ":" + var} - }).dump(); + if (var.empty() || key.empty()) { + return crow::response(400, "Var and Key are required"); } - else - { - res.body = crow::json::wvalue({ - {"success", false}, - {"message", key + ":" + var}, - }).dump(); + + try { + moosClient->Notify(var, key); + return crow::response(200, "{\"success\":true}"); + } catch (const exception& e) { + return crow::response(500, + crow::json::wvalue{{"success", false}, {"message", e.what()}}.dump()); } - res.set_header("Content-Type", "application/json"); - return res; }); - // 启动服务器,监听端口 18080 并启动多线程 - std::cout << "Server started on port 18080" << std::endl; - // app.port(18080).multithreaded().run(); - + // 启动服务器 app.port(18080) .multithreaded() - .concurrency(16) // 增加并发线程数 + .concurrency(16) .run(); return 0;