Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1,034 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Sprout β€” plants that finally have a voice

ESP32 latest release calibrated moisture bands MIT license CI

Hi, I'm Sprout. I watch a windowsill of plants and tell you, in plain words, how each one is doing β€” no guesswork: I read the soil myself and speak for the plant. (Watering? On my roadmap β€” and true to form, I won't claim it until it's calibrated.)


What Sprout is

Sprout is a small automatic plant-care system for a windowsill: capacitive soil-moisture probes on one or more ESP32-class boards β€” each reporting over Wi-Fi (untethered) or a USB-serial cable β€” with a Python logger and analytics behind them and a served dashboard out front. It watches the soil, classifies it into seven calibrated moisture bands, and (once calibration is in) will water before a plant is ever in trouble.

The minimum Sprout is deliberately small: a microcontroller and one soil sensor is already a complete Sprout (ADR-0028) β€” a pump, an OLED, and extra probes are optional enhancements, never an entry bar. And it's past the bench: since the wave-1 go-live (2026-07-04) the greenhouse runs live in soil β€” currently 11 plants, 8 of them with sensors, on 2 boards β€” reporting over Wi-Fi with each session saved to the catalog.

It's an open-source learning-and-portfolio build, made to be enjoyable to run and trustworthy to read β€” process and tooling sized to match, not over-engineered.

Sprout is developed with AI assistance β€” the maintainer works alongside AI coding tools β€” and AI-assisted contributions are as welcome as hand-written ones. Contribute however you work, with or without AI tools; the bar is the same either way: clear, tested, and kind.

Quick start

What you need first

A computer macOS, Linux, or Windows 10/11. All three are supported and tested.
Git git --version should print a number. If not: winget install Git.Git (Windows), xcode-select --install (macOS), sudo apt install git (Debian/Ubuntu).
A GitHub account Only to contribute. Reading, cloning, and running Sprout need no account. To push, either add an SSH key or install the GitHub CLI and run gh auth login. Not a collaborator here? Fork the repo and branch from your fork β€” the normal open-source path.
Python Nothing to install. uv fetches the exact locked interpreter for you.
A board + probe Optional. Sprout runs, builds and tests without hardware; you need one only to read real soil.

Windows β€” where you clone matters. Windows' classic MAX_PATH is 260 characters and applies to the whole path, so we keep tracked paths under 200 and that leaves about 60 characters for your clone location. C:\dev\sprout is ideal; a deep …\OneDrive\Documents\GitHub\… can exhaust the budget and produce a checkout that fails β€” or silently lands incomplete β€” on a machine that has done nothing wrong. just doctor measures yours and tells you the headroom.

macOS / Linux

git clone https://github.com/OrangePeachPink/sprout
cd sprout
./scripts/bootstrap.sh      # installs uv + just if missing, syncs the env, wires the hooks
just start                  # run Sprout β€” opens the dashboard in your browser

Windows (PowerShell β€” works on the 5.1 that ships with Windows)

git clone https://github.com/OrangePeachPink/sprout
cd sprout
.\scripts\bootstrap.ps1
just start

That block is the whole path: bootstrap installs what's missing and then verifies it, printing the versions it just proved on your machine. It's safe to re-run β€” every step checks first and skips what's already there. Only git has to be there first (it's how you got here); your first PR walks that and the GitHub side.

Prefer to do it by hand, or curious what bootstrap does? The two tools are uv (env + runner) and just (the command menu):

uv sync                     # reproduce the exact, locked dev environment
uv run pre-commit install   # the conventions auto-apply on every commit

Or click Open in Codespaces for a ready-made env in the browser β€” the devcontainer installs both tools for you. Then just lists every command, and just check runs your local gate β€” lint, format, and the host test suites. Those two tools are genuinely all you need: just check never asks for a compiler. Only firmware work needs more, and it says so on its own path (just check-firmware).

Once the dashboard is up, click β–Ά Start logging β€” that single action begins logging every connected sensor at once, whether it's plugged in over USB or reporting over Wi-Fi. On a brand-new install with no data yet, the empty-state hands you the same Start button, so day one is never a dead-end.

How it works

   probe          ESP32             classifier            Sprout
   ─────          ─────             ──────────            ──────
   capacitive  β†’  raw ADC count  β†’  seven moisture   β†’   a mood, a first-person line,
   soil read      (higher = drier)  bands (calibrated)   and β€” when ready β€” a pump

The chain is built on one rule: raw counts and the calibrated band are the reading. Any 0–100 figure is a clearly-labelled relative index between the wet/dry anchors β€” never presented as real volumetric water content. A plant's mood, its status color, and any watering all derive from the band, never from that index.

