feat:新增MQTT控制组件和自动告警系统
- 实现MQTT控制功能,处理水泵和灯光控制指令 - 新增土壤湿度和光照强度自动告警系统,阈值可配置 - 新建MQTT控制、自动告警和阈值管理相关文件 - 更新主应用,集成MQTT和自动控制功能 - 新增传感器数据与控制状态遥测上报 - 引入NVS和应用存储分区配置
This commit is contained in:
188
main/auto_alerts.c
Normal file
188
main/auto_alerts.c
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "auto_alerts.h"
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
|
||||
static const char *TAG = "auto_alerts"; // 日志标签
|
||||
|
||||
// 用于保护全局状态的自旋锁(临界区)
|
||||
static portMUX_TYPE s_alerts_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
// 用户注册的回调函数
|
||||
static auto_alert_callback_t s_callback = NULL;
|
||||
// 回调函数的用户上下文指针
|
||||
static void *s_user_ctx = NULL;
|
||||
|
||||
// 土壤湿度告警是否已激活
|
||||
static bool s_soil_alarm_active = false;
|
||||
// 光照强度告警是否已激活
|
||||
static bool s_light_alarm_active = false;
|
||||
|
||||
/**
|
||||
* @brief 发送自动告警事件
|
||||
*
|
||||
* @param metric 告警指标类型(如土壤湿度、光照强度)
|
||||
* @param state 告警状态(告警或恢复正常)
|
||||
* @param value 当前测量值
|
||||
* @param threshold 触发告警的阈值
|
||||
*/
|
||||
static void auto_alerts_emit(auto_alert_metric_t metric,
|
||||
auto_alert_state_t state,
|
||||
float value,
|
||||
float threshold)
|
||||
{
|
||||
auto_alert_event_t event = {
|
||||
.metric = metric,
|
||||
.state = state,
|
||||
.value = value,
|
||||
.threshold = threshold,
|
||||
.timestamp_ms = esp_timer_get_time() / 1000, // 转换为毫秒时间戳
|
||||
};
|
||||
|
||||
auto_alert_callback_t callback = NULL;
|
||||
void *user_ctx = NULL;
|
||||
|
||||
// 进入临界区,安全读取回调和上下文
|
||||
taskENTER_CRITICAL(&s_alerts_lock);
|
||||
callback = s_callback;
|
||||
user_ctx = s_user_ctx;
|
||||
taskEXIT_CRITICAL(&s_alerts_lock);
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
callback(&event, user_ctx); // 调用用户注册的回调函数
|
||||
}
|
||||
|
||||
// 打印日志信息
|
||||
ESP_LOGI(TAG,
|
||||
"alert metric=%d state=%d value=%.1f threshold=%.1f",
|
||||
(int)event.metric,
|
||||
(int)event.state,
|
||||
event.value,
|
||||
event.threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化自动告警模块
|
||||
*
|
||||
* 将所有告警状态重置为未激活。
|
||||
*/
|
||||
void auto_alerts_init(void)
|
||||
{
|
||||
taskENTER_CRITICAL(&s_alerts_lock);
|
||||
s_soil_alarm_active = false;
|
||||
s_light_alarm_active = false;
|
||||
taskEXIT_CRITICAL(&s_alerts_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册自动告警回调函数
|
||||
*
|
||||
* @param callback 用户定义的回调函数
|
||||
* @param user_ctx 用户上下文指针
|
||||
* @return esp_err_t 总是返回 ESP_OK
|
||||
*/
|
||||
esp_err_t auto_alerts_register_callback(auto_alert_callback_t callback, void *user_ctx)
|
||||
{
|
||||
taskENTER_CRITICAL(&s_alerts_lock);
|
||||
s_callback = callback;
|
||||
s_user_ctx = user_ctx;
|
||||
taskEXIT_CRITICAL(&s_alerts_lock);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据当前传感器数据和阈值评估是否触发或解除告警
|
||||
*
|
||||
* @param soil_valid 土壤湿度数据是否有效
|
||||
* @param soil_moisture_pct 当前土壤湿度百分比
|
||||
* @param light_valid 光照数据是否有效
|
||||
* @param light_lux 当前光照强度(单位:lux)
|
||||
* @param thresholds 自动控制阈值配置结构体指针
|
||||
*/
|
||||
void auto_alerts_evaluate(bool soil_valid,
|
||||
float soil_moisture_pct,
|
||||
bool light_valid,
|
||||
float light_lux,
|
||||
const auto_ctrl_thresholds_t *thresholds)
|
||||
{
|
||||
if (thresholds == NULL)
|
||||
{
|
||||
return; // 阈值为空,直接返回
|
||||
}
|
||||
|
||||
// 处理土壤湿度告警逻辑
|
||||
if (soil_valid)
|
||||
{
|
||||
bool emit_alarm = false; // 是否需要触发告警
|
||||
bool emit_recover = false; // 是否需要恢复通知
|
||||
|
||||
taskENTER_CRITICAL(&s_alerts_lock);
|
||||
// 如果当前未告警,且土壤湿度低于启动水泵的阈值,则触发告警
|
||||
if (!s_soil_alarm_active && soil_moisture_pct < thresholds->pump_on_soil_below_pct)
|
||||
{
|
||||
s_soil_alarm_active = true;
|
||||
emit_alarm = true;
|
||||
}
|
||||
// 如果当前处于告警状态,且土壤湿度高于关闭水泵的阈值,则恢复
|
||||
else if (s_soil_alarm_active && soil_moisture_pct > thresholds->pump_off_soil_above_pct)
|
||||
{
|
||||
s_soil_alarm_active = false;
|
||||
emit_recover = true;
|
||||
}
|
||||
taskEXIT_CRITICAL(&s_alerts_lock);
|
||||
|
||||
if (emit_alarm)
|
||||
{
|
||||
auto_alerts_emit(AUTO_ALERT_METRIC_SOIL_MOISTURE,
|
||||
AUTO_ALERT_STATE_ALARM,
|
||||
soil_moisture_pct,
|
||||
thresholds->pump_on_soil_below_pct);
|
||||
}
|
||||
if (emit_recover)
|
||||
{
|
||||
auto_alerts_emit(AUTO_ALERT_METRIC_SOIL_MOISTURE,
|
||||
AUTO_ALERT_STATE_NORMAL,
|
||||
soil_moisture_pct,
|
||||
thresholds->pump_off_soil_above_pct);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理光照强度告警逻辑
|
||||
if (light_valid)
|
||||
{
|
||||
bool emit_alarm = false; // 是否需要触发告警
|
||||
bool emit_recover = false; // 是否需要恢复通知
|
||||
|
||||
taskENTER_CRITICAL(&s_alerts_lock);
|
||||
// 如果当前未告警,且光照强度低于开启补光灯的阈值,则触发告警
|
||||
if (!s_light_alarm_active && light_lux < thresholds->light_on_lux_below)
|
||||
{
|
||||
s_light_alarm_active = true;
|
||||
emit_alarm = true;
|
||||
}
|
||||
// 如果当前处于告警状态,且光照强度高于关闭补光灯的阈值,则恢复
|
||||
else if (s_light_alarm_active && light_lux > thresholds->light_off_lux_above)
|
||||
{
|
||||
s_light_alarm_active = false;
|
||||
emit_recover = true;
|
||||
}
|
||||
taskEXIT_CRITICAL(&s_alerts_lock);
|
||||
|
||||
if (emit_alarm)
|
||||
{
|
||||
auto_alerts_emit(AUTO_ALERT_METRIC_LIGHT_INTENSITY,
|
||||
AUTO_ALERT_STATE_ALARM,
|
||||
light_lux,
|
||||
thresholds->light_on_lux_below);
|
||||
}
|
||||
if (emit_recover)
|
||||
{
|
||||
auto_alerts_emit(AUTO_ALERT_METRIC_LIGHT_INTENSITY,
|
||||
AUTO_ALERT_STATE_NORMAL,
|
||||
light_lux,
|
||||
thresholds->light_off_lux_above);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user