This is the first stable release since v2026.07.11, and it lands everything from four beta builds at once. Most of it changes watering behaviour on purpose, and most of it was found on an imperial install that neither maintainer runs. If you use metric and a zero elevation, very little here reaches you; if you use US customary, please read the unit-system paragraphs before installing.
Accuracy release: several fixes that change the numbers, and two opt-in ways to feed the calculation far better data. Almost all of this came from @clarejor, who reported and fixed most of it against a real imperial install.
An interrupted distributor cycle could leave your pump running against a closed valve. A distributor cycle claims the shared master (pump) for as long as it actually needs it, and the pump switches off once the last claim is released. If a cycle hit an unexpected error part-way through a sweep — a failed service call, a storage write that did not complete — it closed the inlet valve defensively but never released its claim, so the configured "switch master off after" never fired. The pump then ran against a closed inlet until the next cycle for that same distributor came round, which on a daily schedule is roughly a day. Found and fixed by @Eifel-Joe. A follow-up on top of it: on that same error path, a distributor configured not to use the master could switch off a master it had never turned on. This only affects installs using the experimental water distributor together with a master switch.
Changing Home Assistant's unit system no longer corrupts your zones. Zone depths, size and throughput are stored in whichever units you see in the UI, but nothing recorded which unit system wrote them — so switching Home Assistant between metric and US customary silently changed what every one of those numbers meant, by a factor of 25.4 for depths and 10.76 and 3.79 for area and flow. There was no error and no log line, and the panel kept showing the same digits. The worst case was the irrigation trigger: a threshold of -10 mm became -10 inches, a deficit no zone ever reaches, so deficit-gated watering simply stopped. This release records the unit system alongside your data and converts all seven affected values whenever it changes — including a change made in configuration.yaml, which previously went completely unnoticed. Your existing values keep their meaning; the digits will change if you have ever switched systems.
Changing the unit system in the UI now does anything at all. Separately from the above, the handler that reacts to a live unit-system change crashed on its own log line before it did any work, so switching units in the Home Assistant UI produced no conversion and not even a display refresh — units stayed wrong until the next restart. Fixed, and the handler is now covered by tests that assert on the resulting conversion rather than on being called.
And the converted values now actually reach your sensors. Reported by @clarejor while verifying a beta build on their imperial install. The conversion above wrote the correct numbers to storage, but the zone sensors never re-read them: the bucket sensor and the zone duration sensor's attributes kept showing the pre-conversion digits under the new unit label — a factor of 25.4 out, and indistinguishable from a real reading rather than looking like a display glitch. Because sensor.<zone>_bucket is recorded in long-term statistics, that wrong number was also being written into your history for as long as it lasted. Watering itself was never affected, since the runner reads storage rather than the entities. Each converted zone now announces itself so every entity picks the new value up immediately.
Atmospheric pressure is now calculated correctly, so evapotranspiration changes. The conversion from sea-level to station pressure was dimensionally wrong and did almost nothing: at 311 m it moved 1020 hPa by 0.00002 hPa, where the real correction is about 37. Station pressure feeds the psychrometric constant in the FAO-56 equation, so every affected install has been calculating ET from a pressure that was too high. This affects sensor groups configured with relative pressure and all four weather services. If your elevation is set to 0 nothing changes for you; otherwise expect your ET numbers — and therefore your watering durations — to shift slightly.
A zone could stop calculating forever after a one-in-a-million write. Stored timestamps were written with isoformat() but read back with a pattern that required a fractional-seconds part, which isoformat() omits when the microseconds happen to be exactly zero. If that landed on a zone's consumption watermark, the value could never be read — and because the watermark is read at the start of a calculation and only replaced at the end, that zone never calculated again. It failed quietly: the other zones carried on and one line went to the log.
The zone bucket sensor was labelled mm on imperial installs while reporting inches. sensor.<zone>_bucket published the stored value, which is in your display units, under a hardcoded mm — so a bucket of -0.81 in read as -0.81 mm, a factor of 25.4 out. The sibling zone sensors and the panel were always correct; this one entity was the outlier. Metric installs are unaffected. If you are on US customary, Home Assistant will raise a one-time statistics prompt for this entity because its unit changed — the recorded history was inches mislabelled as millimetres, so there is no correct history to preserve.
A wildly implausible solar radiation reading is now capped. This one is not opt-in, so it is worth reading even if you change nothing else. If your Solar Radiation comes from a sensor reporting an instantaneous rate — W/m² or W/sq ft — each reading is now checked against the most a cloudless sky could physically deliver at that moment, and capped at 1.3 times it if it exceeds that. Broken-cloud edge enhancement really can push a pyranometer above clear sky briefly, hence the headroom; nothing physical stays there. The case this exists for is a sensor that sticks: one stuck at a constant 722 W/m² for nineteen hours, including the whole night, produces an impossible amount of evapotranspiration and quietly under-waters every zone in that sensor group. A cap that fires is logged as a warning and re-logged hourly for as long as it keeps firing, because a sensor that needs capping is a sensor worth looking at. Static values, weather-service radiation, and sensors reporting a daily total in MJ/day are all left exactly as they were.
New, off by default: hourly evapotranspiration. By default the FAO-56 equation is run once per calculation, over the window's average weather, and cloud cover biases that systematically — fed one identical hourly series across 362 days it returns 1.14 times the reference on overcast days and 0.93 times on clear ones. With this on (Setup → Experimental) the equation is run for each hour and the hours are summed, which removes that bias, and the water balance is replayed hour by hour so rain and drainage are booked when they actually happened rather than all at the start of the window. That second half matters more than it sounds: booking a day's rain at the window start overflows your maximum bucket and discards water that never overflowed in reality, measured at 186 mm a year on one install. Expect the daily figure to move by up to 12 percent, in either direction depending on the sky. It needs a Solar Radiation source that is measured rather than estimated, and it steps aside on any day where a forecast is blended in or the window cannot be reduced to hourly rows — so no series is ever invented. This is its own switch and is not tied to continuous updates below: a normal hourly-polled install can turn it on and benefit.
New, off by default: continuous updates. Weather sensors are normally read once per update tick, so daily minimum and maximum temperature come from around 24 spot samples rather than the day's real extremes, and every time-weighted average is only as fine as the poll interval. With continuous updates enabled (Setup → Experimental) the integration subscribes to your mapped sensors and records a reading whenever one changes, with a per-field deadband and a per-group debounce so the extra fidelity does not turn into constant storage writes. Existing installs are untouched unless you turn it on — including how averages are calculated, which stays exactly as it was for anyone still polling.
New, off by default: log the runs that did not happen. Contributed by @Eifel-Joe. A scheduled run that skips a zone because it simply has no water demand currently leaves no trace, so a zone that has quietly stopped watering looks the same in its history as a zone that was never scheduled. Turn on run history logging (General → Run history logging) and each such skip is recorded in the zone's run history, at most one per zone per day, and suppressed while a rain delay is active so it cannot double up with the existing paused entries. Run history is capped at 50 entries, and no-demand entries can never crowd your real runs out of it — they take at most one of those slots. Existing installs are untouched unless you turn it on.
Also fixed: with continuous updates enabled, "Clear all weather data" could leave a zone unable to record new readings for a while, because the filter that suppresses tiny sensor movements kept comparing against a value from before the reset. The continuous-updates settings card is also now translated into all eight bundled languages instead of falling back to English.
Also in this release: a maintenance pass on long-standing internal issues. None of these was reported by a user, and most were latent rather than actively breaking — but several would have been very hard to diagnose from the outside, so they are worth naming.
- An unreadable translation file could stop a zone calculating. If a language file could not be opened or was truncated — an interrupted update, for instance — the helper that looks up translated text returned nothing at all instead of falling back, and the calculation that was building an explanation string failed outright for that zone. It now falls back to the untranslated key, which is visibly ugly and entirely harmless.
- Uninstalling left a dead dashboard resource behind. The card registers itself with Lovelace, and nothing removed that registration on uninstall, so every dashboard load afterwards kept requesting a file that no longer existed. Removing the integration now cleans up after itself. A resource you added by hand is never touched.
- The card's "config error" problem is less likely to come back. The check that decides whether the card can be registered properly — rather than through a fallback that races the dashboard render — depended on an internal Home Assistant class name. If Home Assistant ever renamed it, the check would have quietly failed into the racy path, producing exactly the intermittent "custom element doesn't exist" error some of you have seen, with nothing in the logs to explain it. It now tests for the capability instead of the name.
- Reloading the integration no longer accumulates dead internal routes, and the recurring-schedule event's timestamp is now consistently in local time rather than local or UTC depending on which kind of schedule fired it.
- Non-admin users can no longer read your weather-service API keys or your latitude and longitude over the websocket API. The zones card is unchanged for everyone, including its ability to start a run — that is what the card is for.
- Two more translation gaps closed (the "reset water usage" button was English-only in six languages), a batch of dead leftover translation keys removed, and the whole set is now checked automatically so these gaps cannot come back unnoticed.
Your storage is migrated automatically on first start (version 13). No configuration changes are needed.