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.

792 lines
30 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. #include "disinfection_ctl_service.hpp"
  2. #include <cstring>
  3. #include <iostream>
  4. #include "configs/gconfig.hpp"
  5. #include "configs/project_setting.hpp"
  6. #include "iflytop/components/uart_printer/uart_printer.hpp"
  7. #include "iflytoplinuxsdk/src/iflytop/components/ziconv.hpp"
  8. #include "service/device_state_service.hpp"
  9. // #define PROJECT_TYPE_LARGE_SPACE_DISINFECTION 1 // 大空间
  10. // #define PROJECT_TYPE_SMALL_SPACE_DISINFECTION 1 // 小空间
  11. using namespace iflytop;
  12. using namespace std;
  13. #define DVALUE_COMPUTEPERIOD_TIME_S (10.0)
  14. #define MAX_VOLUME (5000)
  15. namespace iflytop {
  16. extern bool g_in_test;
  17. }
  18. static string formattimeS(int sec) {
  19. if (sec >= 0) {
  20. return fmt::format("{:0>2}:{:0>2}:{:0>2}", sec / 3600, sec % 3600 / 60, sec % 60);
  21. } else {
  22. return fmt::format("--:--:--");
  23. }
  24. }
  25. static string getTime() {
  26. struct tm tm = {0};
  27. time_t t = time(nullptr);
  28. localtime_r(&t, &tm);
  29. return fmt::format("{:0>4}-{:0>2}-{:0>2} {:0>2}:{:0>2}:{:0>2}", tm.tm_year + 1900, //
  30. tm.tm_mon + 1, //
  31. tm.tm_mday, //
  32. tm.tm_hour, //
  33. tm.tm_min, tm.tm_sec);
  34. }
  35. static bool zfeq(float a, float b, float eps = 0.01) {
  36. if (fabs(a - b) < eps) {
  37. return true;
  38. }
  39. return false;
  40. }
  41. DisinfectionCtrlService::DisinfectionCtrlService() {}
  42. void DisinfectionCtrlService::initialize() {
  43. GET_TO_SERVICE(m_deviceIoControlService);
  44. GET_TO_SERVICE(m_dbService);
  45. GET_TO_SERVICE(m_disinfectionLogsManager);
  46. GET_TO_SERVICE(m_disinfectionPrinterService);
  47. m_deviceIoControlService->drainingPump_close();
  48. m_deviceIoControlService->replenishingFluidsPump_close();
  49. m_deviceIoControlService->sprayLiquidPump_close();
  50. m_deviceIoControlService->heartingPlate_setPower(false);
  51. m_deviceIoControlService->airBlower_setState(false);
  52. m_deviceIoControlService->airCompressor_setState(false);
  53. m_dvalueComputer.initialize();
  54. }
  55. string DisinfectionCtrlService::createDisinfectionID() {
  56. struct tm tm = {0};
  57. time_t t = time(nullptr);
  58. if (t == -1) {
  59. logger->error("time(nullptr) failed");
  60. exit(-1);
  61. }
  62. struct tm* tmp = localtime_r(&t, &tm);
  63. if (!tmp) {
  64. logger->error("localtime_r failed");
  65. exit(-1);
  66. }
  67. // tm = *utctime::tm_increment_hour(&tm, 8);
  68. // logger->info("trace sendmsg_startCapture {}:{}", __FILE__, __LINE__);
  69. return fmt::format("{:0>4}-{:0>2}{:0>2}-{:0>2}{:0>2}{:0>2}", tm.tm_year + 1900, //
  70. tm.tm_mon + 1, //
  71. tm.tm_mday, //
  72. tm.tm_hour, //
  73. tm.tm_min, tm.tm_sec);
  74. }
  75. float DisinfectionCtrlService::getDisinfectionDValue(float ppm) { //
  76. return m_dvalueComputer.computeDValue(ppm);
  77. }
  78. float DisinfectionCtrlService::computeNowLogLevel(DisinfectionContext& context) {
  79. float dvalue = context.state_dvalue;
  80. if (dvalue > 0) {
  81. /**
  82. * @brief state_now_loglevel
  83. */
  84. return context.state_now_loglevel + DVALUE_COMPUTEPERIOD_TIME_S / (dvalue * 60);
  85. }
  86. return context.state_now_loglevel;
  87. }
  88. void DisinfectionCtrlService::computeRemainTime(DisinfectionContext& context) {
  89. /**
  90. * @brief Dvalue
  91. */
  92. float dvalue = context.state_dvalue;
  93. if (dvalue > 0) {
  94. /**
  95. * @brief state_now_loglevel
  96. */
  97. if (context.cfg_targetLoglevel >= context.state_now_loglevel) {
  98. context.state_remaintime = (context.cfg_targetLoglevel - context.state_now_loglevel) * (dvalue * 60);
  99. } else {
  100. context.state_remaintime = 0;
  101. }
  102. } else {
  103. //
  104. }
  105. logger->info("computeRemainTime minh2o2 {} dvalue {}", context.min_h2o2, dvalue);
  106. }
  107. shared_ptr<DisinfectionLogger> DisinfectionCtrlService::createCSVLogger(string log_file_name) {
  108. shared_ptr<DisinfectionLogger> _logger = m_disinfectionLogsManager->createNewLogger(log_file_name);
  109. _logger->write(
  110. fmt::format("{},"
  111. "{},{},{},{},"
  112. "{},{},{},{},"
  113. "{},{},{},{},"
  114. "{},{},{},"
  115. "{},{},{},{},"
  116. "{},{}"
  117. "\n",
  118. ZIconv::noChange("时间"), //
  119. ZIconv::noChange("仓内-气化过氧化氢浓度"), ZIconv::noChange("仓内-温度"), ZIconv::noChange("仓内-相对湿度"), ZIconv::noChange("仓内-相对饱和度"), //
  120. ZIconv::noChange("环境1-气化过氧化氢浓度"), ZIconv::noChange("环境1-温度"), ZIconv::noChange("环境1-相对湿度"), ZIconv::noChange("环境1-相对饱和度"), //
  121. ZIconv::noChange("环境2-气化过氧化氢浓度"), ZIconv::noChange("环境2-温度"), ZIconv::noChange("环境2-相对湿度"), ZIconv::noChange("环境2-相对饱和度"), //
  122. ZIconv::noChange("D值"), ZIconv::noChange("当前LOG"), ZIconv::noChange("目标LOG"), //
  123. ZIconv::noChange("加热器电源"), ZIconv::noChange("风机电源"), ZIconv::noChange("空压机电源"), ZIconv::noChange("喷液泵(g/min)"), //
  124. ZIconv::noChange("消毒剩余剂量(g)"), ZIconv::noChange("剩余时间(s)")));
  125. return _logger;
  126. }
  127. void DisinfectionCtrlService::dumpDisinfectionLogsToCSV(DisinfectionContext& context) {
  128. #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION)
  129. static_assert(MAX_H2O2_SENSOR_NUM == 3, "MAX_H2O2_SENSOR_NUM must be 3");
  130. auto& cx = context;
  131. string h2o2str[MAX_H2O2_SENSOR_NUM];
  132. string tempstr[MAX_H2O2_SENSOR_NUM];
  133. string humidstr[MAX_H2O2_SENSOR_NUM];
  134. string satstr[MAX_H2O2_SENSOR_NUM];
  135. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  136. h2o2str[i] = fmt::format("{}", cx.h2o2[i]);
  137. tempstr[i] = fmt::format("{}", cx.temp[i]);
  138. humidstr[i] = fmt::format("{}", cx.humid[i]);
  139. satstr[i] = fmt::format("{}", cx.saturation[i]);
  140. }
  141. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  142. if (cx.h2o2[i] < 0) h2o2str[i] = "N/A";
  143. if (cx.temp[i] < 0) tempstr[i] = "N/A";
  144. if (cx.humid[i] < 0) humidstr[i] = "N/A";
  145. if (cx.saturation[i] < 0) satstr[i] = "N/A";
  146. }
  147. auto ds = m_deviceIoControlService;
  148. float dvalue = 0;
  149. if (m_context.state_dvalue <= 0) {
  150. dvalue = 0;
  151. } else {
  152. dvalue = m_context.state_dvalue;
  153. }
  154. int remaintime = getEstimatedRemainingTimeS();
  155. context.csvlogger->write(
  156. fmt::format("{},"
  157. "{},{},{},{},"
  158. "{},{},{},{},"
  159. "{},{},{},{},"
  160. "{},{},{},"
  161. "{},{},{},{},"
  162. "{},{}"
  163. "\n",
  164. getTime(), //
  165. h2o2str[0], tempstr[0], humidstr[0], satstr[0], //
  166. h2o2str[1], tempstr[1], humidstr[1], satstr[1], //
  167. h2o2str[2], tempstr[2], humidstr[2], satstr[2], //
  168. (int32_t)dvalue, (int32_t)m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, //
  169. ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), //
  170. m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime)));
  171. #endif
  172. }
  173. void DisinfectionCtrlService::pushDisinfectionPrinterTask(DisinfectionContext& context) { //
  174. shared_ptr<DisinfectionPrinterTask> task = make_shared<DisinfectionPrinterTask>();
  175. auto ds = GET_SERVICE(DeviceStateService);
  176. auto dio = m_deviceIoControlService;
  177. task->start_tp = context.start_tp;
  178. task->complete_tp = context.complete_tp;
  179. task->stateSnapshotList = context.stateSnapshotList;
  180. task->disinfectantUsage = context.beforeDisinfectantVolume_g - context.afterDisinfectantVolume_g;
  181. task->disinfection_id = context.m_disinfectionID;
  182. task->usr = ds->getLoginUid();
  183. task->targetLog = context.cfg_targetLoglevel;
  184. task->actualLog = context.state_now_loglevel;
  185. task->disinfectantVolume = dio->getDisinfectantVolume_g();
  186. m_disinfectionPrinterService->pushPrintTask(task);
  187. }
  188. void DisinfectionCtrlService::log(DisinfectionContext& context) {
  189. #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION)
  190. auto& cx = context;
  191. auto ds = m_deviceIoControlService;
  192. float dvalue = 0;
  193. if (m_context.state_dvalue <= 0) {
  194. dvalue = 0;
  195. } else {
  196. dvalue = m_context.state_dvalue;
  197. }
  198. int remaintime = getEstimatedRemainingTimeS();
  199. logger->info(
  200. fmt::format("{},"
  201. "s0({},{},{},{}),"
  202. "s1({},{},{},{}),"
  203. "s2({},{},{},{}),"
  204. "min_h2o2:{},max_h2o2:{},max_hum:{},max_sa:{},"
  205. "dv:{},log:{},tlog:{},"
  206. "h:{},airB:{},airC:{},pump:{},"
  207. "g:{},remainS:{}"
  208. "\n",
  209. getTime(), //
  210. cx.h2o2[0], cx.temp[0], cx.humid[0], cx.saturation[0], //
  211. cx.h2o2[1], cx.temp[1], cx.humid[1], cx.saturation[1], //
  212. cx.h2o2[2], cx.temp[2], cx.humid[2], cx.saturation[2], //
  213. m_context.max_h2o2, m_context.min_h2o2, m_context.max_humid, m_context.max_saturation, //
  214. (int32_t)dvalue, (int32_t)m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, //
  215. ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), //
  216. m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime)));
  217. #endif
  218. }
  219. /*******************************************************************************
  220. * WORK *
  221. *******************************************************************************/
  222. void DisinfectionCtrlService::initContext(DisinfectionContext& context, //
  223. int loglevel, //
  224. float injection_pump_speed, //
  225. float stoped_gs, //
  226. float continued_gs, //
  227. float stoped_satur, //
  228. float continued_satur, //
  229. float stoped_humi, //
  230. float continued_humi //
  231. ) {
  232. context.m_disinfectionID = createDisinfectionID();
  233. context.pre_heat_time_s = m_dbService->getSettingVal("pre_heat_time_s");
  234. context.stoped_gs = stoped_gs;
  235. context.continued_gs = continued_gs;
  236. context.stoped_satur = stoped_satur;
  237. context.continued_satur = continued_satur;
  238. context.stoped_humi = stoped_humi;
  239. context.continued_humi = continued_humi;
  240. context.injection_pump_speed = injection_pump_speed;
  241. context.injection_pump_speed_changed = true;
  242. if (g_in_test) {
  243. logger->warn("in test mode, pre_heat_time_s = 5");
  244. context.pre_heat_time_s = 5;
  245. }
  246. logger->info("startDisinfection {} {}", m_context.cfg_targetLoglevel, m_context.m_disinfectionID);
  247. logger->info(" stoped_gs {}", context.stoped_gs);
  248. logger->info(" continued_gs {}", context.continued_gs);
  249. logger->info(" stoped_satur {}", context.stoped_satur);
  250. logger->info(" continued_satur {}", context.continued_satur);
  251. logger->info(" stoped_humi {}", context.stoped_humi);
  252. logger->info(" continued_humi {}", context.continued_humi);
  253. logger->info(" pre_heat_time_s {}", context.pre_heat_time_s);
  254. logger->info("");
  255. context.state_remaintime = context.pre_heat_time_s + loglevel * 90 * 60; // 计算总的加热时间
  256. m_disinfectionWorkState = 1;
  257. context.cfg_targetLoglevel = loglevel;
  258. context.state_now_loglevel = 0;
  259. m_context.state_dvalue = 0;
  260. m_context.m_state = kstate_preheat;
  261. m_context.start_tp = zsystem_clock().now();
  262. m_context.start_steady_tp = zsteady_clock().now();
  263. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  264. m_context.h2o2[i] = 0;
  265. m_context.humid[i] = 0;
  266. m_context.temp[i] = 0;
  267. m_context.saturation[i] = 0;
  268. }
  269. m_context.min_h2o2 = 0;
  270. m_context.max_h2o2 = 0;
  271. m_context.max_humid = 0;
  272. m_context.max_saturation = 0;
  273. m_context.stateSnapshotList.clear();
  274. m_context.afterDisinfectantVolume_g = 0;
  275. m_context.beforeDisinfectantVolume_g = m_deviceIoControlService->getDisinfectantVolume_g();
  276. m_deviceIoControlService->warningLightCtrl(0, 0, 1, 0);
  277. m_deviceIoControlService->heartingPlate_setPower(true);
  278. context.csvlogger = createCSVLogger(context.m_disinfectionID);
  279. }
  280. void DisinfectionCtrlService::finishDisinfection(DisinfectionContext& context) {
  281. context.state_remaintime = 0;
  282. logger->info("stop disinfection {}", context.m_disinfectionID);
  283. // sprayLiquidPump_close();
  284. m_deviceIoControlService->sprayLiquidPump_close();
  285. usleep(1000 * 1000);
  286. // airCompressor(false);
  287. m_deviceIoControlService->airCompressor_setState(false);
  288. usleep(1000 * 1000);
  289. // blower_setPower(false);
  290. m_deviceIoControlService->airBlower_setState(false);
  291. usleep(1000 * 1000);
  292. // heartingPlate_setPower(false);
  293. m_deviceIoControlService->heartingPlate_setPower(false);
  294. m_disinfectionWorkState = 3;
  295. m_deviceIoControlService->warningLightCtrl(0, 1, 0, 0);
  296. }
  297. void DisinfectionCtrlService::processPreheatState(DisinfectionContext& context) {
  298. int hasstarttime = zsteady_clock().elapsedTimeS(context.start_steady_tp);
  299. // logger->info("preheat {}", context.m_disinfectionID);
  300. if ((context.m_state == kstate_preheat && hasstarttime > m_context.pre_heat_time_s)) {
  301. logger->info("preheat finished {}", context.m_disinfectionID);
  302. m_deviceIoControlService->airBlower_setState(true);
  303. usleep(1000 * 1000);
  304. m_deviceIoControlService->airCompressor_setState(true);
  305. usleep(1000 * 1000);
  306. m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed);
  307. context.m_state = kstate_disinfection;
  308. } else {
  309. logger->info("{}: preheat {}", context.m_disinfectionID, m_context.pre_heat_time_s - hasstarttime);
  310. }
  311. }
  312. /**
  313. * @brief
  314. *
  315. */
  316. void DisinfectionCtrlService::processDisinfectionState(DisinfectionContext& context) {
  317. /**
  318. * @brief
  319. */
  320. /**
  321. * @brief 湿
  322. */
  323. if (!m_context.state_is_disinfection_take_break) {
  324. /**
  325. * @brief
  326. */
  327. float nowSatur = m_context.max_saturation;
  328. float nowh2o2 = m_context.max_h2o2;
  329. float humid = m_context.max_humid;
  330. if (m_context.injection_pump_speed_changed) {
  331. m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed);
  332. m_context.injection_pump_speed_changed = false;
  333. }
  334. // humid > m_context.stoped_satur
  335. if (nowSatur > m_context.stoped_satur || nowh2o2 > m_context.stoped_gs || humid > m_context.stoped_humi) {
  336. logger->info("stop sprayLiquid");
  337. m_deviceIoControlService->sprayLiquidPump_close();
  338. usleep(1000 * 1000);
  339. m_deviceIoControlService->airCompressor_setState(false);
  340. // m_context.sprayLiquidFlag = false;
  341. m_context.state_is_disinfection_take_break = true;
  342. }
  343. } else {
  344. float nowSatur = m_context.max_saturation;
  345. float nowh2o2 = m_context.max_h2o2;
  346. float humid = m_context.max_humid;
  347. // && humid < m_context.continued_satur
  348. if (nowSatur < m_context.continued_satur && nowh2o2 < m_context.continued_gs && humid < context.continued_humi) {
  349. logger->info("start sprayLiquid");
  350. m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed);
  351. usleep(1000 * 1000);
  352. m_deviceIoControlService->airCompressor_setState(true);
  353. m_context.state_is_disinfection_take_break = false;
  354. }
  355. }
  356. }
  357. void DisinfectionCtrlService::disinfectionLoop(bool& breakflag) {
  358. // logger->info("disinfection running {} {}s preheatFlag:{}", m_context.m_disinfectionID, m_context.state_remaintime, m_context.m_preheatFlag);
  359. ThisThread thisThread;
  360. m_context.state_remaintime--;
  361. bool forcelog = false;
  362. if (m_context.state_remaintime < 0) {
  363. m_context.state_remaintime = 0;
  364. }
  365. /**
  366. * @brief
  367. */
  368. updateH2O2SensorData(m_context);
  369. /**
  370. * @brief D值
  371. */
  372. m_context.state_dvalue = getDisinfectionDValue(m_context.min_h2o2);
  373. if (zsteady_clock().elapsedTimeS(m_context.state_last_compute_dvalue_tp) > DVALUE_COMPUTEPERIOD_TIME_S) {
  374. m_context.state_last_compute_dvalue_tp = zsteady_clock().now();
  375. //
  376. if (m_context.m_state == kstate_disinfection) {
  377. m_context.state_now_loglevel = computeNowLogLevel(m_context);
  378. computeRemainTime(m_context);
  379. }
  380. }
  381. if (m_context.m_state == kstate_preheat) {
  382. /**
  383. * @brief
  384. */
  385. processPreheatState(m_context);
  386. } else if (m_context.m_state == kstate_disinfection) {
  387. /**
  388. * @brief
  389. */
  390. processDisinfectionState(m_context);
  391. //
  392. if (m_context.state_remaintime <= 0 && m_context.state_now_loglevel > (m_context.cfg_targetLoglevel + 0.01)) {
  393. m_context.state_remaintime = 0;
  394. m_context.state_now_loglevel = m_context.cfg_targetLoglevel + 0.01;
  395. logger->info("disinfection finished {},but waitting for h2o2 to safe", m_context.m_disinfectionID);
  396. m_deviceIoControlService->sprayLiquidPump_close();
  397. usleep(1000 * 1000);
  398. m_deviceIoControlService->airCompressor_setState(false);
  399. usleep(1000 * 1000);
  400. m_deviceIoControlService->heartingPlate_setPower(false);
  401. m_context.m_state = kstate_degradation;
  402. forcelog = true;
  403. }
  404. } else if (m_context.m_state == kstate_degradation) {
  405. /**
  406. * @brief h2o2浓度下降
  407. */
  408. logger->info("waitting for h2o2 concentration to safe value {}=>{}", m_context.min_h2o2, 1);
  409. if (m_context.min_h2o2 < 1) {
  410. logger->info("h2o2 concentration to safe value");
  411. breakflag = true;
  412. m_context.m_state = kstate_finished;
  413. }
  414. }
  415. if (m_context.m_state != kstate_finished && thisThread.getExitFlag()) {
  416. breakflag = true;
  417. }
  418. if (breakflag) {
  419. m_context.complete_tp = zsystem_clock().now();
  420. m_context.afterDisinfectantVolume_g = m_deviceIoControlService->getDisinfectantVolume_g();
  421. if (m_context.m_state != kstate_finished) {
  422. m_context.m_state = kstate_finished;
  423. }
  424. m_disinfectionWorkState = 0;
  425. takeStateSnapshot(m_context);
  426. dumpDisinfectionLogsToCSV(m_context);
  427. log(m_context);
  428. pushDisinfectionPrinterTask(m_context);
  429. finishDisinfection(m_context);
  430. m_context.csvlogger = nullptr;
  431. } else {
  432. if (forcelog || zsteady_clock().elapsedTimeS(m_context.state_lastlog_tp) > DVALUE_COMPUTEPERIOD_TIME_S) {
  433. m_context.state_lastlog_tp = zsteady_clock().now();
  434. takeStateSnapshot(m_context);
  435. dumpDisinfectionLogsToCSV(m_context);
  436. log(m_context);
  437. }
  438. }
  439. }
  440. void DisinfectionCtrlService::changeDisinfectionParameter(int injection_pump_speed, //
  441. int stoped_gs, //
  442. int continued_gs, //
  443. int stoped_satur, //
  444. int continued_satur, //
  445. int stoped_humi, //
  446. int continued_humi) {
  447. lock_guard<recursive_mutex> lock(lock_);
  448. m_context.injection_pump_speed = injection_pump_speed;
  449. m_context.stoped_gs = stoped_gs;
  450. m_context.continued_gs = continued_gs;
  451. m_context.stoped_satur = stoped_satur;
  452. m_context.continued_satur = continued_satur;
  453. m_context.stoped_humi = stoped_humi;
  454. m_context.continued_humi = continued_humi;
  455. m_context.injection_pump_speed_changed = true;
  456. logger->info("changeDisinfectionParameter {} {} {} {} {} {} {}", //
  457. injection_pump_speed, stoped_gs, continued_gs, stoped_satur, continued_satur, stoped_humi, continued_humi);
  458. }
  459. void DisinfectionCtrlService::startDisinfection(int loglevel, //
  460. int injection_pump_speed, //
  461. int stoped_gs, //
  462. int continued_gs, //
  463. int stoped_satur, //
  464. int continued_satur, //
  465. int stoped_humi, //
  466. int continued_humi //
  467. ) {
  468. lock_guard<recursive_mutex> lock(lock_);
  469. if (m_disinfectionThread) stopDisinfection();
  470. initContext(m_context, loglevel, injection_pump_speed, stoped_gs, continued_gs, stoped_satur, continued_satur, stoped_humi, continued_humi);
  471. m_disinfectionThread.reset(new Thread("m_disinfectionThread", [this]() {
  472. ThisThread thisThread;
  473. while (true) {
  474. thisThread.sleepForMs(1000);
  475. bool breakflag = false;
  476. disinfectionLoop(breakflag);
  477. if (breakflag) {
  478. break;
  479. }
  480. }
  481. }));
  482. //
  483. }
  484. void DisinfectionCtrlService::stopDisinfection() {
  485. lock_guard<recursive_mutex> lock(lock_);
  486. if (m_disinfectionThread) {
  487. m_disinfectionThread->join();
  488. m_disinfectionThread = nullptr;
  489. }
  490. }
  491. int DisinfectionCtrlService::getDisinfectionWorkState() { return m_context.m_state; }
  492. int32_t DisinfectionCtrlService::getEstimatedRemainingTimeS() {
  493. if (m_context.m_state == kstate_preheat) {
  494. return getPreHeatRaminTimeS();
  495. } else if (m_context.m_state == kstate_disinfection) {
  496. if (m_context.state_dvalue > 0) {
  497. return m_context.state_remaintime;
  498. } else {
  499. return -1;
  500. }
  501. } else {
  502. return 0;
  503. }
  504. }
  505. int32_t DisinfectionCtrlService::getPreHeatRaminTimeS() {
  506. int32_t remaintime = 0;
  507. if (m_context.m_state == kstate_preheat) {
  508. remaintime = m_context.pre_heat_time_s - zsteady_clock().elapsedTimeS(m_context.start_steady_tp);
  509. if (remaintime < 0) {
  510. remaintime = 0;
  511. }
  512. return remaintime;
  513. } else {
  514. return 0;
  515. }
  516. }
  517. string DisinfectionCtrlService::getDisinfectionID() {
  518. return m_context.m_disinfectionID;
  519. }
  520. bool DisinfectionCtrlService::isPreheatState() {
  521. return m_context.m_state == kstate_preheat;
  522. }
  523. /*******************************************************************************
  524. * // 加液 *
  525. *******************************************************************************/
  526. int DisinfectionCtrlService::getReplenishingFluidsWorkState() { return m_replenishingFluidsWorkState; }
  527. void DisinfectionCtrlService::startReplenishingFluids(int stopatg) {
  528. lock_guard<recursive_mutex> lock(lock_);
  529. if (m_disinfectionThread) {
  530. m_disinfectionThread->join();
  531. m_disinfectionThread = nullptr;
  532. }
  533. int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g();
  534. int maxg = DISINFECTANT_BUCKET_CAPACITY;
  535. if (stopatg > maxg) {
  536. logger->warn("start Replenishing fail, stopatg {} > maxg {}", stopatg, maxg);
  537. stopatg = maxg;
  538. }
  539. if (nowvolume > stopatg) {
  540. logger->warn("start Replenishing fail, nowvolume {} > stopatg {}", nowvolume, stopatg);
  541. return;
  542. }
  543. m_disinfectionThread.reset(new Thread("disinfectionThread", [this, stopatg]() {
  544. ThisThread thisThread;
  545. m_deviceIoControlService->replenishingFluidsPump_open();
  546. logger->info("startReplenishingFluids {}g", stopatg);
  547. while (!thisThread.getExitFlag()) {
  548. int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g();
  549. logger->info("replenishingFluids {}g", nowvolume);
  550. if (nowvolume > stopatg) {
  551. break;
  552. }
  553. if (nowvolume > MAX_VOLUME) {
  554. logger->warn("replenishingFluids reach full level {}g", nowvolume);
  555. break;
  556. }
  557. thisThread.sleepForMs(1000);
  558. }
  559. logger->info("stopReplenishingFluids");
  560. // replenishingFluidsPump_close();
  561. m_deviceIoControlService->replenishingFluidsPump_close();
  562. m_replenishingFluidsWorkState = 0;
  563. }));
  564. //
  565. m_replenishingFluidsWorkState = 1;
  566. logger->info("startReplenishingFluids ");
  567. }
  568. void DisinfectionCtrlService::stopReplenishingFluids() {
  569. lock_guard<recursive_mutex> lock(lock_);
  570. if (m_disinfectionThread) {
  571. m_disinfectionThread->join();
  572. m_disinfectionThread = nullptr;
  573. }
  574. logger->info("stopReplenishingFluids");
  575. // replenishingFluidsPump_close();
  576. m_deviceIoControlService->replenishingFluidsPump_close();
  577. m_replenishingFluidsWorkState = 0;
  578. }
  579. /*******************************************************************************
  580. * *
  581. *******************************************************************************/
  582. void DisinfectionCtrlService::startDraining() {
  583. lock_guard<recursive_mutex> lock(lock_);
  584. if (m_disinfectionThread) {
  585. m_disinfectionThread->join();
  586. m_disinfectionThread = nullptr;
  587. }
  588. m_disinfectionThread.reset(new Thread("disinfectionThread", [this]() {
  589. ThisThread thisThread;
  590. m_deviceIoControlService->drainingPump_open();
  591. logger->info("startDraining ");
  592. auto startdrainingtime = zsteady_clock().now();
  593. zsteady_tp volumeReachZeroTime;
  594. bool volumeReachZeroFlag = false;
  595. while (!thisThread.getExitFlag()) {
  596. int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g();
  597. logger->info("draining remain {} g", nowvolume);
  598. if (!volumeReachZeroFlag && nowvolume == 0) {
  599. volumeReachZeroTime = zsteady_clock().now();
  600. volumeReachZeroFlag = true;
  601. }
  602. if (volumeReachZeroFlag) {
  603. logger->info("stopDraining after {} s", 30 - zsteady_clock().elapsedTimeS(volumeReachZeroTime));
  604. if (zsteady_clock().elapsedTimeS(volumeReachZeroTime) > 30) {
  605. break;
  606. }
  607. }
  608. thisThread.sleepForMs(1000);
  609. }
  610. logger->info("stopDraining");
  611. // replenishingFluidsPump_close();
  612. m_deviceIoControlService->drainingPump_close();
  613. m_drainingWorkState = 0;
  614. }));
  615. logger->info("startDraining");
  616. // drainingPump_open();
  617. m_drainingWorkState = 1;
  618. }
  619. void DisinfectionCtrlService::stopDraining() {
  620. lock_guard<recursive_mutex> lock(lock_);
  621. if (m_disinfectionThread) {
  622. m_disinfectionThread->join();
  623. m_disinfectionThread = nullptr;
  624. }
  625. logger->info("stopDraining");
  626. m_drainingWorkState = 0;
  627. // drainingPump_close();
  628. m_deviceIoControlService->drainingPump_close();
  629. }
  630. int DisinfectionCtrlService::getDrainingWorkState() { return m_drainingWorkState; }
  631. void DisinfectionCtrlService::updateH2O2SensorData(DisinfectionContext& context) {
  632. auto& cx = context;
  633. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  634. cx.h2o2[i] = m_deviceIoControlService->H2O2Sensor_readH2O2PPM(i);
  635. }
  636. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  637. cx.humid[i] = m_deviceIoControlService->H2O2Sensor_readHumid(i);
  638. }
  639. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  640. cx.temp[i] = m_deviceIoControlService->H2O2Sensor_readTemperature(i);
  641. }
  642. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  643. cx.saturation[i] = m_deviceIoControlService->H2O2Sensor_readSaturation(i);
  644. }
  645. cx.min_h2o2 = cx.h2o2[0];
  646. cx.max_h2o2 = cx.h2o2[0];
  647. cx.max_humid = cx.humid[0];
  648. cx.max_saturation = cx.saturation[0];
  649. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  650. if (cx.h2o2[i] < cx.min_h2o2) {
  651. cx.min_h2o2 = cx.h2o2[i];
  652. }
  653. if (cx.h2o2[i] > cx.max_h2o2) {
  654. cx.max_h2o2 = cx.h2o2[i];
  655. }
  656. if (cx.humid[i] > cx.max_humid) {
  657. cx.max_humid = cx.humid[i];
  658. }
  659. if (cx.saturation[i] > cx.max_saturation) {
  660. cx.max_saturation = cx.saturation[i];
  661. }
  662. }
  663. if (cx.max_h2o2 < 0) cx.max_h2o2 = 0;
  664. if (cx.min_h2o2 < 0) cx.min_h2o2 = 0;
  665. if (cx.max_humid < 0) cx.max_humid = 0;
  666. if (cx.max_saturation < 0) cx.max_saturation = 0;
  667. }
  668. void DisinfectionCtrlService::takeStateSnapshot(DisinfectionContext& context) {
  669. auto& cx = context;
  670. shared_ptr<StateSnapshot> snapshot = make_shared<StateSnapshot>();
  671. snapshot->time = zsystem_clock().now();
  672. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  673. snapshot->h2o2[i] = cx.h2o2[i];
  674. snapshot->humid[i] = cx.humid[i];
  675. snapshot->temp[i] = cx.temp[i];
  676. snapshot->saturation[i] = cx.saturation[i];
  677. }
  678. snapshot->min_h2o2 = cx.min_h2o2;
  679. snapshot->max_h2o2 = cx.max_h2o2;
  680. snapshot->max_humid = cx.max_humid;
  681. snapshot->max_saturation = cx.max_saturation;
  682. snapshot->state = cx.m_state;
  683. snapshot->dloglevel = cx.state_now_loglevel;
  684. cx.stateSnapshotList.push_back(snapshot);
  685. }