Files
Smart-granary-code/main/auto_ctrl_thresholds.c
2026-03-11 20:14:14 +08:00

199 lines
8.5 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 "auto_ctrl_thresholds.h"
#include "freertos/FreeRTOS.h"
#include "esp_check.h"
// 默认光照强度低于此值时开启补光灯单位lux
#define DEFAULT_LIGHT_ON_LUX_BELOW 200.0f
// 默认光照强度高于此值时关闭补光灯单位lux
#define DEFAULT_LIGHT_OFF_LUX_ABOVE 350.0f
// 默认温度低于此值时开启加热(单位:摄氏度)
#define DEFAULT_HOT_ON_TEMP_BELOW_C 18.0f
// 默认温度高于此值时关闭加热(单位:摄氏度)
#define DEFAULT_HOT_OFF_TEMP_ABOVE_C 20.0f
// 默认温度高于此值时开启制冷(单位:摄氏度)
#define DEFAULT_COOL_ON_TEMP_ABOVE_C 30.0f
// 默认温度低于此值时关闭制冷(单位:摄氏度)
#define DEFAULT_COOL_OFF_TEMP_BELOW_C 28.0f
// 默认湿度高于此值时开启风扇(单位:%RH
#define DEFAULT_FAN_ON_HUMIDITY_ABOVE_PCT 80.0f
// 默认湿度低于此值时关闭风扇(单位:%RH
#define DEFAULT_FAN_OFF_HUMIDITY_BELOW_PCT 70.0f
// 用于保护阈值数据的自旋锁(临界区)
static portMUX_TYPE s_thresholds_lock = portMUX_INITIALIZER_UNLOCKED;
// 全局阈值配置结构体,初始化为默认值
static auto_ctrl_thresholds_t s_thresholds = {
.light_on_lux_below = DEFAULT_LIGHT_ON_LUX_BELOW,
.light_off_lux_above = DEFAULT_LIGHT_OFF_LUX_ABOVE,
.hot_on_temp_below_c = DEFAULT_HOT_ON_TEMP_BELOW_C,
.hot_off_temp_above_c = DEFAULT_HOT_OFF_TEMP_ABOVE_C,
.cool_on_temp_above_c = DEFAULT_COOL_ON_TEMP_ABOVE_C,
.cool_off_temp_below_c = DEFAULT_COOL_OFF_TEMP_BELOW_C,
.fan_on_humidity_above_pct = DEFAULT_FAN_ON_HUMIDITY_ABOVE_PCT,
.fan_off_humidity_below_pct = DEFAULT_FAN_OFF_HUMIDITY_BELOW_PCT,
};
/**
* @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->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");
ESP_RETURN_ON_FALSE(cfg->hot_on_temp_below_c >= -40.0f && cfg->hot_on_temp_below_c <= 125.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"hot_on_temp_below_c out of range");
ESP_RETURN_ON_FALSE(cfg->hot_off_temp_above_c >= -40.0f && cfg->hot_off_temp_above_c <= 125.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"hot_off_temp_above_c out of range");
ESP_RETURN_ON_FALSE(cfg->hot_on_temp_below_c < cfg->hot_off_temp_above_c,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"hot thresholds must satisfy on < off");
ESP_RETURN_ON_FALSE(cfg->cool_off_temp_below_c >= -40.0f && cfg->cool_off_temp_below_c <= 125.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"cool_off_temp_below_c out of range");
ESP_RETURN_ON_FALSE(cfg->cool_on_temp_above_c >= -40.0f && cfg->cool_on_temp_above_c <= 125.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"cool_on_temp_above_c out of range");
ESP_RETURN_ON_FALSE(cfg->cool_off_temp_below_c < cfg->cool_on_temp_above_c,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"cool thresholds must satisfy off < on");
ESP_RETURN_ON_FALSE(cfg->hot_off_temp_above_c <= cfg->cool_off_temp_below_c,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"temperature thresholds overlap excessively");
ESP_RETURN_ON_FALSE(cfg->fan_on_humidity_above_pct >= 0.0f && cfg->fan_on_humidity_above_pct <= 100.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"fan_on_humidity_above_pct out of range");
ESP_RETURN_ON_FALSE(cfg->fan_off_humidity_below_pct >= 0.0f && cfg->fan_off_humidity_below_pct <= 100.0f,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"fan_off_humidity_below_pct out of range");
ESP_RETURN_ON_FALSE(cfg->fan_off_humidity_below_pct < cfg->fan_on_humidity_above_pct,
ESP_ERR_INVALID_ARG,
"auto_ctrl_thresholds",
"fan humidity thresholds must satisfy off < on");
return ESP_OK;
}
/**
* @brief 初始化阈值为默认值
*
* 将全局阈值结构体重置为预设的默认配置。
*/
void auto_ctrl_thresholds_init_defaults(void)
{
const auto_ctrl_thresholds_t defaults = {
.light_on_lux_below = DEFAULT_LIGHT_ON_LUX_BELOW,
.light_off_lux_above = DEFAULT_LIGHT_OFF_LUX_ABOVE,
.hot_on_temp_below_c = DEFAULT_HOT_ON_TEMP_BELOW_C,
.hot_off_temp_above_c = DEFAULT_HOT_OFF_TEMP_ABOVE_C,
.cool_on_temp_above_c = DEFAULT_COOL_ON_TEMP_ABOVE_C,
.cool_off_temp_below_c = DEFAULT_COOL_OFF_TEMP_BELOW_C,
.fan_on_humidity_above_pct = DEFAULT_FAN_ON_HUMIDITY_ABOVE_PCT,
.fan_off_humidity_below_pct = DEFAULT_FAN_OFF_HUMIDITY_BELOW_PCT,
};
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 light_on_lux_below 补光灯开启光照阈值lux
* @param light_off_lux_above 补光灯关闭光照阈值lux
* @return esp_err_t 设置结果
*/
esp_err_t auto_ctrl_thresholds_set_values(float light_on_lux_below,
float light_off_lux_above,
float hot_on_temp_below_c,
float hot_off_temp_above_c,
float cool_on_temp_above_c,
float cool_off_temp_below_c,
float fan_on_humidity_above_pct,
float fan_off_humidity_below_pct)
{
const auto_ctrl_thresholds_t cfg = {
.light_on_lux_below = light_on_lux_below,
.light_off_lux_above = light_off_lux_above,
.hot_on_temp_below_c = hot_on_temp_below_c,
.hot_off_temp_above_c = hot_off_temp_above_c,
.cool_on_temp_above_c = cool_on_temp_above_c,
.cool_off_temp_below_c = cool_off_temp_below_c,
.fan_on_humidity_above_pct = fan_on_humidity_above_pct,
.fan_off_humidity_below_pct = fan_off_humidity_below_pct,
};
return auto_ctrl_thresholds_set(&cfg);
}