Skip to main content

XIAO 土壤湿度传感器入门指南


介绍

XIAO 土壤湿度传感器是一款紧凑、低功耗的环境监测器,由 XIAO ESP32-C6 驱动。仅使用一节 AA 电池供电,提供持久的运行时间和实时的土壤状况更新。它具有预校准自适应土壤湿度感应功能,可精确监测土壤状况。同时,它支持动态监测间隔和即时读数,提供准确、响应迅速的数据。完全兼容 Home Assistant,是智能园艺和精准农业的理想选择——高效、可靠,专为可持续植物护理而设计。

特性

1.三级土壤湿度监测

  • 🌿 正常: 土壤湿度最佳,无需浇水。
  • 🌤 接近干燥: 湿度正在下降,准备尽快浇水。
  • 🌵 干燥: 严重缺水,立即浇水。

默认阈值:

  • 60% → 绿色到黄色转换。
  • 20% → 黄色到红色转换。

2.与 Home Assistant 即插即用
预装 ESPHome — 开箱即用,与 Home Assistant 配合使用,让您直接从智能家居仪表板监控和自动化。

3.自适应监测和即时读数

  • 根据湿度水平自动调整检查间隔(8小时 → 1小时 → 15分钟)。
  • 随时按一次按钮即可获得即时湿度读数。

4.简单校准(可选)
快速三次按下按钮即可为您的特定土壤重新校准:干燥读数 + 湿润读数 → 系统自动调整。

  • 三次短按 → 进入校准模式:
    • 红色 LED 闪烁 → 在 10 秒内,将传感器插入完全干燥的土壤中。
    • 等待红色 LED 停止闪烁,然后等待 3 秒。
    • 绿色 LED 闪烁 → 在 10 秒内,将传感器插入完全湿润的土壤中。
    • 等待绿色 LED 停止闪烁,然后等待 3 秒。
    • 校准结果:
      • 两次快速绿色闪烁 → 成功。
      • 两次快速红色闪烁 → 失败(可能是由于干燥/湿润读数颠倒)。

注意:在校准过程中,如果传感器没有及时插入,初始读数可能不稳定。系统将进行多次采样,应用滤波,并对读数进行平均以确保可靠的校准。

5.长电池寿命
由单节 AA 电池供电,通过优化的电源管理设计,可持续使用长达三个月。

硬件概述

入门指南

本节将指导您首次设置 XIAO 土壤湿度传感器。

所需材料

在本文教程内容开始之前,您可能需要准备以下硬件。

XIAO 土壤湿度传感器Home Assistant Green

Home Assistant Green 是自动化您家庭的最简单且最注重隐私的方式。它提供轻松的设置,让您只需一个系统就能控制所有智能设备,默认情况下所有数据都存储在本地。这款主板受益于蓬勃发展的 Home Assistant 生态系统,并将通过开源每月得到改进。

我们建议在本教程中使用 Home Assistant Green 作为 Home Assistant 主机,或者您可以使用任何带有 Supervisor 的 Home Assistant 主机。

安装 Home Assistant

我们还为一些 Seeed Studio 产品编写了如何安装 Home Assistant 的教程,请参考它们。

如果您没有使用 Seeed Studio 产品,您也可以在官方 Home Assistant 网站上查看并学习如何为其他产品安装 Home Assistant。

步骤 1. 安装 ESPHome

如果您已经安装了 ESPHome,可以跳过此步骤。

转到 Settings -> Add-ons -> ADD-ON STORE

搜索 ESPHome 并点击它。点击 INSTALLSTART

tip

如果您在附加组件商店中找不到 ESPHome,请确保您使用的是支持附加组件的 Home Assistant 安装(如 Home Assistant OS 或监督安装)。对于其他安装类型(如 Home Assistant Container),您可能需要使用 Docker 独立运行 ESPHome Device Builder。有关更多详细信息,请参阅官方 ESPHome 文档

然后,ESPHome Builder 将出现在侧边栏中。

步骤 2:准备土壤湿度传感器

