feat:新增MQTT控制组件和自动告警系统

- 实现MQTT控制功能,处理水泵和灯光控制指令
- 新增土壤湿度和光照强度自动告警系统,阈值可配置
- 新建MQTT控制、自动告警和阈值管理相关文件
- 更新主应用,集成MQTT和自动控制功能
- 新增传感器数据与控制状态遥测上报
- 引入NVS和应用存储分区配置
This commit is contained in:
Wang Beihong
2026-03-07 02:43:30 +08:00
parent cf3634bebb
commit 5980e171c4
13 changed files with 1279 additions and 77 deletions

146
main/auto_ctrl_thresholds.c Normal file
View File

@@ -0,0 +1,146 @@
#include "auto_ctrl_thresholds.h"
#include "freertos/FreeRTOS.h"
#include "esp_check.h"
// 默认土壤湿度低于此百分比时启动水泵(单位:%
#define DEFAULT_PUMP_ON_SOIL_BELOW_PCT 35.0f
// 默认土壤湿度高于此百分比时关闭水泵(单位:%
#define DEFAULT_PUMP_OFF_SOIL_ABOVE_PCT 45.0f
// 默认光照强度低于此值时开启补光灯单位lux
#define DEFAULT_LIGHT_ON_LUX_BELOW 200.0f
// 默认光照强度高于此值时关闭补光灯单位lux
#define DEFAULT_LIGHT_OFF_LUX_ABOVE 350.0f
// 用于保护阈值数据的自旋锁(临界区)
static portMUX_TYPE s_thresholds_lock = portMUX_INITIALIZER_UNLOCKED;
// 全局阈值配置结构体,初始化为默认值
static auto_ctrl_thresholds_t s_thresholds = {
.pump_on_soil_below_pct = DEFAULT_PUMP_ON_SOIL_BELOW_PCT,
.pump_off_soil_above_pct = DEFAULT_PUMP_OFF_SOIL_ABOVE_PCT,
.light_on_lux_below = DEFAULT_LIGHT_ON_LUX_BELOW,
.light_off_lux_above = DEFAULT_LIGHT_OFF_LUX_ABOVE,
};
/**
* @brief 验证自动控制阈值配置的有效性
*
* 检查指针非空、数值范围合法、启停阈值满足 on < off 等条件。
*
* @param cfg 待验证的阈值配置指针
* @return esp_err_t 验证结果ESP_OK 表示有效
*/
static esp_err_t auto_ctrl_thresholds_validate(const auto_ctrl_thresholds_t *cfg)
{
ESP_RETURN_ON_FALSE(cfg != NULL, ESP_ERR_INVALID_ARG, "auto_ctrl_thresholds", "cfg is null");
ESP_RETURN_ON_FALSE(cfg->pump_on_soil_below_pct >= 0.0f && cfg->pump_on_soil_below_pct <= 100.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"pump_on_soil_below_pct out of range");
ESP_RETURN_ON_FALSE(cfg->pump_off_soil_above_pct >= 0.0f && cfg->pump_off_soil_above_pct <= 100.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"pump_off_soil_above_pct out of range");
ESP_RETURN_ON_FALSE(cfg->pump_on_soil_below_pct < cfg->pump_off_soil_above_pct,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"pump thresholds must satisfy on < off");
ESP_RETURN_ON_FALSE(cfg->light_on_lux_below >= 0.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"light_on_lux_below out of range");
ESP_RETURN_ON_FALSE(cfg->light_off_lux_above >= 0.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"light_off_lux_above out of range");
ESP_RETURN_ON_FALSE(cfg->light_on_lux_below < cfg->light_off_lux_above,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"light thresholds must satisfy on < off");
return ESP_OK;
}
/**
* @brief 初始化阈值为默认值
*
* 将全局阈值结构体重置为预设的默认配置。
*/
void auto_ctrl_thresholds_init_defaults(void)
{
const auto_ctrl_thresholds_t defaults = {
.pump_on_soil_below_pct = DEFAULT_PUMP_ON_SOIL_BELOW_PCT,
.pump_off_soil_above_pct = DEFAULT_PUMP_OFF_SOIL_ABOVE_PCT,
.light_on_lux_below = DEFAULT_LIGHT_ON_LUX_BELOW,
.light_off_lux_above = DEFAULT_LIGHT_OFF_LUX_ABOVE,
};
taskENTER_CRITICAL(&s_thresholds_lock);
s_thresholds = defaults;
taskEXIT_CRITICAL(&s_thresholds_lock);
}
/**
* @brief 获取当前阈值配置
*
* 安全地复制当前阈值到输出参数中。
*
* @param out 输出参数,指向接收阈值的结构体
*/
void auto_ctrl_thresholds_get(auto_ctrl_thresholds_t *out)
{
if (out == NULL) {
return;
}
taskENTER_CRITICAL(&s_thresholds_lock);
*out = s_thresholds;
taskEXIT_CRITICAL(&s_thresholds_lock);
}
/**
* @brief 设置新的阈值配置
*
* 验证输入配置有效性后,安全更新全局阈值。
*
* @param cfg 新的阈值配置指针
* @return esp_err_t 设置结果ESP_OK 表示成功
*/
esp_err_t auto_ctrl_thresholds_set(const auto_ctrl_thresholds_t *cfg)
{
ESP_RETURN_ON_ERROR(auto_ctrl_thresholds_validate(cfg), "auto_ctrl_thresholds", "invalid thresholds");
taskENTER_CRITICAL(&s_thresholds_lock);
s_thresholds = *cfg;
taskEXIT_CRITICAL(&s_thresholds_lock);
return ESP_OK;
}
/**
* @brief 通过独立参数设置阈值
*
* 提供一种更便捷的阈值设置方式,内部封装为结构体后调用 set 接口。
*
* @param pump_on_soil_below_pct 水泵启动土壤湿度阈值(%
* @param pump_off_soil_above_pct 水泵关闭土壤湿度阈值(%
* @param light_on_lux_below 补光灯开启光照阈值lux
* @param light_off_lux_above 补光灯关闭光照阈值lux
* @return esp_err_t 设置结果
*/
esp_err_t auto_ctrl_thresholds_set_values(float pump_on_soil_below_pct,
float pump_off_soil_above_pct,
float light_on_lux_below,
float light_off_lux_above)
{
const auto_ctrl_thresholds_t cfg = {
.pump_on_soil_below_pct = pump_on_soil_below_pct,
.pump_off_soil_above_pct = pump_off_soil_above_pct,
.light_on_lux_below = light_on_lux_below,
.light_off_lux_above = light_off_lux_above,
};
return auto_ctrl_thresholds_set(&cfg);
}