diff --git a/appdep/iflytop/core/components/timeutils.hpp b/appdep/iflytop/core/components/timeutils.hpp index 63ef36a..b09f3fe 100644 --- a/appdep/iflytop/core/components/timeutils.hpp +++ b/appdep/iflytop/core/components/timeutils.hpp @@ -78,7 +78,7 @@ class T_TimeUtils { std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); std::string s(30, '\0'); std::strftime(&s[0], s.size(), fmt, std::localtime(&now)); - return s; + return s.c_str(); } }; diff --git a/appsrc/service/disinfection_logs_service.cpp b/appsrc/service/disinfection_logs_service.cpp index b5742b7..f23b689 100644 --- a/appsrc/service/disinfection_logs_service.cpp +++ b/appsrc/service/disinfection_logs_service.cpp @@ -15,6 +15,7 @@ #include #include "appbase/appbean/disinfection_record_csv_header.hpp" +#include "appbase/utils/zsimplepdf.hpp" using namespace std; using namespace iflytop; typedef DisinfectionRecordCSVHeader CSVHeader; @@ -25,6 +26,7 @@ typedef DisinfectionRecordCSVHeader CSVHeader; #define LOG_STORGE_PATH "./disinfection_logs/" #define EXPORT_PATH "/mnt/exportdata/Transmit/" +#define MAX_LOG_NUM 5 #define IF_ERROR_RETURN(x) \ if (!x) { \ return err::kappe_udisk_wr_fail; \ @@ -99,6 +101,25 @@ static void listDirCSVFile(string path, vector& sv) { } return; } + +static int getDirFileNum(string path) { + DIR* dir; + struct dirent* ptr; + if ((dir = opendir(path.c_str())) == NULL) { + return 0; + } + + int num = 0; + while ((ptr = readdir(dir)) != NULL) { + if (ptr->d_name[0] == '.') continue; + if (ptr->d_type == 8) { + string filename = ptr->d_name; + num++; + } + } + return num; +} + static void split(const string& s, vector& sv, const char delim = ' ') { sv.clear(); istringstream iss(s); @@ -110,6 +131,25 @@ static void split(const string& s, vector& sv, const char delim = ' ') { return; } +static string createDisinfectionID() { + struct tm tm = {0}; + time_t t = time(nullptr); + if (t == -1) { + printf("time error\n"); + exit(-1); + } + struct tm* tmp = localtime_r(&t, &tm); + if (!tmp) { + printf("localtime_r error\n"); + exit(-1); + } + return fmt::format("{:0>4}-{:0>2}{:0>2}-{:0>2}{:0>2}", tm.tm_year + 1900, // + tm.tm_mon + 1, // + tm.tm_mday, // + tm.tm_hour, // + tm.tm_min); +} + /******************************************************************************* * CLASS * *******************************************************************************/ @@ -121,11 +161,12 @@ void DisinfectionLogsService::initialize() { GET_TO_SERVICE(m_gConfig); GET_TO_SERVICE(m_udiskMgrService); - REGFN(DisinfectionLogsService, getRecordList); - REGFN(DisinfectionLogsService, getRecord); - REGFN(DisinfectionLogsService, deleteReport); - REGFN(DisinfectionLogsService, exportRecord); - REGFN(DisinfectionLogsService, printRecord); + REGFNV2(DisinfectionLogsService, getRecordList); + REGFNV2(DisinfectionLogsService, getRecord); + REGFNV2(DisinfectionLogsService, deleteReport); + REGFNV2(DisinfectionLogsService, exportRecord); + REGFNV2(DisinfectionLogsService, printRecord); + REGFNV2(DisinfectionLogsService, selftest); m_csvHeaderDict.insert(CSVHeader::time, "时间"); m_csvHeaderDict.insert(CSVHeader::state, "设备状态"); @@ -163,38 +204,57 @@ void DisinfectionLogsService::initialize() { AppEventBus::ins()->onEvent.connect([this](shared_ptr event) { if (auto e = dynamic_pointer_cast(event); e) { logger->info("DisinfectionLogsService: start new disinfection session"); - startNewDisinfectionSession(e->getSessionId()); + onAppDisinfectionStartEvent(e->getSessionId()); return; } if (auto e = dynamic_pointer_cast(event); e) { logger->info("DisinfectionLogsService: finish disinfection session"); - finishDisinfectionSession(); - m_statistics = e->getDisinfectionStatistics(); + onAppDisinfectionFinishedEvent(e->getDisinfectionStatistics()); return; } if (auto e = dynamic_pointer_cast(event); e) { logger->info("DisinfectionLogsService: push state snapshot"); - pushStateSnapshot(e->getStateSnapshot()); + onAppDisinfectionSnapshotEvent(e->getStateSnapshot()); return; } }); + + // m_recordFiles + + /** + * @brief 读取文件夹下所有文件,并按照时间排序 + */ + vector files; + listDirCSVFile(LOG_STORGE_PATH, files); + for (auto& file : files) { + // 获取文件名去掉.csv + file = file.substr(0, file.find(".csv")); + m_recordFiles.push_back(file); + } + + for (auto& file : m_recordFiles) { + logger->info("DisinfectionLogsService: load record file: {}", file); + } + return; } -void DisinfectionLogsService::startNewDisinfectionSession(string sessionId) { // +void DisinfectionLogsService::onAppDisinfectionStartEvent(string sessionId) { // m_snapshots.clear(); m_sessionId = sessionId; } -void DisinfectionLogsService::pushStateSnapshot(shared_ptr snapshot) { m_snapshots.push_back(snapshot); } -void DisinfectionLogsService::finishDisinfectionSession() { +void DisinfectionLogsService::onAppDisinfectionSnapshotEvent(shared_ptr snapshot) { m_snapshots.push_back(snapshot); } +void DisinfectionLogsService::onAppDisinfectionFinishedEvent(shared_ptr statistics) { + m_statistics = statistics; dumpDisinfectionRecord(m_sessionId, m_snapshots); + dumpDisinfectionToPrinterLog(m_sessionId, m_snapshots); + m_recordFiles.push_back(m_sessionId); /** * @brief * 1.创建打印文件缓存 * 2.创建PDF文件缓存 */ - clearRecordFiles(); } @@ -235,7 +295,7 @@ void DisinfectionLogsService::dumpDisinfectionRecord(string sessionId, liststate)); auto h2o2data = s->h2o2Snapshot; - for (uint32_t i = 0; i < h2o2data->getSensorDataNum(); i++) { + for (int i = 0; i < h2o2data->getSensorDataNum(); i++) { if (i == 0) { csv.addValue(m_csvHeaderDict.getChName(CSVHeader::ho2o2_0), /***************/ h2o2data->isExpired[0] ? "N/A" : formatSensorVal(h2o2data->h2o2[0])); csv.addValue(m_csvHeaderDict.getChName(CSVHeader::temp_0), /****************/ h2o2data->isExpired[0] ? "N/A" : formatSensorVal(h2o2data->temp[0])); @@ -313,11 +373,13 @@ void DisinfectionLogsService::dumpDisinfectionToPrinterLog(string sessionId, lis if (tu_sys().dToS(snapshot->time - lastlogtime) > logdtime) logthis = true; if (!logthis) continue; + state = snapshot->state; content += fmt::format("{}\n", format_zsystem_tp(snapshot->time)); if (stateChanged) { content += fmt::format("{}\n", m_dmStateDict.getChName(snapshot->state)); } + if (state == DisinfectionState::disinfection) { content += fmt::format("LOG: {}\n", snapshot->nlog); } @@ -350,15 +412,58 @@ void DisinfectionLogsService::dumpDisinfectionToPrinterLog(string sessionId, lis content += ("\n"); content += ("\n"); - FileUtils().writeToFile(fmt::format("{}{}.log", LOG_STORGE_PATH, sessionId), content.c_str(), content.size()); - logger->info("dump log to printer log file: {},\n", fmt::format("{}{}.log", LOG_STORGE_PATH, sessionId), content); + string logtxtpath = fmt::format("{}{}.log", LOG_STORGE_PATH, sessionId); + logger->info("dump log to printer log file: {},\n", logtxtpath, content); + FileUtils().writeToFile(logtxtpath, content.c_str(), content.size()); + + string pdfpath = fmt::format("{}{}.pdf", LOG_STORGE_PATH, sessionId); + ZSimplePDF pdfwriter(pdfpath); + pdfwriter.addText("\n"); + pdfwriter.addText(content); + pdfwriter.dump(); } void DisinfectionLogsService::dumpDisinfectionToPrinterPdf(string sessionId, list> snapshots) {} - +/** + * @brief 删除记录,多余记录文件 + */ void DisinfectionLogsService::clearRecordFiles() { - // TODO: 删除掉多余的csv文件 - // TODO: 检查时间,如果已经存储文件的时间大于当前时间,也删掉 + // + vector recordlist; + for (auto& record : m_recordFiles) { + recordlist.push_back(record); + } + + if (recordlist.size() == 0) { + logger->info("no record files"); + return; + } + // 从后往前删除,保留最新的MAX_LOG_NUM个 + vector delFiles; + int removeFileNum = recordlist.size() - MAX_LOG_NUM; + if (removeFileNum > 0) { + for (int i = 0; i < removeFileNum; i++) { + delFiles.push_back(recordlist[recordlist.size() - 1 - i]); + } + } + + for (auto& file : delFiles) { + deleteRecordFile(file); + } + + int fileNum = getDirFileNum(LOG_STORGE_PATH); + if ((uint32_t)fileNum != m_recordFiles.size() * 3) { + logger->error("record file num error, delete all record files"); + logger->info("delete all record files"); + dosystem(fmt::format("rm -rf {}/*", LOG_STORGE_PATH)); + m_recordFiles.clear(); + } } +void DisinfectionLogsService::deleteRecordFile(string file) { + string filepath = fmt::format("{}{}.*", LOG_STORGE_PATH, file); + dosystem(fmt::format("rm -rf {}", filepath)); + m_recordFiles.remove_if([file](const string& s) { return s == file; }); +} + int32_t DisinfectionLogsService::exportDisinfectionData(vector files) { string diskpath; if (!m_udiskMgrService->isDetectedUDisk(diskpath)) { @@ -378,6 +483,7 @@ int32_t DisinfectionLogsService::exportDisinfectionData(vector files) { for (auto& file : files) { logger->info("copy file: {}", file); + /**********************************拷贝CSV**********************************/ // 拷贝文件到TMP目录 IF_ERROR_RETURN(dosystem(fmt::format("cp -rf /app/disinfection_logs/{}.csv /tmp/{}.csv", file, file))); // 编码转换 @@ -386,6 +492,12 @@ int32_t DisinfectionLogsService::exportDisinfectionData(vector files) { IF_ERROR_RETURN(dosystem(fmt::format("mv /tmp/{}.csv.1 /tmp/{}.csv", file, file))); // 拷贝文件到U盘 IF_ERROR_RETURN(dosystem(fmt::format("cp -rf /tmp/{}.csv {}", file, EXPORT_PATH))); + // 删除文件 + IF_ERROR_RETURN(dosystem(fmt::format("rm -rf /tmp/{}.csv", file))); + + /**********************************拷贝PDF**********************************/ + // 拷贝pdf文件 + dosystem(fmt::format("cp -rf /app/disinfection_logs/{}.pdf {}", file, EXPORT_PATH)); } // 卸载目录 @@ -411,62 +523,93 @@ bool DisinfectionLogsService::dosystem(string cmd) { * EXT_API * *******************************************************************************/ -void DisinfectionLogsService::getRecordList(shared_ptr cxt) { +void DisinfectionLogsService::fn_getRecordList(shared_ptr cxt) { /** * @brief 读取文件夹下所有文件,并按照时间排序 */ - vector files; - listDirCSVFile(LOG_STORGE_PATH, files); - nlohmann::json loggerlist; - for (auto& file : files) { - // 获取文件名去掉.csv - file = file.substr(0, file.find(".csv")); - loggerlist.push_back(file); - } - cxt->content = loggerlist; + vector record; + for (auto& file : m_recordFiles) record.push_back(file); + cxt->content = record; return; } -void DisinfectionLogsService::getRecord(shared_ptr cxt) { - string logName = cxt->params["logName"]; - +void DisinfectionLogsService::fn_getRecord(shared_ptr cxt) { + string logName = cxt->params["logName"]; string content = FileUtils().readFileAsString(fmt::format("{}{}.csv", LOG_STORGE_PATH, logName)); vector lines; split(content, lines, '\n'); - for (auto& line : lines) { cxt->content.push_back(line); } } -void DisinfectionLogsService::deleteReport(shared_ptr cxt) { +void DisinfectionLogsService::fn_deleteReport(shared_ptr cxt) { string logName = cxt->params["logName"]; - system(fmt::format("rm -f {}{}.csv", LOG_STORGE_PATH, logName).c_str()); + deleteRecordFile(logName); } -void DisinfectionLogsService::exportRecord(shared_ptr cxt) { +void DisinfectionLogsService::fn_exportRecord(shared_ptr cxt) { vector files; for (auto& key : cxt->params["logNames"]) { files.push_back(key); } - auto errcode = exportDisinfectionData(files); if (errcode != err::ksucc) { cxt->ackcode = errcode; return; } - /** - * TODO: 导出pdf - */ } -void DisinfectionLogsService::printRecord(shared_ptr cxt) { +void DisinfectionLogsService::fn_printRecord(shared_ptr cxt) { // - logger->info("printRecord"); - GET_SERVICE(UartPrinter)->print("打印成功测试"); - GET_SERVICE(UartPrinter)->print("打印成功测试"); - GET_SERVICE(UartPrinter)->print("打印成功测试"); - GET_SERVICE(UartPrinter)->print("打印成功测试"); - GET_SERVICE(UartPrinter)->print("打印成功测试"); - GET_SERVICE(UartPrinter)->print(""); - GET_SERVICE(UartPrinter)->print(""); - GET_SERVICE(UartPrinter)->print(""); -} \ No newline at end of file +} + +void DisinfectionLogsService::fn_selftest(shared_ptr cxt) { + string ssid = createDisinfectionID(); + onAppDisinfectionStartEvent(ssid); + + shared_ptr h2o2Snapshot = make_shared(); + h2o2Snapshot->h2o2.push_back(0.1); + h2o2Snapshot->h2o2.push_back(0.2); + h2o2Snapshot->h2o2.push_back(0.3); + h2o2Snapshot->humid.push_back(0.4); + h2o2Snapshot->humid.push_back(0.5); + h2o2Snapshot->humid.push_back(0.6); + h2o2Snapshot->temp.push_back(0.7); + h2o2Snapshot->temp.push_back(0.8); + h2o2Snapshot->temp.push_back(0.9); + h2o2Snapshot->saturation.push_back(1.0); + h2o2Snapshot->saturation.push_back(1.1); + h2o2Snapshot->saturation.push_back(1.2); + h2o2Snapshot->isExpired.push_back(false); + h2o2Snapshot->isExpired.push_back(false); + h2o2Snapshot->isExpired.push_back(false); + + h2o2Snapshot->minH2O2 = 10; + h2o2Snapshot->maxH2O2 = 20; + h2o2Snapshot->maxHumid = 30; + h2o2Snapshot->maxSaturation = 40; + + shared_ptr snapshot = make_shared(); + snapshot->state = DisinfectionState::disinfection; + snapshot->time = zsystem_clock().now(); + snapshot->h2o2Snapshot = h2o2Snapshot; + snapshot->forcelog = false; + snapshot->dval = 0; + snapshot->nlog = 0; + snapshot->tlog = 0; + snapshot->remainDisinfectant = 0; + snapshot->remainTime = 0; + snapshot->ecode = 0; + + onAppDisinfectionSnapshotEvent(snapshot); + onAppDisinfectionSnapshotEvent(snapshot); + onAppDisinfectionSnapshotEvent(snapshot); + + shared_ptr statistics = make_shared(); + statistics->start_tp = zsystem_clock().now(); + statistics->complete_tp = zsystem_clock().now(); + statistics->disinfectantVolume_g = 0; + statistics->tLog = 0; + statistics->finalLog = 0; + + onAppDisinfectionFinishedEvent(statistics); +} diff --git a/appsrc/service/disinfection_logs_service.hpp b/appsrc/service/disinfection_logs_service.hpp index dcdb82f..93da37c 100644 --- a/appsrc/service/disinfection_logs_service.hpp +++ b/appsrc/service/disinfection_logs_service.hpp @@ -31,14 +31,16 @@ class DisinfectionLogsService : public enable_shared_from_this m_recordFiles; + public: DisinfectionLogsService(); void initialize(); - public: - void startNewDisinfectionSession(string sessionId); - void pushStateSnapshot(shared_ptr snapshot); - void finishDisinfectionSession(); + private: + void onAppDisinfectionStartEvent(string sessionId); + void onAppDisinfectionSnapshotEvent(shared_ptr snapshot); + void onAppDisinfectionFinishedEvent(shared_ptr statistics); private: void dumpDisinfectionRecord(string sessionId, list> snapshots); @@ -49,15 +51,18 @@ class DisinfectionLogsService : public enable_shared_from_this cxt); - void getRecord(shared_ptr cxt); - void deleteReport(shared_ptr cxt); - void exportRecord(shared_ptr cxt); - void printRecord(shared_ptr cxt); + void fn_getRecordList(shared_ptr cxt); + void fn_getRecord(shared_ptr cxt); + void fn_deleteReport(shared_ptr cxt); + void fn_exportRecord(shared_ptr cxt); + void fn_printRecord(shared_ptr cxt); + + void fn_selftest(shared_ptr cxt); private: int32_t exportDisinfectionData(vector files); void clearRecordFiles(); + void deleteRecordFile(string file); bool dosystem(string cmd); }; } // namespace iflytop diff --git a/TESTCMD.md b/doc/TESTCMD.md similarity index 100% rename from TESTCMD.md rename to doc/TESTCMD.md