144 lines
4.4 KiB
C
144 lines
4.4 KiB
C
#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_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_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 light_valid 光照数据是否有效
|
||
* @param light_lux 当前光照强度(单位:lux)
|
||
* @param thresholds 自动控制阈值配置结构体指针
|
||
*/
|
||
void auto_alerts_evaluate(bool light_valid,
|
||
float light_lux,
|
||
const auto_ctrl_thresholds_t *thresholds)
|
||
{
|
||
if (thresholds == NULL)
|
||
{
|
||
return; // 阈值为空,直接返回
|
||
}
|
||
|
||
// 处理光照强度告警逻辑
|
||
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);
|
||
}
|
||
}
|
||
} |