Files
Smart-granary-code/main/main.cpp

226 lines
6.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "wifi-connect.h"
#include "esp_lvgl_port.h"
#include "lvgl_st7789_use.h"
#include "ui.h"
#include "vars.h"
#include "relay_ctrl.h"
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "sntp_time.h"
#include "esp_mac.h"
#include "esp_system.h"
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "bh1750_use.h"
#include "aht30.h"
#include "MQ-2.h"
#include "JW01.h"
#include "human_door.h"
#define TAG "MAIN"
#define CO2_SPOILAGE_THRESHOLD_PPM 1000.0f
typedef struct
{
char time_str[32];
float lux;
float temp;
float humidity;
float gas_percent;
float tvoc;
float hcho;
float co2;
bool human_present;
bool door_closed;
} env_data_t;
static env_data_t s_env_data;
static SemaphoreHandle_t s_env_data_lock = NULL;
static bool wait_for_wifi_connected(TickType_t timeout_ticks)
{
const TickType_t start_ticks = xTaskGetTickCount();
while ((xTaskGetTickCount() - start_ticks) < timeout_ticks)
{
if (wifi_connect_get_status() == WIFI_CONNECT_STATUS_CONNECTED)
return true;
vTaskDelay(pdMS_TO_TICKS(200));
}
return false;
}
static void env_data_update_system_info(void)
{
if (s_env_data_lock == NULL)
return;
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
char time_buf[32];
strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
xSemaphoreTake(s_env_data_lock, portMAX_DELAY);
strncpy(s_env_data.time_str, time_buf, sizeof(s_env_data.time_str));
xSemaphoreGive(s_env_data_lock);
set_var_local_time(s_env_data.time_str);
}
static void ui_task(void *arg)
{
for (;;)
{
env_data_update_system_info();
lvgl_port_lock(0);
ui_tick();
lvgl_port_unlock();
vTaskDelay(pdMS_TO_TICKS(30));
}
}
static void status_task(void *arg)
{
(void)arg;
for (;;) {
human_door_state_t io_state{};
if (human_door_read(&io_state) == ESP_OK) {
set_var_hum_status(io_state.human_present ? "有人" : "无人");
set_var_door_status(io_state.door_closed ? "关闭" : "开启");
if (s_env_data_lock) {
xSemaphoreTake(s_env_data_lock, portMAX_DELAY);
s_env_data.human_present = io_state.human_present;
s_env_data.door_closed = io_state.door_closed;
xSemaphoreGive(s_env_data_lock);
}
}
vTaskDelay(pdMS_TO_TICKS(200));
}
}
extern "C" void app_main(void)
{
vTaskDelay(pdMS_TO_TICKS(100));
ESP_LOGI(TAG, "--- APP STARTING ---");
s_env_data_lock = xSemaphoreCreateMutex();
// 1. 初始化 Wi-Fi
ESP_ERROR_CHECK(wifi_connect_init());
// 2. 初始化显示屏和 LVGL
start_lvgl_demo();
// 3. 初始化 UI
lvgl_port_lock(100 / portTICK_PERIOD_MS);
ui_init();
lvgl_port_unlock();
set_var_food_status("良好");
// 7. 创建 UI 任务
xTaskCreate(ui_task, "ui_task", 8192, NULL, 5, NULL);
if (wait_for_wifi_connected(pdMS_TO_TICKS(15000)))
{
set_var_system_ip(wifi_connect_get_ip());
}
// 5. 初始化 I2C 总线并注册传感器 (共享总线)
ESP_ERROR_CHECK(bh1750_user_init());
i2c_master_bus_handle_t i2c_bus = bh1750_get_i2c_bus_handle();
// AHT30 挂载到同一条 I2C 总线上
aht30_handle_t aht30_dev = NULL;
ESP_ERROR_CHECK(aht30_create(i2c_bus, AHT30_I2C_ADDRESS, &aht30_dev));
// MQ-2 使用 ADC(GPIO8)
ESP_ERROR_CHECK(mq2_init());
// JW01 使用 UART0(GPIO43/44)
ESP_ERROR_CHECK(jw01_init());
// GPIO16: HC-SR312, GPIO17: Door switch(低电平=关门)
ESP_ERROR_CHECK(human_door_init());
set_var_hum_status("无人");
set_var_door_status("关闭");
// 6. 创建传感器读取任务
xTaskCreate([](void *arg)
{
aht30_handle_t aht30 = (aht30_handle_t)arg;
uint32_t log_cnt = 0;
for (;;) {
float lux = 0.0f, temp = 0.0f, hum = 0.0f, gas_percent = 0.0f;
jw01_data_t jw01{};
esp_err_t bh_ret = ESP_FAIL;
esp_err_t aht_ret = ESP_FAIL;
esp_err_t mq2_ret = ESP_FAIL;
esp_err_t jw_ret = ESP_FAIL;
// 读取 BH1750
bh_ret = bh1750_user_read(&lux);
if (bh_ret == ESP_OK) {
set_var_light_val(lux);
}
// 读取 AHT30
aht_ret = aht30_get_temperature_humidity_value(aht30, &temp, &hum);
if (aht_ret == ESP_OK) {
set_var_temp(temp);
set_var_humity_val(hum);
}
// 读取 MQ-2更新空气质量变量
mq2_ret = mq2_read_percent(&gas_percent);
if (mq2_ret == ESP_OK) {
set_var_air_quity(gas_percent);
}
// 读取 JW01TVOC/HCHO/CO2
jw_ret = jw01_read(&jw01, 200);
if (jw_ret == ESP_OK) {
if (jw01.co2_valid) {
if (jw01.co2 >= CO2_SPOILAGE_THRESHOLD_PPM) {
set_var_food_status("变质");
} else {
set_var_food_status("良好");
}
}
}
// 每 5 次打印一次综合状态,避免日志刷屏
if ((log_cnt++ % 10) == 0) {
ESP_LOGI(TAG,
"SENS bh=%s lux=%.1f | aht=%s t=%.1f h=%.1f | mq2=%s gas=%.1f | jw01=%s co2_valid=%d co2=%.1f",
esp_err_to_name(bh_ret), lux,
esp_err_to_name(aht_ret), temp, hum,
esp_err_to_name(mq2_ret), gas_percent,
esp_err_to_name(jw_ret), jw01.co2_valid ? 1 : 0, jw01.co2);
}
// 数据存入共享结构体
if (s_env_data_lock) {
xSemaphoreTake(s_env_data_lock, portMAX_DELAY);
s_env_data.lux = lux;
s_env_data.temp = temp;
s_env_data.humidity = hum;
s_env_data.gas_percent = gas_percent;
if (jw01.tvoc_valid) s_env_data.tvoc = jw01.tvoc;
if (jw01.hcho_valid) s_env_data.hcho = jw01.hcho;
if (jw01.co2_valid) s_env_data.co2 = jw01.co2;
xSemaphoreGive(s_env_data_lock);
}
vTaskDelay(pdMS_TO_TICKS(1000));
} }, "sensor_task", 4096 * 3, (void *)aht30_dev, 6, NULL);
// 独立任务:人体与门状态检测
xTaskCreate(status_task, "status_task", 4096, NULL, 6, NULL);
}