You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

706 lines
26 KiB

#include "disinfection_ctl_service.hpp"
using namespace iflytop;
using namespace std;
/**
* @brief
* 流程
* 预热:
*
* 风机开
* 1s
* 空压机
* 1s
* 蠕动泵
* 1s
*
*
* 关蠕动泵
* 1s
* 关空压机
* 1s
* 关风机
*
*/
// #define PRE_HEAT_TIME (2)
// #define PRE_HEAT_TIME (5 * 60)
#define DVALUE_COMPUTEPERIOD_TIME_S (10.0)
#define MAX_VOLUME (5000)
namespace iflytop {
extern bool g_in_test;
}
DisinfectionCtrlService::DisinfectionCtrlService() {}
void DisinfectionCtrlService::initialize() {
GET_TO_SERVICE(m_zcanHost);
GET_TO_SERVICE(m_deviceIoControlService);
GET_TO_SERVICE(m_dbService);
GET_TO_SERVICE(m_disinfectionLogsManager);
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);
}
static string getTime() {
struct tm tm = {0};
time_t t = time(nullptr);
struct tm* tmp = 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);
}
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);
}
static bool zfeq(float a, float b, float eps = 0.01) {
if (fabs(a - b) < eps) {
return true;
}
return false;
}
float DisinfectionCtrlService::getDisinfectionDValue(float ppm) {
/**
* @brief
*
* D值的计算公式是根据美国竞品的数据记录计算得来的
*
* 浓度小于150时,y=-0.5269X+97.868
* 浓度大于150时,y=-0.1405X+40.369
*/
if (zfeq(ppm, 0)) {
return -1;
}
float dvalue = 0;
if (ppm < 150) {
dvalue = -0.5251 * ppm + 98.154;
} else if (ppm >= 150 && ppm < 240) {
dvalue = -0.125 * ppm + 38.913;
} else if (ppm >= 240) {
// 240 -> 8.913
// 1400 -> 2
// y = -0.00603x + 10.4472
dvalue = -0.00596 * ppm + 10.3434;
}
if (dvalue < 2) {
dvalue = 2;
}
return dvalue;
}
float DisinfectionCtrlService::computeNowLogLevel(DisinfectionContext& context) {
float dvalue = context.dvalue;
if (dvalue > 0) {
/**
* @brief 计算 m_nowLoglevel
*/
return context.m_nowLoglevel + DVALUE_COMPUTEPERIOD_TIME_S / (dvalue * 60);
}
return context.m_nowLoglevel;
}
void DisinfectionCtrlService::computeRemainTime(DisinfectionContext& context) {
/**
* @brief 计算Dvalue
*/
float dvalue = context.dvalue;
if (dvalue > 0) {
/**
* @brief 计算 m_nowLoglevel
*/
if (context.m_targetLoglevel >= context.m_nowLoglevel) {
context.m_remaintime = (context.m_targetLoglevel - context.m_nowLoglevel) * (dvalue * 60);
} else {
context.m_remaintime = 0;
}
} else {
//
}
logger->info("computeRemainTime minh2o2 {} dvalue {}", context.h2o2data.min_h2o2, dvalue);
}
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.m_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("");
// m_remaintime = loglevel * 20 * 60; // 计算总的加热时间
context.m_remaintime = context.pre_heat_time_s + loglevel * 90 * 60; // 计算总的加热时间
m_disinfectionWorkState = 1;
context.m_targetLoglevel = loglevel;
context.m_nowLoglevel = 0;
// m_context.m_preheatFlag = true;
m_context.dvalue = 0;
// m_context.stopedflag = false;
m_context.m_state = kpreheat;
m_context.m_starttp = zsteady_clock().now();
m_zcanHost->warning_light_ctrl_c1002(1, 0, 0, 1, 0);
m_deviceIoControlService->heartingPlate_setPower(true);
context.csvlogger = m_disinfectionLogsManager->createNewLogger(context.m_disinfectionID);
// zsteady_clock().elapsedTimeS(m_context.m_starttp), //
// sensors[0].h2o2, sensors[0].temp, sensors[0].humid, sensors[0].saturation, //
// sensors[1].h2o2, sensors[1].temp, sensors[1].humid, sensors[1].saturation, //
// sensors[2].h2o2, sensors[2].temp, sensors[2].humid, sensors[2].saturation, //
// m_context.dvalue, m_context.m_nowLoglevel, (int)m_context.m_targetLoglevel, //
// ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getRPM(), //
// ds->getPressureSensorData(1), ds->getPressureSensorData(2), ds->getPressureSensorData(3), ds->getPressureSensorData(4), //
// m_deviceIoControlService->getDisinfectantVolume_g(), //
// m_context.m_remaintime
context.csvlogger->write(
"Date," //
"Hydrogen peroxide volume(ppm),Temperature(C),Relative humidity(%RH),H2O H2O2 RS(%RS)," //
// "h2o22,temp2,humi2,saturation2," //
// "h2o23,temp3,humi3,saturation3," //
"Dvalue,Loglevel,Targetloglevel," //
"Heating,Blower,Compressor,Pump(g/min)," //
"Disinfectant Volume(g)," //
"Remaining time (s)\n" //
);
}
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("--:--:--");
}
}
void DisinfectionCtrlService::dumpDisinfectionLogsToCSV(DisinfectionContext& context) {
auto* sensors = &m_context.h2o2data.h2o2sensor_data[0];
auto ds = m_deviceIoControlService;
float dvalue = 0;
if (m_context.dvalue <= 0) {
dvalue = 0;
} else {
dvalue = m_context.dvalue;
}
int remaintime = getEstimatedRemainingTimeS();
context.csvlogger->write(
fmt::format("{}," //
"{},{},{},{}," //
// "{},{},{},{}," //
// "{},{},{},{}," //
"{:.2f},{:.2f},{:.2f}," //
"{},{},{},{}," //
// "{},{},{},{}," //
"{}," //
"{}\n" //
,
getTime(), //
sensors[0].h2o2, sensors[0].temp, sensors[0].humid, sensors[0].saturation, //
// sensors[1].h2o2, sensors[1].temp, sensors[1].humid, sensors[1].saturation, //
// sensors[2].h2o2, sensors[2].temp, sensors[2].humid, sensors[2].saturation, //
dvalue, m_context.m_nowLoglevel, m_context.m_targetLoglevel, //
ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), //
m_deviceIoControlService->getDisinfectantVolume_g(), //
formattimeS(remaintime)));
}
void DisinfectionCtrlService::finishDisinfection(DisinfectionContext& context) {
context.m_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_zcanHost->warning_light_ctrl_c1002(1, 0, 0, 0, 0);
context.csvlogger = nullptr;
}
void DisinfectionCtrlService::processPreheatState(DisinfectionContext& context) {
int hasstarttime = zsteady_clock().elapsedTimeS(context.m_starttp);
// logger->info("preheat {}", context.m_disinfectionID);
if ((context.m_state == kpreheat && hasstarttime > m_context.pre_heat_time_s)) {
logger->info("preheat finished {}", context.m_disinfectionID);
// blower_setPower(true);
m_deviceIoControlService->airBlower_setState(true);
usleep(1000 * 1000);
// airCompressor(true);
m_deviceIoControlService->airCompressor_setState(true);
usleep(1000 * 1000);
// sprayLiquidPump_open();
m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed);
context.m_state = kdisinfection;
// context.m_preheatFlag = false;
// context.sprayLiquidFlag = true;
} else {
logger->info("{}: preheat {}", context.m_disinfectionID, m_context.pre_heat_time_s - hasstarttime);
}
}
void DisinfectionCtrlService::dumpDisinfectionLogs(DisinfectionContext& context) {
// float h2o2_g = m_deviceIoControlService->getDisinfectantVolume_g();
auto* sensors = &m_context.h2o2data.h2o2sensor_data[0];
auto ds = m_deviceIoControlService;
logger->info(
"T:{}," //
"s1:({},{},{},{})," //
"s2:({},{},{},{})," //
"s3:({},{},{},{})," //
"D:{},log:({}:{})," //
"io:({},{},{},{})," //
"p:({},{},{},{})," //
"h2o2g:{}," //
"rt:{}" //
,
zsteady_clock().elapsedTimeS(m_context.m_starttp), //
sensors[0].h2o2, sensors[0].temp, sensors[0].humid, sensors[0].saturation, //
sensors[1].h2o2, sensors[1].temp, sensors[1].humid, sensors[1].saturation, //
sensors[2].h2o2, sensors[2].temp, sensors[2].humid, sensors[2].saturation, //
m_context.dvalue, m_context.m_nowLoglevel, (int)m_context.m_targetLoglevel, //
ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getRPM(), //
ds->getPressureSensorData(1), ds->getPressureSensorData(2), ds->getPressureSensorData(3), ds->getPressureSensorData(4), //
m_deviceIoControlService->getDisinfectantVolume_g(), //
getEstimatedRemainingTimeS());
}
/**
* @brief
* 消毒中状态处理
*/
void DisinfectionCtrlService::processDisinfectionState(DisinfectionContext& context) {
ZCHECK(context.m_state == kdisinfection || context.m_state == kdisinfection_take_a_break, "state error");
/**
* @brief 周期性计算剩余时间
*/
/**
* @brief 根据湿度启停喷雾
*/
if (m_context.m_state == kdisinfection) {
/**
* @brief 检查当前
*/
float nowSatur = m_context.h2o2data.max_saturation;
float nowh2o2 = m_context.h2o2data.max_h2o2;
float humid = m_context.h2o2data.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.m_state = kdisinfection_take_a_break;
}
} else {
float nowSatur = m_context.h2o2data.max_saturation;
float nowh2o2 = m_context.h2o2data.max_h2o2;
float humid = m_context.h2o2data.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.m_state = kdisinfection;
}
}
}
void DisinfectionCtrlService::disinfectionLoop(bool& breakflag) {
// logger->info("disinfection running {} {}s preheatFlag:{}", m_context.m_disinfectionID, m_context.m_remaintime, m_context.m_preheatFlag);
m_context.m_remaintime--;
bool forcelog = false;
if (m_context.m_remaintime < 0) {
m_context.m_remaintime = 0;
}
/**
* @brief 更新传感器信息
*/
m_deviceIoControlService->getAllSensorData(m_context.h2o2data);
/**
* @brief 计算D值
*/
m_context.dvalue = getDisinfectionDValue(m_context.h2o2data.min_h2o2);
if (zsteady_clock().elapsedTimeS(m_context.m_lastComputeDvalueTp) > DVALUE_COMPUTEPERIOD_TIME_S) {
m_context.m_lastComputeDvalueTp = zsteady_clock().now();
//
if (m_context.m_state == kdisinfection || m_context.m_state == kdisinfection_take_a_break) {
m_context.m_nowLoglevel = computeNowLogLevel(m_context);
computeRemainTime(m_context);
}
}
if (m_context.m_state == kpreheat) {
/**
* @brief 预热中
*/
processPreheatState(m_context);
} else if (m_context.m_state == kdisinfection || m_context.m_state == kdisinfection_take_a_break) {
/**
* @brief 消毒中
*/
processDisinfectionState(m_context);
//
if (m_context.m_remaintime <= 0 && m_context.m_nowLoglevel > (m_context.m_targetLoglevel + 0.01)) {
m_context.m_remaintime = 0;
m_context.m_nowLoglevel = m_context.m_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 = kwait_for_h2o2_down;
forcelog = true;
}
} else if (m_context.m_state == kwait_for_h2o2_down) {
/**
* @brief 等待h2o2浓度下降
*/
logger->info("waitting for h2o2 concentration to safe value {}=>{}", m_context.h2o2data.min_h2o2, 1);
if (m_context.h2o2data.min_h2o2 < 1) {
logger->info("h2o2 concentration to safe value");
breakflag = true;
forcelog = true;
m_context.m_state = kfinished;
}
} else {
ZCHECK(false, "state error");
}
if (forcelog || zsteady_clock().elapsedTimeS(m_context.m_lastlogTp) > DVALUE_COMPUTEPERIOD_TIME_S) {
m_context.m_lastlogTp = zsteady_clock().now();
dumpDisinfectionLogs(m_context);
dumpDisinfectionLogsToCSV(m_context);
}
}
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<recursive_mutex> lock(lock_);
// logger->info("changeInjectionPumpSpeed {}=>{}", m_context.injection_pump_speed, speed);
// m_context.injection_pump_speed = speed;
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<recursive_mutex> lock(lock_);
/**
* @TODO
* 检查当前环境湿度,湿度过大,不允许消毒
*/
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 (!thisThread.getExitFlag()) {
thisThread.sleepForMs(1000);
bool breakflag = false;
disinfectionLoop(breakflag);
if (breakflag) {
break;
}
}
//
finishDisinfection(m_context);
}));
//
}
int DisinfectionCtrlService::getDisinfectionWorkState() { return m_context.m_state; }
void DisinfectionCtrlService::stopDisinfection() {
lock_guard<recursive_mutex> lock(lock_);
if (m_disinfectionThread) {
m_disinfectionThread->join();
m_disinfectionThread = nullptr;
}
m_context.m_state = kfinished;
m_disinfectionWorkState = 0;
}
int32_t DisinfectionCtrlService::getEstimatedRemainingTimeS() {
lock_guard<recursive_mutex> lock(lock_);
if (m_context.m_state == kpreheat) {
return getPreHeatRaminTimeS();
} else if (m_context.m_state == kdisinfection || m_context.m_state == kdisinfection_take_a_break) {
if (m_context.dvalue > 0) {
return m_context.m_remaintime;
} else {
return -1;
}
} else {
return 0;
}
}
int32_t DisinfectionCtrlService::getPreHeatRaminTimeS() {
lock_guard<recursive_mutex> lock(lock_);
int32_t remaintime = 0;
if (m_context.m_state == kpreheat) {
remaintime = m_context.pre_heat_time_s - zsteady_clock().elapsedTimeS(m_context.m_starttp);
if (remaintime < 0) {
remaintime = 0;
}
return remaintime;
} else {
return 0;
}
}
string DisinfectionCtrlService::getDisinfectionID() {
lock_guard<recursive_mutex> lock(lock_);
return m_context.m_disinfectionID;
}
bool DisinfectionCtrlService::isPreheatState() {
lock_guard<recursive_mutex> lock(lock_);
return m_context.m_state == kpreheat;
}
int DisinfectionCtrlService::getReplenishingFluidsWorkState() { return m_replenishingFluidsWorkState; }
int DisinfectionCtrlService::getDrainingWorkState() { return m_drainingWorkState; }
/*******************************************************************************
* // 加液 *
*******************************************************************************/
/**
* @brief 开始加液
*
* @param stopatg
*/
void DisinfectionCtrlService::startReplenishingFluids(int stopatg) {
lock_guard<recursive_mutex> lock(lock_);
if (m_disinfectionThread) {
m_disinfectionThread->join();
m_disinfectionThread = nullptr;
}
int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g();
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 ");
}
/**
* @brief 停止加液
*
*/
void DisinfectionCtrlService::stopReplenishingFluids() {
lock_guard<recursive_mutex> lock(lock_);
if (m_disinfectionThread) {
m_disinfectionThread->join();
m_disinfectionThread = nullptr;
}
logger->info("stopReplenishingFluids");
// replenishingFluidsPump_close();
m_deviceIoControlService->replenishingFluidsPump_close();
m_replenishingFluidsWorkState = 0;
}
/*******************************************************************************
* 排液 *
*******************************************************************************/
/**
* @brief 开始排液
*
*/
void DisinfectionCtrlService::startDraining() {
lock_guard<recursive_mutex> 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;
}
/**
* @brief 停止排液体
*/
void DisinfectionCtrlService::stopDraining() {
lock_guard<recursive_mutex> lock(lock_);
if (m_disinfectionThread) {
m_disinfectionThread->join();
m_disinfectionThread = nullptr;
}
logger->info("stopDraining");
m_drainingWorkState = 0;
// drainingPump_close();
m_deviceIoControlService->drainingPump_close();
}