diff --git a/include/app_config.hpp b/include/app_config.hpp index 5a041e2..ecc44ef 100644 --- a/include/app_config.hpp +++ b/include/app_config.hpp @@ -76,6 +76,9 @@ struct AppConfig std::vector cameras; MQTTConfig mqtt; + // ⭐ 运行期从 orin 获取的 VID(优先生效) + std::string runtime_vid; + static AppConfig load_from_file(const std::string& filepath) { AppConfig cfg; diff --git a/src/mqtt_client_wrapper.cpp b/src/mqtt_client_wrapper.cpp index 7792c86..0622a91 100644 --- a/src/mqtt_client_wrapper.cpp +++ b/src/mqtt_client_wrapper.cpp @@ -19,6 +19,30 @@ std::atomic g_streaming{false}; std::string g_dispatch_id; std::mutex g_dispatch_id_mutex; +static std::atomic g_mqtt_activated{false}; +static std::string g_last_vid; + +static bool try_activate_mqtt() +{ + if (g_app_config.runtime_vid.empty()) return false; + + if (g_mqtt_activated.load() && g_last_vid == g_app_config.runtime_vid) return true; + + // VID 首次 or 发生变化 + g_app_config.mqtt.topics.fill_with_veh_id(g_app_config.runtime_vid); + g_last_vid = g_app_config.runtime_vid; + + LOG_INFO("[MQTT] Activated with VID=" + g_last_vid); + + mqtt_client->subscribe(g_app_config.mqtt.topics.video_down); + mqtt_client->subscribe(g_app_config.mqtt.topics.record_query); + mqtt_client->subscribe(g_app_config.mqtt.topics.record_play); + mqtt_client->subscribe(g_app_config.mqtt.topics.vehicle_ctrl); + + g_mqtt_activated.store(true); + return true; +} + static void send_heartbeat() { if (!mqtt_client || !mqtt_client->isConnected()) return; @@ -69,10 +93,7 @@ static void send_heartbeat() static void on_mqtt_connected() { LOG_INFO("[MQTT] Connected to broker: " + g_app_config.mqtt.server_ip); - mqtt_client->subscribe(g_app_config.mqtt.topics.video_down); - mqtt_client->subscribe(g_app_config.mqtt.topics.record_query); - mqtt_client->subscribe(g_app_config.mqtt.topics.record_play); - mqtt_client->subscribe(g_app_config.mqtt.topics.vehicle_ctrl); + g_mqtt_activated.store(false); // 重连后需要重新激活 } static void on_mqtt_disconnected() { LOG_WARN("[MQTT] Disconnected from broker: " + g_app_config.mqtt.server_ip); } @@ -363,8 +384,12 @@ void mqtt_client_thread_func() // 主循环:心跳 while (g_running && mqtt_client->isConnected()) { - send_heartbeat(); + try_activate_mqtt(); // VID 到来时触发订阅 + if (g_mqtt_activated.load()) + { + send_heartbeat(); + } auto sleep_time = heartbeat_interval; while (sleep_time.count() > 0 && g_running && mqtt_client->isConnected()) { diff --git a/src/serial_AT.cpp b/src/serial_AT.cpp index 13e68e4..3248d92 100644 --- a/src/serial_AT.cpp +++ b/src/serial_AT.cpp @@ -54,11 +54,9 @@ void start_http_server(int port) http_server->Post("/api/v1/device/register", [](const httplib::Request& req, httplib::Response& res) { - LOG_INFO("[http] /device/register called"); - - // 解析 A 的信息(可选,先简单点) - LOG_INFO("[http] payload: " + req.body); + LOG_INFO("[http] /api/v1/device/register called"); + // ---------- 1. IMEI 是否就绪 ---------- if (!is_imei_ready()) { res.status = 503; @@ -66,13 +64,46 @@ void start_http_server(int port) return; } + // ---------- 2. 解析请求体(尝试获取 VID) ---------- + std::string vid; + if (!req.body.empty()) + { + try + { + auto jreq = nlohmann::json::parse(req.body); + if (jreq.contains("vid") && jreq["vid"].is_string()) + { + vid = jreq["vid"].get(); + LOG_INFO("[http] register vid = " + vid); + + // ⭐ 运行期 VID:只记录,不判断 + g_app_config.runtime_vid = vid; + } + } + catch (const std::exception& e) + { + LOG_WARN(std::string("[http] invalid json payload: ") + e.what()); + } + } + else + { + LOG_WARN("[http] empty register payload"); + } + + // ---------- 3. 返回 B 的身份 ---------- std::string imei = get_imei(); - nlohmann::json j; - j["ok"] = true; - j["server"] = {{"device_type", "tbox"}, {"imei", imei}, {"fw", "b-v2.1.0"}}; + nlohmann::json jres; + jres["ok"] = true; + jres["server"] = {{"device_type", "neardi"}, {"imei", imei}, {"fw", "b-v2.1.0"}}; - res.set_content(j.dump(-1), "application/json"); + // 可选:把 vid 回显(方便 A / 调试) + if (!vid.empty()) + { + jres["peer"] = {{"vid", vid}}; + } + + res.set_content(jres.dump(), "application/json"); }); http_thread = std::thread(