Apologies, I haven't posted an update here for a while for a few reasons. The weather is getting better and I've been more inclined to get outdoors and enjoy it. I'd recommend the same to anyone, no matter how much you love your coding time. Also I've mainly been working on the electronic parts of my project, making it up as I go, and working through the Rust book on the side.
The circuit is almost complete. At first I was going to bring wires out to screw terminals on the exterior of the box but that seemed clunky and fragile so I've ordered a bunch of 2.5mm DC jacks which I'll mount around the box, and connect everything up with cables that plug in. Should be much more robust, although using the same connector for everything from 12V supply to the moisture sensors is not ideal. I'll just have to make sure I label them.
On the board are the weather sensor, three moisture sensors with the analog outputs fed into an MCP3008 ADC chip, and three TIP120 darlington transistors controlled by GPIO lines, for the water valves. I've added LED indicators to show when the valves are (meant to be) open. On the top of the box is a push button wired directly to a GPIO line and ground - I'll add a feature in software to open and close the water valves directly when the button is pushed. Manual overrides are handy.
I'm really enjoying learning Rust. It feels familiar like C but with the added advantages of a strong type system and modern programming features. The ability to write chains of iterator adaptors, functional style, and have it compile to much the same machine instructions as the imperative loop is really impressive. I look forward to using this more.
The controller software structure is getting clearer in my head - essentially an event bus onto which various modules can publish or subscribe to events. Then I'll write separate modules for all the various bits of hardware and software features, and use an external config file to determine which modules are instantiated. Seems like that'll be enough to force me to write something resembling real-world code, at the same time it will also be maintainable for behaviour tweaks as the summer passes. At the weekend I'm hoping to get started with multithreaded Rust code so I can start putting together the basic structure of the application.