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.

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