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.

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