Back
Greenery client · 2026 – active

An 8,000 m² PoC blueberry field that waters itself

The story

Client needed a PoC autonomous system that waters a field while also future proofing infrastructure to collect data.

A Raspberry Pi in a sealed cabinet at the edge of the field opens three solenoid valves on a schedule, waters 2,400 blueberry bushes section by section, and writes down everything it did.

Worth noting

  • · Three valves, eight rows each, optimized
  • · The web process is always unprivileged
  • · Any uncertainty closes every valve

The problem

The PoC plantation is 8,000 m²: 24 rows of 100 m, 2,400 blueberry bushes, two drip lines per row with 499 emitters at 2.2 L/h — about 1,100 litres an hour to water one row properly. Client runs a greenery company and has an experimental field for discovering optimal water usage, this one is a blueberry field, client mostly works with grass and bushes.

What we built

The systme is being built in two phases — first control and valves — and soil sensors in Phase 2, because water has to turn on and off reliably before anything clever is worth putting on top of it. The field is divided into three sections of eight rows with one solenoid valve each, and that number came last: the first design put a valve on every row (24 outputs, far too expensive), the second used six, and once the client confirmed the pump comfortably carries a full eight-row section at 8.8 m³/h, three was enough. Three valves fit straight onto the Raspberry Pi's own pins, so the port expander left the bill of materials and took its failure modes with it. Everything lives in one IP65 cabinet at the edge of the field: a Raspberry Pi 4, an eight-channel opto-isolated relay board, a 230 to 24 V AC transformer, a small UPS on two 18650 cells, and a breaker. The valves are normally closed and run on 24 V AC, so losing power means no water rather than a valve stuck open. Proofed to recover from all non-physical failures.

Modules & surfaces

  • Control workerA loop on a one-second tick: heartbeat, emergency stop, active run, schedule lookup, then the pins. It is the only process that decides what the field is doing.
  • Pin ownershipOne long-lived gpioset holds all three lines and is swapped only when the target state changes. Asking for a state that is already held does nothing.
  • SchedulerEntries per section — days of the week, start time, duration. When two fall due at once the lower section number wins and the other is written down as skipped rather than quietly dropped.
  • Control cabinetRaspberry Pi, relay board, 230 to 24 V AC transformer, UPS and breaker on a DIN rail inside an IP65 enclosure, with three valves on 50 m of outdoor cable.
  • Operator panelFive screens: live status with cancel and +15 min, quick manual watering, the schedule, history with charts, and system health. State refreshes every two seconds.
  • Audit logFive tables and fifteen event types. Every run and every decision is written down, so the history answers questions instead of inviting arguments.
  • Restart recoveryOn boot, runs left open are marked interrupted, every valve closes, and nothing resumes on its own. SIGTERM closes the valves before the process exits.

How we approached it

Two things shaped the implementation. The first was libgpiod v2: gpioset does not set a pin and exit, it holds the lines and blocks until it is killed, and the kernel releases them only then — so fire-and-forget is not available, because the next call gets a busy error and the value would not have stuck anyway. Exactly one long-lived process holds the desired state of all three pins and is replaced only when the target actually changes, and every write defines all three outputs, so there is no code path that opens valve 2 without saying what valves 1 and 3 are doing. The second was a rule: any uncertainty closes every valve. Boot, a failed write, a worker that has not ticked in 30 seconds, an error anywhere in the loop — all of them land in the same state, with all three valves shut. Watering never resumes by itself after a restart; there is a five-second gap of everything-closed between one valve shutting and the next opening, because opening two valves into the same manifold is how you get water hammer; and manual watering is capped on the server, not just in the form. The pump is wired to none of it — it is the client's, it has its own pressure switch, and it manages itself.

Outcome

The field has watered itself through the 2026 season. The log holds 211 runs, and a representative week is 25 waterings and 42 hours 32 minutes of valve-open time across the three sections, all of it started by the schedule. run is a row in the database — which section, scheduled or manual, when it started, when it was meant to end, when it actually ended, and why — and fifteen event types cover the rest: boot, skips, pre-emptions, relay tests, GPIO errors, emergency stops.

In use