// #include "tts/piper_tts_interface.h" // #include // #include // 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; // } // #include // #include // #include // #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 通道 // 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; // // 注意:传感器对象在 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; // } // // 每秒钟读取一次 // std::this_thread::sleep_for(std::chrono::seconds(1)); // } // return 0; // } // 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 #include #include #include #include #include // 用于解析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::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 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; }