一些给APP的展示修改
This commit is contained in:
parent
975a28dfe5
commit
4e8cb2e4a0
|
|
@ -3,7 +3,7 @@
|
||||||
"config_base_path": "/app/config/",
|
"config_base_path": "/app/config/",
|
||||||
"data_cache_db_path": "edge_data_cache.db",
|
"data_cache_db_path": "edge_data_cache.db",
|
||||||
"data_storage_db_path": "edge_proxy_data.db",
|
"data_storage_db_path": "edge_proxy_data.db",
|
||||||
"device_id": "rk3588-proxy-001",
|
"device_id": "rk3588-proxy-002",
|
||||||
"log_level": "info",
|
"log_level": "info",
|
||||||
"mqtt_broker": "tcp://localhost:1883",
|
"mqtt_broker": "tcp://localhost:1883",
|
||||||
"mqtt_client_id_prefix": "edge-proxy-",
|
"mqtt_client_id_prefix": "edge-proxy-",
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
12345
|
12345
|
||||||
],
|
],
|
||||||
"video_service": {
|
"video_service": {
|
||||||
"enabled": true
|
"enabled": false
|
||||||
},
|
},
|
||||||
"video_streams": [
|
"video_streams": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,47 @@
|
||||||
{
|
{
|
||||||
"modbus_rtu_devices": [
|
"modbus_rtu_devices": [
|
||||||
{
|
{
|
||||||
"enabled": false,
|
"enabled": true,
|
||||||
"device_id": "rtu_temp_sensor_lab",
|
"device_id": "rtu_temp_sensor_lab",
|
||||||
"port_path": "/dev/ttyS7",
|
"port_path": "/dev/ttyS7",
|
||||||
"baud_rate": 9600,
|
"baud_rate": 9600,
|
||||||
"slave_id": 1,
|
"slave_id": 1,
|
||||||
"poll_interval_ms": 5000,
|
"poll_interval_ms": 5000,
|
||||||
"data_points": [
|
"data_points": [
|
||||||
{"name": "temperature", "address": 0, "type": "INT16", "scale": 0.1},
|
{
|
||||||
{"name": "humidity", "address": 1, "type": "UINT16", "scale": 0.1}
|
"name": "temperature",
|
||||||
|
"address": 0,
|
||||||
|
"type": "INT16",
|
||||||
|
"scale": 0.1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "humidity",
|
||||||
|
"address": 1,
|
||||||
|
"type": "UINT16",
|
||||||
|
"scale": 0.1
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"enabled": false,
|
"enabled": true,
|
||||||
"device_id": "rotary encoder",
|
"device_id": "rotary encoder",
|
||||||
"port_path": "/dev/ttyS7",
|
"port_path": "/dev/ttyS7",
|
||||||
"baud_rate": 9600,
|
"baud_rate": 9600,
|
||||||
"slave_id": 111,
|
"slave_id": 111,
|
||||||
"poll_interval_ms": 5000,
|
"poll_interval_ms": 5000,
|
||||||
"data_points": [
|
"data_points": [
|
||||||
{"name": "count", "address": 1, "type": "INT16", "scale": 1.0},
|
{
|
||||||
{"name": "total_count", "address": 2, "type": "INT16", "scale": 1.0}
|
"name": "count",
|
||||||
|
"address": 1,
|
||||||
|
"type": "INT16",
|
||||||
|
"scale": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "total_count",
|
||||||
|
"address": 2,
|
||||||
|
"type": "INT16",
|
||||||
|
"scale": 1.0
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -32,7 +52,11 @@
|
||||||
"slave_id": 10,
|
"slave_id": 10,
|
||||||
"poll_interval_ms": 1000,
|
"poll_interval_ms": 1000,
|
||||||
"data_points": [
|
"data_points": [
|
||||||
{"name": "count", "address": 32, "type": "UINT32"}
|
{
|
||||||
|
"name": "count",
|
||||||
|
"address": 32,
|
||||||
|
"type": "UINT32"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -45,9 +69,24 @@
|
||||||
"slave_id": 1,
|
"slave_id": 1,
|
||||||
"poll_interval_ms": 1000,
|
"poll_interval_ms": 1000,
|
||||||
"data_points": [
|
"data_points": [
|
||||||
{"name": "motor_speed", "address": 100, "type": "UINT16", "scale": 1.0},
|
{
|
||||||
{"name": "pressure", "address": 102, "type": "FLOAT32", "scale": 0.01},
|
"name": "motor_speed",
|
||||||
{"name": "valve_status","address": 104, "type": "UINT16", "scale": 1.0}
|
"address": 100,
|
||||||
|
"type": "UINT16",
|
||||||
|
"scale": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pressure",
|
||||||
|
"address": 102,
|
||||||
|
"type": "FLOAT32",
|
||||||
|
"scale": 0.01
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "valve_status",
|
||||||
|
"address": 104,
|
||||||
|
"type": "UINT16",
|
||||||
|
"scale": 1.0
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -56,4 +95,4 @@
|
||||||
"inter_device_delay_ms": 150
|
"inter_device_delay_ms": 150
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
|
@ -2,14 +2,16 @@
|
||||||
#include "config_manager.h"
|
#include "config_manager.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
ConfigManager& ConfigManager::getInstance() {
|
ConfigManager &ConfigManager::getInstance()
|
||||||
|
{
|
||||||
static ConfigManager instance;
|
static ConfigManager instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
json ConfigManager::createDefaultConfig() {
|
json ConfigManager::createDefaultConfig()
|
||||||
|
{
|
||||||
// --- 修改: 添加新的 video_service 和 video_streams 默认值 ---
|
// --- 修改: 添加新的 video_service 和 video_streams 默认值 ---
|
||||||
return json {
|
return json{
|
||||||
{"device_id", "default-edge-proxy-01"},
|
{"device_id", "default-edge-proxy-01"},
|
||||||
{"config_base_path", "/app/config/"},
|
{"config_base_path", "/app/config/"},
|
||||||
{"mqtt_broker", "tcp://localhost:1883"},
|
{"mqtt_broker", "tcp://localhost:1883"},
|
||||||
|
|
@ -25,63 +27,54 @@ json ConfigManager::createDefaultConfig() {
|
||||||
|
|
||||||
// --- 新增: 视频服务配置 ---
|
// --- 新增: 视频服务配置 ---
|
||||||
{
|
{
|
||||||
"video_service", {
|
"video_service", {{"enabled", false}}},
|
||||||
{"enabled", false}
|
{"video_streams", {{{"id", "cam_01_example"}, {"enabled", false}, {"input_url", "rtsp://your_camera_stream"}, {"output_rtsp", "rtsp://localhost:8554/cam_01_out"}, {"module_type", "intrusion_detection"}, {"module_config", {{"model_path", "/app/models/yolov5s.rknn"}, {"rknn_thread_num", 3}, {"intrusion_zone", {0, 0, 1920, 1080}}, {"time_threshold_sec", 5.0}}}}}}};
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"video_streams", {
|
|
||||||
{
|
|
||||||
{"id", "cam_01_example"},
|
|
||||||
{"enabled", false},
|
|
||||||
{"input_url", "rtsp://your_camera_stream"},
|
|
||||||
{"output_rtsp", "rtsp://localhost:8554/cam_01_out"},
|
|
||||||
{"module_type", "intrusion_detection"},
|
|
||||||
{"module_config", {
|
|
||||||
{"model_path", "/app/models/yolov5s.rknn"},
|
|
||||||
{"rknn_thread_num", 3},
|
|
||||||
{"intrusion_zone", {0, 0, 1920, 1080}},
|
|
||||||
{"time_threshold_sec", 5.0}
|
|
||||||
}}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigManager::save_unlocked() {
|
bool ConfigManager::save_unlocked()
|
||||||
|
{
|
||||||
std::ofstream ofs(m_configFilePath);
|
std::ofstream ofs(m_configFilePath);
|
||||||
if (!ofs.is_open()) {
|
if (!ofs.is_open())
|
||||||
|
{
|
||||||
spdlog::error("Failed to open config file '{}' for writing.", m_configFilePath);
|
spdlog::error("Failed to open config file '{}' for writing.", m_configFilePath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
ofs << m_config_json.dump(4);
|
ofs << m_config_json.dump(4);
|
||||||
return true;
|
return true;
|
||||||
} catch (const json::exception& e) {
|
}
|
||||||
|
catch (const json::exception &e)
|
||||||
|
{
|
||||||
spdlog::error("Failed to serialize config. Error: {}", e.what());
|
spdlog::error("Failed to serialize config. Error: {}", e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfigManager::load(const std::string& configFilePath) {
|
bool ConfigManager::load(const std::string &configFilePath)
|
||||||
|
{
|
||||||
std::unique_lock<std::shared_mutex> lock(m_mutex);
|
std::unique_lock<std::shared_mutex> lock(m_mutex);
|
||||||
m_configFilePath = configFilePath;
|
m_configFilePath = configFilePath;
|
||||||
|
|
||||||
std::ifstream ifs(m_configFilePath);
|
std::ifstream ifs(m_configFilePath);
|
||||||
if (!ifs.is_open()) {
|
if (!ifs.is_open())
|
||||||
|
{
|
||||||
spdlog::warn("Config file '{}' not found. Creating with default values.", m_configFilePath);
|
spdlog::warn("Config file '{}' not found. Creating with default values.", m_configFilePath);
|
||||||
m_config_json = createDefaultConfig();
|
m_config_json = createDefaultConfig();
|
||||||
if(save_unlocked()) {
|
if (save_unlocked())
|
||||||
|
{
|
||||||
spdlog::info("Default config file created at '{}'.", m_configFilePath);
|
spdlog::info("Default config file created at '{}'.", m_configFilePath);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
spdlog::error("Failed to create default config file.");
|
spdlog::error("Failed to create default config file.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
ifs >> m_config_json;
|
ifs >> m_config_json;
|
||||||
// **重要**:合并默认值。
|
// **重要**:合并默认值。
|
||||||
json defaults = createDefaultConfig();
|
json defaults = createDefaultConfig();
|
||||||
|
|
@ -90,11 +83,14 @@ bool ConfigManager::load(const std::string& configFilePath) {
|
||||||
|
|
||||||
spdlog::info("Successfully loaded config from '{}'. Device ID: {}", m_configFilePath, m_config_json.value("device_id", "N/A"));
|
spdlog::info("Successfully loaded config from '{}'. Device ID: {}", m_configFilePath, m_config_json.value("device_id", "N/A"));
|
||||||
|
|
||||||
if (save_unlocked()) {
|
if (save_unlocked())
|
||||||
|
{
|
||||||
spdlog::debug("Config file updated with new default keys if any.");
|
spdlog::debug("Config file updated with new default keys if any.");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (const json::exception& e) {
|
}
|
||||||
|
catch (const json::exception &e)
|
||||||
|
{
|
||||||
spdlog::error("Failed to parse config file '{}'. Error: {}. Using default values.", m_configFilePath, e.what());
|
spdlog::error("Failed to parse config file '{}'. Error: {}. Using default values.", m_configFilePath, e.what());
|
||||||
m_config_json = createDefaultConfig();
|
m_config_json = createDefaultConfig();
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -102,103 +98,118 @@ bool ConfigManager::load(const std::string& configFilePath) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ... (save, getDeviceID, ... getPiperModelPath 保持不变) ...
|
// ... (save, getDeviceID, ... getPiperModelPath 保持不变) ...
|
||||||
bool ConfigManager::save() {
|
bool ConfigManager::save()
|
||||||
|
{
|
||||||
std::unique_lock<std::shared_mutex> lock(m_mutex);
|
std::unique_lock<std::shared_mutex> lock(m_mutex);
|
||||||
return save_unlocked();
|
return save_unlocked();
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getDeviceID() {
|
std::string ConfigManager::getDeviceID()
|
||||||
|
{
|
||||||
return get<std::string>("device_id", "default-edge-proxy-01");
|
return get<std::string>("device_id", "default-edge-proxy-01");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getConfigBasePath() {
|
std::string ConfigManager::getConfigBasePath()
|
||||||
|
{
|
||||||
return get<std::string>("config_base_path", "/app/config/");
|
return get<std::string>("config_base_path", "/app/config/");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getMqttBroker() {
|
std::string ConfigManager::getMqttBroker()
|
||||||
|
{
|
||||||
return get<std::string>("mqtt_broker", "tcp://localhost:1883");
|
return get<std::string>("mqtt_broker", "tcp://localhost:1883");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getMqttClientID() {
|
std::string ConfigManager::getMqttClientID()
|
||||||
|
{
|
||||||
return get<std::string>("mqtt_client_id_prefix", "edge-proxy-") + getDeviceID();
|
return get<std::string>("mqtt_client_id_prefix", "edge-proxy-") + getDeviceID();
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getDataStorageDbPath() {
|
std::string ConfigManager::getDataStorageDbPath()
|
||||||
|
{
|
||||||
return getConfigBasePath() + get<std::string>("data_storage_db_path", "edge_proxy_data.db");
|
return getConfigBasePath() + get<std::string>("data_storage_db_path", "edge_proxy_data.db");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getDataCacheDbPath() {
|
std::string ConfigManager::getDataCacheDbPath()
|
||||||
|
{
|
||||||
return getConfigBasePath() + get<std::string>("data_cache_db_path", "edge_data_cache.db");
|
return getConfigBasePath() + get<std::string>("data_cache_db_path", "edge_data_cache.db");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getDevicesConfigPath() {
|
std::string ConfigManager::getDevicesConfigPath()
|
||||||
|
{
|
||||||
return getConfigBasePath() + "devices.json";
|
return getConfigBasePath() + "devices.json";
|
||||||
}
|
}
|
||||||
int ConfigManager::getWebServerPort() {
|
int ConfigManager::getWebServerPort()
|
||||||
|
{
|
||||||
return get<int>("web_server_port", 8080);
|
return get<int>("web_server_port", 8080);
|
||||||
}
|
}
|
||||||
std::vector<uint16_t> ConfigManager::getTcpServerPorts() {
|
std::vector<uint16_t> ConfigManager::getTcpServerPorts()
|
||||||
|
{
|
||||||
return get<std::vector<uint16_t>>("tcp_server_ports", {12345});
|
return get<std::vector<uint16_t>>("tcp_server_ports", {12345});
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getLogLevel() {
|
std::string ConfigManager::getLogLevel()
|
||||||
|
{
|
||||||
return get<std::string>("log_level", "debug");
|
return get<std::string>("log_level", "debug");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getAlarmRulesPath() {
|
std::string ConfigManager::getAlarmRulesPath()
|
||||||
|
{
|
||||||
return getConfigBasePath() + get<std::string>("alarm_rules_path", "alarms.json");
|
return getConfigBasePath() + get<std::string>("alarm_rules_path", "alarms.json");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getPiperExecutablePath() {
|
std::string ConfigManager::getPiperExecutablePath()
|
||||||
|
{
|
||||||
return get<std::string>("piper_executable_path", "/usr/bin/piper");
|
return get<std::string>("piper_executable_path", "/usr/bin/piper");
|
||||||
}
|
}
|
||||||
std::string ConfigManager::getPiperModelPath() {
|
std::string ConfigManager::getPiperModelPath()
|
||||||
|
{
|
||||||
return get<std::string>("piper_model_path", "/app/models/model.onnx");
|
return get<std::string>("piper_model_path", "/app/models/model.onnx");
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- (getIsVideoServiceEnabled 保持不变) ---
|
bool ConfigManager::getIsVideoServiceEnabled() const
|
||||||
bool ConfigManager::getIsVideoServiceEnabled() const {
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(m_mutex);
|
std::shared_lock<std::shared_mutex> lock(m_mutex);
|
||||||
try {
|
try
|
||||||
if (m_config_json.contains("video_service")) {
|
{
|
||||||
|
if (m_config_json.contains("video_service"))
|
||||||
|
{
|
||||||
return m_config_json["video_service"].value("enabled", false);
|
return m_config_json["video_service"].value("enabled", false);
|
||||||
}
|
}
|
||||||
} catch (const json::type_error& e) {
|
}
|
||||||
|
catch (const json::type_error &e)
|
||||||
|
{
|
||||||
spdlog::warn("Config type mismatch for key 'video_service.enabled'. Error: {}", e.what());
|
spdlog::warn("Config type mismatch for key 'video_service.enabled'. Error: {}", e.what());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 移除: getVideoModelPath ---
|
std::vector<ConfigManager::VideoStreamConfig> ConfigManager::getVideoStreamConfigs() const
|
||||||
// std::string ConfigManager::getVideoModelPath() const { ... }
|
{
|
||||||
|
|
||||||
|
|
||||||
// --- 修改: getVideoStreamConfigs ---
|
|
||||||
std::vector<ConfigManager::VideoStreamConfig> ConfigManager::getVideoStreamConfigs() const {
|
|
||||||
std::vector<VideoStreamConfig> configs;
|
std::vector<VideoStreamConfig> configs;
|
||||||
|
|
||||||
std::shared_lock<std::shared_mutex> lock(m_mutex);
|
std::shared_lock<std::shared_mutex> lock(m_mutex);
|
||||||
|
|
||||||
try {
|
try
|
||||||
// --- 修改: 路径变为顶层的 "video_streams" ---
|
{
|
||||||
if (m_config_json.contains("video_streams") &&
|
if (m_config_json.contains("video_streams") &&
|
||||||
m_config_json["video_streams"].is_array())
|
m_config_json["video_streams"].is_array())
|
||||||
{
|
{
|
||||||
for (const auto& stream_json : m_config_json["video_streams"]) {
|
for (const auto &stream_json : m_config_json["video_streams"])
|
||||||
|
{
|
||||||
VideoStreamConfig cfg;
|
VideoStreamConfig cfg;
|
||||||
cfg.id = stream_json.value("id", "");
|
cfg.id = stream_json.value("id", "");
|
||||||
cfg.enabled = stream_json.value("enabled", false);
|
cfg.enabled = stream_json.value("enabled", false);
|
||||||
cfg.input_url = stream_json.value("input_url", "");
|
cfg.input_url = stream_json.value("input_url", "");
|
||||||
cfg.output_rtsp = stream_json.value("output_rtsp", "");
|
cfg.output_rtsp = stream_json.value("output_rtsp", "");
|
||||||
|
|
||||||
// --- 移除 ---
|
|
||||||
// cfg.rknn_thread_num = stream_json.value("rknn_thread_num", 1);
|
|
||||||
|
|
||||||
// --- 新增 ---
|
|
||||||
cfg.module_type = stream_json.value("module_type", "");
|
cfg.module_type = stream_json.value("module_type", "");
|
||||||
cfg.module_config = stream_json.value("module_config", json::object()); // 传递整个json对象
|
cfg.module_config = stream_json.value("module_config", json::object());
|
||||||
|
|
||||||
if (cfg.module_type.empty()) {
|
if (cfg.module_type.empty())
|
||||||
|
{
|
||||||
spdlog::warn("Video stream '{}' has no 'module_type' defined. It may fail to start.", cfg.id);
|
spdlog::warn("Video stream '{}' has no 'module_type' defined. It may fail to start.", cfg.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
configs.push_back(cfg);
|
configs.push_back(cfg);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
spdlog::warn("Config key 'video_streams' not found or is not an array.");
|
spdlog::warn("Config key 'video_streams' not found or is not an array.");
|
||||||
}
|
}
|
||||||
} catch (const json::exception& e) {
|
}
|
||||||
// 捕获所有可能的 JSON 解析异常
|
catch (const json::exception &e)
|
||||||
|
{
|
||||||
spdlog::error("Error parsing 'video_streams': {}", e.what());
|
spdlog::error("Error parsing 'video_streams': {}", e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,38 +10,41 @@
|
||||||
|
|
||||||
using json = nlohmann::json;
|
using json = nlohmann::json;
|
||||||
|
|
||||||
class ConfigManager {
|
class ConfigManager
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
//
|
struct VideoStreamConfig
|
||||||
// --- 核心修改 ---
|
{
|
||||||
//
|
|
||||||
struct VideoStreamConfig {
|
|
||||||
std::string id;
|
std::string id;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
std::string input_url;
|
std::string input_url;
|
||||||
std::string output_rtsp;
|
std::string output_rtsp;
|
||||||
// int rknn_thread_num; // <-- 移除 (已移动到 module_config)
|
|
||||||
|
|
||||||
std::string module_type; // <-- 新增: "intrusion_detection" 或 "face_recognition"
|
std::string module_type;
|
||||||
json module_config; // <-- 新增: 传递模块的特定配置 (最灵活的方式)
|
json module_config;
|
||||||
};
|
};
|
||||||
|
|
||||||
static ConfigManager& getInstance();
|
static ConfigManager &getInstance();
|
||||||
bool load(const std::string& configFilePath);
|
bool load(const std::string &configFilePath);
|
||||||
bool save();
|
bool save();
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
T get(const std::string& key, const T& default_value) {
|
T get(const std::string &key, const T &default_value)
|
||||||
|
{
|
||||||
std::shared_lock<std::shared_mutex> lock(m_mutex);
|
std::shared_lock<std::shared_mutex> lock(m_mutex);
|
||||||
|
|
||||||
if (!m_config_json.contains(key)) {
|
if (!m_config_json.contains(key))
|
||||||
|
{
|
||||||
spdlog::debug("Config key '{}' not found, using default value.", key);
|
spdlog::debug("Config key '{}' not found, using default value.", key);
|
||||||
return default_value;
|
return default_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
return m_config_json.at(key).get<T>();
|
return m_config_json.at(key).get<T>();
|
||||||
} catch (const json::type_error& e) {
|
}
|
||||||
|
catch (const json::type_error &e)
|
||||||
|
{
|
||||||
spdlog::warn("Config type mismatch for key '{}'. Expected '{}', found '{}'. Using default. Error: {}",
|
spdlog::warn("Config type mismatch for key '{}'. Expected '{}', found '{}'. Using default. Error: {}",
|
||||||
key,
|
key,
|
||||||
typeid(T).name(),
|
typeid(T).name(),
|
||||||
|
|
@ -51,8 +54,9 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void set(const std::string& key, const T& value) {
|
void set(const std::string &key, const T &value)
|
||||||
|
{
|
||||||
{
|
{
|
||||||
std::unique_lock<std::shared_mutex> lock(m_mutex);
|
std::unique_lock<std::shared_mutex> lock(m_mutex);
|
||||||
m_config_json[key] = value;
|
m_config_json[key] = value;
|
||||||
|
|
@ -61,12 +65,12 @@ public:
|
||||||
|
|
||||||
save();
|
save();
|
||||||
|
|
||||||
if (key == "log_level") {
|
if (key == "log_level")
|
||||||
|
{
|
||||||
spdlog::set_level(spdlog::level::from_str(value));
|
spdlog::set_level(spdlog::level::from_str(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string getDeviceID();
|
std::string getDeviceID();
|
||||||
std::string getConfigBasePath();
|
std::string getConfigBasePath();
|
||||||
std::string getMqttBroker();
|
std::string getMqttBroker();
|
||||||
|
|
@ -82,13 +86,13 @@ public:
|
||||||
std::string getPiperModelPath();
|
std::string getPiperModelPath();
|
||||||
|
|
||||||
bool getIsVideoServiceEnabled() const;
|
bool getIsVideoServiceEnabled() const;
|
||||||
std::vector<VideoStreamConfig> getVideoStreamConfigs() const; // (签名不变, 实现改变)
|
std::vector<VideoStreamConfig> getVideoStreamConfigs() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConfigManager() = default;
|
ConfigManager() = default;
|
||||||
~ConfigManager() = default;
|
~ConfigManager() = default;
|
||||||
ConfigManager(const ConfigManager&) = delete;
|
ConfigManager(const ConfigManager &) = delete;
|
||||||
ConfigManager& operator=(const ConfigManager&) = delete;
|
ConfigManager &operator=(const ConfigManager &) = delete;
|
||||||
json createDefaultConfig();
|
json createDefaultConfig();
|
||||||
|
|
||||||
bool save_unlocked();
|
bool save_unlocked();
|
||||||
|
|
|
||||||
149
src/main.cpp
149
src/main.cpp
|
|
@ -1,50 +1,73 @@
|
||||||
// main.cpp
|
// main.cpp
|
||||||
#include "network/tcp_server.h"
|
|
||||||
#include "mqtt/mqtt_client.h"
|
|
||||||
#include "mqtt/mqtt_router.h"
|
|
||||||
#include "systemMonitor/system_monitor.h"
|
|
||||||
#include "spdlog/spdlog.h"
|
|
||||||
#include "deviceManager/device_manager.h"
|
|
||||||
#include "dataCache/data_cache.h"
|
|
||||||
#include "dataCache/cache_uploader.h"
|
|
||||||
#include "web/web_server.h"
|
|
||||||
#include "dataCache/live_data_cache.h"
|
|
||||||
#include "dataStorage/data_storage.h"
|
|
||||||
#include "config/config_manager.h"
|
|
||||||
#include "videoServiceManager/video_service_manager.h"
|
|
||||||
#include "alarm/alarm_service.h"
|
|
||||||
#include "tts/piper_tts_interface.h"
|
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/asio/steady_timer.hpp>
|
#include <boost/asio/steady_timer.hpp>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <iostream>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "alarm/alarm_service.h"
|
||||||
|
#include "config/config_manager.h"
|
||||||
|
#include "dataCache/cache_uploader.h"
|
||||||
|
#include "dataCache/data_cache.h"
|
||||||
|
#include "dataCache/live_data_cache.h"
|
||||||
|
#include "dataStorage/data_storage.h"
|
||||||
|
#include "deviceManager/device_manager.h"
|
||||||
|
#include "mqtt/mqtt_client.h"
|
||||||
|
#include "mqtt/mqtt_router.h"
|
||||||
|
#include "network/tcp_server.h"
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
#include "systemMonitor/system_monitor.h"
|
||||||
|
#include "tts/piper_tts_interface.h"
|
||||||
|
#include "videoServiceManager/video_service_manager.h"
|
||||||
|
#include "web/web_server.h"
|
||||||
|
|
||||||
boost::asio::io_context g_io_context;
|
boost::asio::io_context g_io_context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 周期性轮询系统状态并发布到 MQTT
|
* @brief 周期性轮询系统状态并发布到 MQTT
|
||||||
*/
|
*/
|
||||||
void poll_system_metrics(
|
void poll_system_metrics(boost::asio::steady_timer& timer,
|
||||||
boost::asio::steady_timer& timer,
|
|
||||||
SystemMonitor::SystemMonitor& monitor,
|
SystemMonitor::SystemMonitor& monitor,
|
||||||
MqttClient& mqtt_client,
|
MqttClient& mqtt_client, AlarmService& alarm_service) {
|
||||||
AlarmService& alarm_service
|
|
||||||
) {
|
|
||||||
if (g_io_context.stopped()) return;
|
if (g_io_context.stopped()) return;
|
||||||
auto cpu_util = monitor.getCpuUtilization();
|
auto cpu_util = monitor.getCpuUtilization();
|
||||||
auto mem_info = monitor.getMemoryInfo();
|
auto mem_info = monitor.getMemoryInfo();
|
||||||
double mem_total_gb = mem_info.total_kb / 1024.0 / 1024.0;
|
double mem_total_gb = mem_info.total_kb / 1024.0 / 1024.0;
|
||||||
|
|
||||||
double mem_usage_percentage = (mem_info.total_kb > 0)
|
double mem_usage_percentage =
|
||||||
? (100.0 * (mem_info.total_kb - mem_info.available_kb) / mem_info.total_kb)
|
(mem_info.total_kb > 0)
|
||||||
|
? (100.0 * (mem_info.total_kb - mem_info.available_kb) /
|
||||||
|
mem_info.total_kb)
|
||||||
: 0.0;
|
: 0.0;
|
||||||
|
|
||||||
|
auto thermalInfoString = monitor.getChipTemperature();
|
||||||
|
|
||||||
std::string topic = "proxy/system_status";
|
std::string topic = "proxy/system_status";
|
||||||
std::string payload = "{\"cpu_usage\":" + std::to_string(cpu_util.totalUsagePercentage) +
|
std::string payload;
|
||||||
",\"mem_total_gb\":" + std::to_string(mem_total_gb) +
|
|
||||||
",\"mem_usage_percentage\":" + std::to_string(mem_usage_percentage) + "}";
|
try {
|
||||||
|
nlohmann::json payload_json;
|
||||||
|
payload_json["cpu_usage"] = cpu_util.totalUsagePercentage;
|
||||||
|
payload_json["mem_total_gb"] = mem_total_gb;
|
||||||
|
payload_json["mem_usage_percentage"] = mem_usage_percentage;
|
||||||
|
payload_json["thermal_info"] = nlohmann::json::parse(thermalInfoString);
|
||||||
|
|
||||||
|
payload = payload_json.dump();
|
||||||
|
|
||||||
|
} catch (const nlohmann::json::parse_error& e) {
|
||||||
|
spdlog::error("Failed to parse thermalInfo JSON: {}. Sending partial data.",
|
||||||
|
e.what());
|
||||||
|
nlohmann::json fallback_json;
|
||||||
|
fallback_json["cpu_usage"] = cpu_util.totalUsagePercentage;
|
||||||
|
fallback_json["mem_total_gb"] = mem_total_gb;
|
||||||
|
fallback_json["mem_usage_percentage"] = mem_usage_percentage;
|
||||||
|
fallback_json["thermal_info_error"] = "parsing_failed";
|
||||||
|
fallback_json["raw_thermal_info"] = thermalInfoString;
|
||||||
|
|
||||||
|
payload = fallback_json.dump();
|
||||||
|
}
|
||||||
|
|
||||||
alarm_service.process_system_data(payload);
|
alarm_service.process_system_data(payload);
|
||||||
|
|
||||||
|
|
@ -52,20 +75,17 @@ void poll_system_metrics(
|
||||||
spdlog::debug("System metrics published.");
|
spdlog::debug("System metrics published.");
|
||||||
|
|
||||||
timer.expires_at(timer.expiry() + std::chrono::seconds(15));
|
timer.expires_at(timer.expiry() + std::chrono::seconds(15));
|
||||||
timer.async_wait(std::bind(poll_system_metrics,
|
timer.async_wait(std::bind(poll_system_metrics, std::ref(timer),
|
||||||
std::ref(timer),
|
std::ref(monitor), std::ref(mqtt_client),
|
||||||
std::ref(monitor),
|
std::ref(alarm_service)));
|
||||||
std::ref(mqtt_client),
|
|
||||||
std::ref(alarm_service)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
const std::string config_path = "/app/config/config.json";
|
const std::string config_path = "/app/config/config.json";
|
||||||
if (!ConfigManager::getInstance().load(config_path)) {
|
if (!ConfigManager::getInstance().load(config_path)) {
|
||||||
std::cerr << "Failed to load configuration from " << config_path
|
std::cerr << "Failed to load configuration from " << config_path
|
||||||
<< ". Running with defaults, but this may cause issues." << std::endl;
|
<< ". Running with defaults, but this may cause issues."
|
||||||
|
<< std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& config = ConfigManager::getInstance();
|
auto& config = ConfigManager::getInstance();
|
||||||
|
|
@ -91,45 +111,39 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
DataCache data_cache;
|
DataCache data_cache;
|
||||||
LiveDataCache live_data_cache;
|
LiveDataCache live_data_cache;
|
||||||
MqttClient mqtt_client(config.getMqttBroker(),
|
MqttClient mqtt_client(config.getMqttBroker(), config.getMqttClientID());
|
||||||
config.getMqttClientID()
|
|
||||||
);
|
|
||||||
|
|
||||||
PiperTTSInterface tts_service(
|
PiperTTSInterface tts_service(config.getPiperExecutablePath(),
|
||||||
config.getPiperExecutablePath(),
|
config.getPiperModelPath());
|
||||||
config.getPiperModelPath()
|
|
||||||
);
|
|
||||||
|
|
||||||
AlarmService alarm_service(g_io_context,
|
AlarmService alarm_service(g_io_context, tts_service, mqtt_client,
|
||||||
tts_service,
|
|
||||||
mqtt_client,
|
|
||||||
data_storage);
|
data_storage);
|
||||||
|
|
||||||
if (!alarm_service.load_rules(config.getAlarmRulesPath())) {
|
if (!alarm_service.load_rules(config.getAlarmRulesPath())) {
|
||||||
spdlog::error("Failed to load alarm rules. Alarms may be disabled.");
|
spdlog::error("Failed to load alarm rules. Alarms may be disabled.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto report_to_mqtt = [&](const UnifiedData& data) {
|
auto report_to_mqtt = [&](const UnifiedData& data) {
|
||||||
if (data_storage.storeProcessedData(data)) {
|
if (data_storage.storeProcessedData(data)) {
|
||||||
spdlog::debug("Successfully stored PROCESSED data for device '{}'", data.device_id);
|
spdlog::debug("Successfully stored PROCESSED data for device '{}'",
|
||||||
|
data.device_id);
|
||||||
} else {
|
} else {
|
||||||
spdlog::error("Failed to store PROCESSED data for device '{}'", data.device_id);
|
spdlog::error("Failed to store PROCESSED data for device '{}'",
|
||||||
|
data.device_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
live_data_cache.update_data(data.device_id, data.data_json);
|
live_data_cache.update_data(data.device_id, data.data_json);
|
||||||
|
|
||||||
// [新] 1. 在发布前处理告警
|
|
||||||
alarm_service.process_device_data(data.device_id, data.data_json);
|
alarm_service.process_device_data(data.device_id, data.data_json);
|
||||||
|
|
||||||
// 2. 正常上报或缓存
|
|
||||||
if (mqtt_client.is_connected()) {
|
if (mqtt_client.is_connected()) {
|
||||||
std::string topic = "devices/" + data.device_id + "/data";
|
std::string topic = "devices/" + data.device_id + "/data";
|
||||||
g_io_context.post([&, topic, payload = data.data_json]() {
|
g_io_context.post([&, topic, payload = data.data_json]() {
|
||||||
mqtt_client.publish(topic, payload, 1, false);
|
mqtt_client.publish(topic, payload, 1, false);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
spdlog::warn("MQTT disconnected. Caching data for device '{}'.", data.device_id);
|
spdlog::warn("MQTT disconnected. Caching data for device '{}'.",
|
||||||
|
data.device_id);
|
||||||
data_cache.add(data);
|
data_cache.add(data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -142,12 +156,13 @@ int main(int argc, char* argv[]) {
|
||||||
SystemMonitor::SystemMonitor monitor;
|
SystemMonitor::SystemMonitor monitor;
|
||||||
|
|
||||||
if (!data_cache.open(config.getDataCacheDbPath())) {
|
if (!data_cache.open(config.getDataCacheDbPath())) {
|
||||||
spdlog::critical("Failed to initialize data cache at '{}'. Exiting.", config.getDataCacheDbPath());
|
spdlog::critical("Failed to initialize data cache at '{}'. Exiting.",
|
||||||
|
config.getDataCacheDbPath());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
CacheUploader cache_uploader(g_io_context, mqtt_client, data_cache);
|
CacheUploader cache_uploader(g_io_context, mqtt_client, data_cache);
|
||||||
|
|
||||||
mqtt_client.set_connected_handler([&](const std::string& cause){
|
mqtt_client.set_connected_handler([&](const std::string& cause) {
|
||||||
spdlog::info("MQTT client connected: {}", cause);
|
spdlog::info("MQTT client connected: {}", cause);
|
||||||
cache_uploader.start_upload();
|
cache_uploader.start_upload();
|
||||||
});
|
});
|
||||||
|
|
@ -155,25 +170,18 @@ int main(int argc, char* argv[]) {
|
||||||
mqtt_client.connect();
|
mqtt_client.connect();
|
||||||
mqtt_router.start();
|
mqtt_router.start();
|
||||||
|
|
||||||
|
|
||||||
monitor.getCpuUtilization();
|
monitor.getCpuUtilization();
|
||||||
boost::asio::steady_timer system_monitor_timer(g_io_context, std::chrono::seconds(15));
|
boost::asio::steady_timer system_monitor_timer(g_io_context,
|
||||||
|
std::chrono::seconds(15));
|
||||||
system_monitor_timer.async_wait(std::bind(poll_system_metrics,
|
|
||||||
std::ref(system_monitor_timer),
|
|
||||||
std::ref(monitor),
|
|
||||||
std::ref(mqtt_client),
|
|
||||||
std::ref(alarm_service)
|
|
||||||
));
|
|
||||||
|
|
||||||
|
system_monitor_timer.async_wait(std::bind(
|
||||||
|
poll_system_metrics, std::ref(system_monitor_timer), std::ref(monitor),
|
||||||
|
std::ref(mqtt_client), std::ref(alarm_service)));
|
||||||
|
|
||||||
device_manager.load_and_start(config.getDevicesConfigPath());
|
device_manager.load_and_start(config.getDevicesConfigPath());
|
||||||
|
|
||||||
WebServer web_server(monitor,
|
WebServer web_server(monitor, device_manager, live_data_cache,
|
||||||
device_manager,
|
alarm_service, config.getWebServerPort());
|
||||||
live_data_cache,
|
|
||||||
alarm_service,
|
|
||||||
config.getWebServerPort());
|
|
||||||
web_server.start();
|
web_server.start();
|
||||||
if (config.getIsVideoServiceEnabled()) {
|
if (config.getIsVideoServiceEnabled()) {
|
||||||
video_manager.load_and_start(config);
|
video_manager.load_and_start(config);
|
||||||
|
|
@ -182,8 +190,10 @@ int main(int argc, char* argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::signal_set signals(g_io_context, SIGINT, SIGTERM);
|
boost::asio::signal_set signals(g_io_context, SIGINT, SIGTERM);
|
||||||
signals.async_wait([&](const boost::system::error_code& error, int signal_number) {
|
signals.async_wait(
|
||||||
spdlog::warn("Interrupt signal ({}) received. Shutting down.", signal_number);
|
[&](const boost::system::error_code& error, int signal_number) {
|
||||||
|
spdlog::warn("Interrupt signal ({}) received. Shutting down.",
|
||||||
|
signal_number);
|
||||||
|
|
||||||
// a. 停止所有数据采集
|
// a. 停止所有数据采集
|
||||||
spdlog::info("[Shutdown] A. Stopping device manager services...");
|
spdlog::info("[Shutdown] A. Stopping device manager services...");
|
||||||
|
|
@ -213,7 +223,6 @@ int main(int argc, char* argv[]) {
|
||||||
spdlog::info("All services are running. Press Ctrl+C to exit.");
|
spdlog::info("All services are running. Press Ctrl+C to exit.");
|
||||||
g_io_context.run();
|
g_io_context.run();
|
||||||
|
|
||||||
|
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
spdlog::critical("An unhandled exception occurred: {}", e.what());
|
spdlog::critical("An unhandled exception occurred: {}", e.what());
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
namespace SystemMonitor {
|
namespace SystemMonitor {
|
||||||
|
|
||||||
|
|
@ -71,27 +72,35 @@ MemoryInfo SystemMonitor::getMemoryInfo() const {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<ThermalInfo> SystemMonitor::getChipTemperature() const {
|
std::string SystemMonitor::getChipTemperature() const {
|
||||||
std::vector<ThermalInfo> temps;
|
// std::vector<ThermalInfo> temps;
|
||||||
const std::vector<std::pair<std::string, std::string>> zones = {
|
const std::vector<std::pair<std::string, std::string>> zones = {
|
||||||
{"CPU Core", "/sys/class/thermal/thermal_zone0/temp"},
|
{"CPU Core", "/sys/class/thermal/thermal_zone0/temp"},
|
||||||
{"GPU Core", "/sys/class/thermal/thermal_zone1/temp"},
|
{"GPU Core", "/sys/class/thermal/thermal_zone1/temp"},
|
||||||
{"NPU Core", "/sys/class/thermal/thermal_zone2/temp"},
|
{"NPU Core", "/sys/class/thermal/thermal_zone2/temp"},
|
||||||
{"Other", "/sys/class/thermal/thermal_zone3/temp"}
|
{"Other", "/sys/class/thermal/thermal_zone3/temp"}
|
||||||
};
|
};
|
||||||
|
json jsonArray = json::array();
|
||||||
|
|
||||||
for (const auto& zone : zones) {
|
for (const auto& zone : zones) {
|
||||||
std::string temp_str = readFile(zone.second);
|
std::string temp_str = readFile(zone.second);
|
||||||
if (!temp_str.empty()) {
|
if (!temp_str.empty()) {
|
||||||
try {
|
try {
|
||||||
ThermalInfo info;
|
|
||||||
info.zoneName = zone.first;
|
json tempObject;
|
||||||
info.temperatureCelsius = std::stod(temp_str) / 1000.0;
|
tempObject["zoneName"] = zone.first;
|
||||||
temps.push_back(info);
|
tempObject["temperatureCelsius"] = std::stod(temp_str) / 1000.0;
|
||||||
|
|
||||||
|
jsonArray.push_back(tempObject);
|
||||||
|
|
||||||
|
// ThermalInfo info;
|
||||||
|
// info.zoneName = zone.first;
|
||||||
|
// info.temperatureCelsius = std::stod(temp_str) / 1000.0;
|
||||||
|
// temps.push_back(info);
|
||||||
} catch (...) { /* 忽略转换失败 */ }
|
} catch (...) { /* 忽略转换失败 */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return temps;
|
return jsonArray.dump(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
CpuUtilization SystemMonitor::getCpuUtilization(int interval_ms) const {
|
CpuUtilization SystemMonitor::getCpuUtilization(int interval_ms) const {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <nlohmann/json.hpp> // 包含 nlohmann/json 库
|
||||||
namespace SystemMonitor {
|
namespace SystemMonitor {
|
||||||
|
|
||||||
struct SystemInfo {
|
struct SystemInfo {
|
||||||
|
|
@ -47,7 +48,7 @@ public:
|
||||||
SystemInfo getSystemInfo() const;
|
SystemInfo getSystemInfo() const;
|
||||||
std::vector<StorageDevice> getStorageInfo() const;
|
std::vector<StorageDevice> getStorageInfo() const;
|
||||||
MemoryInfo getMemoryInfo() const;
|
MemoryInfo getMemoryInfo() const;
|
||||||
std::vector<ThermalInfo> getChipTemperature() const;
|
std::string getChipTemperature() const;
|
||||||
CpuUtilization getCpuUtilization(int interval_ms = 1000) const;
|
CpuUtilization getCpuUtilization(int interval_ms = 1000) const;
|
||||||
std::string getKernelLogs(int last_n_lines = 20) const;
|
std::string getKernelLogs(int last_n_lines = 20) const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
// 文件名: src/web/web_server.cc
|
// 文件名: src/web/web_server.cc
|
||||||
#include "web_server.h"
|
#include "web_server.h"
|
||||||
#include "spdlog/spdlog.h"
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
WebServer::WebServer(SystemMonitor::SystemMonitor& monitor, DeviceManager& deviceManager, LiveDataCache& liveDataCache, AlarmService& alarm_service, uint16_t port)
|
#include "config/config_manager.h"
|
||||||
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
|
WebServer::WebServer(SystemMonitor::SystemMonitor& monitor,
|
||||||
|
DeviceManager& deviceManager, LiveDataCache& liveDataCache,
|
||||||
|
AlarmService& alarm_service, uint16_t port)
|
||||||
: crow::Crow<crow::CORSHandler>(),
|
: crow::Crow<crow::CORSHandler>(),
|
||||||
m_monitor(monitor),
|
m_monitor(monitor),
|
||||||
m_device_manager(deviceManager),
|
m_device_manager(deviceManager),
|
||||||
m_live_data_cache(liveDataCache),
|
m_live_data_cache(liveDataCache),
|
||||||
m_alarm_service(alarm_service),
|
m_alarm_service(alarm_service),
|
||||||
m_port(port)
|
m_port(port) {
|
||||||
{
|
|
||||||
auto& cors = this->get_middleware<crow::CORSHandler>();
|
auto& cors = this->get_middleware<crow::CORSHandler>();
|
||||||
cors
|
cors.global()
|
||||||
.global()
|
|
||||||
.origin("*")
|
.origin("*")
|
||||||
.headers("Content-Type", "Authorization")
|
.headers("Content-Type", "Authorization")
|
||||||
.methods("GET"_method, "POST"_method, "OPTIONS"_method);
|
.methods("GET"_method, "POST"_method, "OPTIONS"_method);
|
||||||
|
|
@ -23,9 +26,7 @@ WebServer::WebServer(SystemMonitor::SystemMonitor& monitor, DeviceManager& devic
|
||||||
setup_routes();
|
setup_routes();
|
||||||
}
|
}
|
||||||
|
|
||||||
WebServer::~WebServer() {
|
WebServer::~WebServer() { stop(); }
|
||||||
stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WebServer::start() {
|
void WebServer::start() {
|
||||||
if (m_thread.joinable()) {
|
if (m_thread.joinable()) {
|
||||||
|
|
@ -47,8 +48,14 @@ void WebServer::stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebServer::setup_routes() {
|
void WebServer::setup_routes() {
|
||||||
CROW_ROUTE((*this), "/api/system/status").methods("GET"_method)
|
CROW_ROUTE((*this), "/api/system/id").methods("GET"_method)([this] {
|
||||||
([this] {
|
auto deviceID = ConfigManager::getInstance().getDeviceID();
|
||||||
|
crow::json::wvalue response;
|
||||||
|
response["deviceID"] = deviceID;
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE((*this), "/api/system/status").methods("GET"_method)([this] {
|
||||||
auto cpu_util = m_monitor.getCpuUtilization();
|
auto cpu_util = m_monitor.getCpuUtilization();
|
||||||
auto mem_info = m_monitor.getMemoryInfo();
|
auto mem_info = m_monitor.getMemoryInfo();
|
||||||
|
|
||||||
|
|
@ -56,15 +63,17 @@ void WebServer::setup_routes() {
|
||||||
response["cpu_usage_percentage"] = cpu_util.totalUsagePercentage;
|
response["cpu_usage_percentage"] = cpu_util.totalUsagePercentage;
|
||||||
response["memory_total_kb"] = mem_info.total_kb;
|
response["memory_total_kb"] = mem_info.total_kb;
|
||||||
response["memory_free_kb"] = mem_info.available_kb;
|
response["memory_free_kb"] = mem_info.available_kb;
|
||||||
response["memory_usage_percentage"] = (mem_info.total_kb > 0)
|
response["memory_usage_percentage"] =
|
||||||
? (1.0 - static_cast<double>(mem_info.available_kb) / mem_info.total_kb) * 100.0
|
(mem_info.total_kb > 0)
|
||||||
|
? (1.0 -
|
||||||
|
static_cast<double>(mem_info.available_kb) / mem_info.total_kb) *
|
||||||
|
100.0
|
||||||
: 0.0;
|
: 0.0;
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
|
|
||||||
CROW_ROUTE((*this), "/api/devices").methods("GET"_method)
|
CROW_ROUTE((*this), "/api/devices").methods("GET"_method)([this] {
|
||||||
([this] {
|
|
||||||
auto devices_info = m_device_manager.get_all_device_info();
|
auto devices_info = m_device_manager.get_all_device_info();
|
||||||
|
|
||||||
std::vector<crow::json::wvalue> devices_json;
|
std::vector<crow::json::wvalue> devices_json;
|
||||||
|
|
@ -87,9 +96,7 @@ void WebServer::setup_routes() {
|
||||||
return crow::json::wvalue(devices_json);
|
return crow::json::wvalue(devices_json);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
CROW_ROUTE((*this), "/api/data/latest").methods("GET"_method)([this] {
|
||||||
CROW_ROUTE((*this), "/api/data/latest").methods("GET"_method)
|
|
||||||
([this] {
|
|
||||||
auto latest_data_map = m_live_data_cache.get_all_data();
|
auto latest_data_map = m_live_data_cache.get_all_data();
|
||||||
|
|
||||||
crow::json::wvalue response;
|
crow::json::wvalue response;
|
||||||
|
|
@ -100,8 +107,7 @@ void WebServer::setup_routes() {
|
||||||
return response;
|
return response;
|
||||||
});
|
});
|
||||||
|
|
||||||
CROW_ROUTE((*this), "/api/alarms/active").methods("GET"_method)
|
CROW_ROUTE((*this), "/api/alarms/active").methods("GET"_method)([this] {
|
||||||
([this] {
|
|
||||||
try {
|
try {
|
||||||
auto json_string = m_alarm_service.getActiveAlarmsJson().dump();
|
auto json_string = m_alarm_service.getActiveAlarmsJson().dump();
|
||||||
|
|
||||||
|
|
@ -120,13 +126,14 @@ void WebServer::setup_routes() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
CROW_ROUTE((*this), "/api/alarms/history").methods("GET"_method)
|
CROW_ROUTE((*this), "/api/alarms/history")
|
||||||
([this](const crow::request& req) {
|
.methods("GET"_method)([this](const crow::request& req) {
|
||||||
int limit = 100;
|
int limit = 100;
|
||||||
if (req.url_params.get("limit")) {
|
if (req.url_params.get("limit")) {
|
||||||
try {
|
try {
|
||||||
limit = std::stoi(req.url_params.get("limit"));
|
limit = std::stoi(req.url_params.get("limit"));
|
||||||
} catch (const std::exception&) { /* ignore invalid */ }
|
} catch (const std::exception&) { /* ignore invalid */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (limit <= 0) limit = 100;
|
if (limit <= 0) limit = 100;
|
||||||
|
|
||||||
|
|
@ -147,7 +154,4 @@ void WebServer::setup_routes() {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -38,6 +38,7 @@ private:
|
||||||
LiveDataCache& m_live_data_cache;
|
LiveDataCache& m_live_data_cache;
|
||||||
AlarmService& m_alarm_service;
|
AlarmService& m_alarm_service;
|
||||||
|
|
||||||
|
|
||||||
uint16_t m_port;
|
uint16_t m_port;
|
||||||
|
|
||||||
std::thread m_thread;
|
std::thread m_thread;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue