#include "disinfection_ctl_service.hpp" #include #include #include "configs/gconfig.hpp" #include "configs/project_setting.hpp" #include "iflytop/components/uart_printer/uart_printer.hpp" #include "iflytoplinuxsdk/src/iflytop/components/ziconv.hpp" #include "service/device_state_service.hpp" // #define PROJECT_TYPE_LARGE_SPACE_DISINFECTION 1 // 大空间 // #define PROJECT_TYPE_SMALL_SPACE_DISINFECTION 1 // 小空间 using namespace iflytop; using namespace std; #define DVALUE_COMPUTEPERIOD_TIME_S (10.0) #define DUMP_LOG_PERIOD (5 * 60.0) #define MAX_VOLUME (5000) namespace iflytop { extern bool g_in_test; } static string formattimeS(int sec) { if (sec >= 0) { return fmt::format("{:0>2}:{:0>2}:{:0>2}", sec / 3600, sec % 3600 / 60, sec % 60); } else { return fmt::format("--:--:--"); } } static string getTime() { struct tm tm = {0}; time_t t = time(nullptr); localtime_r(&t, &tm); return fmt::format("{:0>4}-{:0>2}-{: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, tm.tm_sec); } static bool zfeq(float a, float b, float eps = 0.01) { if (fabs(a - b) < eps) { return true; } return false; } DisinfectionCtrlService::DisinfectionCtrlService() {} void DisinfectionCtrlService::initialize() { GET_TO_SERVICE(m_deviceIoControlService); GET_TO_SERVICE(m_dbService); GET_TO_SERVICE(m_disinfectionLogsManager); GET_TO_SERVICE(m_disinfectionPrinterService); m_deviceIoControlService->drainingPump_close(); m_deviceIoControlService->replenishingFluidsPump_close(); m_deviceIoControlService->sprayLiquidPump_close(); m_deviceIoControlService->heartingPlate_setPower(false); m_deviceIoControlService->airBlower_setState(false); m_deviceIoControlService->airCompressor_setState(false); m_dvalueComputer.initialize(); } string DisinfectionCtrlService::createDisinfectionID() { struct tm tm = {0}; time_t t = time(nullptr); if (t == -1) { logger->error("time(nullptr) failed"); exit(-1); } struct tm* tmp = localtime_r(&t, &tm); if (!tmp) { logger->error("localtime_r failed"); exit(-1); } // tm = *utctime::tm_increment_hour(&tm, 8); // logger->info("trace sendmsg_startCapture {}:{}", __FILE__, __LINE__); return fmt::format("{:0>4}-{:0>2}{: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, tm.tm_sec); } float DisinfectionCtrlService::getDisinfectionDValue(float ppm) { // return m_dvalueComputer.computeDValue(ppm); } float DisinfectionCtrlService::computeNowLogLevel(DisinfectionContext& context) { float dvalue = context.state_dvalue; if (dvalue > 0) { /** * @brief 计算 state_now_loglevel */ return context.state_now_loglevel + DVALUE_COMPUTEPERIOD_TIME_S / (dvalue * 60); } return context.state_now_loglevel; } void DisinfectionCtrlService::computeRemainTime(DisinfectionContext& context) { /** * @brief 计算Dvalue */ float dvalue = context.state_dvalue; if (dvalue > 0) { /** * @brief 计算 state_now_loglevel */ if (context.cfg_targetLoglevel >= context.state_now_loglevel) { context.state_remaintime = (context.cfg_targetLoglevel - context.state_now_loglevel) * (dvalue * 60); } else { context.state_remaintime = 0; } } else { // } logger->info("computeRemainTime minh2o2 {} dvalue {}", context.min_h2o2, dvalue); } shared_ptr DisinfectionCtrlService::createCSVLogger(string log_file_name) { shared_ptr _logger = m_disinfectionLogsManager->createNewLogger(log_file_name); _logger->write( fmt::format("{}," "{},{},{},{}," "{},{},{},{}," "{},{},{},{}," "{},{},{}," "{},{},{},{}," "{},{}" "\n", ZIconv::noChange("时间"), // ZIconv::noChange("仓内-气化过氧化氢浓度"), ZIconv::noChange("仓内-温度"), ZIconv::noChange("仓内-相对湿度"), ZIconv::noChange("仓内-相对饱和度"), // ZIconv::noChange("环境1-气化过氧化氢浓度"), ZIconv::noChange("环境1-温度"), ZIconv::noChange("环境1-相对湿度"), ZIconv::noChange("环境1-相对饱和度"), // ZIconv::noChange("环境2-气化过氧化氢浓度"), ZIconv::noChange("环境2-温度"), ZIconv::noChange("环境2-相对湿度"), ZIconv::noChange("环境2-相对饱和度"), // ZIconv::noChange("D值"), ZIconv::noChange("当前LOG"), ZIconv::noChange("目标LOG"), // ZIconv::noChange("加热器电源"), ZIconv::noChange("风机电源"), ZIconv::noChange("空压机电源"), ZIconv::noChange("喷液泵(g/min)"), // ZIconv::noChange("消毒剩余剂量(g)"), ZIconv::noChange("剩余时间(s)"))); return _logger; } void DisinfectionCtrlService::dumpDisinfectionLogsToCSV(DisinfectionContext& context) { #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION) static_assert(MAX_H2O2_SENSOR_NUM == 3, "MAX_H2O2_SENSOR_NUM must be 3"); auto& cx = context; string h2o2str[MAX_H2O2_SENSOR_NUM]; string tempstr[MAX_H2O2_SENSOR_NUM]; string humidstr[MAX_H2O2_SENSOR_NUM]; string satstr[MAX_H2O2_SENSOR_NUM]; for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { h2o2str[i] = fmt::format("{}", cx.h2o2[i]); tempstr[i] = fmt::format("{}", cx.temp[i]); humidstr[i] = fmt::format("{}", cx.humid[i]); satstr[i] = fmt::format("{}", cx.saturation[i]); } for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { if (cx.h2o2[i] < 0) h2o2str[i] = "N/A"; if (cx.temp[i] < 0) tempstr[i] = "N/A"; if (cx.humid[i] < 0) humidstr[i] = "N/A"; if (cx.saturation[i] < 0) satstr[i] = "N/A"; } auto ds = m_deviceIoControlService; float dvalue = 0; if (m_context.state_dvalue <= 0) { dvalue = 0; } else { dvalue = m_context.state_dvalue; } int remaintime = getEstimatedRemainingTimeS(); context.csvlogger->write( fmt::format(" {} ," " {} , {} , {} , {} ," " {} , {} , {} , {} ," " {} , {} , {} , {} ," " {} , {} , {} ," " {} , {} , {} , {} ," " {} , {} " "\n", getTime(), // h2o2str[0], tempstr[0], humidstr[0], satstr[0], // h2o2str[1], tempstr[1], humidstr[1], satstr[1], // h2o2str[2], tempstr[2], humidstr[2], satstr[2], // (int32_t)dvalue, (int32_t)m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, // ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), // m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime))); #endif } void DisinfectionCtrlService::pushDisinfectionPrinterTask(DisinfectionContext& context) { // shared_ptr task = make_shared(); auto ds = GET_SERVICE(DeviceStateService); auto dio = m_deviceIoControlService; task->start_tp = context.start_tp; task->complete_tp = context.complete_tp; task->stateSnapshotList = context.stateSnapshotList; task->disinfectantUsage = context.beforeDisinfectantVolume_g - context.afterDisinfectantVolume_g; task->disinfection_id = context.m_disinfectionID; task->usr = ds->getLoginUid(); task->targetLog = context.cfg_targetLoglevel; task->actualLog = context.state_now_loglevel; task->disinfectantVolume = dio->getDisinfectantVolume_g(); m_disinfectionPrinterService->pushPrintTask(task); } void DisinfectionCtrlService::log(DisinfectionContext& context) { #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION) auto& cx = context; auto ds = m_deviceIoControlService; float dvalue = 0; if (m_context.state_dvalue <= 0) { dvalue = 0; } else { dvalue = m_context.state_dvalue; } int remaintime = getEstimatedRemainingTimeS(); logger->info( fmt::format("{}," "s0({},{},{},{})," "s1({},{},{},{})," "s2({},{},{},{})," "min_h2o2:{},max_h2o2:{},max_hum:{},max_sa:{}," "dv:{},log:{},tlog:{}," "h:{},airB:{},airC:{},pump:{}," "g:{},remainS:{}" "\n", getTime(), // cx.h2o2[0], cx.temp[0], cx.humid[0], cx.saturation[0], // cx.h2o2[1], cx.temp[1], cx.humid[1], cx.saturation[1], // cx.h2o2[2], cx.temp[2], cx.humid[2], cx.saturation[2], // m_context.min_h2o2, m_context.max_h2o2, m_context.max_humid, m_context.max_saturation, // (int32_t)dvalue, m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, // ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), // m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime))); #endif } /******************************************************************************* * WORK * *******************************************************************************/ void DisinfectionCtrlService::initContext(DisinfectionContext& context, // int loglevel, // float injection_pump_speed, // float stoped_gs, // float continued_gs, // float stoped_satur, // float continued_satur, // float stoped_humi, // float continued_humi // ) { context.m_disinfectionID = createDisinfectionID(); context.pre_heat_time_s = m_dbService->getSettingVal("pre_heat_time_s"); context.stoped_gs = stoped_gs; context.continued_gs = continued_gs; context.stoped_satur = stoped_satur; context.continued_satur = continued_satur; context.stoped_humi = stoped_humi; context.continued_humi = continued_humi; context.injection_pump_speed = injection_pump_speed; context.injection_pump_speed_changed = true; if (g_in_test) { logger->warn("in test mode, pre_heat_time_s = 5"); context.pre_heat_time_s = 5; } logger->info("startDisinfection {} {}", m_context.cfg_targetLoglevel, m_context.m_disinfectionID); logger->info(" stoped_gs {}", context.stoped_gs); logger->info(" continued_gs {}", context.continued_gs); logger->info(" stoped_satur {}", context.stoped_satur); logger->info(" continued_satur {}", context.continued_satur); logger->info(" stoped_humi {}", context.stoped_humi); logger->info(" continued_humi {}", context.continued_humi); logger->info(" pre_heat_time_s {}", context.pre_heat_time_s); logger->info(""); context.state_remaintime = context.pre_heat_time_s + loglevel * 90 * 60; // 计算总的加热时间 m_disinfectionWorkState = 1; context.cfg_targetLoglevel = loglevel; context.state_now_loglevel = 0; m_context.state_dvalue = 0; m_context.m_state = kstate_preheat; m_context.start_tp = zsystem_clock().now(); m_context.start_steady_tp = zsteady_clock().now(); for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { m_context.h2o2[i] = 0; m_context.humid[i] = 0; m_context.temp[i] = 0; m_context.saturation[i] = 0; } m_context.min_h2o2 = 0; m_context.max_h2o2 = 0; m_context.max_humid = 0; m_context.max_saturation = 0; m_context.stateSnapshotList.clear(); m_context.afterDisinfectantVolume_g = 0; m_context.beforeDisinfectantVolume_g = m_deviceIoControlService->getDisinfectantVolume_g(); m_deviceIoControlService->warningLightCtrl(0, 0, 1, 0); m_deviceIoControlService->heartingPlate_setPower(true); context.csvlogger = createCSVLogger(context.m_disinfectionID); m_context.firstLog = true; } void DisinfectionCtrlService::finishDisinfection(DisinfectionContext& context) { context.state_remaintime = 0; logger->info("stop disinfection {}", context.m_disinfectionID); // sprayLiquidPump_close(); m_deviceIoControlService->sprayLiquidPump_close(); usleep(1000 * 1000); // airCompressor(false); m_deviceIoControlService->airCompressor_setState(false); usleep(1000 * 1000); // blower_setPower(false); m_deviceIoControlService->airBlower_setState(false); usleep(1000 * 1000); // heartingPlate_setPower(false); m_deviceIoControlService->heartingPlate_setPower(false); m_disinfectionWorkState = 3; m_deviceIoControlService->warningLightCtrl(0, 1, 0, 0); } void DisinfectionCtrlService::processPreheatState(DisinfectionContext& context) { int hasstarttime = zsteady_clock().elapsedTimeS(context.start_steady_tp); // logger->info("preheat {}", context.m_disinfectionID); if ((context.m_state == kstate_preheat && hasstarttime > m_context.pre_heat_time_s)) { logger->info("preheat finished {}", context.m_disinfectionID); m_deviceIoControlService->airBlower_setState(true); usleep(1000 * 1000); m_deviceIoControlService->airCompressor_setState(true); usleep(1000 * 1000); m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed); context.m_state = kstate_disinfection; } else { logger->info("{}: preheat {}", context.m_disinfectionID, m_context.pre_heat_time_s - hasstarttime); } } /** * @brief * 消毒中状态处理 */ void DisinfectionCtrlService::processDisinfectionState(DisinfectionContext& context) { /** * @brief 周期性计算剩余时间 */ /** * @brief 根据湿度启停喷雾 */ if (!m_context.state_is_disinfection_take_break) { /** * @brief 检查当前 */ float nowSatur = m_context.max_saturation; float nowh2o2 = m_context.max_h2o2; float humid = m_context.max_humid; if (m_context.injection_pump_speed_changed) { m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed); m_context.injection_pump_speed_changed = false; } // humid > m_context.stoped_satur if (nowSatur > m_context.stoped_satur || nowh2o2 > m_context.stoped_gs || humid > m_context.stoped_humi) { logger->info("stop sprayLiquid"); m_deviceIoControlService->sprayLiquidPump_close(); usleep(1000 * 1000); m_deviceIoControlService->airCompressor_setState(false); // m_context.sprayLiquidFlag = false; m_context.state_is_disinfection_take_break = true; } } else { float nowSatur = m_context.max_saturation; float nowh2o2 = m_context.max_h2o2; float humid = m_context.max_humid; // && humid < m_context.continued_satur if (nowSatur < m_context.continued_satur && nowh2o2 < m_context.continued_gs && humid < context.continued_humi) { logger->info("start sprayLiquid"); m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed); usleep(1000 * 1000); m_deviceIoControlService->airCompressor_setState(true); m_context.state_is_disinfection_take_break = false; } } } void DisinfectionCtrlService::processState_Preheat(DisinfectionContext& context) { /** * @brief 预热中 */ m_context.state_dvalue = 0; processPreheatState(m_context); } void DisinfectionCtrlService::processState_Disinfection(DisinfectionContext& context, bool& updatedval) { m_context.state_dvalue = getDisinfectionDValue(m_context.min_h2o2); if (zsteady_clock().elapsedTimeS(m_context.state_last_compute_dvalue_tp) > DVALUE_COMPUTEPERIOD_TIME_S) { m_context.state_last_compute_dvalue_tp = zsteady_clock().now(); m_context.state_now_loglevel = computeNowLogLevel(m_context); computeRemainTime(m_context); updatedval = true; } /** * @brief 消毒中 */ processDisinfectionState(m_context); // if (m_context.state_remaintime <= 0 && m_context.state_now_loglevel > (m_context.cfg_targetLoglevel + 0.01)) { m_context.state_remaintime = 0; m_context.state_now_loglevel = m_context.cfg_targetLoglevel + 0.01; logger->info("disinfection finished {},but waitting for h2o2 to safe", m_context.m_disinfectionID); m_deviceIoControlService->sprayLiquidPump_close(); usleep(1000 * 1000); m_deviceIoControlService->airCompressor_setState(false); usleep(1000 * 1000); m_deviceIoControlService->heartingPlate_setPower(false); m_context.m_state = kstate_degradation; } } void DisinfectionCtrlService::processState_Degradation(DisinfectionContext& context) { // 降解 m_context.state_dvalue = 0; logger->info("waitting for h2o2 concentration to safe value {}=>{}", m_context.min_h2o2, 1); if (m_context.min_h2o2 < 1) { logger->info("h2o2 concentration to safe value"); m_context.m_state = kstate_finished; } } void DisinfectionCtrlService::disinfectionLoop(bool& breakflag) { // logger->info("disinfection running {} {}s preheatFlag:{}", m_context.m_disinfectionID, m_context.state_remaintime, m_context.m_preheatFlag); ThisThread thisThread; disinfection_state_t enterstate; disinfection_state_t exitstate; bool statechanged = false; bool updatedval = false; enterstate = m_context.m_state; m_context.state_remaintime--; if (m_context.state_remaintime < 0) m_context.state_remaintime = 0; updateH2O2SensorData(m_context); /******************************************************************************* * 状态处理 * *******************************************************************************/ if (thisThread.getExitFlag()) { m_context.m_state = kstate_finished; } else if (m_context.m_state == kstate_preheat) { processState_Preheat(m_context); } else if (m_context.m_state == kstate_disinfection) { processState_Disinfection(m_context, updatedval); } else if (m_context.m_state == kstate_degradation) { processState_Degradation(m_context); } exitstate = m_context.m_state; if (exitstate != enterstate) { statechanged = true; } /******************************************************************************* * 打印日志 * *******************************************************************************/ if (exitstate == kstate_finished) { /** * @brief 消毒结束 */ breakflag = true; m_context.complete_tp = zsystem_clock().now(); m_context.afterDisinfectantVolume_g = m_deviceIoControlService->getDisinfectantVolume_g(); if (m_context.m_state != kstate_finished) { m_context.m_state = kstate_finished; } m_disinfectionWorkState = 0; takeStateSnapshot(m_context); dumpDisinfectionLogsToCSV(m_context); log(m_context); pushDisinfectionPrinterTask(m_context); finishDisinfection(m_context); m_context.csvlogger = nullptr; } else { if (updatedval) { log(m_context); } if (m_context.firstLog || statechanged || zsteady_clock().elapsedTimeS(m_context.state_lastlog_tp) > DUMP_LOG_PERIOD) { m_context.state_lastlog_tp = zsteady_clock().now(); takeStateSnapshot(m_context); dumpDisinfectionLogsToCSV(m_context); m_context.firstLog = false; } } } void DisinfectionCtrlService::changeDisinfectionParameter(int injection_pump_speed, // int stoped_gs, // int continued_gs, // int stoped_satur, // int continued_satur, // int stoped_humi, // int continued_humi) { lock_guard lock(lock_); m_context.injection_pump_speed = injection_pump_speed; m_context.stoped_gs = stoped_gs; m_context.continued_gs = continued_gs; m_context.stoped_satur = stoped_satur; m_context.continued_satur = continued_satur; m_context.stoped_humi = stoped_humi; m_context.continued_humi = continued_humi; m_context.injection_pump_speed_changed = true; logger->info("changeDisinfectionParameter {} {} {} {} {} {} {}", // injection_pump_speed, stoped_gs, continued_gs, stoped_satur, continued_satur, stoped_humi, continued_humi); } void DisinfectionCtrlService::startDisinfection(int loglevel, // int injection_pump_speed, // int stoped_gs, // int continued_gs, // int stoped_satur, // int continued_satur, // int stoped_humi, // int continued_humi // ) { lock_guard lock(lock_); if (m_disinfectionThread) stopDisinfection(); initContext(m_context, loglevel, injection_pump_speed, stoped_gs, continued_gs, stoped_satur, continued_satur, stoped_humi, continued_humi); m_disinfectionThread.reset(new Thread("m_disinfectionThread", [this]() { ThisThread thisThread; while (true) { thisThread.sleepForMs(1000); bool breakflag = false; disinfectionLoop(breakflag); if (breakflag) { break; } } })); // } void DisinfectionCtrlService::stopDisinfection() { lock_guard lock(lock_); if (m_disinfectionThread) { m_disinfectionThread->join(); m_disinfectionThread = nullptr; } } int DisinfectionCtrlService::getDisinfectionWorkState() { return m_context.m_state; } int32_t DisinfectionCtrlService::getEstimatedRemainingTimeS() { if (m_context.m_state == kstate_preheat) { return getPreHeatRaminTimeS(); } else if (m_context.m_state == kstate_disinfection) { if (m_context.state_dvalue > 0) { return m_context.state_remaintime; } else { return -1; } } else { return 0; } } int32_t DisinfectionCtrlService::getPreHeatRaminTimeS() { int32_t remaintime = 0; if (m_context.m_state == kstate_preheat) { remaintime = m_context.pre_heat_time_s - zsteady_clock().elapsedTimeS(m_context.start_steady_tp); if (remaintime < 0) { remaintime = 0; } return remaintime; } else { return 0; } } string DisinfectionCtrlService::getDisinfectionID() { return m_context.m_disinfectionID; } bool DisinfectionCtrlService::isPreheatState() { return m_context.m_state == kstate_preheat; } /******************************************************************************* * // 加液 * *******************************************************************************/ int DisinfectionCtrlService::getReplenishingFluidsWorkState() { return m_replenishingFluidsWorkState; } void DisinfectionCtrlService::startReplenishingFluids(int stopatg) { lock_guard lock(lock_); if (m_disinfectionThread) { m_disinfectionThread->join(); m_disinfectionThread = nullptr; } int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g(); int maxg = DISINFECTANT_BUCKET_CAPACITY; if (stopatg > maxg) { logger->warn("start Replenishing fail, stopatg {} > maxg {}", stopatg, maxg); stopatg = maxg; } if (nowvolume > stopatg) { logger->warn("start Replenishing fail, nowvolume {} > stopatg {}", nowvolume, stopatg); return; } m_disinfectionThread.reset(new Thread("disinfectionThread", [this, stopatg]() { ThisThread thisThread; m_deviceIoControlService->replenishingFluidsPump_open(); logger->info("startReplenishingFluids {}g", stopatg); while (!thisThread.getExitFlag()) { int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g(); logger->info("replenishingFluids {}g", nowvolume); if (nowvolume > stopatg) { break; } if (nowvolume > MAX_VOLUME) { logger->warn("replenishingFluids reach full level {}g", nowvolume); break; } thisThread.sleepForMs(1000); } logger->info("stopReplenishingFluids"); // replenishingFluidsPump_close(); m_deviceIoControlService->replenishingFluidsPump_close(); m_replenishingFluidsWorkState = 0; })); // m_replenishingFluidsWorkState = 1; logger->info("startReplenishingFluids "); } void DisinfectionCtrlService::stopReplenishingFluids() { lock_guard lock(lock_); if (m_disinfectionThread) { m_disinfectionThread->join(); m_disinfectionThread = nullptr; } logger->info("stopReplenishingFluids"); // replenishingFluidsPump_close(); m_deviceIoControlService->replenishingFluidsPump_close(); m_replenishingFluidsWorkState = 0; } /******************************************************************************* * 排液 * *******************************************************************************/ void DisinfectionCtrlService::startDraining() { lock_guard lock(lock_); if (m_disinfectionThread) { m_disinfectionThread->join(); m_disinfectionThread = nullptr; } m_disinfectionThread.reset(new Thread("disinfectionThread", [this]() { ThisThread thisThread; m_deviceIoControlService->drainingPump_open(); logger->info("startDraining "); auto startdrainingtime = zsteady_clock().now(); zsteady_tp volumeReachZeroTime; bool volumeReachZeroFlag = false; while (!thisThread.getExitFlag()) { int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g(); logger->info("draining remain {} g", nowvolume); if (!volumeReachZeroFlag && nowvolume == 0) { volumeReachZeroTime = zsteady_clock().now(); volumeReachZeroFlag = true; } if (volumeReachZeroFlag) { logger->info("stopDraining after {} s", 30 - zsteady_clock().elapsedTimeS(volumeReachZeroTime)); if (zsteady_clock().elapsedTimeS(volumeReachZeroTime) > 30) { break; } } thisThread.sleepForMs(1000); } logger->info("stopDraining"); // replenishingFluidsPump_close(); m_deviceIoControlService->drainingPump_close(); m_drainingWorkState = 0; })); logger->info("startDraining"); // drainingPump_open(); m_drainingWorkState = 1; } void DisinfectionCtrlService::stopDraining() { lock_guard lock(lock_); if (m_disinfectionThread) { m_disinfectionThread->join(); m_disinfectionThread = nullptr; } logger->info("stopDraining"); m_drainingWorkState = 0; // drainingPump_close(); m_deviceIoControlService->drainingPump_close(); } int DisinfectionCtrlService::getDrainingWorkState() { return m_drainingWorkState; } void DisinfectionCtrlService::updateH2O2SensorData(DisinfectionContext& context) { auto& cx = context; for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { cx.h2o2[i] = m_deviceIoControlService->H2O2Sensor_readH2O2PPM(i); } for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { cx.humid[i] = m_deviceIoControlService->H2O2Sensor_readHumid(i); } for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { cx.temp[i] = m_deviceIoControlService->H2O2Sensor_readTemperature(i); } for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { cx.saturation[i] = m_deviceIoControlService->H2O2Sensor_readSaturation(i); } cx.min_h2o2 = cx.h2o2[0]; cx.max_h2o2 = cx.h2o2[0]; cx.max_humid = cx.humid[0]; cx.max_saturation = cx.saturation[0]; for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { if (cx.h2o2[i] < cx.min_h2o2) { cx.min_h2o2 = cx.h2o2[i]; } if (cx.h2o2[i] > cx.max_h2o2) { cx.max_h2o2 = cx.h2o2[i]; } if (cx.humid[i] > cx.max_humid) { cx.max_humid = cx.humid[i]; } if (cx.saturation[i] > cx.max_saturation) { cx.max_saturation = cx.saturation[i]; } } if (cx.max_h2o2 < 0) cx.max_h2o2 = 0; if (cx.min_h2o2 < 0) cx.min_h2o2 = 0; if (cx.max_humid < 0) cx.max_humid = 0; if (cx.max_saturation < 0) cx.max_saturation = 0; } void DisinfectionCtrlService::takeStateSnapshot(DisinfectionContext& context) { auto& cx = context; shared_ptr snapshot = make_shared(); snapshot->time = zsystem_clock().now(); for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) { snapshot->h2o2[i] = cx.h2o2[i]; snapshot->humid[i] = cx.humid[i]; snapshot->temp[i] = cx.temp[i]; snapshot->saturation[i] = cx.saturation[i]; } snapshot->min_h2o2 = cx.min_h2o2; snapshot->max_h2o2 = cx.max_h2o2; snapshot->max_humid = cx.max_humid; snapshot->max_saturation = cx.max_saturation; snapshot->state = cx.m_state; snapshot->dloglevel = cx.state_now_loglevel; cx.stateSnapshotList.push_back(snapshot); }