| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- /**
- * @Author: 李建
- * @Date: 2025/9/9 13:55
- * Description: 热泵控制器
- * Copyright: Copyright (©) 2025 永续绿建. All rights reserved.
- */
- #include "heatpump_controller.h"
- #include "system/miscellaneous_interface.h"
- #include "freertos/FreeRTOS.h"
- #include <freertos/task.h>
- #include <cJSON.h>
- #include <esp_log.h>
- #include "freertos/semphr.h"
- #include "sht30.h"
- #include "gateway/access.h"
- #include "sub_device/command.h"
- #include "lvgl_port.h"
- #include "modbus_master.h"
- hp_controller_t hp_controller = {0};
- static SemaphoreHandle_t report_task_sem; // 上报任务信号量,用于实现操作完成上立即上报当前状态
- static TaskHandle_t cloud_report_handle;
- static const char *TAG = "hp_controller";
- static TaskHandle_t report_trigger_handle;
- static TaskHandle_t status_task_handle;
- static bool need_report_error = false;
- void set_bit(uint16_t *num, uint8_t bit, bool value) {
- if (bit > 15) return;
- if (value) {
- *num |= (1 << bit);
- } else {
- *num &= ~(1 << bit);
- }
- }
- bool get_bit(uint16_t num, uint8_t bit) {
- if (bit > 15) return false;
- return (num >> bit) & 1;
- }
- esp_err_t set_relay_status(uint8_t no, uint8_t value) {
- esp_err_t err = ESP_OK;
- set_bit(&hp_controller.relay_status, no, value);
- nvs_set_uint16(hp_controller.relay_status, NVS_RELEY_STATUS_KEY);
- if (cloud_connected) {
- xSemaphoreGive(report_task_sem);
- }
- return err;
- }
- static void update_power_ui(bool on_off) {
- // 同步更新 UI
- if (guider_ui.screen) {
- lvgl_port_lock(-1);
- //lv_obj_set_state(guider_ui.screen_ib_power, LV_IMAGEBUTTON_STATE_CHECKED_RELEASED, on_off);
- if (on_off) {
- lv_obj_remove_flag(guider_ui.screen_cont_power_on, LV_OBJ_FLAG_HIDDEN);
- lv_obj_add_flag(guider_ui.screen_cont_power_off, LV_OBJ_FLAG_HIDDEN);
- } else {
- lv_obj_remove_flag(guider_ui.screen_cont_power_off, LV_OBJ_FLAG_HIDDEN);
- lv_obj_add_flag(guider_ui.screen_cont_power_on, LV_OBJ_FLAG_HIDDEN);
- }
- lvgl_port_unlock();
- }
- }
- /******************************************云端指令开始*************************************************************/
- // 云端指令:设置电源开关
- static void cloud_set_power(char *params) {
- cJSON *data = cJSON_Parse(params);
- if (data != NULL) {
- cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
- hp_controller.power = value->valueint;
- heatpump_set_power(true);
- update_power_ui(hp_controller.power);
- cJSON_Delete(data);
- }
- }
- // 云端指令:设置模式
- static void cloud_set_mode(char *params) {
- cJSON *data = cJSON_Parse(params);
- if (data != NULL) {
- cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
- hp_controller.mode = value->valueint;
- if (guider_ui.screen) {
- if (hp_controller.mode == 1) {
- lvgl_port_lock(0);
- lv_label_set_text_static(guider_ui.screen_lab_mode, "制冷");
- lv_obj_set_style_arc_color(guider_ui.screen_arc_temp, lv_color_hex(0x00d9ff),
- LV_PART_INDICATOR | LV_STATE_DEFAULT);
- lv_label_set_text_fmt(guider_ui.screen_lab_ac_temp, "%d", hp_controller.cool_set_temp);
- lv_obj_add_state(guider_ui.screen_ib_cool, LV_STATE_CHECKED);
- lv_obj_remove_state(guider_ui.screen_ib_heat, LV_STATE_CHECKED);
- lv_arc_set_range(guider_ui.screen_arc_temp, 7 * 2, 22 * 2);
- lv_arc_set_value(guider_ui.screen_arc_temp, hp_controller.cool_set_temp * 2);
- lvgl_port_unlock();
- } else if (hp_controller.mode == 2) {
- lvgl_port_lock(0);
- lv_obj_set_style_arc_color(guider_ui.screen_arc_temp, lv_color_hex(0xfa890a),
- LV_PART_INDICATOR | LV_STATE_DEFAULT);
- lv_label_set_text_static(guider_ui.screen_lab_mode, "制热");
- lv_label_set_text_fmt(guider_ui.screen_lab_ac_temp, "%d", hp_controller.heat_set_temp);
- lv_obj_remove_state(guider_ui.screen_ib_cool, LV_STATE_CHECKED);
- lv_obj_add_state(guider_ui.screen_ib_heat, LV_STATE_CHECKED);
- lv_arc_set_range(guider_ui.screen_arc_temp, 30 * 2, 60 * 2);
- lv_arc_set_value(guider_ui.screen_arc_temp, hp_controller.heat_set_temp * 2);
- lvgl_port_unlock();
- }
- }
- heatpump_set_mode(hp_controller.mode);
- cJSON_Delete(data);
- }
- }
- // 云端指令:设置水温
- static void cloud_set_water_temp(char *params) {
- cJSON *data = cJSON_Parse(params);
- if (data != NULL) {
- cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
- heatpump_set_temp(value->valueint);
- // 更新UI
- if (guider_ui.screen) {
- lvgl_port_lock(0);
- lv_label_set_text_fmt(guider_ui.screen_lab_ac_temp, "%d", value->valueint);
- lv_arc_set_value(guider_ui.screen_arc_temp, value->valueint * 2);
- lvgl_port_unlock();
- }
- cJSON_Delete(data);
- }
- }
- // 云端指令 :设置分集水器某一路开关
- static void cloud_set_IO(char *params) {
- cJSON *data = cJSON_Parse(params);
- if (data != NULL) {
- cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
- cJSON *no = cJSON_GetObjectItemCaseSensitive(data, "no");
- if (no->valueint > 8 || value->valueint > 1) return;
- uint8_t n = no->valueint - 1;
- uint8_t v = value->valueint;
- set_relay_status(n, v); // 要减1
- // 更新UI
- if (guider_ui.WaterValvePage) {
- lvgl_port_lock(0);
- if (n == 0) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_1, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_1, LV_STATE_CHECKED);
- }
- if (n == 1) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_2, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_2, LV_STATE_CHECKED);
- }
- if (n == 2) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_3, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_3, LV_STATE_CHECKED);
- }
- if (n == 3) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_4, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_4, LV_STATE_CHECKED);
- }
- if (n == 4) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_5, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_5, LV_STATE_CHECKED);
- }
- if (n == 5) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_6, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_6, LV_STATE_CHECKED);
- }
- if (n == 6) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_7, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_7, LV_STATE_CHECKED);
- }
- if (n == 7) {
- v
- ? lv_obj_set_state(guider_ui.WaterValvePage_sw_8, LV_STATE_CHECKED, true)
- : lv_obj_clear_state(guider_ui.WaterValvePage_sw_8, LV_STATE_CHECKED);
- }
- lvgl_port_unlock();
- }
- cJSON_Delete(data);
- }
- }
- // 云端指令:联动开关
- static void cloud_set_link(char *params) {
- cJSON *data = cJSON_Parse(params);
- if (data != NULL) {
- cJSON *value = cJSON_GetObjectItemCaseSensitive(data, "value");
- hp_controller.linkage = value->valueint;
- heatpump_set_linkage();
- cJSON_Delete(data);
- }
- }
- /******************************************云端指令END*************************************************************/
- static void register_sparrow_commands() {
- sparrow_command set_power_cmd = {
- .name = "setPower",
- .unpack = &cloud_set_power
- };
- register_sparrow_command(set_power_cmd);
- // setMode
- sparrow_command set_mode_cmd = {
- .name = "setMode",
- .unpack = &cloud_set_mode
- };
- register_sparrow_command(set_mode_cmd);
- // setWaterTemp
- sparrow_command set_water_temp = {
- .name = "setWaterTemp",
- .unpack = &cloud_set_water_temp
- };
- register_sparrow_command(set_water_temp);
- // setIO
- sparrow_command set_io = {
- .name = "setIO",
- .unpack = &cloud_set_IO
- };
- register_sparrow_command(set_io);
- // setLinkage
- sparrow_command set_link = {
- .name = "setLinkage",
- .unpack = &cloud_set_link
- };
- register_sparrow_command(set_link);
- }
- _Noreturn static void report_trigger_task(void *arg) {
- for (;;) {
- if (cloud_connected) {
- xSemaphoreGive(report_task_sem);
- }
- vTaskDelay(pdTICKS_TO_MS(system_setting.report_data_duration * 1000));
- }
- }
- /**
- * 状态同步任务
- * @param arg
- */
- _Noreturn static void status_sync_task(void *arg) {
- esp_err_t err = ESP_OK;
- vTaskDelay(pdMS_TO_TICKS(5000));
- char in_temp_buf[12];
- char out_hum_buf[12];
- for (;;) {
- // 联动判断
- if (gpio_get_level(41) == 0 && system_setting.allow_linkage == 1) {
- hp_controller.power = 1;
- update_power_ui(true);
- }
- err = mm_set_param(CID_HP_POWER, &hp_controller.power);
- err = mm_set_param(CID_HP_SET_MODE, &hp_controller.mode);
- if (hp_controller.mode == MODE_COOL) mm_set_param(CID_HP_COOL_SET_TEMP, &hp_controller.cool_set_temp);
- if (hp_controller.mode == MODE_HEAT) mm_set_param(CID_HP_HEAT_SET_TEMP, &hp_controller.heat_set_temp);
- mm_get_param(CID_HP_OUTDOOR_TEMP, &hp_controller.outdoor_temp);
- mm_get_param(CID_HP_OUT_WATER_TEMP, &hp_controller.out_water_temp);
- err = mm_get_param(CID_HP_IN_WATER_TEMP, &hp_controller.in_water_temp);
- if (guider_ui.screen) {
- snprintf(in_temp_buf, sizeof(in_temp_buf), "%d°C", hp_controller.in_water_temp);
- snprintf(out_hum_buf, sizeof(out_hum_buf), "%d°C", hp_controller.out_water_temp);
- lvgl_port_lock(-1);
- lv_label_set_text_static(guider_ui.screen_lab_in_temp, in_temp_buf);
- lv_label_set_text_static(guider_ui.screen_lab_out_temp, out_hum_buf);
- if (err != ESP_OK) {
- lv_obj_remove_flag(guider_ui.screen_lab_icon_485, LV_OBJ_FLAG_HIDDEN);
- } else {
- lv_obj_add_flag(guider_ui.screen_lab_icon_485, LV_OBJ_FLAG_HIDDEN);
- }
- lvgl_port_unlock();
- }
- // 如果开启了分集水器控制
- if (system_setting.active_fjsq == 1) {
- uint8_t status = get_bit(hp_controller.relay_status, 0);
- err = mm_set_param(CID_RELAY_1_STATUS, &status);
- if (err == ESP_OK) hp_controller.fjsq_exist = 1;
- status = get_bit(hp_controller.relay_status, 1);
- mm_set_param(CID_RELAY_2_STATUS, &status);
- status = get_bit(hp_controller.relay_status, 2);
- mm_set_param(CID_RELAY_3_STATUS, &status);
- status = get_bit(hp_controller.relay_status, 3);
- mm_set_param(CID_RELAY_4_STATUS, &status);
- status = get_bit(hp_controller.relay_status, 4);
- mm_set_param(CID_RELAY_5_STATUS, &status);
- status = get_bit(hp_controller.relay_status, 5);
- mm_set_param(CID_RELAY_6_STATUS, &status);
- status = get_bit(hp_controller.relay_status, 6);
- mm_set_param(CID_RELAY_7_STATUS, &status);
- status = get_bit(hp_controller.relay_status, 7);
- err = mm_set_param(CID_RELAY_8_STATUS, &status);
- if (err != ESP_OK) hp_controller.fjsq_exist = 0;
- }
- // 读取故障
- mm_get_param(CID_HP_ERROR, &hp_controller.error);
- if (hp_controller.error == 1) {
- lvgl_port_lock(-1);
- lv_obj_remove_flag(guider_ui.screen_lab_icon_err, LV_OBJ_FLAG_HIDDEN);
- lvgl_port_unlock();
- need_report_error = true;
- xSemaphoreGive(report_task_sem);
- } else {
- lvgl_port_lock(-1);
- lv_obj_add_flag(guider_ui.screen_lab_icon_err, LV_OBJ_FLAG_HIDDEN);
- lvgl_port_unlock();
- }
- ESP_LOGD(TAG, "error:%d", hp_controller.error);
- vTaskDelay(5000 / portTICK_PERIOD_MS);
- }
- }
- /**
- * 云端上报任务
- * @param arg
- */
- _Noreturn static void cloud_report_task(void *arg) {
- for (;;) {
- if (xSemaphoreTake(report_task_sem, portMAX_DELAY) == pdTRUE) {
- if (need_report_error) {
- need_report_error = false;
- cJSON *data = cJSON_CreateObject();
- cJSON_AddNumberToObject(data, "error", hp_controller.error);
- cJSON *root = cJSON_CreateObject();
- cJSON_AddStringToObject(root, "cmd", "error");
- cJSON_AddItemToObject(root, "params", data);
- const publish_message_t msg = {
- .topic = "error",
- .data = root,
- };
- sparrow_publish_event(msg);
- }
- ESP_LOGD(TAG, "cloud report");
- cJSON *data = cJSON_CreateObject();
- cJSON_AddNumberToObject(data, "power", hp_controller.power);
- cJSON_AddNumberToObject(data, "cool_set_water_temp", hp_controller.cool_set_temp);
- cJSON_AddNumberToObject(data, "heat_set_water_temp", hp_controller.heat_set_temp);
- cJSON_AddNumberToObject(data, "mode", hp_controller.mode);
- cJSON_AddNumberToObject(data, "temperature", (int) sht30Data.temperature);
- cJSON_AddNumberToObject(data, "humidity", (int) sht30Data.humidity);
- cJSON_AddNumberToObject(data, "outdoor_temp", hp_controller.outdoor_temp);
- cJSON_AddNumberToObject(data, "out_water_temp", hp_controller.out_water_temp);
- cJSON_AddNumberToObject(data, "in_water_temp", hp_controller.in_water_temp);
- cJSON_AddNumberToObject(data, "fjsq_exist", hp_controller.fjsq_exist);
- cJSON_AddNumberToObject(data, "fjsq_status", hp_controller.relay_status);
- cJSON_AddNumberToObject(data, "linkage", hp_controller.linkage);
- cJSON *root = cJSON_CreateObject();
- cJSON_AddStringToObject(root, "cmd", "status");
- cJSON_AddItemToObject(root, "params", data);
- const publish_message_t msg = {
- .topic = "status",
- .data = root,
- };
- sparrow_publish_status(msg);
- }
- }
- }
- void heatpump_controller_init(system_setting_t *setting) {
- hp_controller.mode = setting->hp_mode;
- hp_controller.power = setting->hp_power;
- hp_controller.cool_set_temp = setting->hp_cool_set_temp;
- hp_controller.heat_set_temp = setting->hp_heat_set_temp;
- hp_controller.relay_status = setting->reley_status;
- hp_controller.linkage = setting->allow_linkage;
- register_sparrow_commands();
- report_task_sem = xSemaphoreCreateBinary();
- // 启动状态同步任务
- xTaskCreate(status_sync_task, "status_sync_task", 6 * 1024, NULL, 5, &status_task_handle);
- // 启动云端上报任务,受信号量控制,无信号时任务不作操作,只有本地有操作或定时上报任务触发时才会上报。
- xTaskCreate(cloud_report_task, "report_task", 6 * 1024, NULL, 5, &cloud_report_handle);
- // 启动云端上报任务
- xTaskCreate(report_trigger_task, "trigger_task", 2 * 1024, NULL, 5, &report_trigger_handle);
- // 初始化联动IO
- const gpio_config_t io_config = {
- .pin_bit_mask = (1ULL << 41),
- .mode = GPIO_MODE_DEF_INPUT
- };
- gpio_config(&io_config);
- }
- esp_err_t heatpump_set_power(bool saved) {
- esp_err_t err = ESP_OK;
- if (saved)
- nvs_set_uint16(hp_controller.power, NVS_HP_POWER_KEY);
- if (cloud_connected) {
- xSemaphoreGive(report_task_sem);
- }
- return err;
- }
- esp_err_t heatpump_set_mode(uint8_t mode) {
- esp_err_t err = ESP_OK;
- nvs_set_uint16(hp_controller.mode, NVS_HP_MODE_KEY);
- if (cloud_connected) {
- xSemaphoreGive(report_task_sem);
- }
- return err;
- }
- esp_err_t heatpump_set_temp(uint16_t temp) {
- esp_err_t err = ESP_OK;
- if (hp_controller.mode == MODE_COOL) {
- hp_controller.cool_set_temp = temp;
- nvs_set_uint16(hp_controller.cool_set_temp, NVS_HP_COOL_SET_TEMP_KEY);
- }
- if (hp_controller.mode == MODE_HEAT) {
- hp_controller.heat_set_temp = temp;
- nvs_set_uint16(hp_controller.heat_set_temp, NVS_HP_HEAT_SET_TEMP_KEY);
- }
- if (cloud_connected) {
- xSemaphoreGive(report_task_sem);
- }
- return err;
- }
- esp_err_t heatpump_set_linkage() {
- esp_err_t err = ESP_OK;
- nvs_set_uint16(hp_controller.linkage, NVS_ALLOW_LINKAGE_KEY);
- return err;
- }
- void stop_controller() {
- vTaskDelete(status_task_handle);
- vTaskDelete(cloud_report_handle);
- vTaskDelete(report_trigger_handle);
- // 停止modbus 协议 stack
- modbus_master_destroy();
- }
|