默认情况下,您的设备(XIAO ESP32C6)预装了 XIAO 土壤湿度传感器的固件。但是,如果您需要修改或升级默认固件,可以在下面的资源部分找到出厂 YAML 配置文件。您可以根据需要自定义逻辑并通过 Home Assistant 刷写。

tip

为确保读数准确,请在使用前对传感器进行快速校准。

步骤 3:网络配置

  1. 启用接入点

    • 首次上电时,模块将创建一个 Wi-Fi 网络(SSID:Xiao-Soil-Moisture-Monitor)。
  2. 访问配置

    • 使用手机或电脑连接到该网络。
    • 打开浏览器并导航到 http://192.168.4.1
    • 输入您家庭 Wi-Fi 网络的 SSID 和密码。
  1. Home Assistant 集成
    • 连接到家庭网络后,模块将在 Home Assistant 的 Settings -> Devices & Services 下可被发现。

这样,您可以将模块连接到您的 Home Assistant 网络并让 Home Assistant 发现它。

步骤 4:添加模块设备

  1. 自动发现

    • 确保在 Home Assistant 中安装了 ESPHome
    • 导航到 Settings -> Devices & Services -> Integrations 并查找设备。
  2. 手动配置

    • 如果没有自动发现,请通过指定其 IP 地址手动添加设备。

添加设备后,您将在Home Assistant概览页面上看到一个名为Solid_sensor的新传感器卡片,显示电池测量值和当前土壤湿度状态。

现在您的土壤传感器已经启动并运行,请尽情享受监测植物的乐趣吧!

高级用法

您可以修改原始固件逻辑,并直接通过Home Assistant刷写您的自定义版本土壤传感器。

步骤1. 安装ESPHome

请参阅上面步骤1中的安装指南。

步骤2. 添加新设备

转到ESPHome并点击NEW DEVICE

给设备起一个您喜欢的名称,然后点击NEXT

创建新设备后,点击EDIT

步骤3. 安装固件

这里是出厂固件:


这里是一个可直接使用的ESPHome YAML配置,适用于Home Assistant:

点击这里预览完整代码
esphome:
name: soil-moisture-monitor
friendly_name: XIAO 土壤湿度监测器
platformio_options:
platform: https://github.com/mnowak32/platform-espressif32.git#boards/seeed_xiao_esp32c6
on_boot:
then:
# - output.turn_off: gpio_3_output
- output.turn_on: gpio_14_output
- light.turn_on:
id: pwm_led
brightness: 68% # 设置68%占空比
- if:
condition:
lambda: 'return id(wifi_net_status) == 0;'
then:
- logger.log: "设备尚未设置网络"
- deep_sleep.prevent: deep_sleep_control
else:
- logger.log: "设备已联网"
- delay: 1s
- script.execute: check_moisture_once

esp32:
board: seeed_xiao_esp32c6
variant: ESP32C6
flash_size: 4MB
framework:
type: esp-idf
version: "5.2.1"
platform_version: 6.6.0
sdkconfig_options:
CONFIG_ESPTOOLPY_FLASHSIZE_4MB: y

# LED 黄色 D10 18
# LED 红色 D9 20
# LED 绿色 D8 19
# 按钮 D2 2

# 电池 D0 0
# PWM 输出 D3 21
# 土壤传感器 D1 1

output:
- platform: gpio
pin: GPIO18
id: yellow_led_output

- platform: gpio
pin: GPIO19
id: green_led_output

- platform: gpio
pin: GPIO20
id: red_led_output

- platform: ledc
pin: GPIO21
id: pwm_output
frequency: 200kHz # 设置频率为200kHz

- platform: gpio
pin: GPIO14
id: gpio_14_output

light:
- platform: binary
id: yellow_led
output: yellow_led_output

- platform: binary
id: green_led
output: green_led_output

- platform: binary
id: red_led
output: red_led_output

- platform: monochromatic
output: pwm_output
id: pwm_led
name: "200kHz PWM"
internal: true
default_transition_length: 0s

