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;