From a0caa24dead5e96112260f42c8d88e85fe5cec64 Mon Sep 17 00:00:00 2001 From: lzq Date: Tue, 8 Jul 2025 15:49:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 2 + config/config.json | 41 +++++++++++----- src/application.cpp | 28 ++++++++++- src/application.h | 2 + src/barrier/generic_barrier.cpp | 49 ++++++++++++++++--- src/http/http_svr.h | 12 +++++ src/mqtt/mqtt_cli.cpp | 35 +++++++++++-- src/mqtt/mqtt_cli.h | 8 ++- src/oss/oss.cpp | 4 +- src/platform_scale/generic_platform_scale.cpp | 2 +- src/platform_scale/generic_platform_scale.h | 1 + .../platform_scale_properties.h | 2 + src/report_svr/report_svr.cpp | 10 +++- src/sound_column/generic_sound_column.cpp | 22 +++++++-- src/sound_column/generic_sound_column.h | 12 +++++ src/sound_column/sound_column.h | 27 +++++----- 16 files changed, 207 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1abbc36..7a0f80e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ find_package(HCNet CONFIG REQUIRED) find_package(ICU REQUIRED COMPONENTS uc) find_path(CPP_HTTPLIB_INCLUDE_DIRS "httplib.h") # 使用时要先于 windows.h 包含 find_path(CPPCODEC_INCLUDE_DIRS "cppcodec/base32_crockford.hpp") +#find_library(WS2_32_LIB NAMES ws2_32) set(SOURCE_DIRS src/common src/vidicon @@ -43,6 +44,7 @@ set(LINK_DIRS src ) set(LIBRARIES +# ${WS2_32_LIB} openssl::libssl openssl::libcrypto mqtt_cpp_iface::mqtt_cpp_iface diff --git a/config/config.json b/config/config.json index 3c398b5..dd28729 100644 --- a/config/config.json +++ b/config/config.json @@ -27,7 +27,7 @@ { "sn": "remote", "name": "远程", - "server": "127.0.0.1", + "server": "47.117.76.168", "port": 1883, "clientId": "yztq", "username": "dcs", @@ -45,7 +45,7 @@ } ], "reportSvr": { - "server": "http://127.0.0.1:8080", + "server": "https://biz-api.jstqhj.cn:443", "passUrl": "/api/site/report-car-pass?debug=1", "reportUrl": "/api/site/report-v2?debug=1" }, @@ -53,6 +53,7 @@ { "name": "进前置", "sn": "b11ceeb5-af42d80f", + "ip": "192.168.120.240", "io": 0, "platformScale": "1", "soundColumn": "1", @@ -61,32 +62,36 @@ { "name": "进", "sn": "25ec7559-74125e77", + "ip": "192.168.120.235", "io": 0, "platformScale": "1", - "soundColumn": "1", + "soundColumn": "2", "vidicon": "1" }, { "name": "出前置", "sn": "351b2406-6fae5ab5", + "ip": "192.168.120.243", "io": 0, "platformScale": "1", - "soundColumn": "1", - "vidicon": "1" + "soundColumn": "2", + "vidicon": "2" }, { "name": "出", "sn": "34fc9ce5-8b091060", + "ip": "192.168.120.238", "io": 0, "platformScale": "1", "soundColumn": "1", - "vidicon": "1" + "vidicon": "2" } ], "platformScales": [ { "sn": "1", "name": "地磅", + "sample": 20, "port": "COM2", "baudRate": 1200, "byteSize": 8, @@ -97,19 +102,33 @@ "soundColumns": [ { "sn": "1", - "name": "音柱", - "server": "http://localhost:8080", + "name": "音柱1", + "server": "http://192.168.120.246:80", + "path": "/v1/speech" + }, + { + "sn": "2", + "name": "音柱2", + "server": "http://192.168.120.237:80", "path": "/v1/speech" } ], "vidicons": [ { "sn": "1", - "name": "摄像头", - "ip": "192.168.2.64", + "name": "摄像头1", + "ip": "192.168.120.245", "port": 8000, "username": "admin", - "passwd": "Zsy8899." + "passwd": "gk147258" + }, + { + "sn": "2", + "name": "摄像头2", + "ip": "192.168.120.244", + "port": 8000, + "username": "admin", + "passwd": "gk147258" } ] } \ No newline at end of file diff --git a/src/application.cpp b/src/application.cpp index 0be04d6..699a6b7 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -42,8 +42,35 @@ namespace zsy } } + void Application::removePid() + { + std::regex pattern(R"(deviceAccessLayer_\d+\.txt)"); + + std::filesystem::path path = std::filesystem::path(pidFilePath); + + try + { + for (const auto &entry: std::filesystem::directory_iterator(path)) + { + std::string filename = entry.path().filename().string(); + if (std::regex_match(filename, pattern)) + { + std::filesystem::remove(entry.path()); + LOGGER_INFO("PID 文件删除成功:{}", entry.path().string()); + } + } + } catch (const std::exception &e) + { + LOGGER_ERROR("PID 文件删除失败:{}", e.what()); + }catch (...) + { + LOGGER_ERROR("未知异常,PID 文件删除失败"); + } + } + void Application::writePid() { + removePid(); try { pid = std::to_string(GetCurrentProcessId()); @@ -54,7 +81,6 @@ namespace zsy { LOGGER_ERROR("无法打开文件:{}", pidFile); } - outFile << pid; outFile.close(); } catch (const std::exception &e) diff --git a/src/application.h b/src/application.h index 0d82b79..9332e42 100644 --- a/src/application.h +++ b/src/application.h @@ -20,6 +20,8 @@ namespace zsy void loadConfig(); + void removePid(); + void writePid(); public: diff --git a/src/barrier/generic_barrier.cpp b/src/barrier/generic_barrier.cpp index 48617f2..682027c 100644 --- a/src/barrier/generic_barrier.cpp +++ b/src/barrier/generic_barrier.cpp @@ -46,10 +46,32 @@ namespace zsy LOGGER_ERROR("未找到 MQTT 远程客户端"); } + Application::httpSvr->getEndpoint("/data", [](const httplib::Request &req, httplib::Response &res) + { + nlohmann::json j; + try + { + // double weight = Application::deviceHolder->getPlatformScale("b11ceeb5-af42d80f")->reading(); + // j["地磅读数"] = weight; + // Application::deviceHolder->getSoundColumn( "b11ceeb5-af42d80f")->play("欢迎光临"); + // auto reportPassResult = Application::reportSvr->reportPass("苏K85076", "b11ceeb5-af42d80f", ""); + } catch (std::exception &e) + { + LOGGER_ERROR("错误", e.what()); + j["错误"] = ""; + } + catch (...) + { + LOGGER_ERROR("错误"); + j["错误"] = ""; + } + res.set_content(j.dump(), "application/json"); + }); + Application::httpSvr->postEndpoint("/plateRecognize", [](const httplib::Request &req, httplib::Response &res) { - static std::unordered_map cache; - static std::mutex cacheMutex; + // static std::unordered_map cache; + // static std::mutex cacheMutex; try { auto body = req.body; @@ -73,11 +95,11 @@ namespace zsy } if (license.find("无") != std::string::npos) { - LOGGER_ERROR("车牌识别失败"); + LOGGER_WARN("车牌识别失败"); res.set_content(R"({})", "application/json"); return; } - auto ms = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); + /*auto ms = std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); auto key = serialno + license; long long time = ms + 60000 * 5; { @@ -96,7 +118,7 @@ namespace zsy } } cache[key] = ms; - } + }*/ Application::threadPool->submit([imageFile,license, barrier = Application::deviceHolder->getBarrier(serialno)] { @@ -182,11 +204,14 @@ namespace zsy { LOGGER_INFO("车牌识别结果处理中,设备名称:{}", config.name); // 播放语音 1 - Application::threadPool->submit([sn = config.sn] + /*Application::threadPool->submit([sn = config.sn] + { + Application::deviceHolder->getSoundColumn(sn)->play("欢迎光临"); + });*/ + std::thread t1([sn = config.sn] { Application::deviceHolder->getSoundColumn(sn)->play("欢迎光临"); }); - // 上传车头照 auto imageFileDecode = SysUtil::base64_decode(imageFile); const std::shared_ptr imageFileStream = std::make_shared(imageFileDecode, std::ios_base::in | std::ios_base::binary); @@ -205,10 +230,16 @@ namespace zsy auto reportPassResult = Application::reportSvr->reportPass(license, config.sn, carFrontUrl); if (!(reportPassResult.code == 0 && (reportPassResult.data.type == 1 || reportPassResult.data.type == 2))) { + LOGGER_INFO("不处理:{}", config.name); + t1.join(); return; } // 上报结果不为 0,播放语音 2 并读地磅,拍车斗并上传 - Application::threadPool->submit([sn =config.sn] + /*Application::threadPool->submit([sn =config.sn] + { + Application::deviceHolder->getSoundColumn(sn)->play("正在称重,请稍后"); + });*/ + std::thread t2([sn = config.sn] { Application::deviceHolder->getSoundColumn(sn)->play("正在称重,请稍后"); }); @@ -230,6 +261,8 @@ namespace zsy // 上报 2 Application::reportSvr->report(license, config.sn, weight, carFrontUrl, carBodyUrl, reportPassResult.data.orderNo); + t1.join(); + t2.join(); } catch (std::exception &e) { LOGGER_ERROR("车牌识别结果处理失败: {}", e.what()); diff --git a/src/http/http_svr.h b/src/http/http_svr.h index 0e6152c..f49814a 100644 --- a/src/http/http_svr.h +++ b/src/http/http_svr.h @@ -41,6 +41,18 @@ namespace zsy svr->Post(std::move(path), std::forward(handler)); } + template + void getEndpoint(std::string path, Func &&handler) + { + std::shared_lock lock(status_mtx); + if (status == 0) + { + LOGGER_ERROR("HTTP 服务不可用"); + return; + } + svr->Get(path, std::forward(handler)); + } + ~HttpSvr(); }; } // zsy diff --git a/src/mqtt/mqtt_cli.cpp b/src/mqtt/mqtt_cli.cpp index 9037d2f..1723fcc 100644 --- a/src/mqtt/mqtt_cli.cpp +++ b/src/mqtt/mqtt_cli.cpp @@ -9,13 +9,11 @@ namespace zsy const std::string MqttCli::TYPE_REMOTE = "remote"; const std::string MqttCli::TYPE_LOCAL = "local"; - MqttCli::MqttCli(MqttProperties &config, std::shared_ptr eventManager) - : status(0), - config(config), - eventManager(eventManager) + void MqttCli::connect() { try { + LOGGER_ERROR("MQTT:{} 正在连接...", config.clientId); ioc = std::make_shared(); cli = MQTT_NS::make_sync_client(*ioc, config.server, config.port); cli->set_client_id(config.clientId); @@ -49,11 +47,34 @@ namespace zsy } } + MqttCli::MqttCli(MqttProperties &config, std::shared_ptr eventManager) + : status(0), + config(config), + eventManager(eventManager) + { + connect(); + } + + void MqttCli::reconnect() + { + do + { + std::unique_lock lock(status_mtx); + if (status == 2) break; + mqtt::error_code ec; + cli->connect(ec); + if (!ec) break; + + LOGGER_INFO("MQTT 10 秒后重新连接:{},{}", config.clientId, SysUtil::str_w_a(SysUtil::str_a_w( ec.message(),"GBK" ))); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } while (true); + } + void MqttCli::run() { try { - cli->connect(); + reconnect(); ioc->run(); } catch (std::exception &e) { @@ -102,6 +123,7 @@ namespace zsy std::unique_lock lock(status_mtx); status = 0; LOGGER_INFO("MQTT 连接已关闭:{}", config.clientId); + reconnect(); } void MqttCli::onError(mqtt::error_code ec) @@ -109,6 +131,7 @@ namespace zsy std::unique_lock lock(status_mtx); status = 0; LOGGER_INFO("MQTT 错误:{} {}", config.clientId, ec.message()); + reconnect(); } bool MqttCli::onMessage(mqtt::optional packet_id, mqtt::publish_options pubopts, mqtt::buffer topic_, mqtt::buffer payload_) @@ -138,6 +161,8 @@ namespace zsy MqttCli::~MqttCli() { + std::unique_lock lock(status_mtx); + status = 2; cli->disconnect(); ioc->stop(); } diff --git a/src/mqtt/mqtt_cli.h b/src/mqtt/mqtt_cli.h index b6eef9a..2c0ef52 100644 --- a/src/mqtt/mqtt_cli.h +++ b/src/mqtt/mqtt_cli.h @@ -22,13 +22,15 @@ namespace zsy using CLI_PTR = std::shared_ptr; using packet_id_t = CLI::packet_id_t; MqttProperties config; - // 0-->不可用、1-->可用 + // 0-->不可用、1-->可用、2-->已停止 uint8_t status; std::shared_mutex status_mtx; std::shared_ptr eventManager; std::unique_ptr eventLoop; - CLI_PTR cli; std::shared_ptr ioc; + CLI_PTR cli; + + void connect(); void run(); @@ -40,6 +42,8 @@ namespace zsy bool onMessage(MQTT_NS::optional packet_id, MQTT_NS::publish_options pubopts, MQTT_NS::buffer topic_,MQTT_NS::buffer payload_); + void reconnect(); + public: static const std::string TYPE_REMOTE; static const std::string TYPE_LOCAL; diff --git a/src/oss/oss.cpp b/src/oss/oss.cpp index 5ba27a0..aa3697d 100644 --- a/src/oss/oss.cpp +++ b/src/oss/oss.cpp @@ -34,7 +34,9 @@ namespace zsy // 构建请求 httplib::Client cli(config.bucketName + "." + config.endpoint); - + cli.set_connection_timeout(5); + cli.set_read_timeout(10); + cli.set_write_timeout(10); // 设置请求头 httplib::Headers headers = { {"Date", date}, diff --git a/src/platform_scale/generic_platform_scale.cpp b/src/platform_scale/generic_platform_scale.cpp index 55d976b..3fe09c6 100644 --- a/src/platform_scale/generic_platform_scale.cpp +++ b/src/platform_scale/generic_platform_scale.cpp @@ -103,7 +103,7 @@ namespace zsy std::this_thread::sleep_for(std::chrono::milliseconds(1000)); auto processor = static_cast(serialPort->processor); int count = 0; - while (processor->steady.load() < 20) + while (processor->steady.load() < config.sample) { count++; if (count >= 10) diff --git a/src/platform_scale/generic_platform_scale.h b/src/platform_scale/generic_platform_scale.h index e372955..d594384 100644 --- a/src/platform_scale/generic_platform_scale.h +++ b/src/platform_scale/generic_platform_scale.h @@ -12,6 +12,7 @@ namespace zsy { public: std::atomic steady; + std::atomic weight; GenericPlatformScaleProcessor(); diff --git a/src/platform_scale/platform_scale_properties.h b/src/platform_scale/platform_scale_properties.h index 19fc727..3888783 100644 --- a/src/platform_scale/platform_scale_properties.h +++ b/src/platform_scale/platform_scale_properties.h @@ -8,6 +8,7 @@ namespace zsy { std::string sn; std::string name; + uint8_t sample; std::string port; uint32_t baudRate{9600}; uint8_t byteSize{8}; @@ -19,6 +20,7 @@ namespace zsy { PARSE_JSON(sn, o.sn); PARSE_JSON(name, o.name); + PARSE_JSON(sample, o.sample); PARSE_JSON(port, o.port); PARSE_JSON(baudRate, o.baudRate); PARSE_JSON(byteSize, o.byteSize); diff --git a/src/report_svr/report_svr.cpp b/src/report_svr/report_svr.cpp index 795a253..76325ea 100644 --- a/src/report_svr/report_svr.cpp +++ b/src/report_svr/report_svr.cpp @@ -31,6 +31,9 @@ namespace zsy LOGGER_INFO("上报数据:{}{} {}", config.server, config.passUrl, body); httplib::Client cli(config.server); + cli.set_connection_timeout(5); + cli.set_read_timeout(10); + cli.set_write_timeout(10); auto response = cli.Post(config.passUrl.c_str(), headers, body, "application/json"); if (response) { @@ -87,10 +90,13 @@ namespace zsy auto body = data.dump(); - LOGGER_INFO("上报数据:{}{} {}", config.server, config.passUrl, body); + LOGGER_INFO("上报数据:{}{} {}", config.server, config.reportUrl, body); httplib::Client cli(config.server); - auto response = cli.Post(config.passUrl.c_str(), headers, body, "application/json"); + cli.set_connection_timeout(5); + cli.set_read_timeout(10); + cli.set_write_timeout(10); + auto response = cli.Post(config.reportUrl.c_str(), headers, body, "application/json"); if (response) { LOGGER_INFO("上报结果:{}", response->body); diff --git a/src/sound_column/generic_sound_column.cpp b/src/sound_column/generic_sound_column.cpp index 4993be7..bde48d1 100644 --- a/src/sound_column/generic_sound_column.cpp +++ b/src/sound_column/generic_sound_column.cpp @@ -7,7 +7,7 @@ namespace zsy { GenericSoundColumn::GenericSoundColumn(const SoundColumnProperties &config): config(config) { - Application::eventManager->subscribe(config.sn + "/play", [this](const EventManager::Event & event) + Application::eventManager->subscribe(config.sn + "/play", [this](const EventManager::Event &event) { if (!event.data.has_value()) return; auto jsonData = event.data.value(); @@ -22,7 +22,7 @@ namespace zsy auto clientId = cli->getClientId(); if (cli) { - Application::eventManager->subscribe(clientId + "/yztq/1/voice", [](const EventManager::Event & event) + Application::eventManager->subscribe(clientId + "/yztq/1/voice", [](const EventManager::Event &event) { if (!event.data.has_value()) { @@ -63,9 +63,9 @@ namespace zsy }; nlohmann::json data{ - {"loop", {{"times", 1}}}, + {"loop", {{"times", 2}, {"gap", 2}}}, {"prompt", true}, - {"queue", false}, + {"queue", true}, {"rcn", "0"}, {"rdn", "0"}, {"reg", 0}, @@ -79,6 +79,10 @@ namespace zsy LOGGER_INFO("播放语音:{}{} {}", config.server, config.path, body); httplib::Client cli(config.server); + cli.set_connection_timeout(5); + cli.set_read_timeout(10); + cli.set_write_timeout(10); + auto response = cli.Post(config.path.c_str(), headers, body, "application/json"); if (response) @@ -90,7 +94,15 @@ namespace zsy LOGGER_ERROR("语音播放失败,HTTP状态码:{}", status); } else { - LOGGER_INFO("语音播放成功"); + auto json = nlohmann::json::parse(response->body); + auto result = json.get(); + if (result.code == 200) + { + LOGGER_INFO("语音播放成功"); + } else + { + LOGGER_ERROR("语音播放失败,错误:{}", result.message); + } } } else { diff --git a/src/sound_column/generic_sound_column.h b/src/sound_column/generic_sound_column.h index 3514671..fb13871 100644 --- a/src/sound_column/generic_sound_column.h +++ b/src/sound_column/generic_sound_column.h @@ -5,6 +5,18 @@ namespace zsy { + struct PlaySoundColumnResult + { + int code; + std::string message; + }; + + inline void from_json(const nlohmann::json &j, PlaySoundColumnResult &o) + { + PARSE_JSON(code, o.code); + PARSE_JSON(message, o.message); + } + class GenericSoundColumn final : public SoundColumn { SoundColumnProperties config; diff --git a/src/sound_column/sound_column.h b/src/sound_column/sound_column.h index 624e8f4..63e6f78 100644 --- a/src/sound_column/sound_column.h +++ b/src/sound_column/sound_column.h @@ -34,22 +34,21 @@ namespace zsy static std::string convert(const std::string &numberStr) { - static const std::vector digits = {"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"}; - std::string chineseStr; - for (char c: numberStr) - { - if ('0' <= c && c <= '9') - { - chineseStr += digits[c - '0']; - } else if (c == '.') - { - chineseStr += '点'; - } else - { - chineseStr += c; + static const std::unordered_map digitMap = { + {'0', "零"}, {'1', "一"}, {'2', "二"}, {'3', "三"}, {'4', "四"}, + {'5', "五"}, {'6', "六"}, {'7', "七"}, {'8', "八"}, {'9', "九"}, + {'.', "点"} + }; + + std::string result; + for (char c : numberStr) { + if (digitMap.contains(c)) { + result += digitMap.at(c); + } else { + result += c; } } - return chineseStr; + return result; } }; } // zsy