Battery-powered ESP32 soil moisture node using ESPHome, designed for long-term, low-maintenance garden deployment.
It measures:
- Soil moisture (capacitive VH400 probe)
- Garden air temperature & humidity
- Enclosure temperature & humidity
- Battery voltage and ESP 5 V rail voltage (prevents Sleep)
All sensors receive battery positive (V+), and their ground return path is switched through a MOSFET, ensuring near-zero sensor current during deep sleep.
- ESP32 running ESPHome (ESP-IDF)
- Dual SHT31 sensors for ambient and enclosure temperature/humidity
- VH400 capacitive soil moisture probe powered from a 5 V boost converter
- Hard power removal from sensors using a low-side MOSFET
- Custom ESPHome I²C bus component delays I²C initialization until sensors are powered
This project targets users already familiar with ESPHome and Home Assistant. Electronics knowledge is helpful but not required.
- MCU: ESP32 dev board
- Sensors:
- SHT31 @ I²C address
0x44(garden) - SHT31 @ I²C address
0x45(enclosure) - Vegetronix VH400 moisture probe (analog output)
- SHT31 @ I²C address
- Power:
- Single-cell LiPo (4.2 V max)
- 5 V boost converter for VH400
- Sensors connected directly to battery V+
- Sensor ground switched via IRLZ44N MOSFET
- Switching & Measurement:
- MOSFET gate controlled by ESP32
GPIO17(via 200 Ω, 100 kΩ pull-down) - Boost rail sense (30 kΩ / 20 kΩ divider → GPIO36)
- Battery sense (36 kΩ / 100 kΩ divider → GPIO32)
- MOSFET gate controlled by ESP32
- GPIO Use:
GPIO21– I²C SDAGPIO22– I²C SCLGPIO34– VH400 analog inputGPIO32– battery voltage ADCGPIO36– 5 V rail ADCGPIO17– MOSFET gateGPIO39– external wake
The system uses battery V+ to power all sensors, but prevents any actual current flow until sensor ground is connected.
- Sensor V+ is always present.
- Sensor ground is routed through an IRLZ44N MOSFET.
- When the MOSFET is off, sensors are effectively unpowered.
- This prevents:
- I²C bus lockups on boot
- Sensor leakage current during deep sleep
- Boost converter idle draw
GPIO17 HIGH enables the MOSFET and powers all sensors; LOW disables them.
Battery V+ (to sensors) ESP32 (center) Sensors
───────────────────────────── ───────────────────────────── ────────────────
5V ┌──────────────────────────┐
│ | |
[30 kΩ] │ ESP32 │
● Node (5V sense tap) ◄┤ GPIO36 adc_5v_raw |
| ◄| GPIO39 WAKE_IN |
[20 kΩ] │ │
│ │ │
GND │ │
│ │
LiPo 4.2 V max ◄│ ----------------------- │ ------► SHT31 (4.2V)
│ | | VH400 (1.5–4.5V → 5 V)
[36 kΩ] │ │
│ │ │
● Node (LiPo sense tap) ◄│ GPIO32 adc_batt_raw │
│ │ │
[100 kΩ] │ │
│ │ ─┤ GPIO34 ADC_SOIL ──► VH400 analog out
GND │ ─┤ GPIO21 I2C_SDA ──► SDA of SHT31 @0x44, @0x45
| ─┤ GPIO22 i2C-SCL ──► SCL of SHT31 @0x44, @0x45
|
│ ─┤ GPIO17 VDD_SW ──200 Ω──► IRLZ44N GATE
│ [100 kΩ] gate pull-down → GND
│ |
└──────────────────────────┘
The ESPHome configuration:
- Uses ESP-IDF for low-level control.
- Manages dual SHT31 sensors on I²C.
- Reads VH400 analog moisture values.
- Measures battery and boost voltages via ADC.
- Controls the MOSFET gate (
GPIO17) to power-cycle sensors each wake cycle. - Performs deep sleep for long life, with adaptive intervals.
A custom I²C component ensures I²C doesn't initialize until sensors are truly powered.
File location:
copy: /homeassistant/esphome/components/i2c/i2c_bus_esp_idf.h
to: /homeassistant/esphome/my_components/i2c/i2c_bus_esp_idf.h
// Original:
// float get_setup_priority() const override { return setup_priority::BUS; }
// Modified:
float get_setup_priority() const override { return setup_priority::DATA; }- ESPHome orders initialization based on setup priority.
- By switching to
DATA, the I²C bus initializes later, after:GPIO17enables the sensor ground MOSFET- Sensors and the boost converter stabilize
This prevents intermittent failures such as:
- I²C scan failures
- Missing devices on wake
- First-read failures after deep sleep
ESPHOME Components Access Instructions
- ESP32 wakes.
GPIO17→ HIGH to enable the MOSFET and power sensors.- Short stabilization delay.
- Modified I²C bus initializes.
- Sensors read:
- SHT31 ×2
- VH400 analog moisture
- Battery & 5 V rail (Prevents Sleep)
- Values published to Home Assistant.
- Sleep interval chosen (normal, low battery, or night).
GPIO17→ LOW cuts all sensor power.- ESP32 enters deep sleep.
Typical entities exposed:
- Ambient temperature / humidity
- Enclosure temperature / humidity
- Soil moisture (processed)
- Raw VH400 analog voltage
- Battery voltage
- Boost converter voltage
- Battery percentage
- Wi-Fi RSSI
- Sleep/wake event entity
GNU General Public License v3.0 (GPL-3.0)
Full text