Hi everyone,
Zroshua is a native Home Assistant add-on for irrigation — a full web UI in the sidebar, zones built on top of your existing switch / valve entities, watering groups with controlled concurrency, a scheduler that understands your hydraulics, weather and sensor logic, statistics and a Lovelace card.

Why I built it
I run 32 irrigation zones at home — Zigbee relays driving solenoids, two water sources (a well pump and a rain barrel), drip lines, sprinklers, lawn and beds.
Everything I needed already existed as separate pieces: a scheduling integration, an ET calculator, Node-RED flows for rain skips and Telegram, a pile of template sensors and a hand-built dashboard on top. It worked. But living with it every day, six things kept hurting:
1. Every change was a YAML change. Moving one start time by 15 minutes because the week turned hot, giving one bed two extra minutes, disabling a zone while I fix a leaking fitting — all of it meant opening an editor and reloading. At 32 zones the config was long enough that I was afraid to touch it in July.
2. There was no “just skip tonight”. Not disable — skip. One bed, one run, and then go back to normal by itself. I ended up building helper booleans and automations to un-set them, which is exactly the kind of thing that silently breaks in August.
3. The real constraint is hydraulics, not time. Two pumps on one power line that must never run together. A barrel that is refilled by the well, so those two can’t overlap either. A flow budget you can’t exceed or the pressure collapses. Expressing “these groups are mutually exclusive” pairwise, in YAML, for every combination, is a combinatorial mess — and it silently rots every time you add a zone.
4. Everything ended up running one zone at a time, because that was the only obviously safe option. 32 zones at 10–20 minutes each is more hours than a night has. In reality a good half of my zones can run together — two drip lines barely register on the flow meter, and the beds fed from the barrel don’t care what the well is doing. But whether two zones may overlap depends on which source they draw from, how much water each of them takes, and what else happens to be running at that second. No static config expresses that, so I did what everyone does: serialised the lot and watched the last bed get watered at four in the morning. Bumping one zone’s duration then pushed every zone behind it, and the whole schedule quietly drifted into the day. I wanted concurrency to be computed — run as many zones in parallel as the flow budget and the source rules actually allow, order them, and queue the rest with a visible reason rather than a guess.
5. I wanted the sensors to change the plan, not just block it. Soil moisture that trims a run to 60 % instead of skipping it entirely. A short cooling burst on the lawn when a real temperature sensor passes 30 °C between 13:00 and 16:00. A bed that gets watered early if its own sensor dries out before the next scheduled run. Forecast-driven duration scaling. And, crucially: a run stretched by +20 % on a hot day must still be guaranteed not to collide with the next group.
6. I wanted decisions to be explainable. When the garden was dry in the morning, I wanted to open a page and read “skipped: rain sensor dry-out until 09:17” — not diff log files and guess.
So I stopped gluing pieces together and wrote a scheduler.
What’s different
It’s an add-on, not an integration. That was a deliberate choice:
- A sidebar panel via ingress — a mobile-first SPA. No custom cards required, no YAML, changes apply instantly.
- Its own process under the Supervisor watchdog. The scheduler doesn’t share the HA event loop, and it survives HA restarts — active runs are persisted and resumed; on startup any zone found “on” without a matching run is reconciled off.
- Its own database (SQLite by default, MariaDB/Postgres optional) for run history, skip reasons and consumption stats.
- It still controls any hardware, because it drives your HA entities: ESPHome, Zigbee, Shelly — anything that is a
switchor avalve.
Hydraulics is a first-class concept. A water source has a max flow budget (l/min — the scheduler never lets concurrent zones exceed it), a pump entity kept on while any of its zones run (reference-counted, with start/stop delays and a configurable “what to do after the last zone” policy), a dependency on another source, an optional flow sensor with idle-flow leak detection and a flow-deviation alert, an energy meter, and capacity tracking for barrels with a live level estimate published back to HA. Mark two sources as never at the same time and every pair of groups drawing from them becomes mutually exclusive automatically — the scheduler, the timeline and the time-slot picker all respect it, with no per-pair rules to write.
Planning is predictive, not just a list. Temperature scaling can stretch a run, so the timeline reserves the worst case: each run is drawn with its planned length plus a hatched worst-case tail, and gaps after the tail are guaranteed free. Upcoming runs carry a red will skip badge with the reason when they’d be skipped under the current state, and a yellow may skip when it depends on data only known at start time. Every start time is either start at or finish by — pick the latter and the start is computed backwards from the worst-case length, so “lawn done before the 07:00 school run” stays true even on +20 % days.
Everything is journaled. Started, finished, every skip with its reason, temperature adjustments, faults, reconciliations.
And some things I just wanted for myself: a site map — draw your property as an SVG in Figma/Inkscape, upload it, tap shapes to assign them to zones (a zone can be several shapes); fill colour is the watering type, brightness/animation is the live state, with remaining minutes drawn on the zone. Plus water/energy/cost statistics with CSV export, Telegram and notify.* notifications with per-target event filters, group-level notification mode (13 beds = 2 messages, not 26), a daily digest and quiet hours.
Lovelace card
For controlling irrigation from a normal dashboard, the add-on ships a card with five views (dashboard, groups, zones, upcoming, timeline). With the Mosquitto add-on present it’s zero setup — the add-on copies the JS into /config/www and registers the resource itself:
yaml
type: custom:zroshua-card
view: dashboard
The card reads a single sensor.zroshua_state published over MQTT and sends actions back via mqtt.publish, so there’s no per-entity wiring. MQTT discovery also publishes a proper “Zroshua” device: per-zone switches, next-watering timestamps, daily water/energy sensors (including per source), barrel level sensors, and a pause-all switch — with device_class/state_class set, so long-term statistics and the Energy dashboard work out of the box.
Status
It runs my own 32-zone system every day, but it’s young and I’m the only person who has stress-tested it. I’d really like testers and feedback — especially from people with unusual hydraulics (multiple pumps, cisterns, gravity feeds, shared house/irrigation supply), because that’s where my assumptions are most likely to be wrong.
Roadmap: ET/bucket-based suggested durations, volume-based watering (litres instead of minutes), Telegram inline actions, and more localisations.
Repo and full documentation: GitHub - RobinCK/zroshua: Native Home Assistant add-on for smart irrigation: zones, groups, a conflict-aware scheduler, weather & sensors, statistics, a live site map and Lovelace card · GitHub