script:
- id: red_led_blink
mode: restart
then:
- repeat:
count: 10
then:
- light.turn_on: red_led
- delay: 500ms
- light.turn_off: red_led
- delay: 500ms

- id: green_led_blink
mode: restart
then:
- repeat:
count: 10
then:
- light.turn_on: green_led
- delay: 500ms
- light.turn_off: green_led
- delay: 500ms

- id: fast_blink_green
then:
- repeat:
count: 5
then:
- light.turn_on: green_led
- delay: 200ms
- light.turn_off: green_led
- delay: 200ms

- id: fast_blink_red
then:
- repeat:
count: 5
then:
- light.turn_on: red_led
- delay: 200ms
- light.turn_off: red_led
- delay: 200ms

- id: red_led_blink_3_times
then:
- repeat:
count: 1
then:
- light.turn_on: red_led
- delay: 1000ms
- light.turn_off: red_led
- delay: 100ms
- id: yellow_led_blink_3_times
then:
- repeat:
count: 1
then:
- light.turn_on: yellow_led
- delay: 1000ms
- light.turn_off: yellow_led
- delay: 100ms

- id: green_led_blink_3_times
then:
- repeat:
count: 1
then:
- light.turn_on: green_led
- delay: 1000ms
- light.turn_off: green_led
- delay: 100ms

- id: do_calibration
then:
- deep_sleep.prevent: deep_sleep_control
- logger.log: "开始校准"
- script.execute: red_led_blink
- delay: 10s
- script.stop: red_led_blink
- lambda: |-
float sum = 0;
for (int i = 0; i < 10; i++) {
id(soil_sensor).update();
sum += id(soil_sensor).state;
delay(200);
}
id(dry_value) = sum / 10.0;
ESP_LOGI("calibration", "干燥值: %f", id(dry_value));

- delay: 3s

- script.execute: green_led_blink
- delay: 10s
- script.stop: green_led_blink
- lambda: |-
float sum = 0;
for (int i = 0; i < 10; i++) {
id(soil_sensor).update();
sum += id(soil_sensor).state;
delay(200);
}
id(wet_value) = sum / 10.0;
ESP_LOGI("calibration", "湿润值: %f", id(wet_value));

- delay: 3s

- lambda: |-
if (id(dry_value) > id(wet_value)) {
ESP_LOGI("calibration", "校准成功");
id(fast_blink_green).execute();
} else {
ESP_LOGW("calibration", "校准失败");
id(fast_blink_red).execute();
}

- delay: 3s
- script.execute: check_moisture_once
- delay: 3s
- deep_sleep.enter: deep_sleep_control

- id: check_moisture_once
then:
- lambda: |-
for(int i = 0; i < 10; i++){
id(soil_sensor).update();
delay(200);
}
float moisture = id(soil_sensor).state;
ESP_LOGI("moisture_check", "湿度读数: %f", moisture);
float Diff = id(dry_value) - id(wet_value);
ESP_LOGI("moisture_check", "差值为: %f", Diff);
ESP_LOGI("moisture_check", "ref_dry 差值为: %f",id(dry_value) - Diff * id(ref_dry));
ESP_LOGI("moisture_check", "ref_wet 差值为: %f",id(dry_value) - Diff * id(ref_wet));
if (moisture >= (id(dry_value) - Diff * id(ref_dry))) { // 越干燥 -> 电压越高
id(red_led_blink_3_times).execute();
id(deep_sleep_control).set_sleep_duration(900000);
} else if(moisture > (id(dry_value) - Diff * id(ref_wet)) && moisture < (id(dry_value) - Diff * id(ref_dry))){
id(yellow_led_blink_3_times).execute();
id(deep_sleep_control).set_sleep_duration(3600000);
}else{
// moisture > (id(dry_value) - Diff * id(ref_wet))
id(green_led_blink_3_times).execute();
id(deep_sleep_control).set_sleep_duration(28800000);
}

