You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I’m running a residential lawn irrigation system on Home Assistant with Irrigation Unlimited driving 6 zones split across 2 hose bibs (3 zones each). Each bib can only run one zone at a time (flow/pressure limit), but both bibs can run concurrently — so I use two sequences that run in parallel, which IU handles well.
My soil is heavy clay. Clay absorbs water slowly, so applying a zone’s full runtime in one shot causes runoff and pooling long before the water reaches the root zone. The standard fix is cycle-and-soak: split each zone’s runtime into shorter cycles with a soak period between them so the water can infiltrate. For clay, that soak needs to be a meaningful, guaranteed minimum (commonly ~60 minutes).
Why the current options don’t fully solve it
IU can approximate cycle-and-soak today with repeat + delay, but there are real gaps for this use case:
delay sits between every zone, not between a zone’s own cycles. To guarantee a per-zone soak I have to set a large delay, which inserts that delay after every zone and creates hours of idle dead time. There’s no concept of a per-zone minimum soak that gets intelligently filled by running the other zones in the meantime — the way commercial controllers (RainMachine, Rain Bird) do it.
No minimum-soak guarantee. If I rely on other zones to fill the soak, the soak is just however long those zones happen to take. With only 3 zones per bib, that falls well short of the ~60 minutes clay needs, and there’s no way to enforce a floor.
No even distribution / minimum cycle length. Splitting purely by a max cycle length leaves a tiny trailing cycle (e.g. 15 + 15 + 5 min). I’d want the total distributed evenly across cycles, with a configurable minimum cycle length so no cycle runs for an impractically short time.
No “skip when budget met.” Zones with small needs get cycled the same number of times as zones with large needs, wasting passes and extending the run window.
Desired outcome
A native cycle-and-soak mode (per sequence or per zone) that:
Splits each zone’s total runtime into evenly distributed cycles, capped at a configurable max cycle length (the runoff threshold) and floored at a configurable min cycle length
Enforces a configurable minimum soak between a zone’s own cycles, filling that soak by interleaving the other zones and inserting idle time only when needed to reach the minimum
Lets zones with smaller totals finish early and drop out of later cycles
Re-derives the per-cycle split from a total set via adjust_time, so Smart Irrigation (and similar) integrations work without the caller having to pre-divide by a repeat count
This would make IU a clean fit for clay-soil lawns and, importantly, resolve the long-standing friction between repeat and adjust_time / Smart Irrigation that several users have hit (#203, #211).
Proposed approach
A new opt-in cycle-and-soak block, configurable at the sequence (and optionally zone) level. Sketch of the config:
sequences:
- name: "Bib 1 - Front/Side"cycle:
max_duration: "00:15"# runoff threshold; cap per cyclemin_duration: "00:10"# floor; never run a cycle shorter than thismin_soak: "01:00"# guaranteed soak between a zone's own cycleszones:
- zone_id: 1duration: "00:45"# total; cycle logic derives the per-cycle split...
Behavior:
For each zone, derive the cycle count from its total duration: num_cycles = ceil(total / max_duration)
Distribute the total evenly across those cycles: per_cycle = total / num_cycles. This avoids a tiny trailing cycle (e.g. 45 min → 3 × 15, never 15 + 15 + 15 + 0, and 35 min → 3 × ~11.7, never 15 + 15 + 5).
Apply the minimum cycle floor: cap num_cycles at floor(total / min_duration) so per_cycle never drops below min_duration. If a zone’s total is itself below min_duration (e.g. a rained-on day), run it once for whatever it needs.
Between a zone’s own cycles, guarantee min_soak. Fill that soak by interleaving the other zones in the sequence; insert idle delay only for the remainder needed to reach min_soak.
Zones with fewer cycles complete early and drop out of later passes, rather than being padded to match the longest zone.
Key integration point: when a zone’s total is set via adjust_time, the cycle logic re-derives the per-cycle split from that new total. This is what makes the feature compose cleanly with Smart Irrigation (which pushes a daily total per zone) without the caller having to divide by a repeat count — and is the part that today’s repeat breaks.
This mirrors how commercial controllers (RainMachine, Rain Bird) implement cycle-and-soak: even distribution, a minimum cycle length, a minimum soak floor, and other zones filling the soak window.
Notes from testing (current behavior, v2025.10.0)
For reference, behavior I confirmed empirically while exploring workarounds:
repeat multiplies the adjust_timeactual value (push 9 min with repeat: 3 → zone runs 27 min total).
delay is applied between every zone in a sequence, not between a single zone’s cycles.
In adjust_time, the zones parameter targets the position within the sequence (1-based), not the global zone id.
Problem / Use Case
I’m running a residential lawn irrigation system on Home Assistant with Irrigation Unlimited driving 6 zones split across 2 hose bibs (3 zones each). Each bib can only run one zone at a time (flow/pressure limit), but both bibs can run concurrently — so I use two sequences that run in parallel, which IU handles well.
My soil is heavy clay. Clay absorbs water slowly, so applying a zone’s full runtime in one shot causes runoff and pooling long before the water reaches the root zone. The standard fix is cycle-and-soak: split each zone’s runtime into shorter cycles with a soak period between them so the water can infiltrate. For clay, that soak needs to be a meaningful, guaranteed minimum (commonly ~60 minutes).
Why the current options don’t fully solve it
IU can approximate cycle-and-soak today with
repeat+delay, but there are real gaps for this use case:delaysits between every zone, not between a zone’s own cycles. To guarantee a per-zone soak I have to set a largedelay, which inserts that delay after every zone and creates hours of idle dead time. There’s no concept of a per-zone minimum soak that gets intelligently filled by running the other zones in the meantime — the way commercial controllers (RainMachine, Rain Bird) do it.repeatmultiplies theadjust_timevalue. I drive durations from Smart Irrigation viaadjust_time, which pushes a total runtime per zone. Withrepeat: N, that total is multiplied by N, so the zone runs N× too long (or hits the max-duration cap). This makes the Smart Irrigation integration and cycle-and-soak mutually difficult — see related issues Smart Irrigation integration with Irrigation Unlimited not fully functional #203 and Despite different configuration the watering time is limited to one hour ("magically") #211.Desired outcome
A native cycle-and-soak mode (per sequence or per zone) that:
adjust_time, so Smart Irrigation (and similar) integrations work without the caller having to pre-divide by a repeat countThis would make IU a clean fit for clay-soil lawns and, importantly, resolve the long-standing friction between
repeatandadjust_time/ Smart Irrigation that several users have hit (#203, #211).Proposed approach
A new opt-in cycle-and-soak block, configurable at the sequence (and optionally zone) level. Sketch of the config:
Behavior:
num_cycles = ceil(total / max_duration)per_cycle = total / num_cycles. This avoids a tiny trailing cycle (e.g. 45 min → 3 × 15, never 15 + 15 + 15 + 0, and 35 min → 3 × ~11.7, never 15 + 15 + 5).num_cyclesatfloor(total / min_duration)soper_cyclenever drops belowmin_duration. If a zone’s total is itself belowmin_duration(e.g. a rained-on day), run it once for whatever it needs.min_soak. Fill that soak by interleaving the other zones in the sequence; insert idle delay only for the remainder needed to reachmin_soak.Key integration point: when a zone’s total is set via
adjust_time, the cycle logic re-derives the per-cycle split from that new total. This is what makes the feature compose cleanly with Smart Irrigation (which pushes a daily total per zone) without the caller having to divide by a repeat count — and is the part that today’srepeatbreaks.This mirrors how commercial controllers (RainMachine, Rain Bird) implement cycle-and-soak: even distribution, a minimum cycle length, a minimum soak floor, and other zones filling the soak window.
Notes from testing (current behavior, v2025.10.0)
For reference, behavior I confirmed empirically while exploring workarounds:
repeatmultiplies theadjust_timeactualvalue (push 9 min withrepeat: 3→ zone runs 27 min total).delayis applied between every zone in a sequence, not between a single zone’s cycles.adjust_time, thezonesparameter targets the position within the sequence (1-based), not the global zone id.