bonus-edge-proxy/src/test.cc

279 lines
12 KiB
C++
Raw Normal View History

2025-10-23 09:36:06 +08:00
// #include "tts/piper_tts_interface.h"
// #include <string>
// #include <iostream>
2025-10-21 18:35:53 +08:00
2025-10-23 09:36:06 +08:00
// int main() {
// // 使用默认配置 (piper 和 /app/piper_models/zh_CN-huayan-medium.onnx)
// PiperTTSInterface tts_speaker;
// // 如果你的piper可执行文件不在PATH中或者模型路径不同你可以这样指定
// // PiperTTSInterface tts_speaker("/path/to/your/piper_executable", "/path/to/your/model.onnx");
// std::string text_to_say = "请执行上述调试步骤,特别是禁用文件删除后手动检查和播放 WAV 文件,这将提供更多线索";
// if (tts_speaker.say_text_and_play(text_to_say)) {
// std::cout << "语音播报完成。" << std::endl;
// } else {
// std::cerr << "语音播报失败,请检查日志。" << std::endl;
// }
// return 0;
// }
2025-10-21 18:35:53 +08:00
// #include <iostream>
// #include <chrono>
// #include <thread>
// #include "systemMonitor/iio_sensor.h" // 包含我们刚刚创建的头文件
// int main() {
// // --- 配置参数 ---
// // !!! 修改这里以匹配你的设备和通道 !!!
// const std::string iio_device_path = "/sys/bus/iio/devices/iio:device0";
// const std::string iio_channel_name = "in_voltage2_raw"; // 例如,连接到 IN2 通道
2025-10-21 15:34:24 +08:00
2025-10-21 18:35:53 +08:00
// const double adc_reference_voltage = 1.8; // ADC参考电压
// const int64_t adc_resolution = 4096; // ADC分辨率 (e.g., 2^12 for 12-bit)
// const double signal_gain = 11.0; // 信号通路的增益
// std::cout << "--- Starting IIO Sensor Reader (Version 2) ---" << std::endl;
// std::cout << "Reading from device: " << iio_device_path << std::endl;
// std::cout << "Reading channel: " << iio_channel_name << std::endl;
// std::cout << "-----------------------------------------------" << std::endl;
2025-10-21 15:34:24 +08:00
2025-10-21 18:35:53 +08:00
// // 注意:传感器对象在 try 块外创建,如果构造失败(找不到文件),会立即被捕获
// IioSensor sensor(iio_device_path, iio_channel_name);
// while (true) {
// try {
// // 封装后的调用方式非常简洁!
// // 每次调用 readVoltage内部都会重新打开文件读取一次
// double actual_voltage = sensor.readVoltage(adc_reference_voltage, adc_resolution, signal_gain);
// // 输出结果
// std::cout << "Actual Voltage: " << actual_voltage << " V" << std::endl;
// } catch (const IioSensorError& e) {
// // 如果单次读取失败(例如文件内容格式错误、无权限等),打印错误但继续循环
// std::cerr << "[!] Read Error: " << e.what() << std::endl;
// }
2025-10-21 15:34:24 +08:00
2025-10-21 18:35:53 +08:00
// // 每秒钟读取一次
// std::this_thread::sleep_for(std::chrono::seconds(1));
// }
// return 0;
2025-10-23 09:36:06 +08:00
// }
// 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 "alert/alarm_manager.h" // <-- 添加报警管理器头文件
#include <boost/asio.hpp>
#include <boost/asio/steady_timer.hpp>
#include <csignal>
#include <iostream>
#include <functional>
#include <nlohmann/json.hpp> // 用于解析data_json
// 用于 ASIO 服务的全局 io_context
boost::asio::io_context g_io_context;
// !!! 你提供的 UnifiedData 结构确认 !!!
struct UnifiedData {
std::string device_id; // 产生数据的设备唯一ID
int64_t timestamp_ms; // 数据产生的时间戳 (毫秒级UTC)
std::string data_json; // 采用JSON字符串格式具有良好的灵活性和可扩展性
};
/**
* @brief MQTT
*/
void poll_system_metrics(
boost::asio::steady_timer& timer,
SystemMonitor::SystemMonitor& monitor,
MqttClient& mqtt_client,
AlarmManager& alarm_manager // <-- 传递 alarm_manager
) {
if (g_io_context.stopped()) return;
auto cpu_util = monitor.getCpuUtilization();
auto mem_info = monitor.getMemoryInfo();
double mem_total_gb = mem_info.total_kb / 1024.0 / 1024.0;
double mem_free_gb = mem_info.free_kb / 1024.0 / 1024.0;
double mem_usage_percentage = (mem_total_gb - mem_free_gb) / mem_total_gb * 100.0;
std::string topic = "proxy/system_status";
nlohmann::json system_status_json;
system_status_json["device_id"] = "proxy_system"; // 统一一个设备ID用于报警
system_status_json["timestamp_ms"] = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
).count();
system_status_json["cpu_usage"] = cpu_util.totalUsagePercentage;
system_status_json["mem_total_gb"] = mem_total_gb;
system_status_json["mem_usage_percentage"] = mem_usage_percentage;
std::string payload = system_status_json.dump();
mqtt_client.publish(topic, payload);
spdlog::debug("System metrics published.");
// !!! 对系统指标进行报警检查 !!!
alarm_manager.check_data_for_alarms("proxy_system", system_status_json);
timer.expires_at(timer.expiry() + std::chrono::seconds(15));
timer.async_wait(std::bind(poll_system_metrics, std::ref(timer), std::ref(monitor), std::ref(mqtt_client), std::ref(alarm_manager)));
}
int main(int argc, char* argv[]) {
try {
spdlog::set_level(spdlog::level::debug);
spdlog::info("Edge Proxy starting up...");
} catch (const spdlog::spdlog_ex& ex) {
std::cerr << "Log initialization failed: " << ex.what() << std::endl;
return 1;
}
spdlog::info("Initializing Data Storage...");
if (!DataStorage::getInstance().initialize("edge_proxy_data.db")) {
spdlog::critical("Failed to initialize DataStorage. Exiting.");
return 1;
}
try {
DataCache data_cache;
LiveDataCache live_data_cache;
MqttClient mqtt_client("tcp://localhost:1883", "edge-proxy-main-client");
// --- 报警管理器初始化 ---
AlarmManager alarm_manager;
// 加载报警规则
if (!alarm_manager.load_rules("../config/alarms.json")) {
spdlog::critical("Failed to load alarm rules. Exiting.");
return 1;
}
// 注册报警回调函数:当报警触发时,通过 MQTT 发布报警消息
alarm_manager.register_alarm_callback([&](const AlarmEvent& event) {
std::string alarm_topic = "alerts/device/" + event.device_id + "/" + AlarmManager::alarm_level_to_string(event.level);
nlohmann::json alarm_payload;
alarm_payload["event_id"] = event.event_id;
alarm_payload["rule_id"] = event.rule_id;
alarm_payload["device_id"] = event.device_id;
alarm_payload["data_point_name"] = event.data_point_name;
alarm_payload["current_value"] = event.current_value;
alarm_payload["threshold"] = event.threshold;
alarm_payload["level"] = AlarmManager::alarm_level_to_string(event.level);
alarm_payload["timestamp"] = event.timestamp;
alarm_payload["message"] = event.message;
// 使用 g_io_context.post 将 MQTT 发布操作调度到主线程,避免在回调中直接阻塞
g_io_context.post([&, alarm_topic, payload_str = alarm_payload.dump()]() {
mqtt_client.publish(alarm_topic, payload_str, 1, false); // QoS 1, 不保留
});
spdlog::info("Published alarm: TOPIC={} PAYLOAD={}", alarm_topic, alarm_payload.dump());
});
// --- 报警管理器初始化结束 ---
auto report_to_mqtt = [&](const UnifiedData& data) {
// 使用 DataStorage 单例存储处理后的 UnifiedData 对象
if (DataStorage::getInstance().storeProcessedData(data)) {
spdlog::debug("Successfully stored PROCESSED data for device '{}'", data.device_id);
} else {
spdlog::error("Failed to store PROCESSED data for device '{}'", data.device_id);
}
// 更新实时数据缓存
live_data_cache.update_data(data.device_id, data.data_json);
// !!! 新增:进行数据比较和报警检查 !!!
try {
// 将 UnifiedData::data_json (string) 解析为 nlohmann::json 对象
// 这假设 data.data_json 总是有效的 JSON
nlohmann::json parsed_data_json = nlohmann::json::parse(data.data_json);
alarm_manager.check_data_for_alarms(data.device_id, parsed_data_json);
} catch (const nlohmann::json::exception& e) {
spdlog::error("Failed to parse data_json for alarm checking for device '{}': {}", data.device_id, e.what());
}
if (mqtt_client.is_connected()) {
// 网络正常,直接上报
std::string topic = "devices/" + data.device_id + "/data";
g_io_context.post([&, topic, payload = data.data_json]() {
mqtt_client.publish(topic, payload, 1, false);
});
} else {
// 网络断开,写入缓存
spdlog::warn("MQTT disconnected. Caching data for device '{}'.", data.device_id);
data_cache.add(data);
}
};
DeviceManager device_manager(g_io_context, report_to_mqtt);
MqttRouter mqtt_router(mqtt_client, device_manager);
std::vector<uint16_t> listen_ports = { 12345 };
TCPServer tcp_server(g_io_context, listen_ports, mqtt_client);
SystemMonitor::SystemMonitor monitor;
if (!data_cache.open("edge_data_cache.db")) {
spdlog::critical("Failed to initialize data cache. Exiting.");
return 1;
}
CacheUploader cache_uploader(g_io_context, mqtt_client, data_cache);
mqtt_client.set_connected_handler([&](const std::string& cause){
spdlog::info("MQTT client connected: {}", cause);
cache_uploader.start_upload();
});
mqtt_client.connect();
mqtt_router.start();
monitor.getCpuUtilization();
boost::asio::steady_timer system_monitor_timer(g_io_context, std::chrono::seconds(15));
// 将 alarm_manager 传递给 poll_system_metrics
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_manager)));
device_manager.load_and_start("../config/devices.json");
WebServer web_server(monitor, device_manager, live_data_cache, 8080);
web_server.start();
boost::asio::signal_set signals(g_io_context, SIGINT, SIGTERM);
signals.async_wait([&](const boost::system::error_code& error, int signal_number) {
spdlog::warn("Interrupt signal ({}) received. Shutting down.", signal_number);
// a. 首先停止所有数据采集线程
spdlog::info("[Shutdown] A. Stopping device manager services...");
device_manager.stop_all();
// b. 停止Web服务器线程
spdlog::info("[Shutdown] B. Stopping web server...");
web_server.stop();
// c. 断开MQTT连接 (这将释放它对io_context的'劫持')
spdlog::info("[Shutdown] C. Disconnecting from MQTT broker...");
mqtt_client.disconnect();
// d. 最后安全地停止io_context
spdlog::info("[Shutdown] D. Stopping main event loop...");
g_io_context.stop();
});
spdlog::info("All services are running. Press Ctrl+C to exit.");
g_io_context.run();
} catch (const std::exception& e) {
spdlog::critical("An unhandled exception occurred: {}", e.what());
return 1;
}
spdlog::info("Server has been shut down gracefully. Exiting.");
return 0;
}