Firmware 2.2.1(7) API Reference [Oct 30, 2026]
Introduction
Overview
- Authentication (
pw): All API calls require the device password via thepwparameter. The value must be provided as a lowercase MD5 hash. The OpenSprinkler app and web interfaces handle this hashing automatically. If you are making direct API calls, you must hash your plaintext password before sending the request. You can use any standard MD5 generation tool for this. - Device IP: Throughout this document,
os-ipdenotes the controller's IP address or hostname. Some routers require a.lansuffix, for examplehttp://garden-os.lan/. Do not include this suffix in thehnamesetting. - Command Parameters: Parameters can be sent in any order. You do NOT need to include every parameter in a request - any omitted parameter will retain its current value on the device.
- Return values are all formatted in JSON, for example:
{"fwv":221},{"result":1}. An error response may also include anitemfield identifying the offending parameter, for example:{"result":17,"item":"sn1t"}when the integer sensor-type optionsn1tis set to an out-of-range value such as256. This field may be absent or empty when no specific parameter is identified. Below is the list of error codes:
| Code | Meaning |
|---|---|
1 |
Success |
2 |
Unauthorized (missing device password or device password is incorrect) |
3 |
Mismatch (new password and confirmation password do not match) |
16 |
Data Missing (missing required parameters) |
17 |
Out of Range (value exceeds the acceptable range) |
18 |
Data Format Error (provided data does not match required format) |
19 |
RF code Error (RF code does not match required format) |
32 |
Page Not Found (page not found or requested file missing) |
48 |
Not Permitted (e.g. cannot operate on the requested station) |
64 |
Upload failed (e.g. OTA firmware update failed) |
80 |
Internal Error (e.g. a storage or write operation failed) |
Changes in Firmware 2.2.1(7)
- Cycle and Soak: Adds per-station cycle-and-soak settings through
/cs./jnexposes the settings incsand the capability version incsver./jcadds a separatecsarray describing active cycle-and-soak runs, pluscserrfor configuration errors andqrejfor queue-admission rejections. Manual station starts through/cmbypass cycle and soak by default; usecs=1to apply. - Onboard Analog Sensors: Adds Expanded Sensor type
5for OpenSprinkler v4's built-in SN1-SN4 inputs. Set the port'ssnXtoption to Analog (4) through/coto enable this feature. A port cannot be both analog and digital at the same time; conflicting port-mode changes are rejected with Not Permitted (48)./jsdadvertises the supported inputs and conversion settings; unsupported hardware retains a disabled type placeholder. - CH390 Wired Ethernet: Adds CH390 support on OpenSprinkler v3/v4, with controller identification, link/IP status and recovery diagnostics in
/db. - Network Status:
/jc.RSSIis omitted on wired Ethernet. Saved DHCP address fields now follow lease changes on either interface. - Chip Temperature: Adds ESP32-C6 chip-temperature readings to the existing System Internal sensor type (
3), using the existing temperature metric ID (3). This measures the chip's die temperature, not ambient air temperature. - Hostname: Adds
hnameto/jcand/coon OpenSprinkler v3/v4. The default isos-followed by the last three MAC-address bytes in hexadecimal. Hostname changes require a reboot;/db.hostnamereports the effective name. - Runtime Queue Admission: Program and Run-Once requests are admitted as a whole rather than partially queued when capacity is insufficient. Rejected requests return Not Permitted (
48), and/jc.qrejcounts capacity-related admission rejections. Clients should read/jn.qmaxrather than assume queue capacity equals the number of stations. - Remote Extension Mode: Entering RE with
/cv?re=1clears all running and queued work. While RE is on, automatic program starts are suppressed, and manual commands bypass weather, sensor and cycle-and-soak adjustments./crwith repeats returns Not Permitted (48). See/cv.
The green highlights below identify changes introduced in 2.2.1(7).
Controller Status & Configuration
Get Controller Variables /jc
Usage: http://os-ip/jc?pw=xxx
| Variable | Explanation |
|---|---|
devt |
Device time in Unix epoch seconds (local time, adjusted to the device’s time zone). |
nbrd |
Number of 8-station groups/boards, including the main controller. |
en |
Operation enable bit (1: enabled; 0: disabled). |
sn1/sn2 |
Built-in Sensor SN1 and SN2 status (1: active; 0: inactive). |
sn3/sn4 |
Similar to sn1/sn2. Available on OpenSprinkler v3.4 and v4. |
rd |
Rain delay flag (1: manual rain delay active; 0: not active). |
rdst |
Rain delay stop time (epoch seconds); 0: rain delay is not in effect. |
sunrise |
Today’s sunrise time, number of minutes since midnight. |
sunset |
Today’s sunset time, number of minutes since midnight. |
eip |
External IPv4, as a 32-bit integer: (ip[3]<<24)+(ip[2]<<16)+(ip[1]<<8)+ip[0]. |
lwc |
Timestamp (epoch seconds) of the last weather request. |
lswc |
Timestamp (epoch seconds) of the last weather response. 0 means no successful response yet. |
lupt |
Timestamp of the most recent device reboot (epoch seconds). |
lrbtc |
Cause code for the last reboot (see Reboot Cause Codes). |
lrun |
Last completed station run: [station, pid, duration, end]. station is 0-based; pid is the 1-based program index, with special value 99 indicating a manual run and 254 a run-once program. duration is the actual elapsed runtime in seconds and may exceed 65535 after weather or sensor adjustment; end is the completion time in epoch seconds. |
RSSI |
Wi-Fi signal strength (dBm, OpenSprinkler v3 and v4). Omitted on wired Ethernet. |
mac |
Hardware MAC address. |
loc |
GPS coordinates of the device location. |
jsp |
JavaScript URL. Default: https://ui.opensprinkler.com/js |
wsp |
Weather script URL. Default: weather.opensprinkler.com |
wto |
JSON object containing weather adjustment options; fields depend on the selected adjustment method. |
wtdata |
JSON object containing raw data relayed from the weather server; used to compute watering percentage. |
wterr |
Error code from the last weather server response (see Weather Error Codes). |
ifkey |
IFTTT Webhooks key (enables IFTTT notifications). |
mqtt |
JSON object containing MQTT configuration parameters. |
curr |
Total current draw across all zones (mA). Available only on controllers with current sensing capability. |
sbits |
Station status bits. An array where each byte is an LSB bitfield for an 8-station group. Example: 2 (0b00000010) → 2nd station is open. |
bap |
Bundle-applied station bitfields, using the same layout as sbits. A set bit means an applied output is currently claimed by at least one Bundle Station. A station may have both a direct queue entry and a bundle claim. |
ps |
Program status array with one [pid, rem, start, gid] entry per station. pid is 0 when idle, normally the 1-based program index, 99 for a manual run, or 254 for a run-once program. rem: the remaining runtime; start: the scheduled start time; gid: the sequential group ID. If the corresponding sbit=0 while pid!=0, the station is queued but not running. For a short Bundle Station run extended to complete member staggering, rem reflects the effective extended runtime; the duration saved in the program is unchanged. |
cs |
Cycle-and-soak runtime entries, one per governed queue entry, not one per station. Empty ([]) when no such entries exist. See the entry format below. Unlike /jn.cs, this reports runtime state rather than saved station settings. |
cserr |
Cycle-and-soak error flag (0: no error detected; 1: a configuration/storage or scheduling error was detected). |
qrej |
Program/Run-Once admissions rejected for lack of queue capacity since boot, including scheduled starts. |
flwrt |
Flow-rate scaling interval (seconds). This value is NOT the sampling interval; flcrt/flwrt gives the estimated flow rate in pulses per second. |
flcrt |
Estimated pulse count scaled to flwrt seconds, not a literal count accumulated over that period. |
flcto |
Flow count (total): cumulative flow-sensor clicks since power-on (reset on reboot). |
pq |
Pause state (0: inactive; 1: active). |
pt |
Countdown timer for an active pause (seconds). |
nq |
Number of elements in the program queue (zones running or waiting). |
otc |
JSON object containing OpenThings Cloud (OTC) configuration parameters. |
otcs |
OTC connection status (0: not enabled; 1: connecting; 2: disconnected; 3: connected). |
dname |
Device name (included in notification messages to identify the controller). |
hname |
Configured hostname (v3/v4 only). Set through /co; /db.hostname is the one in effect. |
gpio |
Array of spare/free GPIO pins (usable for GPIO stations). |
email |
JSON object containing email notification settings. |
ocs |
Overcurrent status. 0: none; 255: system-wide overcurrent; any other value is the one-based station number that triggered the overcurrent condition. Unlike regular API station indices, this value starts at 1. |
wtrestr |
Weather restriction status (0: inactive; 1: active). |
wls |
Array of current multi-day average watering levels. Length depends on provider (e.g., Apple up to 10 days; others may support fewer). |
apdv |
Active/Actual USB-PD voltage in decivolts; divide by 10 to obtain volts (for example, 90 means 9.0 V). Read-only, for DC-powered OS v3.4. |
Cycle-and-soak runtime entries (cs): Each entry has the format [sid, pid, state, remaining, segment, soak_until, start, cycles_left]:
| Field | Meaning |
|---|---|
sid |
Station index, starting from 0. Multiple entries may refer to the same station. |
pid |
Program identifier, using the same convention as ps. |
state |
0: waiting; 1: watering; 2: soaking; 3: paused; 4: waiting for a master-off tail to expire. |
remaining |
Total watering seconds still owed, including segment and subsequent cycles; excludes soak and other waiting time. |
segment |
Remaining seconds in the current cycle while watering; otherwise the duration reserved for the next/resumed cycle. 0 for a master-tail entry. |
soak_until |
Soak deadline in local epoch seconds, using the same time basis as devt. 0 when no soak deadline has been set. |
start |
Scheduled start time of the current/next cycle, in local epoch seconds. |
cycles_left |
Number of later cycles, excluding the current/reserved cycle represented by segment. |
For a cycle-and-soak run, ps.rem is the current cycle; cs.remaining is the total still owed.
Change Controller Variables /cv
Usage: http://os-ip/cv?pw=xxx&rsn=x&rrsn=x&rbt=x&en=x&rd=x&re=x&update=x&ap=x&rocs=x
| Parameter | Meaning |
|---|---|
rsn |
Reset all stations (both running and queued). 1 triggers the reset; 0: no effect. |
rrsn |
Reset all running stations (but not queued ones). 1 triggers the reset. |
rbt |
Reboot the controller. 1 triggers the reboot. |
en |
Enable/disable operation. 1: enable; 0: disable. The setting is saved and persists across reboot. |
rd |
Set rain delay (hours). Range: 0–32767. 0 clears any active rain delay. |
re |
Set Remote Extension mode (1/0). See below for details. |
ap |
Reset to AP mode for Wi-Fi reconfiguration without erasing settings/programs. Available on OpenSprinkler v3 and v4 only. |
update |
Trigger firmware update (OSPi/Linux only). |
rocs |
Clear overcurrent status (ocs). 1: clears. |
Examples:
http://os-ip/cv?pw=xxx&rbt=1: reboot controllerhttp://os-ip/cv?pw=xxx&en=0: disable operationhttp://os-ip/cv?pw=xxx&rd=24: set a 24-hour rain delay
Remote Extension (RE) mode:
- Entering this mode with
re=1stops all outputs and clears the queue immediately. - In RE, automatic program starts and program-switch starts are suppressed; program-scheduled reboots still run.
/cm,/mpand/crwork, but ignore weather/sensor adjustments, sequential groups, cycle and soak, and local rain delay and sensors. - Sensor reading, logging, notifications and overcurrent protection stay active. Weather queries stop, so Weather-derived Expanded Sensors will go stale.
Cycle-and-soak behavior:
rsn=1cancels all runs, including remaining cycles and chains currently waiting or soaking.rrsn=1cancels currently running chains, including their remaining cycles. Chains currently waiting or soaking remain queued.
Get Options /jo
Usage: http://os-ip/jo?pw=xxx
Note: options marked RO are read-only and ignored if submitted through /co. The exact fields returned are hardware- and platform-dependent; for example, DHCP and static-network configuration fields are omitted on Linux/OSPi, while power-related fields are emitted only for applicable controller types.
| Variable | Explanation |
|---|---|
fwv |
Firmware version (e.g., 221 → v2.2.1). RO |
fwm |
Firmware build number. RO |
tz |
Time zone (offset_hours*4+48). Examples: GMT+0→48; GMT−4→32; GMT+9:30→86. The value must be between 0–108. |
dhcp |
Use DHCP (1: yes, 0: no). |
ip{1,2,3,4} |
Static IP (ignored if dhcp=1). |
gw{1,2,3,4} |
Gateway (router) IP (ignored if dhcp=1). |
dns{1,2,3,4} |
DNS server IP (ignored if dhcp=1). |
subn{1,2,3,4} |
Subnet mask (ignored if dhcp=1). |
ntp |
Use NTP sync (1: yes, 0: no). |
ntp{1,2,3,4} |
Custom NTP server IP (ignored if ntp=0). |
hp{0,1} |
The lower and upper bytes of HTTP port: http_port=(hp1<<8)+hp0. |
hwv |
Hardware version (for example, 34 for OpenSprinkler v3.4 or 40 for v4.0). RO |
hwt |
Hardware type (172 / 0xAC: AC-powered; 220 / 0xDC: DC-powered; 26 / 0x1A: Latch). RO |
ext |
Configured number of 8-zone expansion groups (excluding the main controller). A physical 16-zone Zone Expander counts as two groups. |
sdt |
Station delay time (seconds). Range [-600, 600] (i.e. [-10, 10] minutes), in increments of 5 seconds. |
mas? |
Master station 1–4, specified as a 1-based station number (0: none). ? is empty for Master 1 (legacy naming), or 2, 3, or 4 for the corresponding master. |
mton? |
Master ON time adjustment in seconds. Uses the same ? suffix as mas?. Range [-600, 600], step 5. |
mtof? |
Master OFF time adjustment in seconds. Uses the same ? suffix as mas?. Range [-600, 600], step 5. |
ms |
Legacy flattened master array with three values per master: [station, encodedOnAdjustment, encodedOffAdjustment, ...]. It contains 12 values for four masters. station uses the same 1-based numbering as mas? (0: none); each encoded adjustment is (seconds+600)/5. New clients should use the named mas?, mton?, and mtof? fields instead. RO |
sn?t |
Built-in Sensor type, where ? is 1–4. Value: 0: none, 1: rain, 2: flow, 3: soil, 4: analog (v4 only), 240: program switch. Flow (2) is valid only for sn1t; SN3/SN4 are available on OpenSprinkler v3.4 and v4. Analog (4) sets the port for high-impedance voltage reading through an Onboard Analog Expanded Sensor. See the port-mode rules under /co. |
sn?o |
Sensor option. 0: normally closed; 1: normally open (default). ? is 1-4, the same as sn?t. |
sn?on/sn?of |
Sensor activation / deactivation delay in minutes. These delays apply only to rain and soil sensors. ? is 1-4, the same as sn?t. |
wl |
Water level (% watering). Range 0–250. |
den |
Operation enable bit. To change, you must use the /cv command. |
ipas |
Ignore password. 1: ignore; 0: do not ignore. |
devid |
Device ID. |
dim |
LCD dimming level (0: display off when idle). |
bst |
Boost time (milliseconds) for DC-powered & Latch controllers. Range 0–1000, step size 4. |
laton/latof |
Latch-solenoid ON/OFF boost voltage (0: use the firmware default of 9 V; otherwise 1–24 volts). Returned only on Latch controllers. |
uwt |
Weather adjustment method. 0: Manual; 1: Zimmerman; 2: Auto Rain Delay; 3: ETo; 4: Monthly. NOTE: Previously uwt.bit[7] flagged California water restriction; that bit is no longer used: instead, water restriction is indicated in the wto (weather options) variable. |
lg |
Enable logging (1: on, 0: off). |
fpr{0,1} |
Flow pulse rate (scaled by 100), calculated as ((fpr1<<8)+fpr0)/100.0. |
re |
Remote extension mode. To change, you must use the /cv command. |
wimod |
Internal Wi-Fi mode marker (169: AP mode; 42: station mode). Meaningful only on OpenSprinkler v3 and v4. RO |
reset |
Factory-reset selection used by the controller's local setup interface; normally 0. RO |
dexp/mexp |
Detected / maximum supported numbers of 8-zone expansion groups, excluding the main controller. A physical 16-zone Zone Expander counts as two groups; dexp=-1 means expansion hardware cannot be auto-detected. RO |
sar |
Special-station auto-refresh. When 1, special (e.g. RF, Remote IP/OTC, HTTP) stations automatically refresh to remain synchronized with the main controller. Enable this for Remote IP/OTC program runtimes over 18 hours because each forwarded /cm timer remains capped at 18 hours for compatibility. |
fwire |
Force wired connection (OpenSprinkler v3 and v4 only). 1: stay wired; 0: allow Wi-Fi. |
ife |
Notification event enable bits. A bit field: • b0: Program scheduled• b1: Built-in Sensor SN1 update• b2: Flow sensor status update• b3: Weather update (e.g. water level change, eip change)• b4: Reboot• b5: Station finish• b6: Built-in Sensor SN2 update• b7: Rain delay update |
ife2 |
Extended notification bits: • b0: Station start• b1: Flow alert• b2: Current alert• b3: Built-in Sensor SN3 update• b4: Built-in Sensor SN4 update. |
imin |
Undercurrent threshold in mA, in increments of 10 mA. |
imax |
Overcurrent threshold in mA, in increments of 10 mA. 0: system default; 2550: disabled. |
tpdv |
Target USB-PD voltage (in decivolts) for DC-powered OS v3.4+. Example: tpdv=78→7.8 V. |
Change Options /co
Usage: http://os-ip/co?pw=xxx&[opn]=[opv]&loc=x&wto=x&ifkey=x&ttt=x
&otc=x&dname=x&mqtt=x&email=x&hname=x
The nested-object options wto, otc, mqtt, and email accept either the historical object-body format without the outer braces or a complete JSON object with {}. Existing clients do not need to change their requests.
| Parameter | Meaning |
|---|---|
[opn] |
Option name to modify (see the options list above). RO fields are ignored. You can include multiple option changes in one call (e.g., &tz=32&dhcp=1). |
[opv] |
New value to be assigned to [opn]. |
loc |
Location string (URL-encoded). Accepts "city,state", ZIP code, or "lat,lon". When you use the UI/app to set the location, it always converts it to GPS. |
wto |
Weather options as URL-encoded JSON. The outer {} are optional. Fields depend on the selected method (e.g., Zimmerman has six parameters for the weights and baselines of temp t, humidity h, and rain r). |
ifkey |
IFTTT Webhooks key. |
ttt |
Set device time manually (epoch seconds) on OpenSprinkler v3 and v4. Ignored if ntp=1. Setting the time stops all running and queued stations. Also clears cycle-and-soak state. |
otc |
OpenThings Cloud (OTC) configuration as JSON. The outer {} are optional. A reboot is required for a changed configuration to take effect. Example: otc="en":1,"token":"token","server":"ws.cloud.openthings.io","port":80 |
mqtt |
MQTT configuration as JSON. The outer {} are optional. Example: mqtt="en":1,"host":"x","port":1883,"pubt":"opensprinkler","subt":"" |
email |
Email configuration as JSON. The outer {} are optional. Example: email="en":1,"host":"x","port":465,"user":"a@b.io","pass":"","recipient":"" |
dname |
Device name. |
hname |
Network hostname (v3/v4 only). Accepts 1-32 letters, digits or hyphens; no leading/trailing hyphen or all-digit name. Converted to lowercase. Empty restores the default os-xxxxxx. Requires a reboot; returned by /jc. |
Notes:
- An explicitly empty
ifkey,otc,mqtt, oremailvalue clears that setting. An emptyloc,wto, ordnamevalue is ignored. - On OpenSprinkler v3 and v4, TCP port
8080is reserved for firmware update. An attempt to configure the main HTTP server on port8080returns Out of Range (17) and restores the previous port. - A Bundle Station leader or member cannot be assigned as a master. Such an assignment returns Out of Range (
17). /cois not transactional: after an error, some changes may already have taken effect. Re-read/jo.
Analog port-mode rules:
- Set
sn?t=4before creating an Onboard Analog Expanded Sensor on that port. Only v4 has built-in analog-capable ports. - A port cannot change to Analog while an Onboard Digital Expanded Sensor references it, or change away from Analog (including to
None) while an Onboard Analog Expanded Sensor references it. Disabled sensors still count. Conflicts return Not Permitted (48). Delete or reassign the conflicting configuration first.
Examples:
os-ip/co?pw=xxx&loc=42.01,-75.22: change location to GPS coord42.01,-75.22os-ip/co?pw=xxx&sdt=30: set station delay time to30secondsos-ip/co?pw=xxx&sn1t=1&sn1o=1: configure Built-in Sensor SN1 as a normally-open rain sensoros-ip/co?pw=xxx&sn1t=4: set v4's SN1 port in Analog mode.os-ip/co?pw=xxx&hname=garden-controller: save a custom hostname; reboot to apply it.os-ip/co?pw=xxx&hname=: restore the device's default hostname; reboot to apply it.
Set Device Password /sp
Usage: http://os-ip/sp?pw=xxx&npw=xxx&cpw=xxx
| Parameter | Meaning |
|---|---|
npw |
MD5 hash of the new password. |
cpw |
Repeat the same MD5 hash for confirmation. |
Examples:
os-ip/sp?pw=xxx&npw=e0ff85143dfa717536cbb668cc8f8e8b&cpw=e0ff85143dfa717536cbb668cc8f8e8b: change the device password tosprinkler;npwandcpwcontain its MD5 hash.- If
npwis omitted or empty, aData Missingerror is returned. Ifcpwis omitted or differs fromnpw, aMismatcherror is returned. Refer to the list of error codes.
Change UI and Weather URLs /cu
Usage: http://os-ip/cu?pw=xxx&jsp=xxx&wsp=xxx
jsp: UI source URL (URL-encoded)wsp: Weather server URL (URL-encoded)
Example:
os-ip/cu?pw=xxx&jsp=https%3A%2F%2Fui.opensprinkler.com%2Fjs: set the UI source URL tohttps://ui.opensprinkler.com/js.
The two URLs are saved across reboots and can be changed independently. Omitted or empty parameters remain unchanged, and space characters are removed from submitted URLs. On success, /cu returns an HTML response that redirects the browser to the controller home page.
Stations & Manual Control
Get Station Names and Attributes /jn
Usage: http://os-ip/jn?pw=xxx
| Variable | Explanation |
|---|---|
snames |
Array of station names (length equals number of zones). |
maxlen |
Maximum characters allowed per station name. |
csver |
Cycle-and-soak API version; currently 1. |
qmax |
Runtime queue capacity: 72 (v3), 120 (v4), 255 (OSPi/Linux); previously 72 (v3/v4) and 200 (OSPi/Linux). |
cs |
Per-station cycle-and-soak settings: [enabled, cycle_seconds, soak_seconds]. Unlike /jc.cs, these are saved settings, not runtime status. |
stn_grp |
Sequential group ID for each zone. Values 0–3 identify sequential groups (A, B, C, or D); 255 is the parallel group P. |
masop? |
Master 1–4 operation bitfields. ? is empty for Master 1, or 2, 3, or 4 for the corresponding master. Each array byte represents one 8-zone group, with its least-significant bit corresponding to the first zone in that group. A set bit means the zone activates that master. For example, 254 (0b11111110) assigns every zone except the first to the master. |
ignore_rain |
Rain-delay ignore bitfields, using the same 8-zone-group layout. A set bit means the zone ignores rain delay. |
ignore_sn? |
Sensor SN1–SN4 ignore bitfields, using the same 8-zone-group layout. ? is 1-4; a set bit means the zone ignores that sensor. ignore_sn3 and ignore_sn4 are available only on OpenSprinkler v3.4 and v4. |
stn_dis |
Zone-disable bitfields. A set bit means the zone is disabled. |
stn_spe |
Special-station bitfields. A set bit means the zone is configured as a special station. |
stn_bnd |
Bundle Station leader bitfields. A set bit means the zone is a Bundle Station (st=7) and is thus a bundle leader. |
bmt |
Bundle member type mask. Defines which type of zones are allowed to be a bundle member. Bit n corresponds to special-station type n from /je; a set bit means that type may be selected as a bundle member. The current value is 1, allowing only Standard stations (st=0). |
Example:
{"masop":[255],"masop2":[0],"masop3":[0],"masop4":[0],"ignore_rain":[0],"ignore_sn1":[0],"ignore_sn2":[0],"ignore_sn3":[0],"ignore_sn4":[0],"stn_dis":[0],"stn_spe":[0],"stn_bnd":[0],"bmt":1,"csver":1,"qmax":72,"cs":[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]],"stn_grp":[0,0,0,1,0,0,0,0],"snames":["S01","S02","S03","S04","S05","S06","S07","S08"],"maxlen":32}
Get Special Station Data /je
Usage: http://os-ip/je?pw=xxx
Response Format: {"0":{"st":xxx, "sd":"xxx"}, "1":{"st":xxx, "sd":"xxx"}, ...}
Only stations whose stn_spe bit is set appear.
| Key | Meaning |
|---|---|
station_id |
Object key containing the 0-based station index as a string (for example, "0" or "1"). |
st |
Special-station type code (see table below). |
sd |
Type-specific data payload associated with st. |
Station Types:
st |
Type | Format of sd |
|---|---|---|
0 |
Standard | Should not appear here, as only special stations are listed. |
1 |
RF (Radio Frequency) | Either a legacy 16-character RF hexadecimal code (protocol 1, 24 bits), or a 25-character extended code prefixed with H that supports other protocols and bit lengths. |
2 |
Remote (IP) | 14-character hexadecimal string: 8 characters for the IPv4 address, 4 for the port, and 2 for the 0-based station index. |
3 |
GPIO | 3-character string: 2 digits for the GPIO pin number, and 1 digit for the active state (1 or 0). |
4 |
HTTP | Comma-separated string (up to 275 characters) formatted as: server,port,on_cmd,off_cmd. Assume server is HTTP. |
5 |
HTTPS | Same format as st=4. Assume server is HTTPS. |
6 |
Remote (OTC) | 35-character fixed-width string: 32 characters for the OTC token, 1 reserved character, then 2 hexadecimal characters for the 0-based station index. |
7 |
Bundle Station | Hexadecimal member bitmap with two characters per 8-zone group. Bytes are ordered by board and bit 0 represents the first zone in each group. For an 8-zone controller, 0E selects zones 2, 3, and 4. The leader itself is not included. Eligible member types are advertised by /jn.bmt. |
Example:
{"0":{"st":2,"sd":"c0a80093005002"},"1":{"st":1,"sd":"05331305333C0021"},
"2":{"st":4,"sd":"demo.opensprinkler.com,80,on/?z=1,off"},"3":{"st":7,"sd":"F0"}}
Change Station Names and Attributes /cs
Usage: http://os-ip/cs?pw=xxx&s?=x&m?=x&n?=x&u?=x&v?=x&i?=x&j?=x&k?=x&o?=x&r?=x&d?=x&p?=x&g?=x&sid=xx&st=xx&sd=xx&cse=x&csc=xxx&css=xxx
| Parameter | Meaning |
|---|---|
s? |
Station name: ? is the 0-based station index. Example: s2=Front%20Lawn sets the third station to Front Lawn. Max length is maxlen from /jn. |
m?/n?/u?/v? |
Master 1/2/3/4 operation bitfields, respectively. ? is the 0-based 8-zone-group index (0: zones 1–8). Same layout as masop? in /jn. |
i? |
ignore_rain bitfields. |
j?/k?/o?/r? |
Built-in Sensor SN1/SN2/SN3/SN4 ignore bitfields, respectively. ? is the 0-based 8-zone-group index. SN3/SN4 settings (o?/r?) apply only to OpenSprinkler v3.4 and v4. |
d? |
stn_dis (station disable) bitfields. |
p? |
stn_spe (station special) bitfields. |
g? |
Station group ID (not a bitfield). ? is the 0-based station index; the value is 0–3 for a sequential group or 255 for the parallel group. |
sid |
Target station index (0-based), for special-station or cycle-and-soak settings. |
st |
Special-station type (see /je). |
sd |
Special-station data payload (see /je). URL-encoded. For Bundle Stations (st=7), this must contain exactly two hexadecimal characters per 8-zone group. |
cse |
Enable cycle and soak: 0 or 1. Requires sid. |
csc |
Maximum cycle duration, in seconds: 60–14400. Requires sid. For a Bundle Station leader, it must be at least twice the member stagger time. |
css |
Minimum soak duration, in seconds: 60–14400. Requires sid. |
csreset |
1: reset all stations' cycle-and-soak settings to disabled/zero. Other parameters are ignored. Use it to recover when /jc.cserr=1. |
Note:
- Multiple assignments can be combined in one call; omitted fields are unchanged.
- To make a station "special", set the corresponding
p?bit and providesid/st/sd. - Bundle leaders/members cannot be masters; member types per
/jn.bmt. - Changing a Bundle Station member to a special-station type returns Not Permitted (
48). Remove it from every bundle first. - Cycle and Soak: Total run-time is split into nearly equal cycles, each no longer than
csc, with soak gaps no shorter thancss. Withcse=0,cscandcssmay also be0. Changes affect future runs; queued runs retain their settings.
Examples:
os-ip/cs?pw=xxx&s0=Front%20Lawn&s1=Back%20Lawn: set the first two stations' namesos-ip/cs?pw=xxx&m0=127&s7=Garage: set station 8's name and master operation bits for boardm0(127=all but station 8 activate Master1).os-ip/cs?pw=xxx&sid=2&st=1&sd=00553300553c001c: set special station data for station 3os-ip/cs?pw=xxx&sid=0&st=7&sd=0E: configure zone 1 as a Bundle Station that also activates zones 2, 3, and 4 on an 8-zone controller.os-ip/cs?pw=xxx&g4=1: assign group id1to station 5.os-ip/cs?pw=xxx&sid=0&cse=1&csc=300&css=600: enable cycles of up to 5 minutes with at least 10 minutes of soak for station 1.
Get Station Status /js
Usage: http://os-ip/js?pw=xxx
| Variable | Explanation |
|---|---|
sn |
Array of 1/0 indicating each physically applied station's On/Off status, including bundle-derived outputs. |
bap |
Bundle-applied bitfields. Each byte covers eight zones using the same LSB-first layout as /jc.sbits. A set bit means the applied output is currently claimed by a Bundle Station. |
nstations |
Total number of stations. |
Example: {"sn":[1,1,0,0,0,0,0,0],"bap":[2],"nstations":8}
Stations 1 and 2 (at indices 0 and 1 in the array) are currently open; station 2 is also claimed by a Bundle Station.
Manual Station Run /cm
Usage: http://os-ip/cm?pw=xxx&sid=xx&en=x&t=xxx&ssta=x&qo=x&cs=x
| Parameter | Meaning |
|---|---|
sid |
Station index (starting at 0). |
en |
Enable (1: open, 0: close). |
t |
Runtime in seconds, from 1 to 64800 (18 hours). Required when opening a zone. |
cs |
1: apply the station's cycle-and-soak policy; 0 (default): bypass it. |
qo |
Queuing option (applies when opening a zone). 0: append after other zones (default); 1: insert ahead of other zones. |
ssta |
Shift remaining stations in the same sequential group when closing a zone (en=0). 0: don’t shift; 1: shift. Ignored when opening a zone. |
Note:
- Opening a master station by itself is not allowed (error), as it cannot be operated independently. To run a master alone, you can make use of a dummy zone (i.e. a zone not physically connected) and open that zone, which in turn opens the associated master(s).
- Opening a station that already has a runtime queue entry, whether running or waiting, returns a “not permitted” error. This error is also returned if the runtime queue is full.
- Manually started stations are assigned a program ID of
99. - Closing a cycling station cancels its remaining cycles. Shifting queued stations cannot bypass their required soak time.
- A zone running only as a Bundle member has no queue entry of its own;
/cm?en=0on it returns17. Stop the leader instead.
Examples:
os-ip/cm?pw=xxx&sid=0&en=1&t=360: open station 1 for 6 minutes, append to the queue.os-ip/cm?pw=xxx&sid=3&en=1&t=300&qo=1: open station 4 for 5 minutes, insert ahead of other zones.os-ip/cm?pw=xxx&sid=3&en=0: close station 4. Remaining stations in the same sequential group retain their original assigned start times.os-ip/cm?pw=xxx&sid=3&en=0&ssta=1: close station 4 and shift remaining stations in the same sequential group earlier, subject to required soak time.os-ip/cm?pw=xxx&sid=0&en=1&t=900&cs=1: run station 1 for 15 minutes of watering using its cycle-and-soak policy.
Pause Queue /pq
Usage: http://os-ip/pq?pw=xxx&dur=x&repl=x
| Parameter | Meaning |
|---|---|
dur |
Toggle-style pause. If no pause is active and dur>0, start a pause of dur seconds. If a pause is active, cancels the pause (resume stations) regardless of dur value. |
repl |
Replace/set pause. Sets the pause to repl seconds (starts new or updates existing). repl=0 cancels any active pause. If both repl and dur are present, repl takes precedence. |
For cycle and soak stations: Pause time counts toward soak.
Examples:
os-ip/pq?pw=xxx&dur=600: start a 10-minute pause if none active; otherwise cancel pause.os-ip/pq?pw=xxx&repl=250: start a 250-second pause if none active; otherwise replace it.
Expanded Sensors & Sensor Logs
The endpoints in this section let clients retrieve configured sensors and their latest readings (/jsn), change (add/modify) sensors (/csn), delete sensors (/dsn), and obtain the metadata for sensor configuration interfaces (/jsd). Separate log endpoints retrieve and export historical readings (/jsl) or clear an individual sensor's history (/dsl).
uuid is a stable ID that isn't reused; sid is the current position in sn and can change. Use uuid for durable references.
Get Expanded Sensors /jsn
Usage: http://os-ip/jsn?pw=xxx
Returns the configured sensors and their latest readings. Each sensor contains:
| Key | Meaning |
|---|---|
uuid |
Stable sensor ID (1–65535), unaffected when other sensors are added, deleted, or reordered. |
name |
User-assigned sensor name. |
type |
Sensor type. 0: Aggregate; 1: ADS1115; 2: Weather; 3: System Internal; 4: Onboard Digital (i.e. Built-in Sensor input); 5: Onboard Analog (v4 only). |
unit |
Unit index (see /jsd). |
flag |
Bitmask. Bit 0: sensor enabled; 1: logging enabled; 2: show the sensor value on the homepage. |
status |
Runtime status bitmask:
status=0: no successful reading yet; 1: a valid, in-range reading; 9 (0b01001): a valid reading clamped to max. |
interval |
Sampling interval, in minutes. |
min/max |
Output clamping range. |
value |
Last stored reading. Consult status before using it: after a failed or overdue update, this may be an older reading. |
extra |
Type-specific JSON object, described below. |
Example: {"sn":[{"uuid":1,"name":"Soil 1","unit":0,"flag":3,"status":1,"interval":15,"min":0,"max":5,"value":2.7,"type":1,"extra":{"pin":1,"scale":1,"offset":0,"subtype":0}}],"count":1}
extra Object by Sensor Type:
action, subtype, metric and input are integer indices, as accepted by /csn.
| Sensor type | Fields returned in extra |
|---|---|
| Aggregate | action: aggregation index (0: Min, 1: Max, 2: Average, 3: Sum, 4: Median, 5: Range).children: array of up to 8 {uuid,scale,offset} objects. A child with uuid=0 is unused. |
| ADS1115 | pin, scale, offset, and subtype. Piecewise Linear (subtype:1) also includes points: an array of up to eight {x,y} objects. |
| Weather | action: weather-action index advertised by /jsd in enums.WeatherAction. |
| System Internal | metric: which system metric (see /csn metric). |
| Onboard Digital | input: built-in sensor input index (0–3 = SN1–SN4). |
| Onboard Analog | input: built-in input index (0–3 = SN1–SN4); scale, offset, subtype, and optional points, as for ADS1115. |
extra Examples by Sensor Type:
- ADS1115 (linear):
{"pin":1,"scale":1,"offset":0,"subtype":0} - ADS1115 (piecewise):
{"pin":1,"scale":1,"offset":0,"subtype":1,"points":[{"x":0,"y":0},{"x":3,"y":100}]} - Aggregate:
{"action":2,"children":[{"uuid":1,"scale":1,"offset":0},{"uuid":2,"scale":1,"offset":0}]} - Weather (Today's High Temperature):
{"action":5} - System Internal:
{"metric":3}— Onboard Digital:{"input":0} - Onboard Analog (SMT50 temperature):
{"input":0,"scale":1,"offset":0,"subtype":10}
Change (Add/Modify) Expanded Sensor /csn
Usage: http://os-ip/csn?pw=xxx&uuid=xxx&type=xxx&...
To add a new sensor, use uuid=-1 (or sid=-1); omitted common parameters use the defaults shown below. To modify an existing sensor, specify the target with either uuid (stable ID) or sid (positional index); if both are given, uuid takes precedence; omitted common parameters retain their current values. The type parameter is always required.
| Parameter | Meaning |
|---|---|
uuid |
Sensor stable ID (1–65535); -1 to add a new sensor. |
sid |
Sensor positional index (0-based); -1 to add a new sensor. |
type |
Sensor type. 0: Aggregate; 1: ADS1115; 2: Weather; 3: System Internal; 4: Onboard Digital; 5: Onboard Analog (v4 only). Required. |
name |
Expanded Sensor name. Default: New Sensor. |
min/max |
Output clamping range. Defaults: min=0, max=5. |
interval |
Sampling interval, in minutes (≥ 1). Default: 15. |
unit |
Unit index. Default: 4 (Volt). |
flag |
Bitmask. Bit 0: sensor enable; 1: log; 2: show on homepage. Default: 1 (enabled only). |
Type-Specific Parameters:
| Parameter | Applied to | Meaning |
|---|---|---|
children |
Aggregate | Up to eight source sensors, encoded as semicolon-separated triples uuid,scale,offset;uuid,scale,offset;…. uuid=0 marks an unused child. Child defaults: scale=1, offset=0. |
action |
Aggregate | Aggregate action: 0: Min, 1: Max, 2: Average, 3: Sum, 4: Median, 5: Range (Max-Min). Default: 2 (Average). |
pin |
ADS1115 | Analog input pin (1–16). Default: 1. |
subtype |
ADS1115, Onboard Analog | Conversion subtype:
0. Values 2–9 are reserved and rejected. |
scale/offset |
ADS1115, Onboard Analog | Final adjustment applied as value = scale × sensor_value + offset. Defaults: scale=1, offset=0. |
points |
Piecewise Linear | Comma-separated x0,y0,x1,y1,... pairs, defining 2–8 sample points, sorted by nondecreasing input x. |
metric |
System Internal | Metric selector. On OpenSprinkler v3 and v4: 0: Free Heap, 1: Free Flash, 2: Wi-Fi RSSI. OpenSprinkler v3 additionally supports 4: Heap Fragmentation. On OSPi/Linux: 3: CPU Temperature. v4 also supports 3: Chip Temperature (die temperature, not ambient). |
input |
Onboard Digital, Onboard Analog | Built-in Sensor input: 0-3: SN1-SN4 respectively. SN3/SN4 are available on OpenSprinkler v3.4 and v4. |
action |
Weather | Index advertised by /jsd in enums.WeatherAction:
0 (Current Temperature). |
Subtype-specific units and recommended min/max values are provided by /jsd (see below). API clients should use that metadata when constructing /csn requests.
Onboard Analog requires input when adding or changing to this type, and that port must already be in Analog mode (sn?t=4); otherwise 48. New Onboard Analog sensors default to min=0, max=3.3, unit Volt. Onboard Digital cannot use an Analog port; conflicts return 48. Analog terminal voltage must stay within 0–3.3 V.
Examples:
- Add an ADS1115 voltage sensor on pin 1 (enabled + logging):
/csn?pw=xxx&uuid=-1&type=1&name=Soil+1&pin=1&subtype=0&unit=4&min=0&max=5&interval=15&flag=3 - Add an averaging Aggregate over sensors 1 and 2:
/csn?pw=xxx&uuid=-1&type=0&name=Avg&action=2&children=1,1,0;2,1,0 - Add a Weather Sensor for today's forecast high temperature:
/csn?pw=xxx&uuid=-1&type=2&name=Forecast+High&action=5&flag=1 - Convert sensor 5 to Piecewise Linear (0 V → 0, 3 V → 100):
/csn?pw=xxx&uuid=5&type=1&subtype=1&points=0,0,3,100 - Read v4 SN1 voltage (after setting
sn1t=4):/csn?pw=xxx&uuid=-1&type=5&input=0
Delete Expanded Sensor /dsn
Usage: http://os-ip/dsn?pw=xxx&uuid=xxx
To delete an existing sensor, specify the target with either uuid or sid (uuid takes precedence if both are given). To delete all sensors, use uuid=-1 (or sid=-1).
Get Expanded Sensor Descriptions /jsd
Usage: http://os-ip/jsd?pw=xxx
Returns descriptive metadata used by the UI to build the Expanded Sensor configuration menus: available types, units, and per-type arguments, along with their display names.
What is this for?
Clients that only read or set sensor values can ignore /jsd. It exists for UIs that build sensor-configuration forms dynamically.
The response has five top-level keys:
{ "sensors":[...], "units":[...], "enums":{...}, "as":[...], "flags":[...] }
| Top key | Meaning |
|---|---|
sensors |
Array of sensor-type descriptions. The array index is the sensor type. Each entry contains its display name and type-specific arguments; it may also indicate that the type is disabled or that required hardware was not detected. |
units |
Available sensor units, encoded as [id,name,symbol,group]. The group value indexes enums.SensorUnitGroup. |
enums |
Named arrays used by enum arguments, including SensorUnitGroup, AggregateAction, and WeatherAction. Each array index is the value submitted to /csn. |
as |
The top-level as is the list of arguments common to all sensor types (name, interval, unit, min/max, type). Separately, each entry in sensors has its own as array for that type's specific arguments. |
flags |
Persistent sensor-flag descriptions. The array index is the corresponding bit position in /jsn.flag and /csn.flag; d gives that bit's default state. |
Argument objects (in as) and similar entries use compact keys:
| Compact Key | Meaning |
|---|---|
n |
Display name |
a |
The /csn argument this maps to |
t |
Data or editor type |
d |
Default value |
h |
Optional UI hint |
as |
Type-specific argument array in a sensor-type description |
dis |
1 when the sensor type is disabled |
hwd |
1 when required hardware is detected; 0 when it is not |
o |
Inline options for an enum argument |
id |
Numeric option value submitted to /csn |
l |
Option display label |
hd |
Arguments hidden when an option is selected |
dfl |
Argument defaults applied when an option is selected |
ug |
Allowed sensor-unit group |
lk |
Arguments locked when an option is selected |
e |
Element schema for an array argument |
indicator |
Marks the field used to determine whether an array element is populated |
For example, this object from the common as array describes the sampling interval:
{
"n": "Interval",
"a": "interval",
"t": "int::[1,any]",
"d": "15",
"h": "Sensor's update interval (in minutes)"
}
Sensor type 5 describes Onboard Analog on v4; unsupported boards return {"dis":1} at that index. System Internal metric options now include Chip Temperature on v4.
Get Expanded Sensor Log /jsl
Usage: http://os-ip/jsl?pw=xxx&[uuid=xxx]&[count=xxx]&[before=xxx]&[after=xxx]&[cursor=xxx]&[fmt=xxx]&[page=1]
| Parameter | Meaning |
|---|---|
uuid |
Filter records by sensor uuid; use -1 (default) for all sensors. |
sid |
Filter records by positional index (uuid takes precedence if both are given). |
count |
Max records to return (default 100). max/all returns up to the full capacity. With page=1, this instead bounds the number of slots scanned per request (see Pagination below). |
before |
Return only records at or before this epoch value. |
after |
Return only records at or after this epoch value. |
cursor |
Pagination offset. Without page=1, the number of records to skip from the oldest; with page=1, an absolute physical slot offset (see Pagination below). |
fmt |
Output format: json (default), csv, or binary. |
page |
Set to 1 for reliable physical-slot pagination, including across deleted, sensor-filtered, or time-filtered records. |
Output formats:
json—[[uuid,timestamp,value],...]array of arrays.csv—uuid,timestamp,valuerows with a header; served as asensor_log.csvdownload.binary— packed records (uint32timestamp,floatvalue,uint16uuid); the most compact form for bulk export.
Records are returned oldest-first (chronological order).
Example (json format): [[1,1731000000,2.71],[1,1731000900,2.68]]
Pagination (page=1)
The sensor log is a fixed-size ring (circular buffer) of record slots, where all sensors' records are interleaved. To retrieve many records without tying up the controller, use paginated reads: walk the slots in chunks, where each request scans up to count slots starting at cursor, then returns the cursor to resume from on the next request — repeat until done. Some slots are skipped on output — deleted records, or records filtered out by uuid/sid/before/after — so a page may return fewer than count rows, or none, and still have more to come.
Rules during paginated reads:
countbounds the number of slots scanned per request (the work done), not the number of records returned.- Always set the next
cursorto the returnedX-OS-Next-Cursor(see below). Never add the row count yourself — the server may skip whole out-of-window files and advance the cursor past your value. - Repeat the same
uuid/sid/before/afteron every request. - Stop when
X-OS-Page-Doneis1. Do not stop merely because a page was short, and note that a bounded time window can finish before the cursor reachesX-OS-Total-Slots.
Response headers:
| Variable | Meaning |
|---|---|
X-OS-Next-Cursor |
Physical cursor for the next request. |
X-OS-Total-Slots |
Total number of record slots when the request began. |
X-OS-Window-Start |
First physical slot in the requested time window. |
X-OS-Window-End |
One past the last physical slot in the requested time window. |
X-OS-Page-Done |
1 when the retrieval is complete. |
Client loop:
cursor = 0
do:
resp = GET /jsl?pw=..&uuid=U&after=A&before=B&page=1&count=200&cursor=cursor
append rows from resp.body
cursor = resp.header["X-OS-Next-Cursor"]
while resp.header["X-OS-Page-Done"] != 1
The firmware continues to log sensors during a /jsl request; if a full ring rotates between page requests, its physical ordering can shift and produce a skipped or duplicated record. Paginated export is therefore best-effort rather than a transactional snapshot. Requests without page=1 retain the original API behavior (return the oldest count records after skipping cursor, within any before/after/uuid filters).
Delete Expanded Sensor Log /dsl
Usage: http://os-ip/dsl?pw=xxx&uuid=xxx
Paginated: http://os-ip/dsl?pw=xxx&uuid=xxx&page=1&[cursor=xxx]&[count=xxx]
Delete log records of a sensor specified by its uuid. Use uuid=-1 to clear the entire log.
Pagination (page=1)
Because all sensors' records are interleaved in the log, deleting a single sensor's records means scanning the entire log to find them, which can be slow. Paginated deletion spreads that work across requests, using the same cursor/count slot model as /jsl, but reporting progress in the JSON body rather than in response headers. Each request clears one bounded range and returns:
{"result":1,"next":819,"total":40950,"deleted":37,"done":0}
| Field | Meaning |
|---|---|
next |
Cursor for the next request. |
total |
Total slots present when this request began. |
deleted |
Records deleted in this request. |
done |
1 when next has reached total; otherwise 0. |
Rules:
cursordefaults to0;countdefaults to one log file's record capacity and is capped at that value.- Retrying the same
cursoris safe (the operation is idempotent). - Freeze
totalfrom the first response and continue with the returnednextuntil it reaches that value, even whendeletedis0. Cap the finalcounttoinitialTotal - cursorso records logged after deletion began are left untouched.
Client loop:
cursor = 0; initialTotal = null
do:
cnt = (initialTotal == null) ? DEFAULT : min(DEFAULT, initialTotal - cursor)
resp = POST /dsl?pw=..&uuid=U&page=1&cursor=cursor&count=cnt
if initialTotal == null: initialTotal = resp.total # freeze the target
cursor = resp.next
while cursor < initialTotal
Paginated delete requires a specific, non-zero uuid. On the other hand, clearing all logs with uuid=-1 needs no pagination — it simply deletes every log file without scanning the content, a fast one-shot operation — so uuid=-1 cannot be combined with page=1.
Programs & Scheduling
Get Program Data /jp
Usage: http://os-ip/jp?pw=xxx
| Variable | Explanation |
|---|---|
nprogs |
Number of programs. |
nboards |
Number of 8-zone groups (includes the main controller). |
mnp |
Max number of programs allowed (40 for this firmware). |
mnst |
Max number of fixed start times per program (4 in this firmware). |
pnsize |
Max characters allowed for a program name (32 in this firmware). |
pd |
Array of Program Entries; each follows the structure below. |
Program Entry Structure:
[flag, days0, days1, [start0, start1, start2, start3], [dur0, dur1,...], name, [endr, from, to], sensorAdjustment]
| Field | Explanation |
|---|---|
flag |
Bitfield of program flags (see flag table below). |
days0,days1 |
Start-day data (see Start-day types below). |
start0..start3 |
Start-time data (see Start-time encoding below). |
dur? |
Per-station programmed durations in seconds (max: 64800). The length must equal station count. Supports two special values: 65534 → sunrise-to-sunset duration; 65535 → sunset-to-sunrise duration. These programmed values are capped at 64800, but the effective runtime after weather/sensor scaling may exceed it, up to the maxrt reported by /jpa. |
name |
Program name (≤pnsize characters). |
[endr,from,to] |
Date-range tuple (see Date-range tuple below). |
sensorAdjustment |
Sensor-adjustment object (described below), or {} when no sensor adjustment is assigned. |
flag bitfield
| bit(s) | Meaning |
|---|---|
0 |
Program enable flag (en). 1: enabled; 0: disabled. |
1 |
Use weather flag (uwt). 1: yes; 0: no. |
2–3 |
Odd/Even restriction. 0: none; 1: odd-day; 2: even-day; 3: undefined. |
4–5 |
Start-day type. 0: weekly; 1: single-run; 2: monthly; 3: interval-day. |
6 |
Start-time type. 0: repeating type; 1: fixed times. |
7 |
Date-range enable. 0: off; 1: on. |
Start-day Types. Depending on flag.bits[4-5]:
0→ Weekly:days0.bits[0-6]store the binary selections (LSB) from Monday to Sunday.days1is unused. Example:days0=127 (0b1111111)runs daily;days0=21 (0b0010101)runs Mon/Wed/Fri.1→ Single-run:days0anddays1together form a 16-bit unsigned integer encoding the day (epoch_seconds / 86400).2→ Monthly:days0stores the day of the month (1-31). Use0for the last day of a month.3→ Interval-day:days1is the interval day (everyNdays);days0is the remainder ("starting in" offset). Example:days1=3, days0=0means every3days starting today.
Start-time Encoding. Depending on flag.bit[6]:
1→ Fixed start-time: each ofstart0, 1, 2, 3is a 16-bit integer representing an independent start time. For each:- If
bit[15]=1(negative value), this start time is disabled. - If
bits[13-14]are both0, this is a standard time (0-1439) representing the minute count from00:00 AMto11:59 PM. - If
bit[13]=1, this is a sunset-based time; ifbit[14]=1, this is a sunrise-based time. In either case, the remaining bits define a signed offset from the sunset / sunrise time, withbit[12]being the sign (1=negative), andbits[0-10](i.e.start_time & 0x7FF) the absolute value of offset in minutes.
- If
0→ Repeating start-times:start0stores the first start-time (same encoding as above);start1is the repeat count;start2the interval (everyN) minutes;start3unused. Example:[480,5,120,0]→ start at8:00 AM, repeat every2hours for5times.
Date-range tuple: [endr,from,to]
endr: Date-range enable. Must equalflag.bit[7].from, to: Start and end dates, encoded as(month<<5)+day. Example:Feb 3is encoded as(2<<5)+3=67. Defaults:from=33 (Jan 1),to=415 (Dec 31).fromandtoare both inclusive. Iffrom=to, it defines a range of one day. Iffrom>to, the range wraps into the next year.
Sensor-Adjustment Object:
A program can scale its station run times by an Expanded Sensor reading, on top of the weather-based watering level. This adjustment is set via /cp's snadj parameter, and the resolved per-program factor is reported by /jpa as sa (with ta = wa × sa).
{"flag":flag,"uuid":uuid,"splits":[{"x":x0,"y":y0},{"x":x1,"y":y1},...]}
| Field | Explanation |
|---|---|
flag |
Bitmask. Bit 0 enables the adjustment; other bits are reserved. |
uuid |
Stable ID of the Expanded Sensor used by this program. |
splits |
Up to eight points mapping sensor values (x) to program adjustment factors (y). Points are sorted by nondecreasing x; duplicate x values are allowed and define a step. Values between points are linearly interpolated, while values outside the range use the nearest endpoint factor. |
If the adjustment is disabled, has no points, references a missing or disabled sensor, or the reading is unavailable, invalid, or stale, its effective factor is 1.0 (100%).
Example: {"nprogs":2,"nboards":1,"mnp":40,"mnst":4,"pnsize":32,"pd":[[3,127,0,[480,2,240,0],[0,2700,0,2700,0,0,0,0],"Summer",[0,33,415],{"flag":1,"uuid":5,"splits":[{"x":0,"y":1},{"x":500,"y":0.5}]}],[2,9,0,[120,0,300,0],[0,3720,0,0,0,0,0,0],"Fall Prog",[0,33,415],{}]]}
Change Program Data /cp
Usage: http://os-ip/cp?pw=xxx&pid=xx&en=x&uwt=x&name=xxx
&v=[flag,days0,days1,[start0,start1,start2,start3],[dur0,dur1,dur2…]]&from=xxx&to=xxx&snadj=flag,uuid,x0,y0,...
| Parameter | Meaning |
|---|---|
pid |
Program index, in the range [-1, N-1]. If pid=-1: add a new program; otherwise, modify an existing program. |
en |
Directly set the program's enable bit (flag.bit0). If present, all other parameters are ignored! |
uwt |
Directly set the uwt bit (flag.bit1). If present, all other params are ignored! |
name |
Program name (URL-encoded, without quotes). |
v |
Program body (see /jp endpoint), excluding name, from/to, and sensorAdjustment (set separately via snadj). |
from/to |
Date-range parameters (month<<5)+day (see /jp endpoint). |
snadj |
Optional sensor adjustment encoded as flag,uuid,x0,y0,x1,y1.... Bit 0 of flag enables the adjustment; uuid is the Expanded Sensor's stable ID; and the remaining values define up to eight points with nondecreasing x and nonnegative y. Omit this parameter when modifying a program to preserve its existing adjustment. Use snadj=0,0 (disabled, no sensor) to clear it. |
NOTE: The v parameter is still required when changing snadj: sensor adjustment cannot be modified as a standalone partial update. The program name Run-Once with repeat is reserved for temporary programs created by /cr and will thus be rejected here.
Examples:
os-ip/cp?pw=xxx&pid=0&en=0: disable program 1.os-ip/cp?pw=xxx&pid=1&uwt=1: enable "use weather" on program 2.os-ip/cp?pw=xxx&pid=-1&v=[3,127,0,[480,2,240,0],[1800,1200,0,0,0,0,0,0]]&name=Summer%20Prog: add an enabled program that uses weather adjustment, has no date range or day restriction, runs every day starting at8:00 AM, and repeats twice at4-hour intervals. Station 1 runs for30minutes and station 2 for20minutes. The program name is "Summer Prog".os-ip/cp?pw=xxx&pid=-1&v=[131,127,0,[480,2,240,0],[1800,1200,0,0,0,0,0,0]]&name=Winter%20Program&from=353&to=67: add a new program, enabled, using date range fromNov 1toFeb 3, named "Winter Program", the other parameters are the same as the "Summer Prog" aboveos-ip/cp?pw=xxx&pid=-1&v=[3,127,0,[480,2,240,0],[1800,1200,0,0,0,0,0,0]]&name=Sensor%20Adjusted&snadj=1,5,0,1,500,0.5: add a program using Expanded Sensor UUID5; its sensor factor decreases linearly from1.0at a reading of0to0.5at a reading of500.
Get Program Adjustments /jpa
Usage: http://os-ip/jpa?pw=xxx
Returns the current weather (wa), sensor (sa), and the total (ta) adjustment factors for each program, in the same program order as jp.pd. Factors use 1.0 for 100%; ta is wa × sa. maxrt is a fixed, universal cap on any single station's effective runtime (in seconds). Preview clients should calculate min(base_duration × ta, maxrt).
Example: {"jpa":[{"wa":1.25,"sa":0.8,"ta":1.0}],"maxrt":604800}
Manually Start a Program /mp
Usage: http://os-ip/mp?pw=xxx&pid=xx&uwt=x&usa=x&qo=x
| Parameter | Meaning |
|---|---|
pid |
Program index (starting from 0). |
uwt |
Use weather (1: apply the selected program's configured weather adjustment; 0: use a weather factor of 100%). Default: 0. |
usa |
Use sensor adjustment (1: apply the program's configured sensor adjustment; 0: use a sensor factor of 100%). Default: 0. |
qo |
Queuing option. 0: append the new program to the end of the queue; 1: insert at front (preemptive); 2: replace, i.e. reset all zones, clear queue, then start the new program. If qo is omitted, the default behavior is 2 (backward compatible). |
Notes:
- Program name annotations are honored. Stations started this way get program ID
254, as with/cr. An out-of-rangepidreturns17. - Station cycle-and-soak policies apply.
- A run that doesn't fit in the queue (see
/jn.qmax) is rejected whole with48and nothing changes; withqo=2, current watering is not stopped. - In Remote Extension mode,
uwt,usaand cycle and soak are bypassed.
Examples:
os-ip/mp?pw=xxx&pid=0&uwt=0: reset all zones, then start program 1 at 100% watering level. Asqois omitted, this behavior is backward compatible with previous firmware versions.os-ip/mp?pw=xxx&pid=1&uwt=1&qo=0: append program 2 at the end of the queue, using the current watering level.os-ip/mp?pw=xxx&pid=1&uwt=1&qo=1: insert program 2 at the front of the queue.os-ip/mp?pw=xxx&pid=1&uwt=1&usa=1&qo=2: reset all zones, then start program 2 using both its weather and sensor adjustments.
Delete Program(s) /dp
Usage: http://os-ip/dp?pw=xxx&pid=x
pid: Program index in [0, N-1]. pid=-1 deletes ALL existing programs.
Examples:
os-ip/dp?pw=xxx&pid=1: delete program 2.os-ip/dp?pw=xxx&pid=-1: delete all programs.
Move Up (Re-order) a Program /up
Usage: http://os-ip/up?pw=xxx&pid=x
pid: Program index in [1, N-1]. pid=0 has no effect.
Examples:
os-ip/up?pw=xxx&pid=2: move program 3 up, before program 2.os-ip/up?pw=xxx&pid=0: no effect as the program 1 cannot be moved up.
Run-Once Program /cr
Usage: http://os-ip/cr?pw=xxx&t=[x,x,...,x]&cnt=xxx&int=xxx&uwt=xxx&anno=xxx&qo=x
| Parameter | Meaning |
|---|---|
t |
Array of per-station duration (in seconds). A value of 0 means that station does not run. Stations launched via this command are assigned program ID 254. |
cnt |
Repeat count. 0: run once (no repeats). |
int |
Repeat interval (in minutes). Must be >0 if and only if cnt>0. |
uwt |
Use weather. 1: apply current watering level to durations; 0: no. |
anno |
Program name annotation, in the form of >X where X is an annotation letter. See OpenSprinkler User Manual. |
qo |
Queuing option (same as /mp). 0: append to end; 1: insert at front; 2: replace (reset all zones, clear queue, then start). Default is 2 if qo is omitted. |
NOTES:
- The
tvalue must be a well-formed bracketed, comma-separated list. Fewer entries than the current station count are treated as trailing zero durations. Extra entries are validated but ignored, which permits a saved list from a previously larger station configuration. - Station cycle-and-soak policies apply.
- A run that doesn't fit in the queue (see
/jn.qmax) is rejected whole with48and nothing changes: current watering isn't stopped and no repeat program is created. - In Remote Extension mode,
uwtand cycle and soak are bypassed, andcnt>0returns48. - If the program is set to repeat (
cnt>0andint>0), the firmware auto-creates a single-run program named "Run-Once with repeat" (plusanno). This is necessary to support repeats.
Examples:
os-ip/cr?pw=xxx&t=[60,0,60,0,60,0,60,0]: reset all zones, then start a run-once program that turns on stations 1, 3, 5, and 7 for1minute each. Asqois omitted, this behavior is compatible with previous firmware versions.os-ip/cr?pw=xxx&t=[60,0,60,0,60,0,60,0]&uwt=1&qo=0: append the run-once program at the end of the queue, using the current watering level.os-ip/cr?pw=xxx&t=[60,0,60,0,60,0,60,0]&uwt=0&qo=1: insert the run-once program at the front of the queue, using 100% watering level.os-ip/cr?pw=xxx&t=[60,0,60,0,60,0,60,0]&cnt=3&int=15&anno=>N: similar to the first example above, but also set it to repeat every15minutes for3times. This auto-creates a single-run program, appending the annotation>Nto the program name (>Ntells the program to run zones in reverse order of zone names).
Sprinkler Logs
Get Sprinkler Log Data /jl
Usage:
http://os-ip/jl?pw=xxx&start=xxx&end=xxx&type=x
http://os-ip/jl?pw=xxx&hist=n&type=x
Either selector supports additional parameters including fmt, page, cursor, and count. Use fmt=binary&page=1 for paginated binary output.
| Parameter | Meaning |
|---|---|
start |
Start time (epoch seconds), inclusive. |
end |
End time (epoch seconds), inclusive. Max span: 365 days. |
hist |
History window in days back from today. 0: today only; 1: today and yesterday; and so on. Max span: 365 days. all is supported with binary output only. |
type |
Filter special events (indicated by pid=0). Choices: s1,s2,s3,s4,rd,fl,wl. s3 and s4 are available on OpenSprinkler v3.4 and v4. |
fmt |
Output format. Default: json. Set to binary for compact, paginated output. |
page |
Required as page=1 with fmt=binary. |
cursor |
Binary mode only: opaque pagination token from the preceding response's X-OS-Next-Cursor header. Omit on the first page. The current token is 12 hexadecimal characters, but clients should not parse or modify it. |
count |
Binary mode only: maximum physical log slots scanned in one page. Default: 100; maximum: 2500. Deleted or filtered slots count toward this limit but are not returned. |
For cycle and soak stations: each watering cycle is logged as a separate record.
Log Record Format
[pid,sid,dur,end]: standard run[pid,sid,dur,end,flow]: with the Built-in flow sensor enabled (5th element)
| Field | Meaning |
|---|---|
pid |
Program index (1-based); special events use pid=0. |
sid |
Station index (0-based); or a special event code (string) when pid=0. |
dur |
Duration in seconds. Weather- and sensor-adjusted runs may exceed 65535, up to /jpa.maxrt. |
end |
End time (epoch seconds). |
flow |
Average pulses per minute after the station's 90-second settling period (present only if the Built-in flow sensor is enabled). Multiply by ((fpr1 << 8) + fpr0) / 100 to obtain volume per minute. |
Special Event Code
A log record is a special event if its pid=0, in which case sid is a string code:
sid |
Meaning |
|---|---|
s1-s4 |
Built-in Sensor SN1-SN4 event. SN3/4 events are available on OpenSprinkler v3.4 and v4. |
rd |
Rain delay event |
fl |
Program-cycle flow event; the first numeric value is the total pulse count. |
wl |
Watering level log |
Example Request: http://os-ip/jl?pw=pw_md5&start=1413567367&end=1413657367
Response: [[3,17,616,1413511817], [0,"rd",86400,1413511845], [254,1,5,1413512107], [1,3,2700,1413552661], [5,3,1200,1413559201]]
Binary Pagination
Binary mode returns zero or more 16-byte little-endian records from the bounded sprinkler-log ring. It supports hist=all, numeric hist, or a start/end range (including ranges longer than 365 days) because each request is bounded by count. Repeat the request using X-OS-Next-Cursor exactly as returned, and stop only when X-OS-Page-Done is 1. These pagination headers are returned only in binary mode; JSON mode retains its legacy response format.
Sprinkler Logs written by firmware before 2.2.1(6) are not returned by /jl. OpenSprinkler v3/v4 removes those legacy files during the first 2.2.1(6) boot; Linux and OSPi preserve them on disk for manual archival or deletion.
Response headers:
| Header | Meaning |
|---|---|
X-OS-Next-Cursor |
Opaque cursor for the next page. |
X-OS-Page-Done |
1 when the requested window is exhausted; otherwise 0. |
X-OS-Scanned-Slots |
Number of physical slots consumed by this page, including deleted and filtered records. |
X-OS-Record-Size |
Binary record size; currently 16. |
Binary record layout:
| Offset | Type | Field | Meaning |
|---|---|---|---|
0 |
uint32 |
timestamp |
Run end or event time, in epoch seconds. |
4 |
uint32 |
value |
Station duration, or the special event's second numeric value. |
8 |
uint32 |
aux |
For station records with the flow flag, average pulses per minute multiplied by 100; divide by 100, then apply the fpr factor above to obtain volume per minute. For special events, the first numeric value. |
12 |
uint8 |
type |
0: station; 1: s1; 2: rd; 3: wl; 4: fl; 5: s2; 6: s3; 7: s4; 128: cu. |
13 |
uint8 |
program |
Program identity for station records. |
14 |
uint8 |
station |
Zero-based station index for station records. |
15 |
uint8 |
flags |
Bit 0: aux contains station flow; remaining returned bits are reserved. |
Delete Sprinkler Log Data /dl
Usage:
http://os-ip/dl?pw=xxx&day=n
http://os-ip/dl?pw=xxx&before=n
day: Day index calculated as floor(epoch_seconds/86400). Use day=all to delete all Sprinkler Logs. NOTE: This does not delete Expanded Sensor logs; use /dsl for those.
before: First day index to retain. Records from earlier days are deleted. This form efficiently removes complete older log segments and may be repeated safely.
Examples:
os-ip/dl?pw=xxx&day=16361: delete the log file for dayOct 18, 2014.os-ip/dl?pw=xxx&day=all: delete all Sprinkler Log files.os-ip/dl?pw=xxx&before=20000: delete Sprinkler Log records older than day index20000(Oct 4, 2024).
Combined Data & Diagnostics
Get All /ja
Usage: http://os-ip/ja?pw=xxx
Returns a single JSON combining the return values of /jc, /jo, /jn, /js, /jp, and /jsn.
| Variable | Source |
|---|---|
settings |
/jc (controller variables) |
options |
/jo (options) |
stations |
/jn (station names and attributes) |
status |
/js (station status) |
programs |
/jp (program data) |
sensors |
/jsn (Expanded Sensor data) |
Example Return: {"settings":{...},"options":{...},"stations":{...},"status":{...},"programs":{...},"sensors":{...}}
Debug Information /db
Usage: http://os-ip/db
Returns platform- and build-specific diagnostic information. Authentication is not required. Fields may be added, removed, or changed between builds and should not be treated as a stable application API.
New diagnostic fields include:
| Field | Meaning |
|---|---|
hostname |
Effective network hostname (v3/v4). |
eth_controller |
Active wired controller: enc28j60, w5500, ch390, or none. Wired fields appear only when the controller uses wired Ethernet; otherwise /db reports Wi-Fi fields. |
eth_link, eth_has_ip |
Wired link and IP availability (0/1). |
ch_diag_valid |
Whether CH390 diagnostics are available (0/1). |
ch_bad_ready, ch_bad_header, ch_rx_errors, ch_rx_resets, ch_tx_timeouts, ch_health_failures |
CH390 error and receive-reset counters. |
ch_rx_deferred, ch_empty_ready, ch_rx_incomplete |
CH390 deferred reads, ready-byte detections on an empty ring, and incomplete-frame observations. These do not necessarily indicate faults. |
ch_recoveries, ch_recovery_failures |
CH390 recovery counters. |
ch_fault, ch_fault_ms, ch_pending |
Last CH390 fault code, its time in milliseconds since boot, and recovery-pending flag. |
stack_min |
Minimum free continuation-stack space since boot, in bytes (v3). |
List Files /lf
Usage: http://os-ip/lf?pw=xxx
Lists files and their sizes on the internal file system. This endpoint is available on OpenSprinkler v3 and v4.
Response: {"files":[["/filename",size],["/logs/filename",size],...]}
MQTT Command Subscriptions
When MQTT is enabled and a subscription topic (subt) is configured, the controller accepts selected API commands as MQTT message payloads. The payload uses the endpoint name without a leading slash, followed by the same query parameters as the HTTP endpoint:
cm?pw=xxx&sid=0&en=1&t=300&qo=2
pw is the lowercase MD5 hash of the device password, as with HTTP API requests. It may be omitted only when Ignore Password is enabled on the controller. MQTT commands are fire-and-forget: the controller does not publish an acknowledgement or result code. An invalid or rejected command therefore produces no MQTT response.
| Command | Supported behavior |
|---|---|
cv |
Supports rsn, rbt, en, and rd. Their validation and effects match /cv. Other /cv actions are intentionally not exposed through MQTT. rsn and rbt trigger only when their value is greater than 0. |
cm |
Supports the parameters and behavior of /cm, including qo and cs. Starting a station that is already running or queued is rejected, as is stopping a station that is not queued. |
mp |
Supports the parameters and behavior of /mp, including uwt, usa, and qo. |
cr |
Supports the parameters and behavior of /cr, including cnt, int, uwt, anno, and qo. |
On OpenSprinkler v3 and v4, the MQTT library has a 256-byte packet limit. The MQTT topic and protocol overhead count toward this limit, so the available payload length is less than 256 bytes and varies with the topic length. Commands that exceed the limit are silently discarded by the MQTT library before the firmware receives them. This primarily affects /cr payloads containing durations for many stations. OSPi/Linux uses libmosquitto and has no firmware-defined 256-byte packet limit, although its broker and system configuration may impose limits. Use the HTTP API for commands that do not fit in one MQTT packet.
Reference Tables
Reboot Cause Codes
Interpretation of the lrbtc variable in /jc result.
Source: https://github.com/OpenSprinkler/OpenSprinkler-Firmware/blob/master/defines.h
| Code | Cause |
|---|---|
| 0 | None/unknown |
| 1 | Factory reset |
| 2 | Button triggered |
| 3 | Reset to AP mode |
| 4 | API/timer triggered |
| 5 | API triggered reboot |
| 6 | Switched from AP to client mode |
| 7 | Firmware update |
| 8 | Weather call failed >24h |
| 9 | Network failed too many times |
| 10 | NTP sync reboot |
| 11 | Program-triggered reboot |
| 99 | Power-on |
Weather Error Codes
Interpretation of the wterr variable in /jc result.
| Code | Meaning |
|---|---|
| 0 | Success |
| -1 | Request not received |
| -2 | Cannot connect to weather server |
| -3 | Request timed out |
| -4 | Received empty response |
Positive codes are application errors from the weather service. Refer to https://github.com/OpenSprinkler/OpenSprinkler-Weather/blob/master/src/errors.ts