Battery-powered ESP32-S3 gateway for SDI-12 soil sensors with deep sleep
A battery-powered field gateway that reads 4 soil sensors over the SDI-12 protocol, logs the data, and goes into deep sleep for 1 hour to conserve power. Designed for precision agriculture, environmental monitoring, and research stations.
Each sensor connects on its own dedicated SDI-12 data line with individual level shifting, allowing independent communication without bus collisions.
What it does:
- Reads 4 METER GS3 (or compatible) soil sensors via SDI-12
- Measures soil moisture (VWC), temperature, and electrical conductivity
- Deep sleep between cycles — 1 hour interval, ~10 μA sleep current
- MOSFET-switched sensor power — sensors are powered off during sleep
- State machine architecture — non-blocking, timeout-protected
- 9V battery powered with voltage regulation
- Individual BSS138 level shifters per sensor line
┌─────────┐ ┌────────────────────────────────────────────┐
│ 9V │ │ ESP32-S3 │
│ Battery │────►│ │
└─────────┘ │ GPIO 8 ──► BSS84 P-FET ──► Sensor Power │
│ │
│ GPIO 15 ◄──► BSS138 ◄──► SDI-12 Sensor 1 │
│ GPIO 16 ◄──► BSS138 ◄──► SDI-12 Sensor 2 │
│ GPIO 17 ◄──► BSS138 ◄──► SDI-12 Sensor 3 │
│ GPIO 18 ◄──► BSS138 ◄──► SDI-12 Sensor 4 │
│ │
│ Deep Sleep (1 hour) ──► Wake ──► Read ──► │
└────────────────────────────────────────────┘
Boot → Power ON sensors → Wait 2s → Send M! → Wait → Read D0! → Next sensor → Power OFF → Deep Sleep (1h)
- ESP32 wakes from deep sleep (or boots fresh)
- MOSFET switches ON sensor power (GPIO 8 → LOW)
- Wait 2 seconds for sensors to stabilize
- For each sensor (1–4):
- Send
aM!command (start measurement) - Wait for sensor-requested delay (typically 1–3 sec)
- Send
aD0!command (read data) - Parse response: VWC, temperature, EC
- Send
- Power OFF sensors (GPIO 8 → HIGH)
- Enter deep sleep for 3600 seconds (1 hour)
| Component | Qty | Purpose |
|---|---|---|
| ESP32-S3 DevKit | 1 | Main controller |
| METER GS3 (or compatible) | 4 | Soil moisture / temp / EC sensors |
| BSS138 N-MOSFET | 4 | 3.3V ↔ sensor voltage level shifting (data lines) |
| BSS84 P-MOSFET | 1 | Sensor power switching |
| BC547 NPN | 1 | Gate driver for BSS84 |
| TVS diode | 1 | ESD protection on SDI-12 bus |
| 9V battery | 1 | Power source |
| Resistors | — | 4.7kΩ pull-ups, 10kΩ pull-downs, 150Ω series, 100kΩ gate |
ESP32-S3 Pin Assignment
───────────────────────────────────────
GPIO 8 → Sensor power control (ENERGY_SAVING)
GPIO 15 → SDI-12 Data Line — Sensor 1 (address '1')
GPIO 16 → SDI-12 Data Line — Sensor 2 (address '2')
GPIO 17 → SDI-12 Data Line — Sensor 3 (address '3')
GPIO 18 → SDI-12 Data Line — Sensor 4 (address '4')
9V Battery ──► BC547 (base from GPIO 8)
│
▼
BSS84 P-FET ──► Sensor V+ rail
│
100kΩ pull-up
When GPIO 8 is LOW → BC547 ON → BSS84 gate pulled LOW → sensors powered. When GPIO 8 is HIGH → BC547 OFF → BSS84 gate HIGH → sensors off (~10 μA total).
| State | Description |
|---|---|
| IDLE | Wait for cycle trigger (deep sleep wake or interval) |
| WAKE_SENSORS | Switch on sensor power via MOSFET |
| WAIT_WAKE | 2-second stabilization delay |
| SEND_MEASUREMENT | Send aM! to current sensor |
| WAIT_MEASUREMENT | Wait sensor-requested time (1–3 sec) |
| READ_DATA | Send aD0!, parse response |
| FINISH_CYCLE | Power off sensors, enter deep sleep |
const bool USE_DEEP_SLEEP = true; // true = deep sleep, false = polling
const unsigned long DEEP_SLEEP_TIME_SEC = 3600; // 1 hour
const unsigned long WAKE_DELAY_MS = 2000; // sensor warm-up
const unsigned long RESPONSE_TIMEOUT_MS = 5000; // M! timeout
const unsigned long READ_TIMEOUT_MS = 5000; // D0! timeoutWireless-Soil-Sensor-Gateway/
├── Wireless_Soil_Sensor_Gateway.ino # Main firmware
├── schematic.pdf # Fritzing circuit diagram
├── screenshots/
│ └── schematic.png # Circuit preview
├── README.md
└── LICENSE
Connect sensors and MOSFETs according to the schematic. Each sensor gets its own SDI-12 data line through a BSS138 level shifter.
1. Open Wireless_Soil_Sensor_Gateway.ino in Arduino IDE
2. Select board: ESP32-S3 Dev Module
3. Install library: SDI-12 (by EnviroDIY)
4. Upload
5. Open Serial Monitor (115200 baud)
Connect 9V battery, place sensors in soil at desired depths. The device will read all 4 sensors and sleep for 1 hour between cycles.
The SDI-12 (Serial Data Interface at 1200 baud) protocol is an industry standard for environmental sensors. Each sensor has a unique address ('1'–'4') and responds to ASCII commands:
| Command | Description | Example Response |
|---|---|---|
aM! |
Start measurement | a0013 (wait 1 sec, 3 values) |
aD0! |
Read data | a+0.234+22.5+1.45 (VWC, temp, EC) |
aI! |
Sensor info | Manufacturer, model, version |
Individual data lines — Each sensor has its own GPIO + level shifter instead of a shared bus. This avoids address conflicts and allows parallel communication.
MOSFET power switching — A BSS84 P-channel MOSFET cuts power to all sensors during sleep, reducing current from ~50 mA to ~10 μA.
Non-blocking state machine — The firmware uses a state machine with timeouts instead of blocking delays, ensuring robust operation even if a sensor fails to respond.
Deep sleep — The ESP32-S3 deep sleep mode draws ~10 μA. With a 9V battery (500 mAh), the device can run for months in the field.
Temur Eshmurodov — @myseringan
MIT License — free to use and modify.
