Two rules, then the physics
The idea fits in a sentence: a probe in the soil, a small computer that reads it, a screen in the house that says “water tomorrow”. Two rules shaped everything after it.
The control loop never leaves the garden.Each bed gets its own ESP32 that senses, decides and, one day, waters on its own. WiFi is only a reporting path: the screen in the house asks, the node answers, and nothing arriving over that link can start a pump.
Nothing that can move water exists until the probes are proven.Firmware, calibration, a week of watching real soil dry out. Only then a relay and a pump. So far, nothing in the build can water a plant.
Six physical facts decided the design before any code did. Most sensor tutorials are written for a 5 V Arduino on a desk; a garden is wetter, further away and less forgiving.
ADC1 pins only
The ESP32's second ADC dies whenever WiFi is up. A probe on the wrong pin reads perfectly on the bench and returns garbage once the node joins the network.
Capacitive, never resistive
Resistive prongs electrolyse and corrode away inside a season. Capacitive probes have nothing bare in the soil.
3.3 V, not 5 V
The ESP32 is a 3.3 V part and not 5 V tolerant. Copying Arduino wiring kills boards.
Distance decides architecture
I²C dies past about a metre, and a long analog run degrades the very voltage being measured. So the computer goes to the bed, not the probe to the house.
A pump is another world
12 V, amps not milliamps, an inductive kick when it stops. Its own supply and fuse, and it reaches logic only through an opto-isolated relay.
All grounds meet
Separate supplies, one common ground. A floating ground gives readings that drift and still look plausible, which is worse than no reading.
The bench
An ESP32-WROOM-32U, five capacitive probes, a bag of jumper wires and a breadboard. Three days to get one number worth trusting.
The U in WROOM-32U means a tiny U.FL socket instead of a printed antenna. Without the pigtail it barely hears the router.
The probes arrived on 16 September: HW-390 boards with a TLC555 timer and their own regulator. On the 17th, probe 1 on GPIO34 read 2.750 V in air and 1.566 V pushed into damp potting soil. The very first reading was 0.142 V, because two jumpers were swapped. Lesson one: read the silkscreen, not the wire colour.
Pushing the probe deeper moved the reading from 1.58 to 1.71 V. Insertion depth matters, so every probe goes in to the line printed on its board.
Two probes lost on the breadboard
A plug went in rotated and put 3.3 V straight into probe 1's output. Board and probe ran hot, and probe 1 never read again. Probe 2 never gave a reading at all. The breadboard went in a drawer for good, and three rules came out of it: USB out before any plug moves. Jumper by the silkscreen, never by position. One change, one run.
Two jars
Calibration is two readings: the probe in air, then in a glass of water up to the line. Those voltages become 0 % and 100 %. Each probe gets its own pair, taken on the pin and supply it will live on, because the ESP32's ADC varies chip to chip. Swap the probe or the board and the numbers are void.
The board has three usable supplies (3.3 V, 5 V from USB, a GPIO driven high) and three grounds. That is the ceiling for wiring probes directly, so a node carries three probes.
A screen that stays in the house
The first plan posted readings to a hosted garden app. On 18 September that changed.
Still want to use WiFi, but it should be fully in-house.
The brief, 18 Sep
The deck is a small Python server on a Raspberry Pi 5 with a 1024 × 600 touch screen. It polls the node every 10 seconds, writes a CSV to its own disk and draws the page. Fonts ship with it, so it needs no internet at all. No cloud database, no login. Switch it off and the pots carry on.
The logo was settled on 19 September: watercolour pea pods and tomatoes, with WiFi arcs over the i. It sits in the deck's header next to the mark of Peas & Quiet, the kitchen-garden app this project will one day talk to.
t for the light theme, r to swap percent for raw volts.A window, not a door
On 21 September the deck got a public face at soil2signal.sloveller.com. Same pages, same live readings, and every write refused: nobody outside the house can calibrate a probe or log an event. No readings are copied anywhere. If the Pi is off, the page is off.
The pot week
Probes 3, 4 and 5 went into pots A, B and C. One question for the week: does a line of numbers look like soil drying?
It did. For the first three days the pots dried by one to two and a half points a day. From Wednesday it was four to eight. By Saturday noon Pot A had gone from 83 to 57 %, Pot B from 43 to 25 %, Pot C from 92 to 58 %. Whether the speed-up is warmer weather or the probe's curve in drier soil is still open.
The node rebooted every 15 minutes, all week
ESPHome's API restarts a device if no Home Assistant connects within 15 minutes, and there is no Home Assistant here. The readings looked fine, so it went unnoticed for a week. One line of config fixed it: reboot_timeout: 0s.
A still night is not a stuck probe
The deck calls a probe stuck after five identical readings, about 50 seconds. Overnight the soil barely moves, so most flags fired between 19:00 and 07:00. Real sensors fail to a plausible constant, so the check stays, but it needs a longer window.
“Water in about N days”
A forecast now fits each pot's recent dry-down and says when it will reach its dry line, with a range. A third tab, Week, rolls the log up by the hour: forecast fans, stuck-flag lanes, gaps and WiFi.
Watering, by hand, on purpose
For three pots, a pump is all cost: 12 V, a fuse, a relay, an enclosure, a shared ground. The pots get a printed gravity kit instead.
The kit is TimNooked's Modular Irrigation System from MakerWorld. A funnel feeds perforated pipe, held in the soil on spikes. Everything snaps together with no glue, and none of it is electrical, so it sits outside the rule about moving water and can start now.
The deck's only job on the watering side is to say when. The pour shows up as a step on the moisture curve, and that step against a known dose is each pot's calibration. If the step is clean and repeatable, the kit works. If not, fix the kit, not the firmware.
Status: printing next, in PETG. Sink test first (ml in against ml out), then Pot A for a week at 3 × 500 ml, then B and C.
Leaving it alone
Two weeks away, and nothing in the build can water a pot. So Saturday evening was hands-on checks only: probes seated, chargers on sockets nobody will switch off, and a drink for every pot.
A free soak test
The reboot fix went on at lunchtime, so the deck's reboot counter started at zero. For two weeks nobody touches the node or the Pi. Any reboot now is real, and points at the power supply. Any gap is real. That is half of the next phase's month on the shelf, for free.
One message out
The deck only shows alerts on its own screen, which nobody will be looking at. So one small process on the Pi checks it every 10 minutes and sends a Telegram message when a pot crosses its dry line or the node goes quiet. It only sends. Nothing it receives can act, and it will not grow into a readings feed.
Next summer: one bed, no socket
There is no outdoor socket, decided on 20 September. So every node outside the house runs on the sun.
A bed that only senses gets the same ESP32, asleep 99 % of the time, on a 5 W panel and a small LiPo. It wakes every 30 minutes, powers the probe from a GPIO for 300 ms, reads, lets the deck poll it, and sleeps again. A bed that waters gets a 25 W, 12 V kit.
Deep sleep and a switched probe supply are preconditions, not options. And one bench test decides the solar manager: put the node to sleep and check the 5 V output is still on an hour later. Some cut out below about 50 mA, which is exactly what a sleeping node draws.
A 10-litre watering costs about 0.25 Wh. Summer is not the limit; December is, and the bed is empty then anyway.
Before the relay is ever wired, the firmware gets its interlocks: a hard maximum run time, a minimum gap between waterings, no watering on a stuck reading or when the cached forecast says rain, and a manual switch that can only stop. Then a week of dry runs with the relay clicking and no pump attached, a wet run into a bucket to measure litres, and only then the bed.
The deck, a season on
What the screen in the house could look like once there are beds: battery and signal per node, greenhouse air, a cached forecast, the water butt, and the watering node's rules shown but never controlled. These are mockups; every reading on them is invented.
On a phone the same page folds into one column: greenhouse, rain and butt across the top, a card per bed below, and a line at the bottom that says what the page is. Read only, served by the Pi. Nothing here waters anything.
The garden app and the soil
Peas & Quiet knows what is planted, what is due and what the weather will do. It has never seen the soil. Soil to Signal has the soil and nothing else.
The join is ordered by what crosses the house boundary. The rule: a task may leave the house; a reading never does.
The deck learns the garden
- Tasks, crops and 7-day rain beside the moisture bars
- “Tomato (Sungold)” on the card instead of “Pot A”
- A morning brief that knows the real soil, read over the home network
- A feed logged in the app flags the probe to recalibrate
A task, not a reading
- A pot under its floor for hours raises one “water” task
- Calibrations and probe swaps become journal entries
- A silent node or a low battery raises a “protect” task
On record, not on the roadmap
- An hourly digest so the copilot can tell drought from root rot
- Per-crop moisture floors, copied into the deck by hand
Never, in any tier: cloud → pump.
The plan from here
Phases keep the numbers they were given in the original plan, so they do not run in numeric order. The pots come first; the garden waits on where the greenhouse goes.
Bench node + deck
DoneNode flashed and online, antenna fitted, deck running on the Pi.
Pot week + calibration
Exit metThree calibrated probes, a week that looks like drying. Left: a node-side stuck guard, a looser stuck check, two probes in one pot.
The node on its own
Soak runningA month on a shelf, untouched, log unbroken. Then the printed gravity kit, pot by pot.
Alerts on the deck
Nearly doneSilent node, stuck probe, dry pot and the Telegram nudge are in. Left: real dry lines for pots A and C.
Dashboard
DoneHome, Pots and Week tabs, forecast, read-only mirror.
Probes into the beds
ParkedAfter a WiFi survey of each bed. Recalibrate in bed soil, not potting mix.
Solar sensor nodes
ParkedDeep sleep, switched probe supply, battery gauge, a month outdoors.
The watering node
ParkedThe first thing that moves water. Interlocks, dry run, bucket, bed.
Beyond the deck
LaterThe Peas & Quiet join, and log retention if it ever matters.
- Read the two weeks: reboots, gaps, the dry-down past the line.
- Set real dry lines for pots A and C from what the dry-down showed.
- Loosen the stuck check so a still night is not a fault.
- Work out why the drying sped up: fit on volts, or weight recent days harder.
- Then a stuck guard on the node itself, and print the gravity kit.
Field log
The decisions and the reasons behind them, day by day. Most of these were written down the evening they happened.
- 15 Sep
First firmware, CI that compiles it on every push, and the hardware primer. Saved: two ESP32 soil-probe tutorials and a folder of DIY greenhouse plans.
- 16–17 Sep
Five capacitive probes arrive, labelled 1–5. First real reading on GPIO34: 2.750 V in air, 1.566 V in damp soil. A calibration log is started: one row per probe, per chip, per date.
- 18 Sep
The breadboard session costs two probes. Three survivors are wired direct and two-jar calibrated. Three probes per node becomes the rule.
The dashboard goes fully in-house on the Pi. The plan to post readings to a hosted app is parked, not deleted.
Watering for the pots will be a printed gravity kit. No pump, no relay, no 12 V.
- 19 Sep
The pot week starts: probes in pots A, B and C, a reading every minute. Logo settled. A second ESP32 and five more probes ordered as spares. Solar parked until the manager is chosen.
- 20 Sep
No outdoor socket, so every outdoor node is solar. Peas & Quiet becomes a joint project, joined by tiers.
- 21 Sep
Dry line and a verdict in words on each card. The read-only public mirror goes live. The 2027 deck is drawn, and a printable splash hood for the probe tops.
- 24 Sep
Watering forecast on the cards: days to each pot's dry line, with a range.
- 25 Sep
The Week tab. A spreadsheet mirror that never delivered a row is removed; the CSV on the Pi is the only copy.
- 26 Sep
The 15-minute reboots found and fixed. All pots watered at 20:00, the Telegram alert live at 20:14. Then two weeks of leaving it alone.
Learned the hard way
- Jumper by the silkscreen.Never by wire colour or plug position. A rotated plug put 3.3 V into a probe's output and killed it.
- USB out before any plug moves.One change, one run.
- ADC2 lies once WiFi is up.A probe on an ADC2 pin reads perfectly on the bench and returns noise on the network.
- Calibration is per probe, per chip.Swap either and redo both jars. A new board means new numbers for every probe on it.
- Sensors fail quietly.A dead probe sits at a plausible constant, not an error. Reject a reading identical to the last several before acting on it.
- Push to the line.Insertion depth moved one reading from 1.58 to 1.71 V.
- A flat reading can be the chip.Check the probe board carries a TLC555, not an NE555.
- A still night is not a fault.Overnight soil barely changes; a stuck check needs a window longer than a minute.
- Readings can look fine while the node reboots.Count uptime resets, not just values.
- Fertiliser reads wet.Soil EC makes a capacitive probe read 2–5 % wetter per dS/m, just when the plant needs water to move the feed. Recalibrate when the feeding changes.