💡 划重点

  • 用 ESP32-S3 做主控,电容式土壤湿度传感器做核心感知,DHT22 补充空气温湿度。
  • 本地 OLED 实时显示,MQTT 上报手机或 Home Assistant,出门也能看。
  • 土壤偏干才启动微型水泵滴灌,带滞回区间,避免反复启停。
  • 深睡眠周期唤醒,适合阳台无插座场景,整机成本控制在 60 元内。

需求洞察

目标用户是城市阳台园艺爱好者,尤其是养多肉、薄荷、番茄、草莓的上班族。他们通常只有两三盆到十几盆植物,空间有限,浇水靠记忆和手感。真实痛点有三个:一是忘记浇水,夏季阳台蒸发快,一天就能让叶片发蔫;二是浇水过量,托盘积水导致烂根;三是出差或加班几天,回家发现植物已经救不回来。市售智能花盆价格高、体积固定、不适合已有花盆改造,而专业灌溉控制器又偏贵、偏工程化。这个项目值得做,是因为土壤湿度是盆栽最关键的变量,用几十元就能把“凭感觉浇水”变成“按湿度补水”,而且 ESP32-S3 自带 Wi-Fi,能把数据接到现有智能家居里,扩展成本很低。

方案设计

感知层由电容式土壤湿度传感器和 DHT22 组成。电容式探头比电阻式更耐腐蚀,适合长期插在土里;DHT22 提供空气温湿度,用于判断环境蒸发趋势。控制层是 ESP32-S3,负责 ADC 采样、滑动平均滤波、阈值判断和低功耗调度。执行层是微型直流水泵加继电器或 MOS 管,通过硅胶滴灌管把水送到盆土,每次只运行数秒,防止积水。日志与联网层包括 0.96 寸 OLED 和 MQTT:OLED 显示湿度百分比、温度和运行状态;MQTT 把数据发到本地 Broker 或云平台,同时可接收远程手动浇水指令。低功耗策略是默认深睡眠,每 10 分钟唤醒一次采样,湿度低于阈值才启动水泵并上报,其余时间休眠。

物料清单

物料 数量 用途 估算单价 合计
ESP32-S3 开发板 1 主控与 Wi-Fi 24 元 24 元
电容式土壤湿度传感器 1 测土壤含水率 5 元 29 元
DHT22 温湿度模块 1 测空气温湿度 9 元 38 元
0.96 寸 I2C OLED 1 本地显示 8 元 46 元
微型直流水泵与硅胶管 1 滴灌执行 7 元 53 元
继电器模块 1 控制水泵通断 3 元 56 元
杜邦线与面包板 1 套 连接与固定 2 元 58 元

总成本约 58 元,低于 60 元目标。水泵可用 5V 电源独立供电,避免电机启动拉低主控电压。

接线与结构

题目给定的土壤湿度模拟脚 A0=34,但 ESP32-S3 的 ADC1 通道集中在 GPIO1 到 GPIO10,GPIO34 并不适合直接做 ADC 输入。因此微调为 GPIO4,对应 ADC1_CH3,采样更稳定。DHT22 保持 GPIO15,OLED 保持 GPIO21/22,继电器新增 GPIO5。

模块 引脚 ESP32-S3
土壤湿度 AO GPIO4
土壤湿度 VCC/GND 3.3V/GND
DHT22 DATA GPIO15
DHT22 VCC/GND 3.3V/GND
OLED SDA GPIO21
OLED SCL GPIO22
继电器 IN GPIO5
继电器 VCC/GND 5V/GND
水泵 电源 5V 独立供电,经继电器常开触点

结构上,ESP32-S3 和 OLED 放进小防水盒,土壤探头插入盆土中段,DHT22 固定在盒外通风处,水泵放在水瓶旁,滴灌管插入盆边。

核心代码

以下为 Arduino 骨架,使用 PubSubClient、DHT 和 Adafruit_SSD1306 库。


#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SOIL_PIN 4
#define DHT_PIN 15
#define RELAY_PIN 5
#define DHT_TYPE DHT22

Adafruit_SSD1306 oled(128, 64, &Wire;, -1);
DHT dht(DHT_PIN, DHT_TYPE);
WiFiClient espClient;
PubSubClient mqtt(espClient);

const char* SSID = "your-ssid";
const char* PASS = "your-pass";
const char* BROKER = "192.168.1.10";
const int DRY_RAW = 3200;
const int WET_RAW = 1200;
const int WATER_ON = 35;
const int WATER_OFF = 50;

int readSoilPercent() {
  int raw = analogRead(SOIL_PIN);
  int pct = map(raw, DRY_RAW, WET_RAW, 0, 100);
  return constrain(pct, 0, 100);
}

void waterPump(int seconds) {
  digitalWrite(RELAY_PIN, HIGH);
  delay(seconds * 1000);
  digitalWrite(RELAY_PIN, LOW);
}

void setup() {
  Serial.begin(115200);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, LOW);
  Wire.begin(21, 22);
  oled.clearDisplay();
  dht.begin();
  WiFi.begin(SSID, PASS);
  mqtt.setServer(BROKER, 1883);
  delay(3000);
}

void loop() {
  int soil = readSoilPercent();
  float t = dht.readTemperature();
  float h = dht.readHumidity();

  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setCursor(0, 0);
  oled.printf("Soil:%d%%\nT:%.1fC H:%.0f%%", soil, t, h);
  oled.display();

  if (soil < WATER_ON) {
    waterPump(3);
  } else if (soil > WATER_OFF) {
    digitalWrite(RELAY_PIN, LOW);
  }

  if (mqtt.connect("plant-guard")) {
    char payload[64];
    snprintf(payload, sizeof(payload), "{\"soil\":%d,\"t\":%.1f,\"h\":%.0f}", soil, t, h);
    mqtt.publish("balcony/plant/state", payload);
    mqtt.disconnect();
  }

  esp_sleep_enable_timer_wakeup(10ULL * 60ULL * 1000000ULL);
  esp_deep_sleep_start();
}

调试步骤

  1. 先只接土壤传感器,串口打印原始 ADC 值,记录空气中、刚浇透后的数值,填入 DRY_RAW 和 WET_RAW。
  2. 扫描 OLED 地址,确认 0x3C 能显示,再接入 DHT22 检查读数。
  3. 用 Mosquitto 或 Home Assistant 测试 MQTT 主题,确认 JSON 能收到。
  4. 继电器先接 LED 测试,确认逻辑为高电平触发,再接水泵,避免空转。
  5. 测深睡眠电流,若偏高,检查 OLED 和 DHT 供电,必要时加 MOS 管断电。
  6. 设定 10 分钟唤醒周期,观察一天内的湿度曲线,再调整阈值。

设计图

阳台盆栽土壤湿度守护结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报