修复问题

master
lzq 2025-07-08 15:49:12 +08:00
parent e7cb901478
commit a0caa24dea
16 changed files with 207 additions and 50 deletions

View File

@ -19,6 +19,7 @@ find_package(HCNet CONFIG REQUIRED)
find_package(ICU REQUIRED COMPONENTS uc) find_package(ICU REQUIRED COMPONENTS uc)
find_path(CPP_HTTPLIB_INCLUDE_DIRS "httplib.h") # 使 windows.h find_path(CPP_HTTPLIB_INCLUDE_DIRS "httplib.h") # 使 windows.h
find_path(CPPCODEC_INCLUDE_DIRS "cppcodec/base32_crockford.hpp") find_path(CPPCODEC_INCLUDE_DIRS "cppcodec/base32_crockford.hpp")
#find_library(WS2_32_LIB NAMES ws2_32)
set(SOURCE_DIRS set(SOURCE_DIRS
src/common src/common
src/vidicon src/vidicon
@ -43,6 +44,7 @@ set(LINK_DIRS
src src
) )
set(LIBRARIES set(LIBRARIES
# ${WS2_32_LIB}
openssl::libssl openssl::libssl
openssl::libcrypto openssl::libcrypto
mqtt_cpp_iface::mqtt_cpp_iface mqtt_cpp_iface::mqtt_cpp_iface

View File

@ -27,7 +27,7 @@
{ {
"sn": "remote", "sn": "remote",
"name": "远程", "name": "远程",
"server": "127.0.0.1", "server": "47.117.76.168",
"port": 1883, "port": 1883,
"clientId": "yztq", "clientId": "yztq",
"username": "dcs", "username": "dcs",
@ -45,7 +45,7 @@
} }
], ],
"reportSvr": { "reportSvr": {
"server": "http://127.0.0.1:8080", "server": "https://biz-api.jstqhj.cn:443",
"passUrl": "/api/site/report-car-pass?debug=1", "passUrl": "/api/site/report-car-pass?debug=1",
"reportUrl": "/api/site/report-v2?debug=1" "reportUrl": "/api/site/report-v2?debug=1"
}, },
@ -53,6 +53,7 @@
{ {
"name": "进前置", "name": "进前置",
"sn": "b11ceeb5-af42d80f", "sn": "b11ceeb5-af42d80f",
"ip": "192.168.120.240",
"io": 0, "io": 0,
"platformScale": "1", "platformScale": "1",
"soundColumn": "1", "soundColumn": "1",
@ -61,32 +62,36 @@
{ {
"name": "进", "name": "进",
"sn": "25ec7559-74125e77", "sn": "25ec7559-74125e77",
"ip": "192.168.120.235",
"io": 0, "io": 0,
"platformScale": "1", "platformScale": "1",
"soundColumn": "1", "soundColumn": "2",
"vidicon": "1" "vidicon": "1"
}, },
{ {
"name": "出前置", "name": "出前置",
"sn": "351b2406-6fae5ab5", "sn": "351b2406-6fae5ab5",
"ip": "192.168.120.243",
"io": 0, "io": 0,
"platformScale": "1", "platformScale": "1",
"soundColumn": "1", "soundColumn": "2",
"vidicon": "1" "vidicon": "2"
}, },
{ {
"name": "出", "name": "出",
"sn": "34fc9ce5-8b091060", "sn": "34fc9ce5-8b091060",
"ip": "192.168.120.238",
"io": 0, "io": 0,
"platformScale": "1", "platformScale": "1",
"soundColumn": "1", "soundColumn": "1",
"vidicon": "1" "vidicon": "2"
} }
], ],
"platformScales": [ "platformScales": [
{ {
"sn": "1", "sn": "1",
"name": "地磅", "name": "地磅",
"sample": 20,
"port": "COM2", "port": "COM2",
"baudRate": 1200, "baudRate": 1200,
"byteSize": 8, "byteSize": 8,
@ -97,19 +102,33 @@
"soundColumns": [ "soundColumns": [
{ {
"sn": "1", "sn": "1",
"name": "音柱", "name": "音柱1",
"server": "http://localhost:8080", "server": "http://192.168.120.246:80",
"path": "/v1/speech"
},
{
"sn": "2",
"name": "音柱2",
"server": "http://192.168.120.237:80",
"path": "/v1/speech" "path": "/v1/speech"
} }
], ],
"vidicons": [ "vidicons": [
{ {
"sn": "1", "sn": "1",
"name": "摄像头", "name": "摄像头1",
"ip": "192.168.2.64", "ip": "192.168.120.245",
"port": 8000, "port": 8000,
"username": "admin", "username": "admin",
"passwd": "Zsy8899." "passwd": "gk147258"
},
{
"sn": "2",
"name": "摄像头2",
"ip": "192.168.120.244",
"port": 8000,
"username": "admin",
"passwd": "gk147258"
} }
] ]
} }

View File

@ -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() void Application::writePid()
{ {
removePid();
try try
{ {
pid = std::to_string(GetCurrentProcessId()); pid = std::to_string(GetCurrentProcessId());
@ -54,7 +81,6 @@ namespace zsy
{ {
LOGGER_ERROR("无法打开文件:{}", pidFile); LOGGER_ERROR("无法打开文件:{}", pidFile);
} }
outFile << pid; outFile << pid;
outFile.close(); outFile.close();
} catch (const std::exception &e) } catch (const std::exception &e)

View File

@ -20,6 +20,8 @@ namespace zsy
void loadConfig(); void loadConfig();
void removePid();
void writePid(); void writePid();
public: public:

View File

@ -46,10 +46,32 @@ namespace zsy
LOGGER_ERROR("未找到 MQTT 远程客户端"); 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) Application::httpSvr->postEndpoint("/plateRecognize", [](const httplib::Request &req, httplib::Response &res)
{ {
static std::unordered_map<std::string, long long> cache; // static std::unordered_map<std::string, long long> cache;
static std::mutex cacheMutex; // static std::mutex cacheMutex;
try try
{ {
auto body = req.body; auto body = req.body;
@ -73,11 +95,11 @@ namespace zsy
} }
if (license.find("") != std::string::npos) if (license.find("") != std::string::npos)
{ {
LOGGER_ERROR("车牌识别失败"); LOGGER_WARN("车牌识别失败");
res.set_content(R"({})", "application/json"); res.set_content(R"({})", "application/json");
return; return;
} }
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count(); /*auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
auto key = serialno + license; auto key = serialno + license;
long long time = ms + 60000 * 5; long long time = ms + 60000 * 5;
{ {
@ -96,7 +118,7 @@ namespace zsy
} }
} }
cache[key] = ms; cache[key] = ms;
} }*/
Application::threadPool->submit([imageFile,license, barrier = Application::deviceHolder->getBarrier(serialno)] Application::threadPool->submit([imageFile,license, barrier = Application::deviceHolder->getBarrier(serialno)]
{ {
@ -182,11 +204,14 @@ namespace zsy
{ {
LOGGER_INFO("车牌识别结果处理中,设备名称:{}", config.name); LOGGER_INFO("车牌识别结果处理中,设备名称:{}", config.name);
// 播放语音 1 // 播放语音 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("欢迎光临"); Application::deviceHolder->getSoundColumn(sn)->play("欢迎光临");
}); });
// 上传车头照 // 上传车头照
auto imageFileDecode = SysUtil::base64_decode(imageFile); auto imageFileDecode = SysUtil::base64_decode(imageFile);
const std::shared_ptr<std::istream> imageFileStream = std::make_shared<std::istringstream>(imageFileDecode, std::ios_base::in | std::ios_base::binary); const std::shared_ptr<std::istream> imageFileStream = std::make_shared<std::istringstream>(imageFileDecode, std::ios_base::in | std::ios_base::binary);
@ -205,10 +230,16 @@ namespace zsy
auto reportPassResult = Application::reportSvr->reportPass(license, config.sn, carFrontUrl); auto reportPassResult = Application::reportSvr->reportPass(license, config.sn, carFrontUrl);
if (!(reportPassResult.code == 0 && (reportPassResult.data.type == 1 || reportPassResult.data.type == 2))) if (!(reportPassResult.code == 0 && (reportPassResult.data.type == 1 || reportPassResult.data.type == 2)))
{ {
LOGGER_INFO("不处理:{}", config.name);
t1.join();
return; return;
} }
// 上报结果不为 0播放语音 2 并读地磅,拍车斗并上传 // 上报结果不为 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("正在称重,请稍后"); Application::deviceHolder->getSoundColumn(sn)->play("正在称重,请稍后");
}); });
@ -230,6 +261,8 @@ namespace zsy
// 上报 2 // 上报 2
Application::reportSvr->report(license, config.sn, weight, carFrontUrl, carBodyUrl, reportPassResult.data.orderNo); Application::reportSvr->report(license, config.sn, weight, carFrontUrl, carBodyUrl, reportPassResult.data.orderNo);
t1.join();
t2.join();
} catch (std::exception &e) } catch (std::exception &e)
{ {
LOGGER_ERROR("车牌识别结果处理失败: {}", e.what()); LOGGER_ERROR("车牌识别结果处理失败: {}", e.what());

View File

@ -41,6 +41,18 @@ namespace zsy
svr->Post(std::move(path), std::forward<Func>(handler)); svr->Post(std::move(path), std::forward<Func>(handler));
} }
template<typename Func>
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<Func>(handler));
}
~HttpSvr(); ~HttpSvr();
}; };
} // zsy } // zsy

