turfy · irrigation sidecar · v0.1

An AI sprinkler brain that fails back to dumb.

Turfy is a weather-informed, camera-and-sensor irrigation controller — but the clever part isn’t the AI, it’s that it only touches your lawn when it’s provably healthy. It rides alongside a 1990s Rain Bird as a fail-safe sidecar: take authority while the watchdog is fed, and hand control straight back the instant anything goes wrong. In hardware. Because a stuck valve is a flooded yard and a very large water bill.

Rain Bird ESP-6Si controller faceplate
The subject: a Rain Bird ESP-6Si. Reused, not replaced — Turfy borrows its transformer, its valves, and its job as the always-there fallback brain.

Safe by construction

Rain Bird keeps authority

The 1990s controller stays wired exactly as it is. Turfy is a sidecar on the station outputs — it never replaces the brain, it borrows it.

A hardware dead-man

A 555 missing-pulse watchdog must be fed by the daemon's own main loop every ~24s. Miss a beat and the transfer relays physically drop.

Fail back to dumb

Power loss, kernel panic, daemon hang, wedged I²C — every failure reverts to the Rain Bird with zero software involved. A stuck valve floods a yard; this can't stick.

The invariant the whole design hangs on

A de-energized transfer bank leaves the Rain Bird wired exactlyas it is today. It’s the first line of the acceptance test — proven with a continuity meter before anything is ever powered on.

The transfer-switch architecture

It’s the classic automatic-transfer-switch pattern applied to sprinklers. An SPDT relay per zone: Rain Bird output on NC, Turfy output on NO, valve wire on the common pole. One authority line pulls the whole bank — unpowered, crashed, or watchdog-tripped, the relays drop and the Rain Bird is back in control.

signal path — v0.1
                     24VAC (Rain Bird VT terminals, shared transformer)
                          │
                ┌─────────┴──────────┐
                │ fuse 1A + MOV       │
   ┌────────────┐   ┌─────────────┐   │
   │ Rain Bird  │──▶│ ZONE BANK   │◀──┼── MCP23017 (I2C 0x20) ◀── Pi
   │ ESP-6Si    │   │ (Turfy out) │   │
   │ ST1..ST6   │   └──────┬──────┘   │
   └─────┬──────┘          │ NO       │
         │ NC              ▼          │
   ┌──────────────────────────────┐   │
   │ TRANSFER BANK  8ch SPDT relay │◀──┴── AUTHORITY line
   │ COM ─▶ valve field wires 1..6 │       (Pi GPIO ∧ watchdog)
   └──────────────────────────────┘            ▲
                                    555 missing-pulse detector
                                                ▲
                                    HEARTBEAT GPIO (daemon-toggled)

The one rule that must survive every revision:never run a second 24VAC transformer while the NC path to the Rain Bird exists. Out-of-phase secondaries through the transfer relay = circulating current and dead triacs. Turfy steals 24VAC from the Rain Bird’s own terminals so both controllers switch the same hot leg.

Reverse-engineering the box

Before you can sidecar a sealed 1990s controller, you have to map it. Board by board: what’s the tap point, where does 24VAC come from, and is the fallback actually trustworthy?

The safety core

“The heartbeat must prove applicationliveness, not kernel liveness.”So it’s toggled from the daemon main loop — never cron, never hardware PWM. A cron job would keep ticking after a crash and defeat the entire point.

Authority = liveness ∧ intent

Two 2N2222s in series pull the transfer bank low. It engages only when the 555 says the daemon is alive and the Pi explicitly asserts yes. Either transistor off → the line floats high → the bank drops → Rain Bird.

authority ⇔ (heartbeat alive) ∧ (Pi says yes)
Boot sequence — safe at every step
  1. 1Pi boots. AUTHORITY GPIO defaults pull-down → Rain Bird stays in control regardless of any GPIO chatter.
  2. 2MCP23017 powers up all-inputs (POR default) → zone relays held off. Defined state, no init race.
  3. 3turfy.service self-checks (I²C ack, config sane, time synced), starts the heartbeat, then raises AUTHORITY.
  4. 4Watchdog charges within one timeout; the transfer bank engages and Turfy is driving.

Every way it can fail

FailureResult
Pi power loss / kernel panicfails safeHeartbeat stops → watchdog drops → Rain Bird
Daemon crash or hangfails safeSame — the heartbeat is owned by the daemon loop
Pi reboot GPIO chatterfails safeAUTHORITY pull-down + MCP POR = no valve action
I²C bus wedgefails safeDaemon detects NAK → drops AUTHORITY
Relay 5V supply diesfails safeTransfer coils drop → Rain Bird
Both controllers fire one zonefails safeHarmless — shared transformer, same phase
Healthy daemon, latched zonesoftware invariantNot caught by the watchdog → hard-capped by a per-zone max-runtime in the driver layer, plus flow-meter alarm in v0.2

Validate each layer

Phase 0

Passive learn

An H11AA1 opto per station output logs when the Rain Bird actually waters. Validates zone mapping and collects a baseline schedule — zero risk, Turfy never asserts.

instrumentation
Phase 1

Take authority

Transfer relays + watchdog go live. Turfy replicates the dumb schedule first, proving the fail-safe handover with a meter before anything smart happens.

the sidecar
Phase 2

Flow metering

An inline pulse flow meter learns each zone's baseline GPM — the killer feature. Detects stuck valves, broken heads (flow too high) and clogged lines (flow too low), per zone.

closing the loop
Phase 3

Weather + vision

ET-based scheduling (Penman-Monteith / Hargreaves) scales runtime to replace the daily deficit, minus rainfall. A cheap camera adds an NDVI-ish turf-stress index on top.

the AI layer
v0.1 build package

Two stock relay boards, an MCP23017 for defined power-on state, a 555 watchdog, and an H11AA1 sense bank — a parametric schemdraw source renders the four schematic sheets, so a board photo becomes a one-line edit and re-render.

2× 8-ch SPDT relayMCP23017NE555 + 2N39062× 2N2222 AND7× H11AA1 sense1A fuse + 39V MOVRaspberry Pi