globals:
- id: button_press_count
type: int
restore_value: no
initial_value: '0'
- id: dry_value
type: float
restore_value: yes
initial_value: '2.75'
- id: wet_value
type: float
restore_value: yes
initial_value: '1.2'
- id: wifi_net_status
type: int
restore_value: yes
initial_value: "0"
- id: ref_dry
type: float
restore_value: no
initial_value: "0.23"
- id: ref_wet
type: float
restore_value: no
initial_value: "0.58"

binary_sensor:
- platform: gpio
pin:
number: GPIO2
mode: INPUT_PULLUP
allow_other_uses: true
id: my_button
on_press:
- lambda: |-
id(button_press_count)++;
- delay: 1s # 延迟1秒,看按钮是否连续按下3次
- lambda: |-
if (id(button_press_count) == 3) {
id(button_press_count) = 0;
id(do_calibration).execute(); // 触发校准过程
} else if (id(button_press_count) == 1) {
id(button_press_count) = 0;
id(check_moisture_once).execute(); // 执行一次ADC判断
} else {
id(button_press_count) = 0;
}

deep_sleep:
id: deep_sleep_control
run_duration: 120s
sleep_duration: 180min
wakeup_pin:
number: GPIO2
inverted: true
allow_other_uses: true
mode: INPUT_PULLUP


external_components:
- source: github://pr#7942
components: [ "adc" ]

- source:
type: git
url: https://github.com/ackPeng/esphome.git
ref: api
components: [ api ]
refresh: 0s

sensor:
- platform: adc
id: soil_sensor
pin: GPIO1
name: "土壤湿度测量"
update_interval: 4s
internal: true
attenuation: 12db


- platform: adc
pin: GPIO0
name: "电池测量"
attenuation: 12db
filters: # 当电池电压低于1V时,电池耗尽
- lambda: |-
if (x < 1.0) {
return 0.0;
} else {
return ((x - 1.0) / (1.5 - 1.0)) * 100.0;
}
unit_of_measurement: "%"
update_interval: 5s
force_update: True

- platform: wifi_signal
name: "wifi信号强度"
update_interval: 10s

text_sensor:
- platform: template
name: "土壤湿度状态"
id: soil_status
lambda: |-
float value = id(soil_sensor).state;
float Diff = id(dry_value) - id(wet_value);
if (value >= (id(dry_value) - Diff * id(ref_dry))) {
return {"干燥"};
} else if (value > (id(dry_value) - Diff * id(ref_wet)) && value < (id(dry_value) - Diff * id(ref_dry))) {
return {"接近干燥"};
} else {
return {"湿度正常"};
}
update_interval: never # 不让自动触发上报,我们自己控制

interval:
- interval: 5s
then:
- text_sensor.template.publish:
id: soil_status
state: !lambda |-
return "";
- delay: 10ms
- text_sensor.template.publish:
id: soil_status
state: !lambda |-
float value = id(soil_sensor).state;
float Diff = id(dry_value) - id(wet_value);
if (value >= (id(dry_value) - Diff * id(ref_dry))) {
id(deep_sleep_control).set_sleep_duration(900000);
return "干燥";
} else if (value > (id(dry_value) - Diff * id(ref_wet)) && value < (id(dry_value) - Diff * id(ref_dry))) {
id(deep_sleep_control).set_sleep_duration(3600000);
return "接近干燥";
} else {
id(deep_sleep_control).set_sleep_duration(28800000);
return "湿度正常";
}

# 启用日志记录
logger:

improv_serial:

# 启用Home Assistant API
api:
# encryption:
# key: "YVjz+1l5zHXeyXFVinhaJkqh8RnG0gUVjaWniPEzCj4="

ota:
- platform: esphome
password: "dcad8df988971d761bc72a30d7878a40"

wifi:
# ssid: "my68k"
# password: "1143590135"
on_connect:
then:
- if:
condition:
lambda: 'return id(wifi_net_status) == 0;'
then:
- logger.log: "设备尚未配置,但现在已成功配置"
- globals.set:
id: wifi_net_status
value: '1'
- delay: 5s
- deep_sleep.allow: deep_sleep_control
else:
- logger.log: "设备已联网"

