OpenSprinkler
GEM integrates with OpenSprinkler — an open-source Wi-Fi sprinkler controller — over its documented local HTTP API. No cloud account is required. Each physical valve station maps to a GEM zone; on/off start or stop a manual run, and the device also exposes rain-delay, global enable/disable, reboot, and program-trigger commands.
Prerequisites
- An OpenSprinkler v2.x or v3.x controller, OpenSprinkler Pi (OSPi), or OSBee running firmware 2.1.6 or newer.
- Controller reachable on the LAN from the GEM server on port 80 (or the HTTP port you configured).
- The OpenSprinkler device password. The factory default is
opendoor— change it in the OpenSprinkler mobile app or web UI before deployment.
Setup
- In the OpenSprinkler app, confirm the controller IP and that you can run a station manually.
- (Recommended) Change the device password from the default.
- In GEM, System → Devices → Add Device with driver
opensprinkler. - Set
ipto the controller's LAN IP. Paste your device password intopassword(the driver MD5-hashes it before sending; GEM stores it encrypted). - Save and reload. The driver logs
opensprinkler connected: <id> <name> stations: <n>once it can read station names. - Run
get_stationsto enumerate the controller's stations and their names. - Create one GEM zone per station you want to control. Set
zone.addressto the zero-based station index (station S01 in the OpenSprinkler app → address0). - (Optional) Set
default_durationon each zone to override the device-level default manual-run duration in seconds.
Attribute reference
| Attribute | Required | Default | Description |
|---|---|---|---|
ip | yes | — | OpenSprinkler controller LAN IP. |
password | yes | opendoor | Plaintext password. Driver hashes it with MD5 before sending on every request. |
port | no | 80 | HTTP port on the controller. |
status_interval | no | 10000 | ms between /jc polls. |
default_duration | no | 600 | Seconds for on when no level is provided and the zone has no default_duration. |
request_timeout | no | 10000 | HTTP request timeout (ms). |
Zone attributes
| Attribute | Description |
|---|---|
default_duration | Per-zone override for the manual-run duration used by on. Falls back to the device default. |
state | Driver-managed: on while the station is running, off otherwise. |
remaining_seconds | Driver-managed: seconds left in the current manual run (0 when idle). |
Zone address format
zone.address is the 0-based station index. Station "S01" in the OpenSprinkler app is address 0, "S02" is 1, and so on. The driver does not change the GEM zone address representation — addresses are plain digits, no leading zeros required.
Commands
| Command | Args | Effect |
|---|---|---|
on | address, optional level (seconds) | /cm?sid=<addr>&en=1&t=<seconds> — start a manual run. level overrides default_duration. |
off | address | /cm?sid=<addr>&en=0&t=0 — stop the station. |
stop_all | — | /cv?rsn=1 — stop every running station. |
rain_delay | hours (0 to clear) | /cv?rd=<hours> — set rain-delay. |
enable_controller | — | /cv?en=1 — clear global disable. |
disable_controller | — | /cv?en=0 — globally suppress all irrigation. |
reboot | — | /cv?rbt=1 — soft-reboot. |
run_program | program_id | /mp?pid=<id> — manually start a configured program. |
get_status | — | /jc — controller status. |
get_stations | — | /jn — station list with names. |
get_programs | — | /jp — program list. |
raw_request | path | GET an arbitrary path on the controller (e.g. /jo). The pw= query is appended automatically. |
set_level is not an analog dimmer here — sprinkler valves are on/off only. To pick a duration, pass it as level to the on command (in seconds).
Status polling
Every status_interval ms the driver fetches /jc and reads the ps (program-state) array, which holds [program_id, remaining_seconds, start_unix] per station. A station with remaining_seconds > 0 is reported as on with remaining_seconds set; everything else is off. The driver does not poll per-zone — one HTTP call covers the whole controller.
Known limitations
- No remote authentication beyond the device password. The
pw=parameter is MD5 of the password and is sent on every request. Use HTTPS via a reverse proxy or VPN if the controller is reachable beyond your LAN. - Result code 32 (
not permitted). When the controller is in rain-delay or globally disabled, manualonrequests are accepted but the station does not energize. Either clear the rain-delay or re-enable the controller first. - Station limit. OpenSprinkler v2/v3 supports up to 72 stations via expansion boards. Addresses beyond the configured count return result code 17 (out of range).
- No event push. Status changes are visible on the next poll only. Lower
status_intervalto ~3000 ms for snappier UI feedback.
Troubleshooting
| Symptom | Likely cause |
|---|---|
unauthorized (bad password) | Password is wrong, or the controller still has the factory opendoor default while you configured something else in GEM. |
out of range | Station index is higher than the controller's configured station count. Run get_stations to confirm. |
Status stuck at off | Controller may be globally disabled or in rain-delay — run get_status and inspect en and rd. |
| Connection refused | OpenSprinkler is configured to a non-80 port. Set the port attribute. |