deviceAccessLayer/src/barrier/generic_barrier.cpp

276 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "generic_barrier.h"
#include "application.h"
#include "common/loging.h"
#include "common/snowflake.h"
#include "common/sys_util.h"
namespace zsy
{
static long long getTime()
{
const auto now = std::chrono::system_clock::now();
const auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
const auto epoch = now_ms.time_since_epoch();
return std::chrono::duration_cast<std::chrono::milliseconds>(epoch).count();
}
GenericBarrier::GenericBarrier(const BarrierProperties &config)
: config(config)
{
Application::eventManager->subscribe(config.sn + "/open", [this](const EventManager::Event &)
{
this->open();
});
static auto subscribed = []
{
auto cli = Application::mqttCliHolder->remoteCli();
if (cli)
{
auto clientId = cli->getClientId();
Application::eventManager->subscribe(clientId + "/yztq/1/barrier", [](const EventManager::Event &event)
{
if (!event.data.has_value())
{
LOGGER_ERROR("开门请求参数错误");
return;
}
auto jsonData = event.data.value();
LOGGER_INFO("收到开门请求:{}", jsonData.dump());
const auto req = jsonData.get<DoorReq>();
Application::eventManager->publish(req.deviceNo + "/open", jsonData.dump());
});
} else
{
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;
try
{
auto body = req.body;
LOGGER_INFO("收到车牌识别结果:{}", body);
auto [succ,recognizeResult] = GenericBarrier::parseRecognizeResult(body);
if (!succ)
{
LOGGER_ERROR("车牌识别结果解析失败");
res.set_content(R"({})", "application/json");
return;
}
auto serialno = recognizeResult.alarmInfoPlate.serialno;
auto imageFile = recognizeResult.alarmInfoPlate.result.plateResult.imageFile;
auto license = recognizeResult.alarmInfoPlate.result.plateResult.license;
if (serialno.empty() || imageFile.empty() || license.empty())
{
LOGGER_ERROR("车牌识别结果解析失败");
res.set_content(R"({})", "application/json");
return;
}
if (license.find("") != std::string::npos)
{
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 key = serialno + license;
long long time = ms + 60000 * 5;
{
std::lock_guard<std::mutex> lock(cacheMutex);
std::erase_if(cache, [time](const auto &pair)
{
return pair.second >= time;
});
if (cache.contains(key))
{
if (cache[key] < time)
{
res.set_content(R"({})", "application/json");
LOGGER_INFO("重复的车牌识别结果:{} {}", serialno, license);
return;
}
}
cache[key] = ms;
}*/
Application::threadPool->submit([imageFile,license, barrier = Application::deviceHolder->getBarrier(serialno)]
{
if (!barrier)
{
LOGGER_ERROR("未找到对应的道闸");
return;
}
barrier->resolveRecognizeResult(license, imageFile);
});
} catch (std::exception &e)
{
LOGGER_ERROR("车牌识别结果处理失败: {}", e.what());
}
catch (...)
{
LOGGER_ERROR("未知异常,车牌识别结果处理失败");
}
res.set_content(R"({})", "application/json");
});
return true;
}();
}
void GenericBarrier::open()
{
LOGGER_INFO("收到开门请求:{} {}", config.name, config.sn);
const long timestamp = static_cast<long>(getTime());
BarrierBcd barrier;
barrier.id = "open" + std::to_string(timestamp);
barrier.sn = config.sn;
barrier.timestamp = timestamp;
barrier.payload.body.value = 2;
barrier.payload.body.io = config.io;
nlohmann::json j(barrier);
auto topic = "device/" + config.sn + "/message/down/gpio_out";
auto data = j.dump();
LOGGER_INFO("打开道闸:{} {}", topic, data);
try
{
auto cli = Application::mqttCliHolder->localCli();
if (cli)
{
cli->publish(topic, data, 0);
} else
{
LOGGER_ERROR("未找到 MQTT 本地客户端");
}
} catch (const std::exception &e)
{
LOGGER_INFO("开门失败:{}", e.what());
} catch (...)
{
LOGGER_ERROR("未知异常,开门失败");
}
}
std::tuple<bool, RecognizeResult> GenericBarrier::parseRecognizeResult(const std::string &jsonStr)
{
try
{
auto json = nlohmann::json::parse(jsonStr);
RecognizeResult result = json.get<RecognizeResult>();
return std::make_tuple(true, result);
} catch (std::exception &e)
{
LOGGER_ERROR("未找到车牌识别结果:{}", e.what());
return std::make_tuple(false, RecognizeResult());
}catch (...)
{
LOGGER_ERROR("未知异常,未找到车牌识别结果");
return std::make_tuple(false, RecognizeResult());
}
}
void GenericBarrier::resolveRecognizeResult(const std::string &license, const std::string &imageFile)
{
try
{
LOGGER_INFO("车牌识别结果处理中,设备名称:{}", config.name);
// 播放语音 1
/*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);
auto photoId = Snowflake::genIdStr();
auto now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::tm *localTime = std::localtime(&currentTime);
std::stringstream ss;
ss << std::put_time(localTime, "%Y%m%d");
std::string date = ss.str();
auto [carFrontUrlSucc,carFrontUrl] = Application::oss->upload(date + "/" + license + "_front_" + photoId + ".jpg", *imageFileStream);
// 上报 1
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::deviceHolder->getSoundColumn(sn)->play("正在称重,请稍后");
});*/
std::thread t2([sn = config.sn]
{
Application::deviceHolder->getSoundColumn(sn)->play("正在称重,请稍后");
});
double weight = Application::deviceHolder->getPlatformScale(config.sn)->reading();
auto photographPath = Application::deviceHolder->getVidicon(config.sn)->photograph();
auto [carBodyUrlSucc,carBodyUrl] = Application::oss->upload(date + "/" + license + "_body_" + photoId + ".jpg", photographPath);
if (!photographPath.empty())
{
auto pathPtr = SysUtil::ch_vlt(photographPath.c_str());
if (std::remove(pathPtr.get()) != 0)
{
auto [_,code,msg] = SysUtil::getError();
LOGGER_ERROR("临时照片删除失败:{},错误码:{},错误信息:{}", photographPath, code, msg);
} else
{
LOGGER_ERROR("临时照片删除成功:{}", photographPath);
}
}
// 上报 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());
}
catch (...)
{
LOGGER_ERROR("未知异常,车牌识别结果处理失败");
}
}
} // zsy