Hunter Hydrawise
Driver: hydrawise
Cloud integration with Hunter Hydrawise irrigation controllers via the Hydrawise v2 GraphQL API. The driver signs in with the account email and password (OAuth2 password grant), auto-creates a GEM zone for each controller zone on startup, polls per-zone watering state and water usage, tracks the controller's rain/flow sensors as device attributes for automation triggers, and supports run, stop, suspend, and resume actions per zone or controller-wide.
Unlike the legacy v1 REST integration, this driver does not use an API key. It works for accounts that cannot generate one — including trial and simulated controllers. The bearer token from sign-in expires after about an hour and is refreshed automatically.
Prerequisites
- A Hydrawise account email and password.
- At least one controller on the account — physical or simulated/trial; both are visible over the GraphQL API.
Setup
- In GEM, System → Devices → Add Device with driver
hydrawise. - Enter the Hydrawise account
emailandpassword(the password is stored encrypted). - If the account has more than one controller, set
controller_id(runget_controllersto list them). With a single controller this is auto-detected. - Save. The driver logs in, resolves controllers, auto-creates a GEM zone for each controller zone, and begins polling. GEM ships with a dedicated
irrigationsubsystem, so this works out of the box — no subsystem setup is required. Each new zone is created under the first existing subsystem namedirrigation,water, orsprinkler(normallyirrigation; older sites provisioned before the irrigation subsystem existed fall back towater), is given the on/off water control, takes its label from the controller's zone name, and has itsaddressset to the Hydrawise zone id. Setauto_sync_zonestofalseto disable auto-creation and manage zones by hand. - To add or repair zones manually, run
get_zonesto list the zoneidvalues (or runsync_zonesto re-ensure them).zone.addressis always the Hydrawise zone id, not the physical valve number.
Attributes
Device
| Attribute | Required | Default | Description |
|---|---|---|---|
email | yes | — | Email used to sign in to the Hydrawise app. |
password | yes | — | Password used to sign in (stored encrypted). |
controller_id | no | — | Required when the account has more than one controller (from get_controllers). Auto-detected for single-controller accounts. |
default_run_seconds | no | 300 | Default run duration when seconds is not supplied to a run command. |
min_poll_interval | no | 60 | Idle polling cadence (seconds) against the GraphQL API, used while no zone is watering. The web client is event-driven and the legacy API floored at ~60s — keep this at 60s or higher to avoid throttling. |
active_poll_interval | no | 30 | Active polling cadence (seconds), used only while a zone is actively watering so time_remaining counts down responsively. Reverts to the idle interval once all zones stop. |
auto_sync_zones | no | true | Ensure a GEM zone exists for each controller zone on connect. Set false to manage zones manually. |
water_usage_interval | no | 600 | How often (seconds) week-to-date per-zone water usage is refreshed (kept off the fast poll). |
Sensor readings tracked at the controller (device) level for use as automation trigger sources:
| Attribute | Description |
|---|---|
rain_sensor_active | true when the controller's rain sensor is holding watering. |
flow_rate | Live flow-meter reading in litres/min; 0 when no flow sensor is present. |
The controller's flow_rate and the per-zone water_usage_week are tagged with the water.flowrate / water.usage metric roles, so a Hydrawise controller appears automatically in the generic Water Flow widget — a live supply → zones diagram. See Power Management → The Water Flow widget.
Zone
zone.address is the Hydrawise zone id from get_zones. Driver-managed state attributes:
| Attribute | Description |
|---|---|
state | on while scheduledRuns.currentRun is present, off otherwise. |
time_remaining | Seconds left in the current run (currentRun.remainingTime); 0 when idle. |
next_run | Seconds until the next programmed run (from nextRun.startTime); meaningful when idle. |
next_run_str | Human-readable schedule summary (mirrors the API's scheduledRuns.summary). |
suspended_until | Epoch seconds the zone is suspended until, or 0 if not suspended. |
water_usage | Water delivered in the current run, in litres; 0 when idle. |
water_usage_week | Week-to-date water usage for the zone, in litres (refreshed on a throttle and via get_water_usage). |
Water volumes are stored in canonical litres regardless of the account's display units (the API reports gallons or litres per locale; the driver converts).
You can also set one configurable attribute on a zone (in the zone's Attributes editor):
| Attribute | Default | Description |
|---|---|---|
default_run_seconds | falls back to the device's default_run_seconds (300) | Per-valve run duration used when a run / on command is sent to this zone without an explicit seconds argument. Overrides the device-level default for this zone only. |
Commands
| Command | Args | Effect |
|---|---|---|
on / run | address, optional seconds | Start a manual run on the zone. |
off / stop | address | Stop the zone. |
suspend | address, hours | Suspend the zone for the given number of hours. |
resume | address | Resume a suspended zone (native resumeZone). |
runall | optional seconds | Start all zones on the controller. |
stopall | — | Stop all zones on the controller. |
suspendall | hours | Suspend all zones for the given number of hours. |
resumeall | — | Resume all zones on the controller (native resumeAllZones). |
get_controllers | — | List controllers visible to the account (id, name, online, serial). |
get_zones | — | List zones with their id, number, name, and controller. |
sync_zones | — | Ensure a GEM zone exists for each controller zone (idempotent; runs automatically on connect unless auto_sync_zones is false). |
get_water_usage | optional address | Refresh and return per-zone current-run and week-to-date water usage (litres). |
The controller-wide commands (runall, stopall, suspendall, resumeall) require a resolved controller — set controller_id on multi-controller accounts.
on / run, off / stop, and stopall update the affected zone's state and time_remaining optimistically the moment the controller accepts the action, so the UI reflects the change immediately rather than waiting up to a poll interval. The next poll reconciles against the controller's real state.
Known limitations
- Token lifetime. The OAuth bearer token expires after ~1 hour and is refreshed automatically, falling back to a fresh login if the refresh token is rejected.
- Suspend date format.
suspend/suspendallsend the suspension end time in the GraphQLuntilargument as an RFC-822 string with a two-digit year and a numeric UTC offset (e.g.Thu, 04 Jun 26 16:41:04 +0000). ISO-8601, epoch, and four-digit-year forms are rejected withInvalid date format. Verified live against a real controller. - Sensor classification. Rain vs flow sensors are distinguished by response shape (a flow meter reports
status.waterFlow; a rain sensor reportsstatus.active). The controller used for verification had no sensors attached, so this mapping is correct-by-construction rather than confirmed against live sensor hardware.
Troubleshooting
| Symptom | Check |
|---|---|
Driver never connects / missing email or password | Verify the email and password device attributes are set and correct. |
All-zone commands return controller_id required | The account has multiple controllers — set controller_id (run get_controllers to list them). |
| Zone commands do nothing | zone.address must be the Hydrawise zone id from get_zones, not the physical valve number. |
| Zones aren't auto-created on connect | An irrigation subsystem ships by default, so this normally just works. If it was deleted, recreate an irrigation, water, or sprinkler subsystem; also confirm auto_sync_zones is not false, then run sync_zones. |
| Login fails after working previously | The account password may have changed, or the account may be locked. Re-enter the password. |