A look

Today β€” the Workbench. One command (just start) serves this: Monitor Β· Capture Β· Lab Β· Trial Β· Plants & Sensors Β· Diagnostics & Logs β€” raw ADC and the calibrated band for every probe, plus the calibration ladder. The Workbench is where the instrument is read; Home β€” the glanceable per-plant card grid β€” is where a plant speaks for itself, and ADR-0033 is the plan for getting there. Plain and unpolished on purpose, and it shows exactly what it reads: a probe sitting in open air or in a glass of water is called out as an instrument condition, not handed a plant's mood β€” those aren't soil readings, and the seven moods are reserved for probes actually in a pot.

The live Sprout dashboard β€” per-device channel cards with raw ADC, calibrated band, and a calibration ladder

Where we're headed. This is the design direction β€” Sprout as a calm, first-person character, the mood system in motion across a day. It's a concept, not a screenshot, and not built yet β€” a great place for a UI/UX contributor to jump in (#867).

Brand concept β€” Sprout's calibrated mood system in motion across one day (design, not a screenshot)

Concept, not the app. The design system & mood system live in docs/design/.

The brand

Sprout isn't a readout β€” it's a character. The plant speaks for itself, in the first person, calm and plain-spoken. The full identity, voice rules, the living mark, and the seven-band mood system are in the brand guide:

The reading rules

A few principles behind how Sprout reads a plant:

  • Raw + band are the reading; a percentage is a labelled relative index, never VWC.
  • Mood & automation follow the calibrated band, never the index.
  • Every number is mono, right-aligned, tabular β€” data looks like data.
  • Gaps are surfaced, not smoothed β€” the dashboard shows what the capture actually contains.

Hardware

Part Qty Notes
Capacitive soil moisture sensor 4 Board HW-390, silk "Capacitive Soil Moisture Sensor V2.0.0". 3.3-5.5 V in, 0-3.0 V analog out, 3-pin PH2.0. QA passed - see SENSOR_QA.md.
Mini submersible DC water pump 4 DC 2.5-6 V (rated ~3 / 4.5 V), ~0.18 A, ~100 L/h, submersible. DC only - never mains.
4-channel relay module 1 5 V module. Active-high vs active-low and 3.3 V-drive compatibility to be bench-verified.
PVC vinyl tubing ~4 m ID ~5.54 mm / OD ~8.20 mm.
Microcontroller 1+ ESP32 (classic dual-core; SoC marked ESP-32D, ESP32-D0WD class) from the SunFounder ESP32 kit is the baseline. Firmware also builds for ESP32-S3 and ESP32-C5 boards β€” the supported boards, per-board serial paths, and pin maps live in docs/hardware/BOARDS.md. 3.3 V ADC matches the 0-3.0 V sensor output; 4 sensors on ADC1 (avoid ADC2 = WiFi); WiFi/BT for monitoring.
Status display 1 1.3" SH1106 128x64 I2C OLED (Hosyond 5-pack). On the I2C bus (GPIO21/22), powered at 3.3 V. Shows status / last-watered / errors.

(Kit provenance is recorded in the local parts inventory: UMLIFE watering kit. The SunFounder ESP32 kit also bundled a 5th capacitive sensor β€” an NE555-based v1.2 variant β€” which is not used for this project; see SENSOR_QA.md.)

Firmware (PlatformIO)

Firmware lives in firmware/ as a PlatformIO project (ESP32, Arduino framework). Open the firmware/ folder in VS Code with the PlatformIO IDE extension, or use the CLI from that folder:

  • Build: pio run
  • Upload: pio run -t upload
  • Monitor: pio device monitor (19200 baud, set in platformio.ini)

Build failing with Python version mismatch: penv has X.Y, current interpreter is X.Z. Recreating penv... then uv installation via pip failed with exit code 106? You likely have two PlatformIO installs β€” the IDE extension's bundled core and a standalone pio on your PATH β€” sharing ~/.platformio and rebuilding each other's penv with different Pythons. Native tests still pass (they skip the ESP32 platform), which hides it. The untangle is machine-specific; the fix is to let one install own the core.

Board env is esp32dev (classic ESP32); the esp32s3 and ESP32-C5 envs build from the same source for the other supported boards β€” see docs/hardware/BOARDS.md for per-board serial paths and pin maps. Pin assignments and tunables live in firmware/include/config.h. The build cache and resolved libraries (firmware/.pio/) are git-ignored.

For data capture, prefer the host-side logger (tools/logger/plants_logger.py) over the raw monitor: it stamps each row with UTC time and writes a rotating, self-describing CSV under logs/ per the shared telemetry schema (docs/TELEMETRY_SCHEMA.md). Requires pyserial.

Development & tooling

One command sets up, one command checks β€” the conventions help you instead of getting in your way.

uv sync                     # the exact, locked dev env (Python, ruff, pytest, pre-commit)
uv run pre-commit install   # auto-format + lint + hygiene on every commit
just check                  # your local gate: pre-commit + host/DX/analytics tests (uv + just only)
just check-firmware         # the above PLUS the native C tests β€” needs PlatformIO (firmware work only)
just doctor                 # is Sprout ready on THIS machine? reports, never repairs
just                        # list every command

pre-commit is the single definition of code quality β€” ruff lint + format, markdownlint, and whitespace/EOL hygiene β€” run identically on your machine and in CI, so style is something the repo handles for you, not a thing you have to remember. Per-language configs live at the repo root:

Area Tool Config
Python ruff β€” lint + format (all-in-one) ruff.toml
Markdown markdownlint-cli2 .markdownlint.json
C / C++ (firmware) clang-format + clang-tidy .clang-format Β· .clang-tidy
Endings / encoding git + EditorConfig .gitattributes Β· .editorconfig

Ruff is the modern all-in-one (it replaces flake8 / isort / pyupgrade / black), pinned in the locked env. The firmware C formatter (clang-format) runs in the gate on changed lines, pinned in the same locked env; clang-tidy static analysis stays advisory, not build-blocking.

Where to look

Area Path
Firmware (ESP32 / PlatformIO) firmware/
Host logger & analytics tools/
Design system & brand docs/design/
Decisions of record (ADRs) docs/adr/
Wiring Β· telemetry Β· calibration docs/
What shipped, when Releases Β· CHANGELOG.md

Status

Monitoring is live. Since the wave-1 go-live (2026-07-04), the greenhouse reports in soil over Wi-Fi β€” currently 11 plants, 8 sensors, 2 boards, and subject to change β€” each session saved to the catalog. Watering is deliberately gated: the firmware ships a manual operator-commanded bounded pump pulse (!water / !stop), and the safety order is make watering correct before it's possible β€” per-probe calibration (#170) and fail-safe actuator-off (#93) are done; the remaining gate is bench-verifying the relay path on real hardware (#191), which autonomous watering (#94) waits on. Current standing lives in docs/STATUS.md.

Contributing

Work is proposed, tracked, and merged through GitHub β€” Issues are the ledger, the project board is the working view, and Discussions are the idea inbox. The full loop (branch β†’ PR with Refs #N β†’ the review-before-close verification gate) lives in CONTRIBUTING.md.

Looking for somewhere to jump in? Contributors Welcome is our running list of things we'd love a hand with β€” resistive-sensor support, board configs beyond ESP32 + Arduino, and a host-the-stack tier.

License

Sprout is MIT-licensed β€” a deliberate choice, not a default. MIT is a permissive license: you can do almost anything with the code, and you're never required to open-source your own changes β€” the thing that sets it apart from "copyleft" licenses like the GPL (GNU General Public License), which do require it when you share the software. About as few strings as open source has: do almost anything, just keep the notice.

As a user β€” use it, fork it, learn from it, build on it: for a windowsill, a classroom, or a product you sell. Commercial use is fine. No permission to ask, no fee, no catch. The one obligation is to keep the copyright line and license text with the code.

As a contributor β€” you keep the copyright on what you write. No CLA (Contributor License Agreement β€” the legal form some projects make you sign before they'll accept your code), no copyright assignment, no paperwork. Opening a PR just means your contribution ships under the same MIT terms β€” which is what keeps Sprout free for the next person. It's also why the copyright reads "Veronica K. Hogue and Sprout contributors": the moment you contribute, that "and contributors" is you.

No warranty β€” it's provided as-is. (We read the soil as best we can; we don't promise your monstera survives your vacation.)

We picked the friendliest license we could so the distance between "I found this repo" and "I'm using and improving it" is as close to zero as open source allows. Take it and grow something. 🌱


Built in the open by Veronica Hogue (@OrangePeachPink) Β· source under MIT.

Sprout Β· plants with a pulse Β· tend well.

About

Sprout β€” plants with a pulse 🌱 Local-first, open-source (MIT) plant care on ESP32: each plant tells you how it's doing, in its own words. Monitor (now) Β· predict (in progress) Β· water (next).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

6 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages