155 lines
5.1 KiB
C++
155 lines
5.1 KiB
C++
#include "barrier_vidicon.h"
|
|
#include "application.h"
|
|
#include "nlohmann/json.hpp"
|
|
#include "common/sys_util.h"
|
|
#include "common/snowflake.h"
|
|
|
|
|
|
namespace zsy
|
|
{
|
|
bool BarrierVidicon::saveImageToFile(const std::string &decodedImageData, const std::string &filePath)
|
|
{
|
|
try
|
|
{
|
|
// 以二进制写入模式打开文件
|
|
std::ofstream file(filePath, std::ios::binary | std::ios::trunc);
|
|
|
|
// 检查文件是否成功打开
|
|
if (!file.is_open())
|
|
{
|
|
throw std::system_error(errno, std::generic_category(), "无法打开文件");
|
|
}
|
|
|
|
// 写入解码后的图像数据
|
|
file.write(decodedImageData.data(), decodedImageData.size());
|
|
|
|
// 检查写入是否成功
|
|
if (!file.good())
|
|
{
|
|
throw std::system_error(errno, std::generic_category(), "写入文件失败");
|
|
}
|
|
|
|
return true;
|
|
} catch (const std::exception &e)
|
|
{
|
|
LOGGER_ERROR("图片保存失败");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
BarrierVidicon::~BarrierVidicon()
|
|
{
|
|
}
|
|
|
|
BarrierVidicon::BarrierVidicon(const VidiconProperties &config)
|
|
: config(config)
|
|
, hasNewContent(false)
|
|
{
|
|
SysUtil::createDirs(SysUtil::HOME_DIR + "\\temp");
|
|
auto cli = Application::mqttCliHolder->localCli();
|
|
Application::eventManager->subscribe(MqttCli::TYPE_LOCAL + "/device/" + config.ip + "/message/up/snapshot", [this](const EventManager::Event &event)
|
|
{
|
|
if (!event.data.has_value())
|
|
{
|
|
LOGGER_ERROR("错误的消息格式");
|
|
return;
|
|
}
|
|
auto jsonData = event.data.value();
|
|
|
|
LOGGER_INFO("收到道闸拍照结果:{}", jsonData.dump());
|
|
const auto res = jsonData.get<PhotographResult>();
|
|
|
|
imageContent = res.payload.image_content;
|
|
hasNewContent.store(true);
|
|
});
|
|
Application::eventManager->subscribe(MqttCli::TYPE_LOCAL + "/device/" + config.ip + "/message/down/snapshot/reply", [this](const EventManager::Event &event)
|
|
{
|
|
if (!event.data.has_value())
|
|
{
|
|
LOGGER_ERROR("错误的消息格式");
|
|
return;
|
|
}
|
|
auto jsonData = event.data.value();
|
|
|
|
LOGGER_INFO("收到道闸拍照消息回执:{}", jsonData.dump());
|
|
});
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
std::string BarrierVidicon::photograph()
|
|
{
|
|
try
|
|
{
|
|
LOGGER_INFO("摄像机正在拍照,设备名称:{}", config.name);
|
|
const long timestamp = static_cast<long>(getTime());
|
|
nlohmann::json j{
|
|
{"id", "photograph" + std::to_string(timestamp)},
|
|
{"sn", config.ip},
|
|
{"name", "snapshot"},
|
|
{"version", "1.0"},
|
|
{"timestamp", timestamp},
|
|
{
|
|
"payload", {
|
|
{"type", "snapshot"},
|
|
{"body", {}},
|
|
}
|
|
}
|
|
};
|
|
auto topic = "device/" + config.ip + "/message/down/snapshot";
|
|
auto data = j.dump();
|
|
|
|
LOGGER_INFO("拍照:{} {}", topic, data);
|
|
|
|
try
|
|
{
|
|
auto cli = Application::mqttCliHolder->localCli();
|
|
if (cli)
|
|
{
|
|
hasNewContent.store(false);
|
|
imageContent = "";
|
|
cli->publish(topic, data, 0);
|
|
uint8_t i = 0;
|
|
do
|
|
{
|
|
i++;
|
|
LOGGER_INFO("等待:{}", i);
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
} while (i <= 10 && !hasNewContent.load());
|
|
|
|
const auto filename = "car_body_" + Snowflake::genIdStr() + ".jpg";
|
|
std::string path = SysUtil::HOME_DIR + "\\temp\\" + filename;
|
|
auto content = SysUtil::base64_decode(imageContent);
|
|
bool res = saveImageToFile(content, path);
|
|
return path;
|
|
} else
|
|
{
|
|
LOGGER_ERROR("未找到 MQTT 本地客户端");
|
|
}
|
|
} catch (const std::exception &e)
|
|
{
|
|
LOGGER_INFO("拍照失败:{}", e.what());
|
|
} catch (...)
|
|
{
|
|
LOGGER_ERROR("未知异常,拍照失败");
|
|
}
|
|
return "";
|
|
} catch (std::exception &e)
|
|
{
|
|
LOGGER_ERROR("摄像机拍照失败:{}", e.what());
|
|
return {};
|
|
}
|
|
catch (...)
|
|
{
|
|
LOGGER_ERROR("未知异常,摄像机拍照失败");
|
|
return {};
|
|
}
|
|
}
|
|
}
|