mirror of
https://git.beihong.wang/wangbeihong/iot-bedroom-environment-controller.git
synced 2026-04-23 16:53:05 +08:00
Add Zone.Identifier files for wifi-connect and partitions
- Created new Zone.Identifier file in components/wifi-connect with ZoneId=3. - Created new Zone.Identifier file in partitions.csv with ZoneId=3.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
idf_component_register(SRCS "main.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES esp_wifi cjson nvs_flash lvgl_st7735s_use esp_driver_i2c esp_type_utils esp_timer espressif__servo esp_event esp_netif serial_mcu mqtt
|
||||
PRIV_REQUIRES wifi-connect cjson nvs_flash lvgl_st7735s_use esp_driver_i2c esp_type_utils esp_timer espressif__servo esp_event esp_netif serial_mcu mqtt
|
||||
WHOLE_ARCHIVE
|
||||
)
|
||||
|
||||
|
||||
@@ -15,10 +15,7 @@ dependencies:
|
||||
# # All dependencies of `main` are public by default.
|
||||
# public: true
|
||||
|
||||
protocol_examples_common:
|
||||
path: ../components/protocol_examples_common
|
||||
|
||||
|
||||
espressif/esp_lvgl_port: ^2.7.0
|
||||
|
||||
k0i05/esp_ahtxx: ^1.2.7
|
||||
@@ -27,5 +24,4 @@ dependencies:
|
||||
|
||||
espressif/mqtt: ^1.0.0
|
||||
espressif/cjson: ^1.7.19
|
||||
|
||||
|
||||
chiehmin/sgp30: ^1.0.0
|
||||
|
||||
442
main/main.c
442
main/main.c
@@ -37,14 +37,14 @@
|
||||
#include "ui_display.h"
|
||||
#include "iot_servo.h"
|
||||
#include "serial_mcu.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "wifi-connect.h" // WiFi连接管理
|
||||
|
||||
/* ========================= 2. 宏定义 ========================= */
|
||||
// 日志标签
|
||||
#define TAG "main"
|
||||
#define AHT30_TAG "i2c0_ahtxx_task"
|
||||
#define BH1750_TAG "i2c0_bh1750_task"
|
||||
#define MQ135_TAG "mq135_task"
|
||||
#define MQ135_TAG "mq135_task" // (removed) MQ135-related functionality disabled
|
||||
#define LVGL_TAG "lvgl_task"
|
||||
#define SERVO_TAG "servo_task"
|
||||
#define SNTP_TAG "sntp_task"
|
||||
@@ -123,10 +123,9 @@ typedef struct
|
||||
float temperature;
|
||||
float humidity;
|
||||
float lux;
|
||||
float air_quality;
|
||||
bool ahtxx_valid;
|
||||
bool bh1750_valid;
|
||||
bool mq135_valid;
|
||||
// MQ135 fields removed: air_quality, mq135_valid
|
||||
} sensor_data_t;
|
||||
|
||||
// 设备状态结构体
|
||||
@@ -145,7 +144,7 @@ typedef struct
|
||||
float temperature;
|
||||
float humidity;
|
||||
float light_intensity;
|
||||
uint16_t air_quality;
|
||||
// air_quality removed (MQ135)
|
||||
char curtain_state[10];
|
||||
char led_state[10];
|
||||
uint8_t led_power;
|
||||
@@ -181,9 +180,10 @@ bool g_high_temp_alerted = false; // 高温提醒是否已发送(避免重复
|
||||
|
||||
// 自动通风控制模式配置
|
||||
#define VENTILATION_MODE_TAG "ventilation_mode"
|
||||
#define AIR_QUALITY_THRESHOLD 50.0f // 空气质量阈值
|
||||
bool g_ventilation_mode_enabled = true; // 通风模式是否启用
|
||||
bool g_air_quality_alerted = false; // 空气质量提醒是否已发送(避免重复提醒)
|
||||
// AIR quality and ventilation functionality removed
|
||||
// #define AIR_QUALITY_THRESHOLD 50.0f
|
||||
// bool g_ventilation_mode_enabled = true;
|
||||
// bool g_air_quality_alerted = false;
|
||||
|
||||
// 时间段配置
|
||||
time_period_config_t g_day_period = {
|
||||
@@ -276,7 +276,7 @@ void init_gpio_output(void);
|
||||
// 传感器任务
|
||||
void i2c0_ahtxx_task(void *pvParameters);
|
||||
void i2c0_bh1750_task(void *pvParameters);
|
||||
void mq135_task(void *pvParameters);
|
||||
// MQ135 task removed: void mq135_task(void *pvParameters);
|
||||
|
||||
// 其他任务
|
||||
static void rx_task(void *arg);
|
||||
@@ -1194,7 +1194,7 @@ void mqtt_publish_task(void *pvParameters)
|
||||
g_device_message.telemetry.temperature = 0;
|
||||
g_device_message.telemetry.humidity = 0;
|
||||
g_device_message.telemetry.light_intensity = 0;
|
||||
g_device_message.telemetry.air_quality = 0;
|
||||
// air_quality removed from telemetry
|
||||
strcpy(g_device_message.telemetry.curtain_state, "close");
|
||||
strcpy(g_device_message.telemetry.led_state, "close");
|
||||
g_device_message.telemetry.led_power = 0;
|
||||
@@ -1224,11 +1224,7 @@ void mqtt_publish_task(void *pvParameters)
|
||||
g_device_message.telemetry.light_intensity = g_sensor_data.lux;
|
||||
}
|
||||
|
||||
// 更新空气质量数据
|
||||
if (g_sensor_data.mq135_valid)
|
||||
{
|
||||
g_device_message.telemetry.air_quality = g_sensor_data.air_quality;
|
||||
}
|
||||
// MQ135 data removed: air_quality not populated
|
||||
|
||||
xSemaphoreGive(xMqttMessageMutex);
|
||||
}
|
||||
@@ -1269,7 +1265,7 @@ void mqtt_publish_task(void *pvParameters)
|
||||
cJSON_AddNumberToObject(telemetry_obj, "humidity", roundf(g_device_message.telemetry.humidity * 100) / 100);
|
||||
cJSON_AddNumberToObject(telemetry_obj, "light_intensity", roundf(g_device_message.telemetry.light_intensity * 100) / 100);
|
||||
|
||||
cJSON_AddNumberToObject(telemetry_obj, "air_quality", g_device_message.telemetry.air_quality);
|
||||
// air_quality removed from telemetry
|
||||
cJSON_AddStringToObject(telemetry_obj, "curtain_state", g_device_message.telemetry.curtain_state);
|
||||
cJSON_AddStringToObject(telemetry_obj, "led_state", g_device_message.telemetry.led_state);
|
||||
cJSON_AddNumberToObject(telemetry_obj, "led_power", g_device_message.telemetry.led_power);
|
||||
@@ -2073,12 +2069,7 @@ void i2c0_ahtxx_task(void *pvParameters)
|
||||
ui_update_sensor_data(
|
||||
g_sensor_data.ahtxx_valid ? g_sensor_data.temperature : -1.0f,
|
||||
g_sensor_data.ahtxx_valid ? g_sensor_data.humidity : -1.0f,
|
||||
g_sensor_data.bh1750_valid ? g_sensor_data.lux : -1.0f,
|
||||
g_sensor_data.mq135_valid ? g_sensor_data.air_quality : -1.0f,
|
||||
g_sensor_data.mq135_valid ? (g_sensor_data.air_quality <= 20 ? "Excellent" : g_sensor_data.air_quality <= 100 ? "Good"
|
||||
: g_sensor_data.air_quality <= 300 ? "Moderate"
|
||||
: "High")
|
||||
: "N/A");
|
||||
g_sensor_data.bh1750_valid ? g_sensor_data.lux : -1.0f);
|
||||
xSemaphoreGive(xSensorDataMutex);
|
||||
}
|
||||
|
||||
@@ -2182,12 +2173,7 @@ void i2c0_bh1750_task(void *pvParameters)
|
||||
ui_update_sensor_data(
|
||||
g_sensor_data.ahtxx_valid ? g_sensor_data.temperature : -1.0f,
|
||||
g_sensor_data.ahtxx_valid ? g_sensor_data.humidity : -1.0f,
|
||||
g_sensor_data.bh1750_valid ? g_sensor_data.lux : -1.0f,
|
||||
g_sensor_data.mq135_valid ? g_sensor_data.air_quality : -1.0f,
|
||||
g_sensor_data.mq135_valid ? (g_sensor_data.air_quality <= 20 ? "Excellent" : g_sensor_data.air_quality <= 100 ? "Good"
|
||||
: g_sensor_data.air_quality <= 300 ? "Moderate"
|
||||
: "High")
|
||||
: "N/A");
|
||||
g_sensor_data.bh1750_valid ? g_sensor_data.lux : -1.0f);
|
||||
xSemaphoreGive(xSensorDataMutex);
|
||||
}
|
||||
|
||||
@@ -2213,36 +2199,7 @@ void print_sensor_data(void)
|
||||
{
|
||||
if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
ESP_LOGI(TAG, "======= Sensor Data ========");
|
||||
if (g_sensor_data.ahtxx_valid)
|
||||
{
|
||||
ESP_LOGI(TAG, "Temperature: %.2f°C", g_sensor_data.temperature);
|
||||
ESP_LOGI(TAG, "Humidity: %.2f%%", g_sensor_data.humidity);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Temperature: Invalid");
|
||||
ESP_LOGI(TAG, "Humidity: Invalid");
|
||||
}
|
||||
|
||||
if (g_sensor_data.bh1750_valid)
|
||||
{
|
||||
ESP_LOGI(TAG, "Light Intensity: %.2flx", g_sensor_data.lux);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Light Intensity: Invalid");
|
||||
}
|
||||
|
||||
if (g_sensor_data.mq135_valid)
|
||||
{
|
||||
ESP_LOGI(TAG, "Air Quality: %.2f Index", g_sensor_data.air_quality);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Air Quality: Invalid");
|
||||
}
|
||||
ESP_LOGI(TAG, "==========================");
|
||||
// 已移除所有传感器数据日志打印
|
||||
xSemaphoreGive(xSensorDataMutex);
|
||||
}
|
||||
}
|
||||
@@ -2585,34 +2542,34 @@ static void alarm_clock_main_task(void *arg)
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
esp_log_level_set("dhcps", ESP_LOG_DEBUG);
|
||||
esp_log_level_set("esp_netif", ESP_LOG_DEBUG);
|
||||
esp_log_level_set("esp_netif_lwip", ESP_LOG_DEBUG);
|
||||
esp_log_level_set("wifi", ESP_LOG_DEBUG);
|
||||
initialize_nvs(); // 初始化NVS
|
||||
// esp_log_level_set("*", ESP_LOG_INFO);
|
||||
// esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("mqtt_example", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("transport", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("outbox", ESP_LOG_VERBOSE);
|
||||
// esp_log_level_set("dhcps", ESP_LOG_DEBUG);
|
||||
// esp_log_level_set("esp_netif", ESP_LOG_DEBUG);
|
||||
// esp_log_level_set("esp_netif_lwip", ESP_LOG_DEBUG);
|
||||
// esp_log_level_set("wifi", ESP_LOG_DEBUG);
|
||||
|
||||
// 初始化 Wi-Fi 配网组件,支持长按按键进入配网
|
||||
ESP_ERROR_CHECK(wifi_connect_init());
|
||||
printf("设备启动完成:进入配网模式,手机连接 ESP32-* 后访问 http://192.168.4.1\n");
|
||||
|
||||
ESP_ERROR_CHECK(esp_netif_init()); // Initialize ESP-NETIF
|
||||
// 创建默认事件循环
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
// 连接WIFI
|
||||
ESP_ERROR_CHECK(example_connect());
|
||||
// ESP_ERROR_CHECK(example_connect());
|
||||
|
||||
// Print out Access Point Information
|
||||
wifi_ap_record_t ap_info;
|
||||
ESP_ERROR_CHECK(esp_wifi_sta_get_ap_info(&ap_info));
|
||||
ESP_LOGI(TAG, "--- Access Point Information ---");
|
||||
ESP_LOG_BUFFER_HEX("MAC Address", ap_info.bssid, sizeof(ap_info.bssid));
|
||||
ESP_LOG_BUFFER_CHAR("SSID", ap_info.ssid, sizeof(ap_info.ssid));
|
||||
ESP_LOGI(TAG, "Primary Channel: %d", ap_info.primary);
|
||||
ESP_LOGI(TAG, "RSSI: %d", ap_info.rssi);
|
||||
// // Print out Access Point Information
|
||||
// wifi_ap_record_t ap_info;
|
||||
// ESP_ERROR_CHECK(esp_wifi_sta_get_ap_info(&ap_info));
|
||||
// ESP_LOGI(TAG, "--- Access Point Information ---");
|
||||
// ESP_LOG_BUFFER_HEX("MAC Address", ap_info.bssid, sizeof(ap_info.bssid));
|
||||
// ESP_LOG_BUFFER_CHAR("SSID", ap_info.ssid, sizeof(ap_info.ssid));
|
||||
// ESP_LOGI(TAG, "Primary Channel: %d", ap_info.primary);
|
||||
// ESP_LOGI(TAG, "RSSI: %d", ap_info.rssi);
|
||||
|
||||
// 初始化I2C总线
|
||||
ESP_ERROR_CHECK(i2c_master_init());
|
||||
@@ -2663,10 +2620,9 @@ void app_main(void)
|
||||
xTaskCreate(time_period_check_task, "time_period_task", 4096, NULL, 5, NULL);
|
||||
// 创建降温模式任务
|
||||
xTaskCreate(cooling_mode_task, "cooling_mode_task", 4096, NULL, 5, NULL);
|
||||
// 创建自动通风控制模式任务
|
||||
xTaskCreate(ventilation_mode_task, "ventilation_mode_task", 4096, NULL, 5, NULL);
|
||||
// 创建MQ135传感器任务
|
||||
xTaskCreate(mq135_task, "mq135_task", 4096, NULL, 5, NULL);
|
||||
// 自动通风与 MQ135 相关任务已移除
|
||||
// xTaskCreate(ventilation_mode_task, "ventilation_mode_task", 4096, NULL, 5, NULL);
|
||||
// xTaskCreate(mq135_task, "mq135_task", 4096, NULL, 5, NULL);
|
||||
// 创建外设控制任务
|
||||
xTaskCreate(peripheral_control_task, "peripheral_control_task", 4096, NULL, 5, NULL);
|
||||
|
||||
@@ -2679,7 +2635,7 @@ void app_main(void)
|
||||
while (1)
|
||||
{
|
||||
// 定期打印传感器数据
|
||||
// print_sensor_data();
|
||||
print_sensor_data();
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
@@ -2697,7 +2653,7 @@ static void cooling_mode_task(void *pvParameters)
|
||||
cooling_mode_load_from_nvs();
|
||||
|
||||
// 高温阈值
|
||||
const float HIGH_TEMP_THRESHOLD = 35.0f;
|
||||
const float HIGH_TEMP_THRESHOLD = 48.0f;
|
||||
|
||||
while (1)
|
||||
{
|
||||
@@ -2761,7 +2717,7 @@ static void cooling_mode_task(void *pvParameters)
|
||||
xSemaphoreGive(xControlFlagMutex);
|
||||
}
|
||||
|
||||
ESP_LOGW(COOLING_MODE_TAG, "High temperature alert: %.1f°C (>35°C)", current_temp);
|
||||
ESP_LOGW(COOLING_MODE_TAG, "High temperature alert: %.1f°C (>40°C)", current_temp);
|
||||
|
||||
// 发送MQTT提醒消息
|
||||
if (g_mqtt_client != NULL)
|
||||
@@ -2819,309 +2775,15 @@ static void cooling_mode_task(void *pvParameters)
|
||||
*/
|
||||
static void ventilation_mode_task(void *pvParameters)
|
||||
{
|
||||
ESP_LOGI(VENTILATION_MODE_TAG, "Ventilation mode task started");
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (g_ventilation_mode_enabled)
|
||||
{
|
||||
float current_air_quality = 0;
|
||||
bool air_quality_valid = false;
|
||||
|
||||
// 获取当前空气质量
|
||||
if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
current_air_quality = g_sensor_data.air_quality;
|
||||
air_quality_valid = g_sensor_data.mq135_valid;
|
||||
xSemaphoreGive(xSensorDataMutex);
|
||||
}
|
||||
|
||||
if (air_quality_valid)
|
||||
{
|
||||
// 检测空气质量是否超过阈值
|
||||
if (current_air_quality > AIR_QUALITY_THRESHOLD)
|
||||
{
|
||||
// 需要通风,确保风扇开启
|
||||
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
if (!fan_control_flag)
|
||||
{
|
||||
fan_control_flag = true;
|
||||
ESP_LOGW(VENTILATION_MODE_TAG, "Air quality %.2f > %.1f, Fan ON",
|
||||
current_air_quality, AIR_QUALITY_THRESHOLD);
|
||||
update_telemetry_and_report();
|
||||
}
|
||||
xSemaphoreGive(xControlFlagMutex);
|
||||
}
|
||||
|
||||
// 发送提醒(只发送一次)
|
||||
if (!g_air_quality_alerted)
|
||||
{
|
||||
g_air_quality_alerted = true;
|
||||
|
||||
// 蜂鸣器发出轻微提示音(短促)
|
||||
sendControlFrame(0x02, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(200)); // 持续200ms
|
||||
sendControlFrame(0x02, 0);
|
||||
|
||||
// 发送MQTT提醒消息
|
||||
if (g_mqtt_client != NULL)
|
||||
{
|
||||
cJSON *root = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(root, "type", "device_message");
|
||||
cJSON_AddStringToObject(root, "device_id", g_device_message.device_id);
|
||||
cJSON_AddStringToObject(root, "device_type", g_device_message.device_type);
|
||||
cJSON_AddStringToObject(root, "message_type", "air_quality_alert");
|
||||
|
||||
cJSON *data_obj = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(data_obj, "alert", "卧室需要通风");
|
||||
cJSON_AddNumberToObject(data_obj, "air_quality", roundf(current_air_quality * 10) / 10);
|
||||
cJSON_AddItemToObject(root, "data", data_obj);
|
||||
|
||||
char *json_message = cJSON_Print(root);
|
||||
if (json_message)
|
||||
{
|
||||
esp_mqtt_client_publish(g_mqtt_client, MQTT_PUBLISH_TOPIC_QOS0, json_message, 0, 0, 0);
|
||||
ESP_LOGI(VENTILATION_MODE_TAG, "Air quality alert sent: %s", json_message);
|
||||
free(json_message);
|
||||
}
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (current_air_quality < (AIR_QUALITY_THRESHOLD - 10)) // 添加滞后,防止频繁切换
|
||||
{
|
||||
// 空气质量恢复良好,关闭风扇
|
||||
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
if (fan_control_flag)
|
||||
{
|
||||
fan_control_flag = false;
|
||||
ESP_LOGI(VENTILATION_MODE_TAG, "Air quality %.2f < %.1f, Fan OFF",
|
||||
current_air_quality, AIR_QUALITY_THRESHOLD - 10);
|
||||
update_telemetry_and_report();
|
||||
}
|
||||
xSemaphoreGive(xControlFlagMutex);
|
||||
}
|
||||
|
||||
// 重置提醒标志
|
||||
if (g_air_quality_alerted)
|
||||
{
|
||||
g_air_quality_alerted = false;
|
||||
ESP_LOGI(VENTILATION_MODE_TAG, "Air quality normalized: %.2f, reset alert", current_air_quality);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 每5秒检查一次
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
}
|
||||
ESP_LOGI("ventilation_mode_task", "ventilation mode removed");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// MQ135传感器任务
|
||||
// MQ135 task removed; provide a short stub to avoid undefined references
|
||||
void mq135_task(void *pvParameters)
|
||||
{
|
||||
// 初始化ADC
|
||||
adc1_config_width(ADC_WIDTH_BIT_12); // ADC1 分辨率 12 位
|
||||
adc1_config_channel_atten(ADC_CHANNEL_0, ADC_ATTEN_DB_12); // GPIO34, 12dB
|
||||
|
||||
// 动态校准变量
|
||||
static bool r0_calibrated = false;
|
||||
static float R0 = 10.0f; // 初始 R0(更合理的经验值,10kΩ左右)
|
||||
static int calibrate_count = 0; // 校准采样计数器
|
||||
static float rs_sum = 0.0f; // Rs累加值
|
||||
|
||||
// 采样平滑滤波窗口
|
||||
#define SAMPLE_WINDOW_SIZE 20 // 滑动平均窗口大小
|
||||
static float voltage_buffer[SAMPLE_WINDOW_SIZE] = {0};
|
||||
static int buffer_index = 0;
|
||||
static bool buffer_filled = false;
|
||||
|
||||
// 预热阶段
|
||||
#define WARMUP_SAMPLES 100 // 预热采样次数
|
||||
static int warmup_count = 0;
|
||||
|
||||
ESP_LOGI(MQ135_TAG, "MQ135 sensor task started - Preheating for %d samples...", WARMUP_SAMPLES);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int adc_value = adc1_get_raw(ADC_CHANNEL_0);
|
||||
|
||||
// ADC -> 电压(工程近似)
|
||||
float voltage = (adc_value * 3.3f) / 4095.0f;
|
||||
|
||||
// 电压保护
|
||||
if (voltage >= 3.3f)
|
||||
voltage = 3.29f;
|
||||
if (voltage <= 0.0f)
|
||||
voltage = 0.01f;
|
||||
|
||||
// === 采样平滑滤波 ===
|
||||
// 存入滑动窗口
|
||||
voltage_buffer[buffer_index] = voltage;
|
||||
buffer_index = (buffer_index + 1) % SAMPLE_WINDOW_SIZE;
|
||||
|
||||
// 检查窗口是否填满
|
||||
if (buffer_index == 0)
|
||||
{
|
||||
buffer_filled = true;
|
||||
}
|
||||
|
||||
// 计算滑动平均电压
|
||||
float smoothed_voltage = 0.0f;
|
||||
int window_size = buffer_filled ? SAMPLE_WINDOW_SIZE : buffer_index;
|
||||
|
||||
for (int i = 0; i < window_size; i++)
|
||||
{
|
||||
smoothed_voltage += voltage_buffer[i];
|
||||
}
|
||||
smoothed_voltage /= window_size;
|
||||
|
||||
// 计算 Rs(RL = 10kΩ)
|
||||
float rs = ((3.3f - smoothed_voltage) / smoothed_voltage) * 10.0f;
|
||||
|
||||
// === 预热阶段 ===
|
||||
if (warmup_count < WARMUP_SAMPLES)
|
||||
{
|
||||
warmup_count++;
|
||||
if (warmup_count % 20 == 0) // 每20个采样打印一次进度
|
||||
{
|
||||
ESP_LOGI(MQ135_TAG, "MQ135 preheating... %d/%d", warmup_count, WARMUP_SAMPLES);
|
||||
}
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
else if (warmup_count == WARMUP_SAMPLES)
|
||||
{
|
||||
warmup_count++;
|
||||
ESP_LOGI(MQ135_TAG, "MQ135 preheating completed, starting calibration");
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS); // 短暂延迟
|
||||
continue;
|
||||
}
|
||||
|
||||
// === 温湿度补偿 ===
|
||||
// MQ135传感器对温度和湿度敏感,需要进行补偿
|
||||
float temperature = 20.0f; // 默认20°C
|
||||
float humidity = 65.0f; // 默认65%RH
|
||||
|
||||
// 获取实际温湿度
|
||||
if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
if (g_sensor_data.ahtxx_valid)
|
||||
{
|
||||
temperature = g_sensor_data.temperature;
|
||||
humidity = g_sensor_data.humidity;
|
||||
}
|
||||
xSemaphoreGive(xSensorDataMutex);
|
||||
}
|
||||
|
||||
// 温度补偿公式 (参考MQ135数据手册)
|
||||
// R0(T) = R0(T0) * exp(A * (1/T - 1/T0))
|
||||
// A为温度系数,约为0.00025
|
||||
float temp_compensation = 1.0f + 0.00025f * (temperature - 20.0f);
|
||||
|
||||
// 湿度补偿 (经验公式)
|
||||
float hum_compensation = 1.0f + 0.0005f * (humidity - 65.0f);
|
||||
|
||||
// 应用补偿后的Rs
|
||||
float rs_compensated = rs / (temp_compensation * hum_compensation);
|
||||
|
||||
// === R0校准阶段 ===
|
||||
if (!r0_calibrated && calibrate_count < 100)
|
||||
{
|
||||
rs_sum += rs_compensated;
|
||||
calibrate_count++;
|
||||
|
||||
if (calibrate_count == 100)
|
||||
{
|
||||
// 使用100次采样的平均值作为R0(假设在干净空气中启动)
|
||||
R0 = rs_sum / 100.0f;
|
||||
ESP_LOGI(MQ135_TAG, "MQ135 R0 calibrated to: %.2f (from 100 samples, temp=%.1f°C, hum=%.1f%%)",
|
||||
R0, temperature, humidity);
|
||||
r0_calibrated = true;
|
||||
}
|
||||
else if (calibrate_count % 20 == 0)
|
||||
{
|
||||
ESP_LOGI(MQ135_TAG, "Calibrating R0... %d/100", calibrate_count);
|
||||
}
|
||||
}
|
||||
else if (!r0_calibrated)
|
||||
{
|
||||
// 如果校准未完成,使用初始R0值
|
||||
ESP_LOGI(MQ135_TAG, "Using initial R0: %.2f", R0);
|
||||
}
|
||||
|
||||
// Rs/R0 比值
|
||||
float ratio = rs_compensated / R0;
|
||||
|
||||
// 防止ratio异常(传感器故障或校准错误)
|
||||
if (ratio <= 0.1f || ratio > 100.0f)
|
||||
{
|
||||
ESP_LOGW(MQ135_TAG, "Abnormal ratio detected: %.3f, skipping", ratio);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* =====================================================
|
||||
* MQ135 传感器方程
|
||||
* Rs/R0 = a * (ppm)^b
|
||||
* ppm = (Rs/R0 / a)^(1/b)
|
||||
* 对于 MQ135: a=116.602, b=-2.769
|
||||
* ===================================================== */
|
||||
float mq135_concentration = 116.602f * powf(ratio, -2.769f);
|
||||
|
||||
// 工程修正:不使用放大系数
|
||||
mq135_concentration = mq135_concentration * 1.0f;
|
||||
|
||||
// 下限保护,避免负值或过小值
|
||||
if (mq135_concentration < 1.0f)
|
||||
mq135_concentration = 1.0f;
|
||||
|
||||
// 上限保护
|
||||
if (mq135_concentration > 1000.0f)
|
||||
{
|
||||
ESP_LOGW(MQ135_TAG, "Concentration too high: %.2f, clamped to 1000", mq135_concentration);
|
||||
mq135_concentration = 1000.0f;
|
||||
}
|
||||
|
||||
// 保留两位小数
|
||||
mq135_concentration = roundf(mq135_concentration * 100.0f) / 100.0f;
|
||||
|
||||
// 更新全局数据
|
||||
if (xSensorDataMutex != NULL &&
|
||||
xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
g_sensor_data.air_quality = mq135_concentration;
|
||||
g_sensor_data.mq135_valid = true;
|
||||
xSemaphoreGive(xSensorDataMutex);
|
||||
}
|
||||
|
||||
// UI 更新
|
||||
if (xSensorDataMutex != NULL &&
|
||||
xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE)
|
||||
{
|
||||
ui_update_sensor_data(
|
||||
g_sensor_data.ahtxx_valid ? g_sensor_data.temperature : -1.0f,
|
||||
g_sensor_data.ahtxx_valid ? g_sensor_data.humidity : -1.0f,
|
||||
g_sensor_data.bh1750_valid ? g_sensor_data.lux : -1.0f,
|
||||
mq135_concentration,
|
||||
mq135_concentration <= 20 ? "Excellent" : mq135_concentration <= 100 ? "Good"
|
||||
: mq135_concentration <= 300 ? "Moderate"
|
||||
: "High");
|
||||
xSemaphoreGive(xSensorDataMutex);
|
||||
}
|
||||
|
||||
// 每10次采样打印一次详细日志
|
||||
static int log_count = 0;
|
||||
log_count++;
|
||||
if (log_count >= 10)
|
||||
{
|
||||
log_count = 0;
|
||||
ESP_LOGI(MQ135_TAG, "ADC:%d, Volt:%.3fV->%.3fV, Rs:%.2f, Ratio:%.3f, PPM:%.2f (T:%.1f°C, H:%.1f%%)",
|
||||
adc_value, voltage, smoothed_voltage, rs, ratio, mq135_concentration, temperature, humidity);
|
||||
}
|
||||
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
ESP_LOGI("mq135_task", "mq135 task removed");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
// Remaining MQ135 implementation removed
|
||||
|
||||
Reference in New Issue
Block a user