View File

@ -9,13 +9,11 @@ namespace zsy
const std::string MqttCli::TYPE_REMOTE = "remote"; const std::string MqttCli::TYPE_REMOTE = "remote";
const std::string MqttCli::TYPE_LOCAL = "local"; const std::string MqttCli::TYPE_LOCAL = "local";
MqttCli::MqttCli(MqttProperties &config, std::shared_ptr<EventManager> eventManager) void MqttCli::connect()
: status(0),
config(config),
eventManager(eventManager)
{ {
try try
{ {
LOGGER_ERROR("MQTT{} 正在连接...", config.clientId);
ioc = std::make_shared<boost::asio::io_context>(); ioc = std::make_shared<boost::asio::io_context>();
cli = MQTT_NS::make_sync_client(*ioc, config.server, config.port); cli = MQTT_NS::make_sync_client(*ioc, config.server, config.port);
cli->set_client_id(config.clientId); cli->set_client_id(config.clientId);
@ -49,11 +47,34 @@ namespace zsy
} }
} }
MqttCli::MqttCli(MqttProperties &config, std::shared_ptr<EventManager> 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() void MqttCli::run()
{ {
try try
{ {
cli->connect(); reconnect();
ioc->run(); ioc->run();
} catch (std::exception &e) } catch (std::exception &e)
{ {
@ -102,6 +123,7 @@ namespace zsy
std::unique_lock lock(status_mtx); std::unique_lock lock(status_mtx);
status = 0; status = 0;
LOGGER_INFO("MQTT 连接已关闭:{}", config.clientId); LOGGER_INFO("MQTT 连接已关闭:{}", config.clientId);
reconnect();
} }
void MqttCli::onError(mqtt::error_code ec) void MqttCli::onError(mqtt::error_code ec)
@ -109,6 +131,7 @@ namespace zsy
std::unique_lock lock(status_mtx); std::unique_lock lock(status_mtx);
status = 0; status = 0;
LOGGER_INFO("MQTT 错误:{} {}", config.clientId, ec.message()); LOGGER_INFO("MQTT 错误:{} {}", config.clientId, ec.message());
reconnect();
} }
bool MqttCli::onMessage(mqtt::optional<packet_id_t> packet_id, mqtt::publish_options pubopts, mqtt::buffer topic_, mqtt::buffer payload_) bool MqttCli::onMessage(mqtt::optional<packet_id_t> packet_id, mqtt::publish_options pubopts, mqtt::buffer topic_, mqtt::buffer payload_)
@ -138,6 +161,8 @@ namespace zsy
MqttCli::~MqttCli() MqttCli::~MqttCli()
{ {
std::unique_lock lock(status_mtx);
status = 2;
cli->disconnect(); cli->disconnect();
ioc->stop(); ioc->stop();
} }

View File

@ -22,13 +22,15 @@ namespace zsy
using CLI_PTR = std::shared_ptr<CLI>; using CLI_PTR = std::shared_ptr<CLI>;
using packet_id_t = CLI::packet_id_t; using packet_id_t = CLI::packet_id_t;
MqttProperties config; MqttProperties config;
// 0-->不可用、1-->可用 // 0-->不可用、1-->可用、2-->已停止
uint8_t status; uint8_t status;
std::shared_mutex status_mtx; std::shared_mutex status_mtx;
std::shared_ptr<EventManager> eventManager; std::shared_ptr<EventManager> eventManager;
std::unique_ptr<std::jthread> eventLoop; std::unique_ptr<std::jthread> eventLoop;
CLI_PTR cli;
std::shared_ptr<boost::asio::io_context> ioc; std::shared_ptr<boost::asio::io_context> ioc;
CLI_PTR cli;
void connect();
void run(); void run();
@ -40,6 +42,8 @@ namespace zsy
bool onMessage(MQTT_NS::optional<packet_id_t> packet_id, MQTT_NS::publish_options pubopts, MQTT_NS::buffer topic_,MQTT_NS::buffer payload_); bool onMessage(MQTT_NS::optional<packet_id_t> packet_id, MQTT_NS::publish_options pubopts, MQTT_NS::buffer topic_,MQTT_NS::buffer payload_);
void reconnect();
public: public:
static const std::string TYPE_REMOTE; static const std::string TYPE_REMOTE;
static const std::string TYPE_LOCAL; static const std::string TYPE_LOCAL;

View File

@ -34,7 +34,9 @@ namespace zsy
// 构建请求 // 构建请求
httplib::Client cli(config.bucketName + "." + config.endpoint); 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 = { httplib::Headers headers = {
{"Date", date}, {"Date", date},

View File

@ -103,7 +103,7 @@ namespace zsy
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); std::this_thread::sleep_for(std::chrono::milliseconds(1000));
auto processor = static_cast<GenericPlatformScaleProcessor *>(serialPort->processor); auto processor = static_cast<GenericPlatformScaleProcessor *>(serialPort->processor);
int count = 0; int count = 0;
while (processor->steady.load() < 20) while (processor->steady.load() < config.sample)
{ {
count++; count++;
if (count >= 10) if (count >= 10)

View File

@ -12,6 +12,7 @@ namespace zsy
{ {
public: public:
std::atomic<uint64_t> steady; std::atomic<uint64_t> steady;
std::atomic<double> weight; std::atomic<double> weight;
GenericPlatformScaleProcessor(); GenericPlatformScaleProcessor();

View File

@ -8,6 +8,7 @@ namespace zsy
{ {
std::string sn; std::string sn;
std::string name; std::string name;
uint8_t sample;
std::string port; std::string port;
uint32_t baudRate{9600}; uint32_t baudRate{9600};
uint8_t byteSize{8}; uint8_t byteSize{8};
@ -19,6 +20,7 @@ namespace zsy
{ {
PARSE_JSON(sn, o.sn); PARSE_JSON(sn, o.sn);
PARSE_JSON(name, o.name); PARSE_JSON(name, o.name);
PARSE_JSON(sample, o.sample);
PARSE_JSON(port, o.port); PARSE_JSON(port, o.port);
PARSE_JSON(baudRate, o.baudRate); PARSE_JSON(baudRate, o.baudRate);
PARSE_JSON(byteSize, o.byteSize); PARSE_JSON(byteSize, o.byteSize);

View File

@ -31,6 +31,9 @@ namespace zsy
LOGGER_INFO("上报数据:{}{} {}", config.server, config.passUrl, body); LOGGER_INFO("上报数据:{}{} {}", config.server, config.passUrl, body);
httplib::Client cli(config.server); 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"); auto response = cli.Post(config.passUrl.c_str(), headers, body, "application/json");
if (response) if (response)
{ {
@ -87,10 +90,13 @@ namespace zsy
auto body = data.dump(); auto body = data.dump();
LOGGER_INFO("上报数据:{}{} {}", config.server, config.passUrl, body); LOGGER_INFO("上报数据:{}{} {}", config.server, config.reportUrl, body);
httplib::Client cli(config.server); 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) if (response)
{ {
LOGGER_INFO("上报结果:{}", response->body); LOGGER_INFO("上报结果:{}", response->body);

View File

@ -7,7 +7,7 @@ namespace zsy
{ {
GenericSoundColumn::GenericSoundColumn(const SoundColumnProperties &config): config(config) 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; if (!event.data.has_value()) return;
auto jsonData = event.data.value(); auto jsonData = event.data.value();
@ -22,7 +22,7 @@ namespace zsy
auto clientId = cli->getClientId(); auto clientId = cli->getClientId();
if (cli) 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()) if (!event.data.has_value())
{ {
@ -63,9 +63,9 @@ namespace zsy
}; };
nlohmann::json data{ nlohmann::json data{
{"loop", {{"times", 1}}}, {"loop", {{"times", 2}, {"gap", 2}}},
{"prompt", true}, {"prompt", true},
{"queue", false}, {"queue", true},
{"rcn", "0"}, {"rcn", "0"},
{"rdn", "0"}, {"rdn", "0"},
{"reg", 0}, {"reg", 0},
@ -79,6 +79,10 @@ namespace zsy
LOGGER_INFO("播放语音:{}{} {}", config.server, config.path, body); LOGGER_INFO("播放语音:{}{} {}", config.server, config.path, body);
httplib::Client cli(config.server); 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"); auto response = cli.Post(config.path.c_str(), headers, body, "application/json");
if (response) if (response)
@ -90,7 +94,15 @@ namespace zsy
LOGGER_ERROR("语音播放失败HTTP状态码{}", status); LOGGER_ERROR("语音播放失败HTTP状态码{}", status);
} else } else
{ {
LOGGER_INFO("语音播放成功"); auto json = nlohmann::json::parse(response->body);
auto result = json.get<PlaySoundColumnResult>();
if (result.code == 200)
{
LOGGER_INFO("语音播放成功");
} else
{
LOGGER_ERROR("语音播放失败,错误:{}", result.message);
}
} }
} else } else
{ {

View File

@ -5,6 +5,18 @@
namespace zsy 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 class GenericSoundColumn final : public SoundColumn
{ {
SoundColumnProperties config; SoundColumnProperties config;

View File

@ -34,22 +34,21 @@ namespace zsy
static std::string convert(const std::string &numberStr) static std::string convert(const std::string &numberStr)
{ {
static const std::vector<std::string> digits = {"", "", "", "", "", "", "", "", "", ""}; static const std::unordered_map<char, std::string> digitMap = {
std::string chineseStr; {'0', ""}, {'1', ""}, {'2', ""}, {'3', ""}, {'4', ""},
for (char c: numberStr) {'5', ""}, {'6', ""}, {'7', ""}, {'8', ""}, {'9', ""},
{ {'.', ""}
if ('0' <= c && c <= '9') };
{
chineseStr += digits[c - '0']; std::string result;
} else if (c == '.') for (char c : numberStr) {
{ if (digitMap.contains(c)) {
chineseStr += ''; result += digitMap.at(c);
} else } else {
{ result += c;
chineseStr += c;
} }
} }
return chineseStr; return result;
} }
}; };
} // zsy } // zsy