RainMachine (Local API)
GEM driver for RainMachine smart irrigation controllers via the local HTTPS REST API. Covers the Touch HD 12/16, Mini-8, and Pro-8/16 running firmware 4.x. All control is on-LAN — no RainMachine cloud account is required.
Feature coverage:
- Per-zone manual start (with duration) and stop
- Zone status polling — reflects running / queued / pending / off onto the GEM zone
stateattribute, plusremaining_secondswhen the controller reports it - Stop-all (halts every running zone and any running program at once)
- Program start / stop by id
- Raw GET / POST escape hatches for anything the controller exposes that isn't first-classed here (rain delay, weather adjustments, snapshots, etc.)
Prerequisites
- Firmware. Local API v4 is required. Older Touch / Mini firmware in the 3.x range (or the original RainMachine cloud SDK) is not supported. Update from the RainMachine web UI: Settings → Firmware Updates.
- LAN reachability. Reserve or note the controller's LAN IP. The Local API listens on all interfaces once network is joined; it accepts connections from any host on the same LAN.
- Controller password. From the RainMachine web UI open Settings → Remote Access → Set Password. This is the same password the RainMachine mobile app uses in Local mode (not the cloud login). If you can't remember it, resetting from this screen does not affect programs or history.
Test reachability by opening https://<controller-ip>:8080/api/4/apiVer in a browser (accept the self-signed certificate warning). You should see a JSON payload with apiVer, hwVer, and swVer fields.
Setup steps
- Confirm the API is up. Load
https://<controller-ip>:8080/api/4/apiVerin a browser and confirm you get a JSON response. - Add the device in GEM. In Devices, create a new device with driver
rain_machine. Fill in:ip— controller LAN IPpassword— the Local Access password from the controller's Settings → Remote Access screen (stored encrypted)- Leave
porton the default8080unless you're on an older Touch HD firmware that exposed 8081.
- Enumerate zones. Open the device's Script Console tab and run:
The response is an object with aawait gem.command({device: <device_id>, action: 'get_zones'})
zonesarray. Note the integeruidof each zone (1-based; equal to the terminal number on the controller face). - Create GEM zones. For each RainMachine zone you want to control from GEM, create a zone under an irrigation subsystem. Set
zone.addressto the RainMachine zoneuid(e.g.,1,2,3…). - Verify. From the Script Console, run a short manual start:
Confirm the zone starts on the controller face and that the GEM zoneawait gem.command({device: <device_id>, zone: <zone_id>, action: 'on', level: 60})
stateattribute flips toonwithin a poll cycle (default 20s).
Attributes
Device — required
| Name | Type | Description |
|---|---|---|
ip | string | LAN IP or hostname of the RainMachine controller. |
password | string (secure) | The password set from Settings → Remote Access on the RainMachine web UI. Same value the mobile app uses in Local mode. |
Device — optional
| Name | Type | Default | Description |
|---|---|---|---|
port | int | 8080 | Local API port. Firmware 4.x defaults to 8080; some older Touch HD firmware exposed 8081. |
default_duration | int (seconds) | 600 | Duration used by the on command when no duration_seconds argument is supplied. RainMachine has no truly indefinite manual-on mode. |
status_interval | int (ms) | 20000 | How often to refresh zone state from the controller. Minimum 5s. |
request_timeout | int (ms) | 10000 | HTTP request timeout per call. |
Zone — address
| Field | Description |
|---|---|
address | RainMachine zone id — a 1-based integer matching the Zones page in the controller's web UI (1..16 depending on model). Discover via get_zones. |
Commands
| Name | Args | Description |
|---|---|---|
on | address, duration_seconds | Start a manual run on the specified zone for duration_seconds (falls back to the device default_duration attribute, capped at 43200s / 12h). |
off | address | Stop the specified zone if running. |
stop_all | — | Stop all running zones and any running programs on the controller. |
run_program | program_id | Start a program by id. Enumerate via get_programs. |
stop_program | program_id | Stop a specific program. |
get_zones | — | List every zone on the controller with id, name, active flag, and current state. |
get_zone | address | Full detail for one zone. |
get_programs | — | List every configured program. |
get_status | — | Return the controller's /provision payload (system info + running list). |
refresh_token | — | Force a fresh login. Rarely needed — the driver re-authenticates automatically on token expiry or 401. |
raw_get | path | Advanced: GET any /api/4/<path> resource on the controller. |
raw_post | path, body | Advanced: POST to any /api/4/<path> resource. body is a JSON string. |
Auth model
The Local API is bearer-token based:
POST /api/4/auth/loginwith{"pwd": "<password>", "remember": 1}.- Response returns
{access_token, expiration, statusCode}. - Subsequent calls pass
?access_token=<token>as a query parameter.
The driver caches the token in memory and refreshes automatically when it expires (default 24h) or when the controller returns a 401. There is no long-lived refresh token — the same password is used on each renewal, so a password change on the controller invalidates the driver until the new password is saved on the device row.
Known limitations
- No indefinite manual on. The
onverb always carries a duration in seconds. If you don't passduration_seconds, the driver falls back todefault_duration(600s / 10 min by default). Durations larger than 12 hours are clamped by the controller. - HTTPS only. The Local API refuses plaintext HTTP even on-LAN. The driver disables certificate verification because the controller uses a self-signed cert.
- No first-class rain-delay commands. Rain delay, weather adjustments, and program schedule edits are all reachable via
raw_get/raw_postbut not exposed as verbs here. See the RainMachine Public API v4 documentation for the endpoint list. - No cloud fallback. Everything is on-LAN. If the controller is unreachable (Wi-Fi drop, LAN outage), commands fail — there is no cloud proxy path.
Troubleshooting
| Symptom | Check |
|---|---|
Connect logs auth failed (statusCode=…) | Verify the password by logging into the RainMachine mobile app in Local mode. Reset from Settings → Remote Access on the controller if lost. |
| Timeout on every request | Confirm the controller is reachable at https://<ip>:8080/api/4/apiVer from another host on the same LAN. LAN firewalls or VLAN isolation are the usual culprit. |
zone.state stays off even during a run | Confirm zone.address matches a real RainMachine zone uid from get_zones. Wrong ids poll fine but never see running. |
on completes but the zone does not start | The zone may be marked inactive on the controller (Zones → toggle Active). A running program or a rain delay can also block a manual start. |
| Frequent reconnects | Bump status_interval if you're on a busy LAN — RainMachine controllers rate-limit the auth path and log warnings when the token is renewed frequently. |
stop_all returns success but a program keeps running | RainMachine occasionally lags on stop-all when a program has queued zones. Re-issue after ~5s. |
Related
rainbird.js— LNK-Wifi/IP-based Rain Bird controllers. Different vendor, similar category.hydrawise.js— Hunter Hydrawise cloud controllers (GraphQL). Cloud-only.orbit_bhyve.js— Orbit B-Hyve cloud smart timers.opensprinkler.js— OpenSprinkler open-hardware controller (local HTTP).