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.

915 lines
36 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 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. #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION)
  111. _logger->write(
  112. fmt::format("{},"
  113. " {} , {} , {} , {} ,"
  114. " {} , {} , {} , {} ,"
  115. " {} , {} , {} , {} ,"
  116. " {} , {} , {} ,"
  117. " {} , {} , {} , {} ,"
  118. " {} , {}"
  119. "\n",
  120. ZIconv::noChange("时间"), //
  121. ZIconv::noChange("仓内-气化过氧化氢浓度"), ZIconv::noChange("仓内-温度"), ZIconv::noChange("仓内-相对湿度"), ZIconv::noChange("仓内-相对饱和度"), //
  122. ZIconv::noChange("环境1-气化过氧化氢浓度"), ZIconv::noChange("环境1-温度"), ZIconv::noChange("环境1-相对湿度"), ZIconv::noChange("环境1-相对饱和度"), //
  123. ZIconv::noChange("环境2-气化过氧化氢浓度"), ZIconv::noChange("环境2-温度"), ZIconv::noChange("环境2-相对湿度"), ZIconv::noChange("环境2-相对饱和度"), //
  124. ZIconv::noChange("D值"), ZIconv::noChange("当前LOG"), ZIconv::noChange("目标LOG"), //
  125. ZIconv::noChange("加热器电源"), ZIconv::noChange("风机电源"), ZIconv::noChange("空压机电源"), ZIconv::noChange("喷液泵(g/min)"), //
  126. ZIconv::noChange("消毒剩余剂量(g)"), ZIconv::noChange("剩余时间(s)")));
  127. #endif
  128. #ifdef PROJECT_TYPE_PIPE_DISINFECTION
  129. _logger->write(
  130. fmt::format(" {} ,"
  131. " {} , {} , {} , {} ,"
  132. " {} , {} , {} ,"
  133. " {} , {} , {} , {} ,"
  134. " {} , {} "
  135. "\n",
  136. ZIconv::noChange("时间"), //
  137. ZIconv::noChange("仓内-气化过氧化氢浓度"), ZIconv::noChange("仓内-温度"), ZIconv::noChange("仓内-相对湿度"), ZIconv::noChange("仓内-相对饱和度"), //
  138. ZIconv::noChange("D值"), ZIconv::noChange("当前LOG"), ZIconv::noChange("目标LOG"), //
  139. ZIconv::noChange("加热器电源"), ZIconv::noChange("风机电源"), ZIconv::noChange("空压机电源"), ZIconv::noChange("喷液泵(g/min)"), //
  140. ZIconv::noChange("消毒剩余剂量(g)"), ZIconv::noChange("剩余时间(s)")));
  141. #endif
  142. return _logger;
  143. }
  144. void DisinfectionCtrlService::dumpDisinfectionLogsToCSV(DisinfectionContext& context) {
  145. #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION)
  146. static_assert(MAX_H2O2_SENSOR_NUM == 3, "MAX_H2O2_SENSOR_NUM must be 3");
  147. auto& cx = context;
  148. string h2o2str[MAX_H2O2_SENSOR_NUM];
  149. string tempstr[MAX_H2O2_SENSOR_NUM];
  150. string humidstr[MAX_H2O2_SENSOR_NUM];
  151. string satstr[MAX_H2O2_SENSOR_NUM];
  152. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  153. h2o2str[i] = fmt::format("{}", cx.h2o2[i]);
  154. tempstr[i] = fmt::format("{}", cx.temp[i]);
  155. humidstr[i] = fmt::format("{}", cx.humid[i]);
  156. satstr[i] = fmt::format("{}", cx.saturation[i]);
  157. }
  158. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  159. if (cx.h2o2[i] < 0) h2o2str[i] = "N/A";
  160. if (cx.temp[i] < 0) tempstr[i] = "N/A";
  161. if (cx.humid[i] < 0) humidstr[i] = "N/A";
  162. if (cx.saturation[i] < 0) satstr[i] = "N/A";
  163. }
  164. auto ds = m_deviceIoControlService;
  165. float dvalue = 0;
  166. if (m_context.state_dvalue <= 0) {
  167. dvalue = 0;
  168. } else {
  169. dvalue = m_context.state_dvalue;
  170. }
  171. int remaintime = getEstimatedRemainingTimeS();
  172. context.csvlogger->write(
  173. fmt::format(" {} ,"
  174. " {} , {} , {} , {} ,"
  175. " {} , {} , {} , {} ,"
  176. " {} , {} , {} , {} ,"
  177. " {} , {} , {} ,"
  178. " {} , {} , {} , {} ,"
  179. " {} , {} "
  180. "\n",
  181. getTime(), //
  182. h2o2str[0], tempstr[0], humidstr[0], satstr[0], //
  183. h2o2str[1], tempstr[1], humidstr[1], satstr[1], //
  184. h2o2str[2], tempstr[2], humidstr[2], satstr[2], //
  185. (int32_t)dvalue, (int32_t)m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, //
  186. ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), //
  187. m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime)));
  188. #endif
  189. #ifdef PROJECT_TYPE_PIPE_DISINFECTION
  190. static_assert(MAX_H2O2_SENSOR_NUM == 1, "MAX_H2O2_SENSOR_NUM must be 1");
  191. auto& cx = context;
  192. string h2o2str[MAX_H2O2_SENSOR_NUM];
  193. string tempstr[MAX_H2O2_SENSOR_NUM];
  194. string humidstr[MAX_H2O2_SENSOR_NUM];
  195. string satstr[MAX_H2O2_SENSOR_NUM];
  196. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  197. h2o2str[i] = fmt::format("{}", cx.h2o2[i]);
  198. tempstr[i] = fmt::format("{}", cx.temp[i]);
  199. humidstr[i] = fmt::format("{}", cx.humid[i]);
  200. satstr[i] = fmt::format("{}", cx.saturation[i]);
  201. }
  202. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  203. if (cx.h2o2[i] < 0) h2o2str[i] = "N/A";
  204. if (cx.temp[i] < 0) tempstr[i] = "N/A";
  205. if (cx.humid[i] < 0) humidstr[i] = "N/A";
  206. if (cx.saturation[i] < 0) satstr[i] = "N/A";
  207. }
  208. auto ds = m_deviceIoControlService;
  209. float dvalue = 0;
  210. if (m_context.state_dvalue <= 0) {
  211. dvalue = 0;
  212. } else {
  213. dvalue = m_context.state_dvalue;
  214. }
  215. int remaintime = getEstimatedRemainingTimeS();
  216. context.csvlogger->write(
  217. fmt::format(" {} ,"
  218. " {} , {} , {} , {} ,"
  219. " {} , {} , {} ,"
  220. " {} , {} , {} , {} ,"
  221. " {} , {} "
  222. "\n",
  223. getTime(), //
  224. h2o2str[0], tempstr[0], humidstr[0], satstr[0], //
  225. (int32_t)dvalue, (int32_t)m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, //
  226. ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), //
  227. m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime)));
  228. #endif
  229. }
  230. void DisinfectionCtrlService::pushDisinfectionPrinterTask(DisinfectionContext& context) { //
  231. shared_ptr<DisinfectionPrinterTask> task = make_shared<DisinfectionPrinterTask>();
  232. auto ds = GET_SERVICE(DeviceStateService);
  233. auto dio = m_deviceIoControlService;
  234. task->start_tp = context.start_tp;
  235. task->complete_tp = context.complete_tp;
  236. task->stateSnapshotList = context.stateSnapshotList;
  237. task->disinfectantUsage = context.beforeDisinfectantVolume_g - context.afterDisinfectantVolume_g;
  238. task->disinfection_id = context.m_disinfectionID;
  239. task->usr = ds->getLoginUid();
  240. task->targetLog = context.cfg_targetLoglevel;
  241. task->actualLog = context.state_now_loglevel;
  242. task->disinfectantVolume = dio->getDisinfectantVolume_g();
  243. m_disinfectionPrinterService->pushPrintTask(task);
  244. }
  245. void DisinfectionCtrlService::log(DisinfectionContext& context) {
  246. #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION)
  247. auto& cx = context;
  248. auto ds = m_deviceIoControlService;
  249. float dvalue = 0;
  250. if (m_context.state_dvalue <= 0) {
  251. dvalue = 0;
  252. } else {
  253. dvalue = m_context.state_dvalue;
  254. }
  255. int remaintime = getEstimatedRemainingTimeS();
  256. logger->info(
  257. fmt::format("{},"
  258. "s0({},{},{},{}),"
  259. "s1({},{},{},{}),"
  260. "s2({},{},{},{}),"
  261. "min_h2o2:{},max_h2o2:{},max_hum:{},max_sa:{},"
  262. "dv:{},log:{},tlog:{},"
  263. "h:{},airB:{},airC:{},pump:{},"
  264. "g:{},remainS:{}"
  265. "\n",
  266. getTime(), //
  267. cx.h2o2[0], cx.temp[0], cx.humid[0], cx.saturation[0], //
  268. cx.h2o2[1], cx.temp[1], cx.humid[1], cx.saturation[1], //
  269. cx.h2o2[2], cx.temp[2], cx.humid[2], cx.saturation[2], //
  270. m_context.min_h2o2, m_context.max_h2o2, m_context.max_humid, m_context.max_saturation, //
  271. (int32_t)dvalue, m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, //
  272. ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), //
  273. m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime)));
  274. #endif
  275. #ifdef PROJECT_TYPE_PIPE_DISINFECTION
  276. auto& cx = context;
  277. auto ds = m_deviceIoControlService;
  278. float dvalue = 0;
  279. if (m_context.state_dvalue <= 0) {
  280. dvalue = 0;
  281. } else {
  282. dvalue = m_context.state_dvalue;
  283. }
  284. int remaintime = getEstimatedRemainingTimeS();
  285. logger->info(
  286. fmt::format("{},"
  287. "s0({},{},{},{}),"
  288. "min_h2o2:{},max_h2o2:{},max_hum:{},max_sa:{},"
  289. "dv:{},log:{},tlog:{},"
  290. "h:{},airB:{},airC:{},pump:{},"
  291. "g:{},remainS:{}"
  292. "\n",
  293. getTime(), //
  294. cx.h2o2[0], cx.temp[0], cx.humid[0], cx.saturation[0], //
  295. m_context.min_h2o2, m_context.max_h2o2, m_context.max_humid, m_context.max_saturation, //
  296. (int32_t)dvalue, m_context.state_now_loglevel, (int32_t)m_context.cfg_targetLoglevel, //
  297. ds->heatingStrip_getstate(), ds->airBlower_getstate(), ds->airCompressor_getstate(), ds->sprayLiquidPump_getGPM(), //
  298. m_deviceIoControlService->getDisinfectantVolume_g(), formattimeS(remaintime)));
  299. #endif
  300. }
  301. /*******************************************************************************
  302. * WORK *
  303. *******************************************************************************/
  304. void DisinfectionCtrlService::initContext(DisinfectionContext& context, //
  305. int loglevel, //
  306. float injection_pump_speed, //
  307. float stoped_gs, //
  308. float continued_gs, //
  309. float stoped_satur, //
  310. float continued_satur, //
  311. float stoped_humi, //
  312. float continued_humi //
  313. ) {
  314. context.m_disinfectionID = createDisinfectionID();
  315. context.pre_heat_time_s = m_dbService->getSettingVal("pre_heat_time_s");
  316. context.stoped_gs = stoped_gs;
  317. context.continued_gs = continued_gs;
  318. context.stoped_satur = stoped_satur;
  319. context.continued_satur = continued_satur;
  320. context.stoped_humi = stoped_humi;
  321. context.continued_humi = continued_humi;
  322. context.injection_pump_speed = injection_pump_speed;
  323. context.injection_pump_speed_changed = true;
  324. if (g_in_test) {
  325. logger->warn("in test mode, pre_heat_time_s = 5");
  326. context.pre_heat_time_s = 5;
  327. }
  328. logger->info("startDisinfection {} {}", m_context.cfg_targetLoglevel, m_context.m_disinfectionID);
  329. logger->info(" stoped_gs {}", context.stoped_gs);
  330. logger->info(" continued_gs {}", context.continued_gs);
  331. logger->info(" stoped_satur {}", context.stoped_satur);
  332. logger->info(" continued_satur {}", context.continued_satur);
  333. logger->info(" stoped_humi {}", context.stoped_humi);
  334. logger->info(" continued_humi {}", context.continued_humi);
  335. logger->info(" pre_heat_time_s {}", context.pre_heat_time_s);
  336. logger->info("");
  337. context.state_remaintime = context.pre_heat_time_s + loglevel * 90 * 60; // 计算总的加热时间
  338. m_disinfectionWorkState = 1;
  339. context.cfg_targetLoglevel = loglevel;
  340. context.state_now_loglevel = 0;
  341. m_context.state_dvalue = 0;
  342. m_context.m_state = kstate_preheat;
  343. m_context.start_tp = zsystem_clock().now();
  344. m_context.start_steady_tp = zsteady_clock().now();
  345. for (int i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  346. m_context.h2o2[i] = 0;
  347. m_context.humid[i] = 0;
  348. m_context.temp[i] = 0;
  349. m_context.saturation[i] = 0;
  350. }
  351. m_context.min_h2o2 = 0;
  352. m_context.max_h2o2 = 0;
  353. m_context.max_humid = 0;
  354. m_context.max_saturation = 0;
  355. m_context.stateSnapshotList.clear();
  356. m_context.afterDisinfectantVolume_g = 0;
  357. m_context.beforeDisinfectantVolume_g = m_deviceIoControlService->getDisinfectantVolume_g();
  358. #if (defined PROJECT_TYPE_LARGE_SPACE_DISINFECTION) || (defined PROJECT_TYPE_SMALL_SPACE_DISINFECTION)
  359. m_deviceIoControlService->warningLightCtrl(0, 0, 1, 0);
  360. #endif
  361. #ifdef PROJECT_TYPE_PIPE_DISINFECTION
  362. m_deviceIoControlService->warningLightCtrl(1, 1, 0, 0);
  363. #endif
  364. m_deviceIoControlService->heartingPlate_setPower(true);
  365. m_deviceIoControlService->airBlower_setState(true);
  366. context.csvlogger = createCSVLogger(context.m_disinfectionID);
  367. m_context.firstLog = true;
  368. }
  369. void DisinfectionCtrlService::finishDisinfection(DisinfectionContext& context) {
  370. context.state_remaintime = 0;
  371. logger->info("stop disinfection {}", context.m_disinfectionID);
  372. // sprayLiquidPump_close();
  373. m_deviceIoControlService->sprayLiquidPump_close();
  374. usleep(1000 * 1000);
  375. // airCompressor(false);
  376. m_deviceIoControlService->airCompressor_setState(false);
  377. usleep(1000 * 1000);
  378. // blower_setPower(false);
  379. m_deviceIoControlService->airBlower_setState(false);
  380. usleep(1000 * 1000);
  381. // heartingPlate_setPower(false);
  382. m_deviceIoControlService->heartingPlate_setPower(false);
  383. m_disinfectionWorkState = 3;
  384. m_deviceIoControlService->warningLightCtrl(0, 1, 0, 0);
  385. }
  386. void DisinfectionCtrlService::processPreheatState(DisinfectionContext& context) {
  387. int hasstarttime = zsteady_clock().elapsedTimeS(context.start_steady_tp);
  388. // logger->info("preheat {}", context.m_disinfectionID);
  389. if ((context.m_state == kstate_preheat && hasstarttime > m_context.pre_heat_time_s)) {
  390. logger->info("preheat finished {}", context.m_disinfectionID);
  391. m_deviceIoControlService->airBlower_setState(true);
  392. #ifdef PROJECT_TYPE_PIPE_DISINFECTION
  393. m_deviceIoControlService->airCompressor_channelSelect(1);
  394. m_deviceIoControlService->airCompressor_setValve1(1);
  395. m_deviceIoControlService->airCompressor_setValve2(1);
  396. #endif
  397. usleep(1000 * 1000);
  398. m_deviceIoControlService->airCompressor_setState(true);
  399. usleep(1000 * 1000);
  400. m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed);
  401. context.m_state = kstate_disinfection;
  402. } else {
  403. logger->info("{}: preheat {}", context.m_disinfectionID, m_context.pre_heat_time_s - hasstarttime);
  404. }
  405. }
  406. /**
  407. * @brief
  408. *
  409. */
  410. void DisinfectionCtrlService::processDisinfectionState(DisinfectionContext& context) {
  411. /**
  412. * @brief
  413. */
  414. /**
  415. * @brief 湿
  416. */
  417. if (!m_context.state_is_disinfection_take_break) {
  418. /**
  419. * @brief
  420. */
  421. float nowSatur = m_context.max_saturation;
  422. float nowh2o2 = m_context.max_h2o2;
  423. float humid = m_context.max_humid;
  424. if (m_context.injection_pump_speed_changed) {
  425. m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed);
  426. m_context.injection_pump_speed_changed = false;
  427. }
  428. // humid > m_context.stoped_satur
  429. if (nowSatur > m_context.stoped_satur || nowh2o2 > m_context.stoped_gs || humid > m_context.stoped_humi) {
  430. logger->info("stop sprayLiquid");
  431. m_deviceIoControlService->sprayLiquidPump_close();
  432. usleep(1000 * 1000);
  433. m_deviceIoControlService->airCompressor_setState(false);
  434. // m_context.sprayLiquidFlag = false;
  435. m_context.state_is_disinfection_take_break = true;
  436. }
  437. } else {
  438. float nowSatur = m_context.max_saturation;
  439. float nowh2o2 = m_context.max_h2o2;
  440. float humid = m_context.max_humid;
  441. // && humid < m_context.continued_satur
  442. if (nowSatur < m_context.continued_satur && nowh2o2 < m_context.continued_gs && humid < context.continued_humi) {
  443. logger->info("start sprayLiquid");
  444. m_deviceIoControlService->sprayLiquidPump_open(context.injection_pump_speed);
  445. usleep(1000 * 1000);
  446. m_deviceIoControlService->airCompressor_setState(true);
  447. m_context.state_is_disinfection_take_break = false;
  448. }
  449. }
  450. }
  451. void DisinfectionCtrlService::processState_Preheat(DisinfectionContext& context) {
  452. /**
  453. * @brief
  454. */
  455. m_context.state_dvalue = 0;
  456. processPreheatState(m_context);
  457. }
  458. void DisinfectionCtrlService::processState_Disinfection(DisinfectionContext& context, bool& updatedval) {
  459. m_context.state_dvalue = getDisinfectionDValue(m_context.min_h2o2);
  460. if (zsteady_clock().elapsedTimeS(m_context.state_last_compute_dvalue_tp) > DVALUE_COMPUTEPERIOD_TIME_S) {
  461. m_context.state_last_compute_dvalue_tp = zsteady_clock().now();
  462. m_context.state_now_loglevel = computeNowLogLevel(m_context);
  463. computeRemainTime(m_context);
  464. updatedval = true;
  465. }
  466. /**
  467. * @brief
  468. */
  469. processDisinfectionState(m_context);
  470. //
  471. if (m_context.state_remaintime <= 0 && m_context.state_now_loglevel > (m_context.cfg_targetLoglevel + 0.01)) {
  472. m_context.state_remaintime = 0;
  473. m_context.state_now_loglevel = m_context.cfg_targetLoglevel + 0.01;
  474. logger->info("disinfection finished {},but waitting for h2o2 to safe", m_context.m_disinfectionID);
  475. m_deviceIoControlService->sprayLiquidPump_close();
  476. usleep(1000 * 1000);
  477. m_deviceIoControlService->airCompressor_setState(false);
  478. usleep(1000 * 1000);
  479. m_deviceIoControlService->heartingPlate_setPower(false);
  480. m_context.m_state = kstate_degradation;
  481. }
  482. }
  483. void DisinfectionCtrlService::processState_Degradation(DisinfectionContext& context) {
  484. // 降解
  485. m_context.state_dvalue = 0;
  486. logger->info("waitting for h2o2 concentration to safe value {}=>{}", m_context.min_h2o2, 1);
  487. if (m_context.min_h2o2 < 1) {
  488. logger->info("h2o2 concentration to safe value");
  489. m_context.m_state = kstate_finished;
  490. }
  491. }
  492. void DisinfectionCtrlService::disinfectionLoop(bool& breakflag) {
  493. // logger->info("disinfection running {} {}s preheatFlag:{}", m_context.m_disinfectionID, m_context.state_remaintime, m_context.m_preheatFlag);
  494. ThisThread thisThread;
  495. disinfection_state_t enterstate;
  496. disinfection_state_t exitstate;
  497. bool statechanged = false;
  498. bool updatedval = false;
  499. enterstate = m_context.m_state;
  500. m_context.state_remaintime--;
  501. if (m_context.state_remaintime < 0) m_context.state_remaintime = 0;
  502. updateH2O2SensorData(m_context);
  503. /*******************************************************************************
  504. * *
  505. *******************************************************************************/
  506. if (thisThread.getExitFlag()) {
  507. m_context.m_state = kstate_finished;
  508. } else if (m_context.m_state == kstate_preheat) {
  509. processState_Preheat(m_context);
  510. } else if (m_context.m_state == kstate_disinfection) {
  511. processState_Disinfection(m_context, updatedval);
  512. } else if (m_context.m_state == kstate_degradation) {
  513. processState_Degradation(m_context);
  514. }
  515. exitstate = m_context.m_state;
  516. if (exitstate != enterstate) {
  517. statechanged = true;
  518. }
  519. /*******************************************************************************
  520. * *
  521. *******************************************************************************/
  522. if (exitstate == kstate_finished) {
  523. /**
  524. * @brief
  525. */
  526. breakflag = true;
  527. m_context.complete_tp = zsystem_clock().now();
  528. m_context.afterDisinfectantVolume_g = m_deviceIoControlService->getDisinfectantVolume_g();
  529. if (m_context.m_state != kstate_finished) {
  530. m_context.m_state = kstate_finished;
  531. }
  532. m_disinfectionWorkState = 0;
  533. takeStateSnapshot(m_context);
  534. dumpDisinfectionLogsToCSV(m_context);
  535. log(m_context);
  536. pushDisinfectionPrinterTask(m_context);
  537. finishDisinfection(m_context);
  538. m_context.csvlogger = nullptr;
  539. } else {
  540. if (updatedval) {
  541. log(m_context);
  542. }
  543. if (m_context.firstLog || statechanged || zsteady_clock().elapsedTimeS(m_context.state_lastlog_tp) > DUMP_LOG_PERIOD) {
  544. m_context.state_lastlog_tp = zsteady_clock().now();
  545. takeStateSnapshot(m_context);
  546. dumpDisinfectionLogsToCSV(m_context);
  547. m_context.firstLog = false;
  548. }
  549. }
  550. }
  551. void DisinfectionCtrlService::changeDisinfectionParameter(int injection_pump_speed, //
  552. int stoped_gs, //
  553. int continued_gs, //
  554. int stoped_satur, //
  555. int continued_satur, //
  556. int stoped_humi, //
  557. int continued_humi) {
  558. lock_guard<recursive_mutex> lock(lock_);
  559. m_context.injection_pump_speed = injection_pump_speed;
  560. m_context.stoped_gs = stoped_gs;
  561. m_context.continued_gs = continued_gs;
  562. m_context.stoped_satur = stoped_satur;
  563. m_context.continued_satur = continued_satur;
  564. m_context.stoped_humi = stoped_humi;
  565. m_context.continued_humi = continued_humi;
  566. m_context.injection_pump_speed_changed = true;
  567. logger->info("changeDisinfectionParameter {} {} {} {} {} {} {}", //
  568. injection_pump_speed, stoped_gs, continued_gs, stoped_satur, continued_satur, stoped_humi, continued_humi);
  569. }
  570. void DisinfectionCtrlService::startDisinfection(int loglevel, //
  571. int injection_pump_speed, //
  572. int stoped_gs, //
  573. int continued_gs, //
  574. int stoped_satur, //
  575. int continued_satur, //
  576. int stoped_humi, //
  577. int continued_humi //
  578. ) {
  579. lock_guard<recursive_mutex> lock(lock_);
  580. if (m_disinfectionThread) stopDisinfection();
  581. initContext(m_context, loglevel, injection_pump_speed, stoped_gs, continued_gs, stoped_satur, continued_satur, stoped_humi, continued_humi);
  582. m_disinfectionThread.reset(new Thread("m_disinfectionThread", [this]() {
  583. ThisThread thisThread;
  584. while (true) {
  585. thisThread.sleepForMs(1000);
  586. bool breakflag = false;
  587. disinfectionLoop(breakflag);
  588. if (breakflag) {
  589. break;
  590. }
  591. }
  592. }));
  593. //
  594. }
  595. void DisinfectionCtrlService::stopDisinfection() {
  596. lock_guard<recursive_mutex> lock(lock_);
  597. if (m_disinfectionThread) {
  598. m_disinfectionThread->join();
  599. m_disinfectionThread = nullptr;
  600. }
  601. }
  602. int DisinfectionCtrlService::getDisinfectionWorkState() { return m_context.m_state; }
  603. int32_t DisinfectionCtrlService::getEstimatedRemainingTimeS() {
  604. if (m_context.m_state == kstate_preheat) {
  605. return getPreHeatRaminTimeS();
  606. } else if (m_context.m_state == kstate_disinfection) {
  607. if (m_context.state_dvalue > 0) {
  608. return m_context.state_remaintime;
  609. } else {
  610. return -1;
  611. }
  612. } else {
  613. return 0;
  614. }
  615. }
  616. int32_t DisinfectionCtrlService::getPreHeatRaminTimeS() {
  617. int32_t remaintime = 0;
  618. if (m_context.m_state == kstate_preheat) {
  619. remaintime = m_context.pre_heat_time_s - zsteady_clock().elapsedTimeS(m_context.start_steady_tp);
  620. if (remaintime < 0) {
  621. remaintime = 0;
  622. }
  623. return remaintime;
  624. } else {
  625. return 0;
  626. }
  627. }
  628. string DisinfectionCtrlService::getDisinfectionID() { return m_context.m_disinfectionID; }
  629. bool DisinfectionCtrlService::isPreheatState() { return m_context.m_state == kstate_preheat; }
  630. /*******************************************************************************
  631. * // 加液 *
  632. *******************************************************************************/
  633. int DisinfectionCtrlService::getReplenishingFluidsWorkState() { return m_replenishingFluidsWorkState; }
  634. void DisinfectionCtrlService::startReplenishingFluids(int stopatg) {
  635. lock_guard<recursive_mutex> lock(lock_);
  636. if (m_disinfectionThread) {
  637. m_disinfectionThread->join();
  638. m_disinfectionThread = nullptr;
  639. }
  640. int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g();
  641. int maxg = DISINFECTANT_BUCKET_CAPACITY;
  642. if (stopatg > maxg) {
  643. logger->warn("start Replenishing fail, stopatg {} > maxg {}", stopatg, maxg);
  644. stopatg = maxg;
  645. }
  646. if (nowvolume > stopatg) {
  647. logger->warn("start Replenishing fail, nowvolume {} > stopatg {}", nowvolume, stopatg);
  648. return;
  649. }
  650. m_disinfectionThread.reset(new Thread("disinfectionThread", [this, stopatg]() {
  651. ThisThread thisThread;
  652. m_deviceIoControlService->replenishingFluidsPump_open();
  653. logger->info("startReplenishingFluids {}g", stopatg);
  654. while (!thisThread.getExitFlag()) {
  655. int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g();
  656. logger->info("replenishingFluids {}g", nowvolume);
  657. if (nowvolume > stopatg) {
  658. break;
  659. }
  660. if (nowvolume > MAX_VOLUME) {
  661. logger->warn("replenishingFluids reach full level {}g", nowvolume);
  662. break;
  663. }
  664. thisThread.sleepForMs(1000);
  665. }
  666. logger->info("stopReplenishingFluids");
  667. // replenishingFluidsPump_close();
  668. m_deviceIoControlService->replenishingFluidsPump_close();
  669. m_replenishingFluidsWorkState = 0;
  670. }));
  671. //
  672. m_replenishingFluidsWorkState = 1;
  673. logger->info("startReplenishingFluids ");
  674. }
  675. void DisinfectionCtrlService::stopReplenishingFluids() {
  676. lock_guard<recursive_mutex> lock(lock_);
  677. if (m_disinfectionThread) {
  678. m_disinfectionThread->join();
  679. m_disinfectionThread = nullptr;
  680. }
  681. logger->info("stopReplenishingFluids");
  682. // replenishingFluidsPump_close();
  683. m_deviceIoControlService->replenishingFluidsPump_close();
  684. m_replenishingFluidsWorkState = 0;
  685. }
  686. /*******************************************************************************
  687. * *
  688. *******************************************************************************/
  689. void DisinfectionCtrlService::startDraining() {
  690. lock_guard<recursive_mutex> lock(lock_);
  691. if (m_disinfectionThread) {
  692. m_disinfectionThread->join();
  693. m_disinfectionThread = nullptr;
  694. }
  695. m_disinfectionThread.reset(new Thread("disinfectionThread", [this]() {
  696. ThisThread thisThread;
  697. m_deviceIoControlService->drainingPump_open();
  698. logger->info("startDraining ");
  699. auto startdrainingtime = zsteady_clock().now();
  700. zsteady_tp volumeReachZeroTime;
  701. bool volumeReachZeroFlag = false;
  702. while (!thisThread.getExitFlag()) {
  703. int32_t nowvolume = m_deviceIoControlService->getDisinfectantVolume_g();
  704. logger->info("draining remain {} g", nowvolume);
  705. if (!volumeReachZeroFlag && nowvolume == 0) {
  706. volumeReachZeroTime = zsteady_clock().now();
  707. volumeReachZeroFlag = true;
  708. }
  709. if (volumeReachZeroFlag) {
  710. logger->info("stopDraining after {} s", 30 - zsteady_clock().elapsedTimeS(volumeReachZeroTime));
  711. if (zsteady_clock().elapsedTimeS(volumeReachZeroTime) > 30) {
  712. break;
  713. }
  714. }
  715. thisThread.sleepForMs(1000);
  716. }
  717. logger->info("stopDraining");
  718. // replenishingFluidsPump_close();
  719. m_deviceIoControlService->drainingPump_close();
  720. m_drainingWorkState = 0;
  721. }));
  722. logger->info("startDraining");
  723. // drainingPump_open();
  724. m_drainingWorkState = 1;
  725. }
  726. void DisinfectionCtrlService::stopDraining() {
  727. lock_guard<recursive_mutex> lock(lock_);
  728. if (m_disinfectionThread) {
  729. m_disinfectionThread->join();
  730. m_disinfectionThread = nullptr;
  731. }
  732. logger->info("stopDraining");
  733. m_drainingWorkState = 0;
  734. // drainingPump_close();
  735. m_deviceIoControlService->drainingPump_close();
  736. }
  737. int DisinfectionCtrlService::getDrainingWorkState() { return m_drainingWorkState; }
  738. void DisinfectionCtrlService::updateH2O2SensorData(DisinfectionContext& context) {
  739. auto& cx = context;
  740. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  741. cx.h2o2[i] = m_deviceIoControlService->H2O2Sensor_readH2O2PPM(i);
  742. }
  743. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  744. cx.humid[i] = m_deviceIoControlService->H2O2Sensor_readHumid(i);
  745. }
  746. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  747. cx.temp[i] = m_deviceIoControlService->H2O2Sensor_readTemperature(i);
  748. }
  749. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  750. cx.saturation[i] = m_deviceIoControlService->H2O2Sensor_readSaturation(i);
  751. }
  752. cx.min_h2o2 = cx.h2o2[0];
  753. cx.max_h2o2 = cx.h2o2[0];
  754. cx.max_humid = cx.humid[0];
  755. cx.max_saturation = cx.saturation[0];
  756. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  757. if (cx.h2o2[i] < cx.min_h2o2) {
  758. cx.min_h2o2 = cx.h2o2[i];
  759. }
  760. if (cx.h2o2[i] > cx.max_h2o2) {
  761. cx.max_h2o2 = cx.h2o2[i];
  762. }
  763. if (cx.humid[i] > cx.max_humid) {
  764. cx.max_humid = cx.humid[i];
  765. }
  766. if (cx.saturation[i] > cx.max_saturation) {
  767. cx.max_saturation = cx.saturation[i];
  768. }
  769. }
  770. if (cx.max_h2o2 < 0) cx.max_h2o2 = 0;
  771. if (cx.min_h2o2 < 0) cx.min_h2o2 = 0;
  772. if (cx.max_humid < 0) cx.max_humid = 0;
  773. if (cx.max_saturation < 0) cx.max_saturation = 0;
  774. }
  775. void DisinfectionCtrlService::takeStateSnapshot(DisinfectionContext& context) {
  776. auto& cx = context;
  777. shared_ptr<StateSnapshot> snapshot = make_shared<StateSnapshot>();
  778. snapshot->time = zsystem_clock().now();
  779. for (size_t i = 0; i < MAX_H2O2_SENSOR_NUM; i++) {
  780. snapshot->h2o2[i] = cx.h2o2[i];
  781. snapshot->humid[i] = cx.humid[i];
  782. snapshot->temp[i] = cx.temp[i];
  783. snapshot->saturation[i] = cx.saturation[i];
  784. }
  785. snapshot->min_h2o2 = cx.min_h2o2;
  786. snapshot->max_h2o2 = cx.max_h2o2;
  787. snapshot->max_humid = cx.max_humid;
  788. snapshot->max_saturation = cx.max_saturation;
  789. snapshot->state = cx.m_state;
  790. snapshot->dloglevel = cx.state_now_loglevel;
  791. cx.stateSnapshotList.push_back(snapshot);
  792. }