on_disconnect:
then:
- globals.set:
id: wifi_net_status
value: '0'
# 启用备用热点(强制门户),以防wifi连接失败
ap:
ssid: "Xiao-Soil-Moisture-Monitor"
password: ""

captive_portal:
以下是 YAML 配置中使用的关键函数和逻辑概述。

on_boot – 定义设备启动时发生的操作。

  • 输入参数:无。
  • 操作:打开 GPIO 14,设置 PWM LED 亮度,检查 Wi-Fi 状态,并触发第一次湿度检查。

scripts (red_led_blink, green_led_blink, fast_blink_green, fast_blink_red, etc.) – 预定义的 LED 闪烁模式。

  • 输入参数:无。
  • 操作:以各种模式闪烁 LED 以指示状态或校准步骤。

do_calibration – 运行干燥和湿润土壤的校准过程。

  • 输入参数:无。
  • 操作:闪烁红色 LED,等待干燥读数;然后闪烁绿色 LED,等待湿润读数;存储平均值并确认成功或失败。

check_moisture_once – 读取和评估土壤湿度水平。

  • 输入参数:无。
  • 操作:进行多次 ADC 读数,计算平均值,与校准阈值比较,确定湿度状态,相应地触发 LED 和深度睡眠设置。

binary_sensor (GPIO2) – 处理物理按钮按压逻辑。

  • 输入参数:无。
  • 操作:计算按钮按压次数;单次按压触发湿度检查,三次按压触发校准。

globals – 存储系统状态和校准数据。

  • 变量
    • button_press_count:跟踪按钮按压计数。
    • dry_value, wet_value:存储校准的干燥/湿润 ADC 值。
    • wifi_net_status:跟踪 Wi-Fi 连接状态。
    • ref_dry, ref_wet:用于阈值计算的参考缩放因子。

deep_sleep – 管理省电睡眠周期。

  • 输入参数:无。
  • 操作:运行 120 秒,然后睡眠最多 180 分钟;在按钮按压或间隔时唤醒。

sensor (ADC) – 从土壤传感器和电池读取模拟值。

  • 输入参数:无。
  • 操作:测量土壤湿度和电池电压;电池按比例显示百分比。

text_sensor – 发布人类可读的土壤湿度状态。

  • 输入参数:无。
  • 操作:在 Home Assistant 中显示"Dry"、"Almost Dry"或"Normal Moisture"。

wifi + api + ota – 管理网络连接、Home Assistant 集成和无线固件更新。

  • 输入参数:Wi-Fi SSID 和密码。
  • 操作:将设备连接到网络,公开其 API,并启用远程更新。

点击 INSTALL 将代码安装到设备,您将看到以下图像。

tip

如果您的 Home Assistant 主机(Raspberry PI/Green/Yellow 等)距离您很远,我们建议使用此方法。您可以使用手边的计算机进行安装。

首先,您需要点击 Manual download 下载编译好的固件。

打开这个网站,我们将在这里上传固件到 ePaper 面板。

返回 ESPHome 下载固件。

选择 Factory 格式。

使用 USB 线缆将 ePaper 面板连接到您的计算机并点击 CONNECT

选择 usbmodemxxx(Windows 是 COMxxx)并点击连接。

点击 INSTALL 并选择您刚刚下载的固件。

您的固件将很快被刷入~

重置

如果需要重新刷写固件,您可以使用以下链接恢复默认固件:
https://gadgets.seeed.cc/

首先将您的设备连接到计算机。
然后,在页面上找到 XIAO Soil Moisture Monitor 并点击 Connect 以继续重新刷写。

资源

技术支持与产品讨论

感谢您选择我们的产品!我们在这里为您提供不同的支持,以确保您使用我们产品的体验尽可能顺畅。我们提供多种沟通渠道,以满足不同的偏好和需求。

Loading Comments...