System Variables
System variables are named, server-side values refreshed on an interval by variable drivers (sun & moon times, weather, water levels, calendar events, and more). They can be referenced anywhere a dynamic attribute is accepted — macro conditions, triggers, and schedule rules — using the [$variable_name] syntax.
The Variables Page
Open Variables
Admin → Automation → Variables manages variable driver instances. The grid lists each configured instance with its driver, prefix, interval, description, configuration, and enabled state. Use the grid's Add or Edit buttons to open the full-page editor, Reload to restart an instance, or Delete to remove it. The editor fields are:
- Driver — pick from the installed variable drivers; selecting one shows the driver's description and pre-fills its default interval and configuration template for new rows. Each driver self-describes (template, per-field documentation, produced variables), so the editor guidance always matches the installed drivers.
- Prefix — optional, prepended to every variable name the instance produces. Required to run two instances of the same driver (e.g. two
usgs_waterdatainstances watching different basins). - Update Interval — entered as a value plus unit (seconds/minutes/hours). The minimum accepted interval is 1 second.
- Description — optional free-text note ("what this instance is for"); shown in the grid and beside the values.
- Enabled — toggle. A disabled instance stops polling and produces no values; re-enabling it resumes on save.
- Configuration — a schema-driven form generated from the driver's metadata: typed inputs per field with inline documentation, a map picker for latitude/longitude fields (search by address or zip, or click the map), and a Raw JSON toggle for hand-editing. Insert Template restores the driver's example shape.
- Produced Variables — the variable names this instance will register, derived live from the driver and your current configuration (so a USGS stations-mode list updates as you add stations, even before you save). Click one to copy its
[$name]reference.
Saving (or deleting/disabling) reloads the driver instance immediately — no restart needed, and the first update runs right away (the toast confirms "first update is running").
Below the grid, Current Values shows every stored variable value, grouped under the instance that produces it. Click a name to copy its [$name] reference; Refresh re-reads the latest values.
How Variables Work
Each configured instance carries:
| Field | Purpose |
|---|---|
| Driver | Which variable driver to run (see list below) |
| Interval | Refresh period |
| Configuration | Driver-specific settings (JSON) |
| Prefix | Optional prefix applied to every variable name the driver produces |
| Description | Optional note describing the instance |
| Enabled | Whether the driver runs |
On boot (and whenever you save, reload, disable, or delete a row) the server (re)starts each enabled instance, runs an immediate update, and then refreshes on the configured interval. Each update writes its values to the variable store and an in-memory cache, so [$name] references resolve instantly.
Referencing Variables
A stored value can be dropped into any field that accepts a dynamic attribute — a macro If (condition) step, an Attribute Trigger condition, a Set Attribute step, or a Macro Schedule rule — using [$variable_name]:
[$outdoor_temperature]— the raw value[$lake_elevation] > 493— a trigger or condition comparison[$sunset]— as a schedule rule, fires the macro at the next sunset
You can also do light math on the value inline:
- Date/time variables take
+N/-Nin minutes:[$sunset]+30is 30 minutes after sunset,[$sunrise]-15is 15 minutes before. These are the rules to use for "X minutes after sunrise/sunset" schedules. - Numeric variables take an operator (
+,-,*,/) and/or a clamp:min:max:[$outdoor_temperature]-2,[$wind_speed]*2, or[$x]*10:0:100(multiply, then clamp to 0–100). Integer variables round to the nearest whole number.
Click any name in Current Values (or Produced Variables in the editor) to copy its [$name] reference to the clipboard.
Built-In Drivers
| Driver (display name) | Variables Produced | Default Interval |
|---|---|---|
sun_moon (Sun & Moon) | sunrise, sunset, dawn, dusk, night (each a date/time), moon_phase | 1 hour |
weather (Weather) | outdoor_temperature, feels_like, outdoor_humidity, dew_point, wind_speed, wind_gust, wind_direction, air_pressure, visibility, cloud_cover, uv_index, precipitation, precipitation_today, precipitation_chance, weather_code, weather_condition, today_high, today_low, tomorrow_high, tomorrow_low, tomorrow_precipitation_chance, tomorrow_condition | 10 minutes |
season (Season) | season (spring / summer / fall / winter) | 24 hours |
datetime (Date & Time) | time (date), hour, minute, day_of_week, day_of_month, month, year | 1 minute |
google_calendar (Google Calendar) | google_calendar (JSON array of upcoming events) | 15 minutes |
usgs_waterdata (USGS Water Data) | lake_elevation, streamflow, gage_height, precipitation, water_temperature for a location (or per-station readings — see below) | 15 minutes |
A few details that affect setup:
- Sun & Moon, Weather, and USGS Water Data need a latitude/longitude — use the map picker in the Configuration form. Season and Date & Time need no configuration.
- Sun & Moon date variables always hold the next upcoming occurrence — once today's sunset passes,
sunsetrolls to tomorrow's. Moon phase is one ofnew_moon,waxing_crescent,first_quarter,waxing_gibbous,full_moon,waning_gibbous,last_quarter,waning_crescent. - Date & Time values are in the server's time zone.
day_of_weekisSunday–Saturdayandmonthis the full month name (January–December). - Weather fetches from the free Open-Meteo forecast API (the same service the weather page and widget use) — no API key, account, or URL configuration needed; just the latitude/longitude. Values are imperial (°F, mph, inches, miles) by default; add
"units": "metric"to the configuration JSON for °C / km/h / mm / km.precipitation_chanceis today's maximum probability of precipitation;weather_conditionis condition text likepartly cloudyorlight rain(weather_codeis the raw WMO code behind it). - Google Calendar needs the calendar shared with the GEM service account and an access token from the GEM calendar bridge; each event is stored as
{summary, organizer, status, start, end, location}.
USGS Water Data (usgs_waterdata)
Reads latest readings from the USGS Water Data OGC API for any USGS-hosted monitoring location nationwide. This includes cooperator networks published through USGS — for example the LCRA Highland Lakes gauges in Texas under agency code TX071.
Location Mode (recommended)
Give the driver a latitude/longitude and it auto-selects the best live gauge for each metric and produces a fixed set of variables:
{
"api_key": "optional — raises rate limits",
"latitude": 30.345,
"longitude": -97.84,
"radius_km": 25,
"overrides": {"streamflow": "USGS-08158000"}
}
Variables produced (float): lake_elevation (ft), streamflow (cfs), gage_height (ft), precipitation (in), water_temperature (°C). A metric with no live gauge in radius stays unset (logged once; the driver keeps checking each cycle in case one comes online).
How gauges are selected:
- Only gauges with a fresh reading qualify (within
max_age_hours, default 48) — discontinued stations whose "latest" value is years old are ignored. streamflowandgage_heightprefer the gauge with the largest drainage area in radius, then nearest — so the river main stem wins over a nearer storm creek reading 0 cfs. All other metrics pick the nearest qualifying gauge.- Selections are pinned for the life of the instance and logged at startup (
streamflow -> USGS-08158000 Colorado Rv at Austin, 18.9km), so automation never silently switches gauges mid-season. Restart (save the variable) to re-select. overridespins a specific station per metric when the heuristic picks wrong — e.g. nearest water temperature may be a spring-fed site that doesn't reflect your lake.
Run multiple instances with different prefixes to watch more than one location (e.g. an unprefixed instance for the property plus a travis-prefixed one upstream).
Stations Mode (advanced)
Watch an explicit station list instead — useful for stations outside any sensible radius or parameters beyond the canonical five:
{
"api_key": "optional",
"stations": [
{"id": "TX071-08154500", "alias": "lake_travis", "parameters": ["00062"]},
{"id": "TX071-08161400"}
]
}
id(required) — the monitoring location id,AGENCY-SITENUMBER. Discover stations via the API'smonitoring-locationscollection (e.g.?agency_code=TX071or abbox).alias(optional) — friendly base name; defaults to the id lowercased (tx071_08161400).parameters(optional) — USGS parameter codes to keep; omit to store everything the station reports.
Each reading is stored as <alias>_<parameter_name> (float). Common parameter codes:
| Code | Name | Unit |
|---|---|---|
00060 | streamflow | cfs |
00065 | gage_height | ft |
00062 | lake_elevation | ft above datum |
62614 / 62615 | lake_elevation_ngvd29 / lake_elevation_navd88 | ft |
00045 | precipitation | in |
00010 / 00020 | water_temperature / air_temperature | °C |
00095 | specific_conductance | µS/cm |
00300 | dissolved_oxygen | mg/L |
00400 | ph | — |
63680 | turbidity | FNU |
Unmapped codes are stored as param_<code>. If both stations and a latitude/longitude are present, stations mode wins.
Notes
- Readings are near-real-time (typically 15-minute telemetry) and flagged provisional by USGS until reviewed.
- Readings older than
max_age_hours(default 48) are skipped in both modes. - A station that returns no readings or a non-numeric value is logged and skipped; one failing station does not block the others.
- Per the data volume, an
update_intervalof 15–60 minutes is appropriate. - Example triggers:
[$lake_elevation] > 493(flood watch),[$streamflow] > 5000(high flow),[$lake_travis_lake_elevation] < 660(drought stage, via a stations-mode instance).
Related
- Triggers — fire a macro when a variable crosses a threshold (e.g.
[$lake_elevation] > 493). - Macros — reference variables in If/condition and Set Attribute steps.
- Macro Schedules — use
[$sunrise]/[$sunset](optionally+N/-Nminutes) as a schedule rule.