xf_controller.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. #include <sys/cdefs.h>
  2. /**
  3. * @Author: 李建
  4. * @Date: 2025/3/25 15:23
  5. * Description: 空调控制器
  6. * Copyright: Copyright (©) 2025 永续绿建. All rights reserved.
  7. */
  8. #include <esp_log.h>
  9. #include "freertos/FreeRTOS.h"
  10. #include <freertos/task.h>
  11. #include <cJSON.h>
  12. #include <esp_timer.h>
  13. #include "xf_controller.h"
  14. #include "sub_device/command.h"
  15. #include "modbus_master.h"
  16. #include "system/miscellaneous_interface.h"
  17. #include "lvgl_port.h"
  18. #include "main.h"
  19. #include "esp_modbus_master.h"
  20. #include "mb_endianness_utils.h"
  21. #include "sht30.h"
  22. #include "gateway/access.h"
  23. static const char *TAG = "xf_controller";
  24. static uint8_t err_count = 0;// 通讯失败次数
  25. static SemaphoreHandle_t report_task_sem; // 上报任务信号量,用于实现操作完成上立即上报当前状态
  26. extern void set_xf_mode(lv_ui *ui, uint16_t mode);
  27. static TaskHandle_t cloud_report_handle;
  28. static TaskHandle_t report_trigger_handle;
  29. static TaskHandle_t status_task_handle;
  30. // 初始化空调参数
  31. xf_status_t xf_status = {
  32. .power= 0,
  33. .fan_speed=3,
  34. .mode=1,
  35. .filter_used_time=0,
  36. .set_max_hum=70,
  37. .filter_life_remaining=100,
  38. .error_code=0,
  39. };
  40. void read_xf_status(system_setting_t *setting) {
  41. uint16_t *_power = nvs_get_uint16(NVS_POWER_CONTROLLER);
  42. uint16_t *_mode = nvs_get_uint16(NVS_MODEL_CONTROLLER);
  43. uint16_t *_fan_speed = nvs_get_uint16(NVS_FAN_SPEED_SET);
  44. uint32_t *_filter_used_time = nvs_get_uint32(NVS_FILTER_USED_TIME);
  45. uint16_t *_set_hum_max = nvs_get_uint16(NVS_MAX_HUM_SET);
  46. // uint16_t *_set_hum_min = nvs_get_uint16(NVS_MIN_HUM_SET);
  47. xf_status.power= _power == NULL ? 0 : *_power;
  48. xf_status.mode = _mode == NULL ? 1 : *_mode;
  49. xf_status.fan_speed = _fan_speed == NULL ? 3 : *_fan_speed;
  50. xf_status.filter_used_time = _filter_used_time == NULL ? 0 : *_filter_used_time;
  51. xf_status.set_max_hum = _set_hum_max == NULL ? 70 : *_set_hum_max;
  52. }
  53. // 设置电源
  54. esp_err_t xf_set_power(bool saved) {
  55. esp_err_t err = ESP_OK;
  56. if(saved)
  57. nvs_set_uint16(xf_status.power, NVS_POWER_CONTROLLER);
  58. if (guider_ui.screen_main) {
  59. if(xf_status.power==0)
  60. {
  61. lvgl_port_lock(-1);
  62. lv_obj_add_flag(guider_ui.screen_main_cont_speedset, LV_OBJ_FLAG_HIDDEN);
  63. lv_obj_add_flag(guider_ui.screen_main_cont_humSet, LV_OBJ_FLAG_HIDDEN);
  64. lv_obj_add_flag(guider_ui.screen_main_cont_mode, LV_OBJ_FLAG_HIDDEN);
  65. lvgl_port_unlock();
  66. }else{
  67. lvgl_port_lock(-1);
  68. lv_obj_clear_flag(guider_ui.screen_main_cont_speedset, LV_OBJ_FLAG_HIDDEN);
  69. lv_obj_clear_flag(guider_ui.screen_main_cont_humSet, LV_OBJ_FLAG_HIDDEN);
  70. lv_obj_clear_flag(guider_ui.screen_main_cont_mode, LV_OBJ_FLAG_HIDDEN);
  71. lv_label_set_text_fmt(guider_ui.screen_main_label_humSet_vul, "%d%%", xf_status.set_max_hum);
  72. lv_slider_set_value(guider_ui.screen_main_slider_speedSet_sign, xf_status.fan_speed*20, LV_ANIM_ON);
  73. lv_label_set_text_fmt(guider_ui.screen_main_label_spedSet_vul, "%d档",xf_status.fan_speed);
  74. lv_slider_set_value(guider_ui.screen_main_slider_humSet_sign, xf_status.set_max_hum, LV_ANIM_ON);
  75. set_xf_mode(&guider_ui, xf_status.mode);
  76. lvgl_port_unlock();
  77. }
  78. }
  79. if (cloud_connected) {
  80. xSemaphoreGive(report_task_sem);
  81. }
  82. return err;
  83. }
  84. void esp_timer_cb()
  85. {
  86. if(xf_status.power==1)
  87. {
  88. xf_status.filter_used_time++;
  89. }else{
  90. }
  91. if(xf_status.filter_used_time>=system_setting.filter_life_time)
  92. {
  93. xf_status.filter_used_time=system_setting.filter_life_time;
  94. }
  95. xf_set_filter_life_remain(true);
  96. }
  97. esp_timer_handle_t esp_timer_handle = 0; //定时器句柄
  98. void timer_init_lx() {
  99. //定时器结构体初始化
  100. esp_timer_create_args_t fw_timer = {
  101. .callback = &esp_timer_cb, //定时器回调函数
  102. .arg = NULL, //传递给回调函数的参数
  103. .name = "esp_timer", //定时器名称
  104. };
  105. //创建定时器
  106. esp_timer_create(&fw_timer, &esp_timer_handle);
  107. //启动定时器,定时器周期为60秒
  108. esp_timer_start_periodic(esp_timer_handle, 60000 * 1000);
  109. }
  110. // 设置最大湿度
  111. esp_err_t xf_set_max_hum(bool saved) {
  112. esp_err_t err = ESP_OK;
  113. if(saved)
  114. nvs_set_uint16(xf_status.set_max_hum, NVS_MAX_HUM_SET);
  115. if (cloud_connected) {
  116. xSemaphoreGive(report_task_sem);
  117. }
  118. return err;
  119. }
  120. // 设置最小湿度
  121. //esp_err_t xf_set_min_hum(bool saved) {
  122. // if(saved)
  123. // nvs_set_uint16(xf_status.set_min_hum, NVS_MIN_HUM_SET);
  124. // return mm_set_param(CID_MIN_HUMIDITY, (uint8_t *)&xf_status.set_min_hum);
  125. //}
  126. //设置滤网剩余寿命
  127. void xf_set_filter_life_remain(bool saved) {
  128. if(saved)
  129. nvs_set_uint16(xf_status.filter_used_time, NVS_FILTER_USED_TIME);
  130. }
  131. //设置新风风速
  132. esp_err_t xf_set_fan_speed(bool saved) {
  133. esp_err_t err = ESP_OK;
  134. if(saved)
  135. nvs_set_uint16(xf_status.fan_speed, NVS_FAN_SPEED_SET);
  136. if (cloud_connected) {
  137. xSemaphoreGive(report_task_sem);
  138. }
  139. return err;
  140. }
  141. // 设置模式
  142. esp_err_t xf_set_mode(bool saved) {
  143. esp_err_t err = ESP_OK;
  144. if(saved)
  145. nvs_set_uint16(xf_status.mode, NVS_MODEL_CONTROLLER);
  146. if (cloud_connected) {
  147. xSemaphoreGive(report_task_sem);
  148. }
  149. return err;
  150. }
  151. static void update_power_ui(bool on_off) {
  152. // 同步更新 UI
  153. if (guider_ui.screen_main) {
  154. lvgl_port_lock(-1);
  155. lv_obj_set_state(guider_ui.screen_main_imgbtn_power, LV_IMAGEBUTTON_STATE_CHECKED_RELEASED, on_off);
  156. lvgl_port_unlock();
  157. }
  158. }
  159. // 云端: 设置上报时间间隔
  160. static void cloud_set_report_duration(char *params) {
  161. cJSON *data = cJSON_Parse(params);
  162. if (data != NULL) {
  163. cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
  164. if (cJSON_IsNumber(value)) {
  165. system_setting.report_data_duration = value->valueint;
  166. save_system_setting(&system_setting);
  167. }
  168. }
  169. }
  170. static void cloud_set_power(char *params) {
  171. cJSON *data = cJSON_Parse(params);
  172. if (data != NULL) {
  173. cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
  174. xf_status.power = value->valueint;
  175. xf_set_power(true);
  176. update_power_ui(xf_status.power);
  177. cJSON_Delete(data);
  178. }
  179. }
  180. static void cloud_set_max_hum(char *params) {
  181. cJSON *data = cJSON_Parse(params);
  182. if (data != NULL) {
  183. cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
  184. if((value->valueint<=70)&&(value->valueint>=system_setting.set_min_hum))
  185. {
  186. xf_status.set_max_hum = value->valueint;
  187. if (guider_ui.screen_main) {
  188. lvgl_port_lock(-1);
  189. lv_label_set_text_fmt(guider_ui.screen_main_label_humSet_vul, "%d%%", xf_status.set_max_hum);
  190. lv_slider_set_value(guider_ui.screen_main_slider_humSet_sign, xf_status.set_max_hum,LV_ANIM_OFF);
  191. lvgl_port_unlock();
  192. }
  193. xf_set_max_hum(true);
  194. }
  195. cJSON_Delete(data);
  196. }
  197. }
  198. static void cloud_set_mode(char *params) {
  199. cJSON *data = cJSON_Parse(params);
  200. if (data != NULL) {
  201. cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
  202. xf_status.mode = value->valueint;
  203. if (guider_ui.screen_main) {
  204. lvgl_port_lock(-1);
  205. set_xf_mode(&guider_ui, xf_status.mode);
  206. lvgl_port_unlock();
  207. }
  208. xf_set_mode(true);
  209. cJSON_Delete(data);
  210. }
  211. }
  212. static void cloud_set_fan_level(char *params) {
  213. cJSON *data = cJSON_Parse(params);
  214. if (data != NULL) {
  215. cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
  216. xf_status.fan_speed = value->valueint;
  217. if (guider_ui.screen_main) {
  218. lvgl_port_lock(-1);
  219. lv_slider_set_value(guider_ui.screen_main_slider_speedSet_sign, xf_status.fan_speed*20, LV_ANIM_ON);
  220. lv_label_set_text_fmt(guider_ui.screen_main_label_spedSet_vul, "%d档",xf_status.fan_speed);
  221. lvgl_port_unlock();
  222. }
  223. xf_set_fan_speed(true);
  224. cJSON_Delete(data);
  225. }
  226. }
  227. static void cloud_set_filter_life(char *params) {
  228. cJSON *data = cJSON_Parse(params);
  229. if (data != NULL) {
  230. cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
  231. system_setting.filter_life_time = value->valueint;
  232. save_system_setting(&system_setting);
  233. cJSON_Delete(data);
  234. }
  235. }
  236. static void cloud_reset_filter_life_remain(char *params) {
  237. cJSON *data = cJSON_Parse(params);
  238. if (data != NULL) {
  239. xf_status.filter_used_time=0;
  240. xf_set_filter_life_remain(true);
  241. cJSON_Delete(data);
  242. }
  243. }
  244. static void cloud_set_min_hum(char *params) {
  245. }
  246. //注册云端指令s
  247. void register_sparrow_commands(void) {
  248. sparrow_command set_power_cmd = {
  249. .name = "setPower",
  250. .unpack = &cloud_set_power
  251. };
  252. register_sparrow_command(set_power_cmd);
  253. sparrow_command set_max_hum_cmd = {
  254. .name = "setMaxHum",
  255. .unpack = &cloud_set_max_hum
  256. };
  257. register_sparrow_command(set_max_hum_cmd);
  258. // setMode
  259. sparrow_command set_mode_cmd = {
  260. .name = "setMode",
  261. .unpack = &cloud_set_mode
  262. };
  263. register_sparrow_command(set_mode_cmd);
  264. // setFanLevel
  265. sparrow_command set_fan_level_cmd = {
  266. .name = "setFanLevel",
  267. .unpack = &cloud_set_fan_level,
  268. };
  269. register_sparrow_command(set_fan_level_cmd);
  270. // setNewFan
  271. sparrow_command set_filter_life_cmd = {
  272. .name = "setFilterLife",
  273. .unpack = &cloud_set_filter_life,
  274. };
  275. register_sparrow_command(set_filter_life_cmd);
  276. // setFanVoltage
  277. sparrow_command set_min_hum_cmd = {
  278. .name = "setMinHumCmd",
  279. .unpack = &cloud_set_min_hum,
  280. };
  281. register_sparrow_command(set_min_hum_cmd);
  282. sparrow_command set_duration = {
  283. .name = "setReportDuration",
  284. .unpack = &cloud_set_report_duration
  285. };
  286. register_sparrow_command(set_duration);
  287. sparrow_command reset_filter_life_remain = {
  288. .name = "setReportDuration",
  289. .unpack = &cloud_reset_filter_life_remain
  290. };
  291. register_sparrow_command(reset_filter_life_remain);
  292. }
  293. LV_IMAGE_DECLARE(_power_open_RGB565A8_36x36);
  294. LV_IMAGE_DECLARE(_liang_RGB565A8_30x30);
  295. LV_IMAGE_DECLARE(_cha_RGB565A8_30x30);
  296. /**
  297. * TODO:处理风故障信息
  298. */
  299. void handle_err_code()
  300. {
  301. uint8_t error_code[2] = {0};
  302. esp_err_t err = ESP_OK;
  303. err = mm_get_param(CID_ERROR_CODE, error_code);
  304. if (err == ESP_OK)
  305. {
  306. // ESP_LOGE(TAG, "error_code1:%d",*(uint16_t *)error_code);
  307. if (guider_ui.screen_main)
  308. {
  309. if((*(uint16_t *)error_code&0x0ff)==0)
  310. {
  311. lvgl_port_lock(-1);
  312. lv_obj_add_flag(guider_ui.screen_main_lab_err, LV_OBJ_FLAG_HIDDEN);
  313. lvgl_port_unlock();
  314. } else{
  315. lvgl_port_lock(-1);
  316. lv_obj_clear_flag(guider_ui.screen_main_lab_err, LV_OBJ_FLAG_HIDDEN);
  317. lvgl_port_unlock();
  318. }
  319. }
  320. xf_status.error_code=(uint8_t)(*(uint16_t *)error_code&0x0ff);
  321. // ESP_LOGE(TAG, "error_code:%d",xf_status.error_code);
  322. }
  323. }
  324. void Refresh_UI()
  325. {
  326. uint8_t type = PARAM_TYPE_U16;
  327. uint8_t temp_data[2] = {0}; // temporary buffer to hold maximum CID size
  328. uint16_t temp_data_u16 = 500;
  329. esp_err_t err = ESP_OK;
  330. const mb_parameter_descriptor_t *param_descriptor = NULL;
  331. err = mm_get_param(CID_RETURN_AIR_PM25, temp_data);
  332. if (err == ESP_OK) {
  333. sht30Data.air_quality=*(uint16_t *)temp_data;
  334. if (guider_ui.screen_main) {
  335. lvgl_port_lock(-1);
  336. lv_arc_set_value(guider_ui.screen_main_arc_AIQ, 500);
  337. if (*(uint16_t *) temp_data < 50) {
  338. // lv_arc_set_value(guider_ui.screen_main_arc_AIQ, *(uint16_t *) temp_data);
  339. lv_obj_set_style_bg_image_src(guider_ui.screen_main_label_AIQ_sign, &_you_RGB565A8_30x30,
  340. LV_PART_MAIN | LV_STATE_DEFAULT);
  341. lv_obj_set_style_arc_color(guider_ui.screen_main_arc_AIQ, lv_color_hex(0x2FDA64),
  342. LV_PART_INDICATOR | LV_STATE_DEFAULT);
  343. } else if (*(uint16_t *) temp_data < 150) {
  344. // lv_arc_set_value(guider_ui.screen_main_arc_AIQ, *(uint16_t *) temp_data);
  345. lv_obj_set_style_bg_image_src(guider_ui.screen_main_label_AIQ_sign, &_liang_RGB565A8_30x30,
  346. LV_PART_MAIN | LV_STATE_DEFAULT);
  347. lv_obj_set_style_arc_color(guider_ui.screen_main_arc_AIQ, lv_color_hex(0xFFF502),
  348. LV_PART_INDICATOR | LV_STATE_DEFAULT);
  349. } else if (*(uint16_t *) temp_data <= 500) {
  350. // lv_arc_set_value(guider_ui.screen_main_arc_AIQ, *(uint16_t *) temp_data);
  351. lv_obj_set_style_bg_image_src(guider_ui.screen_main_label_AIQ_sign, &_cha_RGB565A8_30x30,
  352. LV_PART_MAIN | LV_STATE_DEFAULT);
  353. lv_obj_set_style_arc_color(guider_ui.screen_main_arc_AIQ, lv_color_hex(0xd81e06),
  354. LV_PART_INDICATOR | LV_STATE_DEFAULT);
  355. } else if (*(uint16_t *) temp_data > 500) {
  356. // lv_arc_set_value(guider_ui.screen_main_arc_AIQ, temp_data_u16);
  357. lv_obj_set_style_bg_image_src(guider_ui.screen_main_label_AIQ_sign, &_cha_RGB565A8_30x30,
  358. LV_PART_MAIN | LV_STATE_DEFAULT);
  359. lv_obj_set_style_arc_color(guider_ui.screen_main_arc_AIQ, lv_color_hex(0xd81e06),
  360. LV_PART_INDICATOR | LV_STATE_DEFAULT);
  361. } else {
  362. }
  363. lv_label_set_text_fmt(guider_ui.screen_main_label_AIQ_vul, "%d", *(uint16_t *) temp_data);
  364. lvgl_port_unlock();
  365. }
  366. }
  367. err = mm_get_param(CID_RETURN_AIR_CO2, temp_data);
  368. if (err == ESP_OK) {
  369. err_count = 0;
  370. sht30Data.co2=*(uint16_t *)temp_data;
  371. if (guider_ui.screen_main) {
  372. lvgl_port_lock(-1);
  373. lv_label_set_text_fmt(guider_ui.screen_main_label_co2, "%d", *(uint16_t *) temp_data);
  374. lv_obj_add_flag(guider_ui.screen_main_lab_485_err, LV_OBJ_FLAG_HIDDEN);
  375. lvgl_port_unlock();
  376. }
  377. } else {
  378. err_count++;
  379. if (err_count >= 254)
  380. err_count = 30;
  381. }
  382. if (err_count >= 30) {
  383. if (guider_ui.screen_main) {
  384. lvgl_port_lock(-1);
  385. lv_obj_remove_flag(guider_ui.screen_main_lab_485_err, LV_OBJ_FLAG_HIDDEN);
  386. lvgl_port_unlock();
  387. }
  388. }
  389. xf_status.filter_life_remaining=(100-100*xf_status.filter_used_time/system_setting.filter_life_time);
  390. if (guider_ui.screen_main) {
  391. lvgl_port_lock(-1);
  392. lv_label_set_text_fmt(guider_ui.screen_main_label_lvxin, "%d%%", xf_status.filter_life_remaining);
  393. lvgl_port_unlock();
  394. }
  395. }
  396. /**
  397. * 状态同步任务,主要用于与分风箱主控同步当前用户的参数,并处理通讯故障
  398. * @param arg
  399. */
  400. _Noreturn static void status_sync_task(void *arg) {
  401. esp_err_t err = ESP_OK;
  402. for (;;) {
  403. mm_set_param(CID_POWER, (uint8_t *)&xf_status.power);
  404. vTaskDelay(pdTICKS_TO_MS(500));
  405. mm_set_param(CID_MODE, (uint8_t *)&xf_status.mode);
  406. vTaskDelay(pdTICKS_TO_MS(500));
  407. mm_set_param(CID_FAN_SPEED, (uint8_t *)&xf_status.fan_speed);
  408. vTaskDelay(pdTICKS_TO_MS(500));
  409. mm_set_param(CID_MAX_HUMIDITY, (uint8_t *)&xf_status.set_max_hum);
  410. vTaskDelay(pdTICKS_TO_MS(500));
  411. //
  412. // err = xf_set_power(false);
  413. // err = xf_set_mode(true);
  414. // err = xf_set_fan_speed(true);
  415. // err =xf_set_max_hum(true);
  416. // err =xf_set_min_hum(true);
  417. Refresh_UI();
  418. handle_err_code();
  419. vTaskDelay(5000 / portTICK_PERIOD_MS);
  420. }
  421. }
  422. /**
  423. * 云端上报任务
  424. * @param arg
  425. */
  426. _Noreturn static void cloud_report_task(void *arg) {
  427. for (;;) {
  428. if (xSemaphoreTake(report_task_sem, portMAX_DELAY) == pdTRUE) {
  429. ESP_LOGD(TAG, "cloud report");
  430. cJSON *data = cJSON_CreateObject();
  431. cJSON_AddNumberToObject(data, "power", xf_status.power);
  432. cJSON_AddNumberToObject(data, "set_max_hum", xf_status.set_max_hum);
  433. cJSON_AddNumberToObject(data, "filter_life_remaining", xf_status.filter_life_remaining);
  434. cJSON_AddNumberToObject(data, "set_filter_life_time", system_setting.filter_life_time);
  435. cJSON_AddNumberToObject(data, "mode", xf_status.mode);
  436. cJSON_AddNumberToObject(data, "temperature", (int) (sht30Data.temperature));
  437. cJSON_AddNumberToObject(data, "humidity", (int) (sht30Data.humidity));
  438. cJSON_AddNumberToObject(data, "air_quality", (int)sht30Data.air_quality);
  439. cJSON_AddNumberToObject(data, "co2", (int)sht30Data.co2);
  440. cJSON_AddNumberToObject(data, "fan_speed", xf_status.fan_speed);
  441. cJSON_AddNumberToObject(data, "timer_status", system_setting.timer_status);
  442. cJSON_AddNumberToObject(data, "duration", system_setting.duration);
  443. cJSON *root = cJSON_CreateObject();
  444. cJSON_AddStringToObject(root, "cmd", "status");
  445. cJSON_AddItemToObject(root, "params", data);
  446. publish_message_t msg = {
  447. .topic = "status",
  448. .data = root,
  449. };
  450. sparrow_publish_status(msg);
  451. }
  452. }
  453. //
  454. }
  455. _Noreturn static void report_trigger_task(void *arg) {
  456. for (;;) {
  457. if (cloud_connected) {
  458. xSemaphoreGive(report_task_sem);
  459. }
  460. vTaskDelay(pdTICKS_TO_MS(system_setting.report_data_duration * 1000));
  461. }
  462. }
  463. void xf_controller_init(system_setting_t *setting) {
  464. register_sparrow_commands(); // 注册云端指令
  465. report_task_sem = xSemaphoreCreateBinary();
  466. // timer_init_lx();
  467. // 启动状态同步任务
  468. xTaskCreate(status_sync_task, "status_sync_task", 4 * 1024, NULL, 5, &status_task_handle);
  469. // 启动云端上报任务,受信号量控制,无信号时任务不作操作,只有本地有操作或定时上报任务触发时才会上报。
  470. xTaskCreate(cloud_report_task, "report_task", 6 * 1024, NULL, 5, &cloud_report_handle);
  471. xTaskCreate(report_trigger_task, "trigger_task", 2 * 1024, NULL, 5, &report_trigger_handle);
  472. }
  473. void stop_xf_controller() {
  474. vTaskDelete(status_task_handle);
  475. vTaskDelete(cloud_report_handle);
  476. vTaskDelete(report_trigger_handle);
  477. // 停止modbus 协议 stack
  478. modbus_master_destroy();
  479. }