feat: 添加土壤和光照阈值控制,优化状态上报逻辑

This commit is contained in:
Wang Beihong
2026-03-07 02:54:45 +08:00
parent 7accf1279e
commit 981dc2b47c
2 changed files with 105 additions and 40 deletions

View File

@@ -95,7 +95,11 @@ idf.py -p /dev/ttyACM0 flash monitor
"lux": "40", "lux": "40",
"pump": "on", "pump": "on",
"light": "off", "light": "off",
"mode": "auto" "mode": "auto",
"soil_on": 35.0,
"soil_off": 45.0,
"light_on": 100.0,
"light_off": 350.0
} }
``` ```
@@ -103,6 +107,10 @@ idf.py -p /dev/ttyACM0 flash monitor
- `pump``on/off` - `pump``on/off`
- `light``on/off` - `light``on/off`
- `mode``auto/manual` - `mode``auto/manual`
- `soil_on`:土壤湿度低阈值(低于该值自动开泵)
- `soil_off`:土壤湿度高阈值(高于该值自动关泵)
- `light_on`:光照低阈值(低于该值自动开灯)
- `light_off`:光照高阈值(高于该值自动关灯)
### WEX -> ESP32 ### WEX -> ESP32

View File

@@ -83,6 +83,42 @@ static bool s_light_on = false;
// 全局变量自动控制模式使能true=自动false=手动) // 全局变量自动控制模式使能true=自动false=手动)
static bool s_auto_control_enabled = true; static bool s_auto_control_enabled = true;
/**
* @brief 发布当前完整状态快照(含阈值)到传感器主题
*/
static esp_err_t publish_telemetry_snapshot(void)
{
if (!mqtt_control_is_connected())
{
return ESP_ERR_INVALID_STATE;
}
auto_ctrl_thresholds_t thresholds = {0};
auto_ctrl_thresholds_get(&thresholds);
char telemetry_payload[256] = {0};
int len = snprintf(telemetry_payload,
sizeof(telemetry_payload),
"{\"temp\":\"%s\",\"hum\":\"%s\",\"soil\":\"%s\",\"lux\":\"%s\",\"pump\":\"%s\",\"light\":\"%s\",\"mode\":\"%s\",\"soil_on\":%.1f,\"soil_off\":%.1f,\"light_on\":%.1f,\"light_off\":%.1f}",
s_air_temp,
s_air_hum,
s_soil,
s_lux,
s_pump_on ? "on" : "off",
s_light_on ? "on" : "off",
s_auto_control_enabled ? "auto" : "manual",
thresholds.pump_on_soil_below_pct,
thresholds.pump_off_soil_above_pct,
thresholds.light_on_lux_below,
thresholds.light_off_lux_above);
if (len <= 0 || len >= (int)sizeof(telemetry_payload))
{
return ESP_ERR_INVALID_SIZE;
}
return mqtt_control_publish_sensor(telemetry_payload, 0, 0);
}
/** /**
* @brief MQTT 控制命令处理函数 * @brief MQTT 控制命令处理函数
* *
@@ -96,6 +132,8 @@ 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"); ESP_RETURN_ON_FALSE(cmd != NULL, ESP_ERR_INVALID_ARG, TAG, "cmd is null");
esp_err_t final_ret = ESP_OK;
bool has_any_control = cmd->has_mode || cmd->has_thresholds || cmd->has_pump || cmd->has_light;
// 处理模式切换命令 // 处理模式切换命令
if (cmd->has_mode) if (cmd->has_mode)
@@ -107,12 +145,12 @@ static esp_err_t mqtt_control_command_handler(const mqtt_control_command_t *cmd,
// 处理阈值更新命令 // 处理阈值更新命令
if (cmd->has_thresholds) if (cmd->has_thresholds)
{ {
ESP_RETURN_ON_ERROR(auto_ctrl_thresholds_set_values(cmd->soil_on_pct, esp_err_t ret = auto_ctrl_thresholds_set_values(cmd->soil_on_pct,
cmd->soil_off_pct, cmd->soil_off_pct,
cmd->light_on_lux, cmd->light_on_lux,
cmd->light_off_lux), cmd->light_off_lux);
TAG, if (ret == ESP_OK)
"设置阈值失败"); {
ESP_LOGI(TAG, ESP_LOGI(TAG,
"MQTT 更新阈值: soil_on=%.1f soil_off=%.1f light_on=%.1f light_off=%.1f", "MQTT 更新阈值: soil_on=%.1f soil_off=%.1f light_on=%.1f light_off=%.1f",
cmd->soil_on_pct, cmd->soil_on_pct,
@@ -120,24 +158,60 @@ static esp_err_t mqtt_control_command_handler(const mqtt_control_command_t *cmd,
cmd->light_on_lux, cmd->light_on_lux,
cmd->light_off_lux); cmd->light_off_lux);
} }
else
{
ESP_LOGE(TAG, "设置阈值失败: %s", esp_err_to_name(ret));
final_ret = ret;
}
}
// 处理水泵控制命令 // 处理水泵控制命令
if (cmd->has_pump) if (cmd->has_pump)
{ {
ESP_RETURN_ON_ERROR(io_device_control_set_pump(cmd->pump_on), TAG, "MQTT 控制水泵失败"); esp_err_t ret = io_device_control_set_pump(cmd->pump_on);
if (ret == ESP_OK)
{
s_pump_on = cmd->pump_on; s_pump_on = cmd->pump_on;
ESP_LOGI(TAG, "MQTT 控制水泵: %s", cmd->pump_on ? "on" : "off"); ESP_LOGI(TAG, "MQTT 控制水泵: %s", cmd->pump_on ? "on" : "off");
} }
else
{
ESP_LOGE(TAG, "MQTT 控制水泵失败: %s", esp_err_to_name(ret));
final_ret = ret;
}
}
// 处理补光灯控制命令 // 处理补光灯控制命令
if (cmd->has_light) if (cmd->has_light)
{ {
ESP_RETURN_ON_ERROR(io_device_control_set_light(cmd->light_on), TAG, "MQTT 控制补光灯失败"); esp_err_t ret = io_device_control_set_light(cmd->light_on);
if (ret == ESP_OK)
{
s_light_on = cmd->light_on; s_light_on = cmd->light_on;
ESP_LOGI(TAG, "MQTT 控制补光灯: %s", cmd->light_on ? "on" : "off"); ESP_LOGI(TAG, "MQTT 控制补光灯: %s", cmd->light_on ? "on" : "off");
} }
else
{
ESP_LOGE(TAG, "MQTT 控制补光灯失败: %s", esp_err_to_name(ret));
final_ret = ret;
}
}
return ESP_OK; // 任何控制指令处理后都立即上报最新状态(含阈值)作为回复。
if (has_any_control)
{
esp_err_t pub_ret = publish_telemetry_snapshot();
if (pub_ret != ESP_OK)
{
ESP_LOGW(TAG, "控制后立即上报失败: %s", esp_err_to_name(pub_ret));
if (final_ret == ESP_OK)
{
final_ret = pub_ret;
}
}
}
return final_ret;
} }
/** /**
@@ -542,27 +616,10 @@ void app_main(void)
if (telemetry_elapsed_ms >= BOTANY_MQTT_TELEMETRY_PERIOD_MS) if (telemetry_elapsed_ms >= BOTANY_MQTT_TELEMETRY_PERIOD_MS)
{ {
telemetry_elapsed_ms = 0; telemetry_elapsed_ms = 0;
if (mqtt_control_is_connected()) esp_err_t pub_ret = publish_telemetry_snapshot();
if (pub_ret != ESP_OK && pub_ret != ESP_ERR_INVALID_STATE)
{ {
char telemetry_payload[128] = {0}; ESP_LOGW(TAG, "周期状态上报失败: %s", esp_err_to_name(pub_ret));
int len = snprintf(telemetry_payload,
sizeof(telemetry_payload),
"{\"temp\":\"%s\",\"hum\":\"%s\",\"soil\":\"%s\",\"lux\":\"%s\",\"pump\":\"%s\",\"light\":\"%s\",\"mode\":\"%s\"}",
s_air_temp,
s_air_hum,
s_soil,
s_lux,
s_pump_on ? "on" : "off",
s_light_on ? "on" : "off",
s_auto_control_enabled ? "auto" : "manual");
if (len > 0 && len < (int)sizeof(telemetry_payload))
{
esp_err_t pub_ret = mqtt_control_publish_sensor(telemetry_payload, 0, 0);
if (pub_ret != ESP_OK)
{
ESP_LOGW(TAG, "传感器上报失败: %s", esp_err_to_name(pub_ret));
}
}
} }
} }