修复问题

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_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

View File

@ -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"
}
]
}

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()
{
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)

View File

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

View File

@ -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<std::string, long long> cache;
static std::mutex cacheMutex;
// static std::unordered_map<std::string, long long> 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::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;
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<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);
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());

View File

@ -41,6 +41,18 @@ namespace zsy
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();
};
} // zsy

View File

@ -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> eventManager)
: status(0),
config(config),
eventManager(eventManager)
void MqttCli::connect()
{
try
{
LOGGER_ERROR("MQTT{} 正在连接...", config.clientId);
ioc = std::make_shared<boost::asio::io_context>();
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> 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_t> 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();
}

View File

@ -22,13 +22,15 @@ namespace zsy
using CLI_PTR = std::shared_ptr<CLI>;
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> eventManager;
std::unique_ptr<std::jthread> eventLoop;
CLI_PTR cli;
std::shared_ptr<boost::asio::io_context> ioc;
CLI_PTR cli;
void connect();
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_);
void reconnect();
public:
static const std::string TYPE_REMOTE;
static const std::string TYPE_LOCAL;

View File

@ -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},

View File

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

View File

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

View File

@ -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);

View File

@ -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);

View File

@ -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<PlaySoundColumnResult>();
if (result.code == 200)
{
LOGGER_INFO("语音播放成功");
} else
{
LOGGER_ERROR("语音播放失败,错误:{}", result.message);
}
}
} else
{

View File

@ -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;

View File

@ -34,22 +34,21 @@ namespace zsy
static std::string convert(const std::string &numberStr)
{
static const std::vector<std::string> 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<char, std::string> 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