feat: 添加传感器配置和MQTT控制功能,优化自动控制逻辑

This commit is contained in:
Wang Beihong
2026-03-07 02:48:58 +08:00
parent 5980e171c4
commit 7accf1279e

View File

@@ -19,60 +19,92 @@
#include "auto_alerts.h"
#include "mqtt_control.h" // MQTT 控制接口
// 配置宏定义BH1750 光照传感器是否启用(默认禁用)
#ifndef CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE
#define CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE 0
#endif
// 配置宏定义AHT30 温湿度传感器是否启用(默认禁用)
#ifndef CONFIG_I2C_MASTER_MESSAGER_AHT30_ENABLE
#define CONFIG_I2C_MASTER_MESSAGER_AHT30_ENABLE 0
#endif
// 配置宏定义BH1750 读取周期毫秒默认500ms
#ifndef CONFIG_I2C_MASTER_MESSAGER_BH1750_READ_PERIOD_MS
#define CONFIG_I2C_MASTER_MESSAGER_BH1750_READ_PERIOD_MS 500
#endif
// 配置宏定义AHT30 读取周期毫秒默认2000ms
#ifndef CONFIG_I2C_MASTER_MESSAGER_AHT30_READ_PERIOD_MS
#define CONFIG_I2C_MASTER_MESSAGER_AHT30_READ_PERIOD_MS 2000
#endif
// 配置宏定义I2C 是否启用内部上拉电阻(默认启用)
#ifndef CONFIG_I2C_MASTER_MESSAGER_ENABLE_INTERNAL_PULLUP
#define CONFIG_I2C_MASTER_MESSAGER_ENABLE_INTERNAL_PULLUP 1
#endif
// I2C 端口配置
#define BOTANY_I2C_PORT I2C_NUM_0
// I2C SCL 引脚
#define BOTANY_I2C_SCL_GPIO GPIO_NUM_5
// I2C SDA 引脚
#define BOTANY_I2C_SDA_GPIO GPIO_NUM_4
// BH1750 使能标志
#define BOTANY_BH1750_ENABLE CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE
// AHT30 使能标志
#define BOTANY_AHT30_ENABLE CONFIG_I2C_MASTER_MESSAGER_AHT30_ENABLE
// BH1750 读取周期
#define BOTANY_BH1750_PERIOD_MS CONFIG_I2C_MASTER_MESSAGER_BH1750_READ_PERIOD_MS
// AHT30 读取周期
#define BOTANY_AHT30_PERIOD_MS CONFIG_I2C_MASTER_MESSAGER_AHT30_READ_PERIOD_MS
// I2C 内部上拉使能
#define BOTANY_I2C_INTERNAL_PULLUP CONFIG_I2C_MASTER_MESSAGER_ENABLE_INTERNAL_PULLUP
// MQTT 告警主题
#define BOTANY_MQTT_ALERT_TOPIC "topic/alert/esp32_iothome_001"
// MQTT 遥测数据上报周期(毫秒)
#define BOTANY_MQTT_TELEMETRY_PERIOD_MS 5000
// 日志标签
static const char *TAG = "main";
// 全局变量:存储空气温度字符串
static char s_air_temp[16];
// 全局变量:存储空气湿度字符串
static char s_air_hum[16];
// 全局变量:存储土壤湿度字符串
static char s_soil[16];
// 全局变量:存储光照强度字符串
static char s_lux[16];
// 全局变量水泵状态true=开启false=关闭)
static bool s_pump_on = false;
// 全局变量补光灯状态true=开启false=关闭)
static bool s_light_on = false;
// 全局变量自动控制模式使能true=自动false=手动)
static bool s_auto_control_enabled = true;
/**
* @brief MQTT 控制命令处理函数
*
* 处理来自 MQTT 的控制命令,包括模式切换、阈值更新、水泵和补光灯控制。
*
* @param cmd 指向 MQTT 控制命令结构体的指针
* @param user_ctx 用户上下文(未使用)
* @return esp_err_t 处理结果
*/
static esp_err_t mqtt_control_command_handler(const mqtt_control_command_t *cmd, void *user_ctx)
{
(void)user_ctx;
ESP_RETURN_ON_FALSE(cmd != NULL, ESP_ERR_INVALID_ARG, TAG, "cmd is null");
// 处理模式切换命令
if (cmd->has_mode)
{
s_auto_control_enabled = cmd->auto_mode;
ESP_LOGI(TAG, "MQTT 控制模式切换: %s", s_auto_control_enabled ? "auto" : "manual");
}
// 处理阈值更新命令
if (cmd->has_thresholds)
{
ESP_RETURN_ON_ERROR(auto_ctrl_thresholds_set_values(cmd->soil_on_pct,
@@ -89,6 +121,7 @@ static esp_err_t mqtt_control_command_handler(const mqtt_control_command_t *cmd,
cmd->light_off_lux);
}
// 处理水泵控制命令
if (cmd->has_pump)
{
ESP_RETURN_ON_ERROR(io_device_control_set_pump(cmd->pump_on), TAG, "MQTT 控制水泵失败");
@@ -96,6 +129,7 @@ static esp_err_t mqtt_control_command_handler(const mqtt_control_command_t *cmd,
ESP_LOGI(TAG, "MQTT 控制水泵: %s", cmd->pump_on ? "on" : "off");
}
// 处理补光灯控制命令
if (cmd->has_light)
{
ESP_RETURN_ON_ERROR(io_device_control_set_light(cmd->light_on), TAG, "MQTT 控制补光灯失败");
@@ -106,6 +140,12 @@ static esp_err_t mqtt_control_command_handler(const mqtt_control_command_t *cmd,
return ESP_OK;
}
/**
* @brief 将告警指标类型转换为字符串
*
* @param metric 告警指标类型
* @return const char* 对应的字符串表示
*/
static const char *alert_metric_text(auto_alert_metric_t metric)
{
switch (metric)
@@ -119,6 +159,12 @@ static const char *alert_metric_text(auto_alert_metric_t metric)
}
}
/**
* @brief 将告警状态转换为字符串
*
* @param state 告警状态
* @return const char* 对应的字符串表示
*/
static const char *alert_state_text(auto_alert_state_t state)
{
switch (state)
@@ -132,6 +178,14 @@ static const char *alert_state_text(auto_alert_state_t state)
}
}
/**
* @brief 自动告警 MQTT 回调函数
*
* 当自动告警模块触发事件时,通过此函数将告警信息以 JSON 格式发布到 MQTT。
*
* @param event 指向告警事件结构体的指针
* @param user_ctx 用户上下文(未使用)
*/
static void auto_alert_mqtt_callback(const auto_alert_event_t *event, void *user_ctx)
{
(void)user_ctx;
@@ -164,6 +218,19 @@ static void auto_alert_mqtt_callback(const auto_alert_event_t *event, void *user
}
}
/**
* @brief 自动控制逻辑更新函数
*
* 根据当前传感器数据和阈值,决定是否需要开启或关闭水泵和补光灯。
*
* @param soil_valid 土壤湿度数据是否有效
* @param soil_moisture_pct 当前土壤湿度百分比
* @param light_valid 光照数据是否有效
* @param light_lux 当前光照强度lux
* @param thresholds 指向阈值配置结构体的指针
* @param pump_on 指向当前水泵状态的指针(输入/输出)
* @param light_on 指向当前补光灯状态的指针(输入/输出)
*/
static void auto_control_update(bool soil_valid,
float soil_moisture_pct,
bool light_valid,
@@ -175,6 +242,7 @@ static void auto_control_update(bool soil_valid,
bool desired_pump = *pump_on;
bool desired_light = *light_on;
// 根据土壤湿度决定水泵状态
if (soil_valid)
{
if (!desired_pump && soil_moisture_pct < thresholds->pump_on_soil_below_pct)
@@ -187,6 +255,7 @@ static void auto_control_update(bool soil_valid,
}
}
// 根据光照强度决定补光灯状态
if (light_valid)
{
if (!desired_light && light_lux < thresholds->light_on_lux_below)
@@ -199,6 +268,7 @@ static void auto_control_update(bool soil_valid,
}
}
// 如果水泵状态需要改变,则执行控制
if (desired_pump != *pump_on)
{
esp_err_t ret = io_device_control_set_pump(desired_pump);
@@ -216,6 +286,7 @@ static void auto_control_update(bool soil_valid,
}
}
// 如果补光灯状态需要改变,则执行控制
if (desired_light != *light_on)
{
esp_err_t ret = io_device_control_set_light(desired_light);
@@ -234,6 +305,13 @@ static void auto_control_update(bool soil_valid,
}
}
/**
* @brief UI 任务函数
*
* 负责定期切换显示页面每3秒切换一次
*
* @param arg 任务参数(未使用)
*/
static void ui_task(void *arg)
{
(void)arg;
@@ -266,6 +344,11 @@ static void ui_task(void *arg)
}
}
/**
* @brief 等待 Wi-Fi 连接成功
*
* 在初始化 console 之前,确保 Wi-Fi 已连接成功最多等待120秒。
*/
static void wait_for_wifi_connected(void)
{
const uint32_t timeout_s = 120;
@@ -293,6 +376,11 @@ static void wait_for_wifi_connected(void)
ESP_LOGI(TAG, "Wi-Fi 已连接,开始初始化 console");
}
/**
* @brief 主函数
*
* 系统启动入口,初始化所有组件并进入主循环。
*/
void app_main(void)
{
// 初始化 Wi-Fi 配网组件,支持长按按键进入配网
@@ -480,4 +568,4 @@ void app_main(void)
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
}