添加 SU03T 自动语音告警功能,更新状态处理以支持温湿度、火灾和门状态的自动告警

This commit is contained in:
Wang Beihong
2026-04-24 12:49:19 +08:00
parent 5916428fe4
commit 109bdbc848

View File

@@ -61,6 +61,7 @@ static const gpio_num_t kDataPin = GPIO_NUM_14;
#define TWDT_NORMAL_TIMEOUT_MS 5000
#define TWDT_UI_INIT_TIMEOUT_MS 120000
#define DOOR_OPEN_ALARM_SECONDS 60
#define SU03T_AUTO_ALERT_INTERVAL_MS (180000U)
typedef struct
{
@@ -419,6 +420,77 @@ static void su03t_reply_double_value(uint8_t reply_msgno, double value, const ch
ESP_LOGI(TAG, "SU03T TX %s msgno=0x%02X value=%.3f", label, reply_msgno, value);
}
static void su03t_reply_code(uint8_t reply_msgno, const char *label)
{
esp_err_t ret = su03t_send_frame(reply_msgno, NULL, 0);
if (ret != ESP_OK)
{
ESP_LOGW(TAG, "SU03T TX %s failed: %s", label, esp_err_to_name(ret));
return;
}
ESP_LOGI(TAG, "SU03T TX %s msgno=0x%02X", label, reply_msgno);
}
static void su03t_auto_alert_task(void *arg)
{
(void)arg;
int64_t last_temp_ms = 0;
int64_t last_humi_ms = 0;
int64_t last_fire_ms = 0;
int64_t last_door_ms = 0;
for (;;)
{
bool fire_danger = false;
bool door_closed = true;
float humidity = 0.0f;
float temp = 0.0f;
float th_hum_h = 70.0f;
float th_temp_h = 35.0f;
if (s_env_data_lock)
{
xSemaphoreTake(s_env_data_lock, portMAX_DELAY);
fire_danger = s_env_data.fire_danger;
door_closed = s_env_data.door_closed;
humidity = s_env_data.humidity;
temp = s_env_data.temp;
th_hum_h = s_env_data.th_hum_h;
th_temp_h = s_env_data.th_temp_h;
xSemaphoreGive(s_env_data_lock);
}
const int64_t now_ms = esp_timer_get_time() / 1000;
if (temp >= th_temp_h && (now_ms - last_temp_ms) >= SU03T_AUTO_ALERT_INTERVAL_MS)
{
su03t_reply_double_value(0x10, (double)temp, "auto_temp_high");
last_temp_ms = now_ms;
}
if (humidity >= th_hum_h && (now_ms - last_humi_ms) >= SU03T_AUTO_ALERT_INTERVAL_MS)
{
su03t_reply_double_value(0x11, (double)humidity, "auto_humi_high");
last_humi_ms = now_ms;
}
if (fire_danger && (now_ms - last_fire_ms) >= SU03T_AUTO_ALERT_INTERVAL_MS)
{
su03t_reply_code(0x12, "auto_fire_alarm");
last_fire_ms = now_ms;
}
if (!door_closed && (now_ms - last_door_ms) >= SU03T_AUTO_ALERT_INTERVAL_MS)
{
su03t_reply_code(0x13, "auto_door_open");
last_door_ms = now_ms;
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
/* 函数: su03t_rx_callback
* 作用: 执行模块内与函数名对应的业务逻辑。
* 重点: 关注输入合法性、返回码与并发安全。
@@ -442,11 +514,31 @@ static void su03t_rx_callback(const su03t_frame_t *frame, void *user_ctx)
double reply_value = 0.0;
uint8_t reply_msgno = 0;
const char *reply_label = NULL;
bool reply_code_only = false;
bool need_reply = false;
bool human_present = false;
bool door_closed = true;
bool fan_on = false;
bool light_on = false;
bool cool_on = false;
bool hot_on = false;
bool auto_mode = false;
float co2 = 0.0f;
if (s_env_data_lock)
{
xSemaphoreTake(s_env_data_lock, portMAX_DELAY);
human_present = s_env_data.human_present;
door_closed = s_env_data.door_closed;
fan_on = s_env_data.fan_on;
light_on = s_env_data.light_on;
cool_on = s_env_data.cool_on;
hot_on = s_env_data.hot_on;
auto_mode = s_env_data.auto_mode;
co2 = s_env_data.co2;
switch (cmd->id)
{
case SU03T_VOICE_CMD_ASK_TEMP:
@@ -485,6 +577,54 @@ static void su03t_rx_callback(const su03t_frame_t *frame, void *user_ctx)
reply_label = "weight";
need_reply = true;
break;
case SU03T_VOICE_CMD_ASK_HUM:
reply_msgno = human_present ? 0x1A : 0x1B;
reply_label = human_present ? "human_present" : "human_absent";
need_reply = true;
reply_code_only = true;
break;
case SU03T_VOICE_CMD_ASK_DOOR:
reply_msgno = door_closed ? 0x0D : 0x0C;
reply_label = door_closed ? "door_closed" : "door_open";
need_reply = true;
reply_code_only = true;
break;
case SU03T_VOICE_CMD_ASK_FAN:
reply_msgno = fan_on ? 0x14 : 0x15;
reply_label = fan_on ? "fan_on" : "fan_off";
need_reply = true;
reply_code_only = true;
break;
case SU03T_VOICE_CMD_ASK_LIGHT:
reply_msgno = light_on ? 0x20 : 0x21;
reply_label = light_on ? "light_on" : "light_off";
need_reply = true;
reply_code_only = true;
break;
case SU03T_VOICE_CMD_ASK_COOL:
reply_msgno = cool_on ? 0x16 : 0x17;
reply_label = cool_on ? "cool_on" : "cool_off";
need_reply = true;
reply_code_only = true;
break;
case SU03T_VOICE_CMD_ASK_HOT:
reply_msgno = hot_on ? 0x18 : 0x19;
reply_label = hot_on ? "hot_on" : "hot_off";
need_reply = true;
reply_code_only = true;
break;
case SU03T_VOICE_CMD_ASK_CONTROL:
reply_msgno = auto_mode ? 0x1C : 0x1D;
reply_label = auto_mode ? "mode_auto" : "mode_manual";
need_reply = true;
reply_code_only = true;
break;
case SU03T_VOICE_CMD_ASK_RICE:
reply_msgno = (co2 >= CO2_SPOILAGE_THRESHOLD_PPM) ? 0x1F : 0x1E;
reply_label = (co2 >= CO2_SPOILAGE_THRESHOLD_PPM) ? "rice_spoilage" : "rice_good";
need_reply = true;
reply_code_only = true;
break;
default:
break;
}
@@ -492,9 +632,16 @@ static void su03t_rx_callback(const su03t_frame_t *frame, void *user_ctx)
}
if (need_reply)
{
if (reply_code_only)
{
su03t_reply_code(reply_msgno, reply_label);
}
else
{
su03t_reply_double_value(reply_msgno, reply_value, reply_label);
}
}
su03t_voice_handle_frame(frame);
}
@@ -922,6 +1069,9 @@ extern "C" void app_main(void)
// 独立任务:继电器状态同步到 UI
xTaskCreate(relay_status_task, "relay_status_task", 4096, NULL, 5, NULL);
// 独立任务SU03T 自动语音告警(默认 3 分钟节流)
xTaskCreate(su03t_auto_alert_task, "su03t_auto_alert", 4096, NULL, 5, NULL);
// 独立任务MQTT 定时发布传感器数据
xTaskCreate(mqtt_publish_task, "mqtt_publish_task", 4096 * 2, NULL, 5, NULL);
}