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.

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