Skip to content

Schedule

The schedule endpoint returns today’s optimized temperature plan for your HVAC system. Call it once daily to get 48 half-hour intervals covering the next 24 hours.

For multi-appliance schedules (HVAC + EV charger + battery + water heater in one call) use /api/v1/schedules.

Auth: Required (Bearer JWT)

Terminal window
curl https://api.hungrymachines.io/api/v1/schedule \
-H "Authorization: Bearer YOUR_TOKEN"
{
"date": "2025-11-18",
"schedule": {
"intervals": [0, 1, 2, "...", 47],
"high_temps": [74.0, 74.0, "...(48 values)"],
"low_temps": [70.0, 70.0, "...(48 values)"],
"setpoint_temps": [72.0, 71.5, "...(48 values)"],
"temp_trajectory": [72.1, 71.6, "...(48 values)"]
},
"mode": "cool",
"estimated_savings_pct": 18.5,
"model_confidence": 0.23,
"generated_at": "2025-11-18T04:15:00+00:00",
"source": "optimization"
}
FieldTypeDescription
datestringSchedule date (YYYY-MM-DD)
schedule.intervalsint[48]Always [0, 1, ..., 47] — 48 half-hour slots
schedule.high_tempsfloat[48]Per-interval upper comfort bound (°F). Display-only reference for charts; the thermostat does not see this value.
schedule.low_tempsfloat[48]Per-interval lower comfort bound (°F). Display-only — same as high_temps.
schedule.setpoint_tempsfloat[48] | nullThe 48-element command the integration applies to the thermostat at each 30-min boundary. Single source of truth for what to set, regardless of HVAC mode (cool, heat, auto). null on source: "defaults" rows and on legacy rows generated before this field existed.
schedule.temp_trajectoryfloat[48] | nullUnclamped indoor-temperature forecast from the simulator for charting. null on defaults / legacy rows.
modestring"cool", "heat", "auto", or "off"
estimated_savings_pctfloatEstimated % savings vs. a naive fixed-setpoint thermostat
model_confidencefloat | nullR-squared of the fitted thermal model. null while the user is still on defaults.
generated_atstringWhen the optimization ran (UTC ISO 8601)
stalebooleanOnly present (and true) when returning a prior day’s schedule because no run completed today
sourcestring"optimization" or "defaults"

Every schedule contains exactly 48 intervals, each a 30-minute window:

IntervalTime
000:00–00:30
100:30–01:00
1608:00–08:30
3417:00–17:30
4723:30–00:00

Compute the current interval as interval = hour * 2 + (1 if minute >= 30 else 0). All timestamps in the API are UTC — convert to your local timezone before applying.

If no optimization ran today (e.g., the nightly job hasn’t fired yet, or a network blip prevented it), the most recent available schedule is returned with stale: true:

{
"date": "2025-11-17",
"stale": true,
"source": "optimization",
"...": "..."
}

If the optimizer hasn’t yet produced a per-user thermal model, the response uses the comfort band derived from your preferences with setpoint_temps: null:

{
"date": "2025-11-18",
"schedule": {
"intervals": [0, 1, "...", 47],
"high_temps": [73.5, 73.5, "...(all same)"],
"low_temps": [70.5, 70.5, "...(all same)"]
},
"mode": "cool",
"estimated_savings_pct": 0,
"model_confidence": null,
"generated_at": "2025-11-18T12:00:00+00:00",
"source": "defaults"
}
  1. Call GET /api/v1/schedule once when your client starts and once daily (e.g., after 06:30 UTC when nightly + initial-fit have both completed).
  2. Cache the response locally.
  3. Every 30 minutes, look up the current interval idx and apply setpoint_temps[idx] to your thermostat. If setpoint_temps is null, fall back to the midpoint of high_temps[idx] and low_temps[idx].
StatusDetailCause
401"Not authenticated"Missing or invalid token

Run optimization synchronously for the authenticated user and return the freshly-written schedules. Designed for “user just hit Save on a constraint editor — show them the new chart now” flows; the response is the same shape as GET /api/v1/schedules (all appliances at once), not a single schedule.

Auth: Required (Bearer JWT)

Terminal window
curl -X POST https://api.hungrymachines.io/api/v1/schedule/recompute \
-H "Authorization: Bearer YOUR_TOKEN"

Same shape as GET /api/v1/schedules:

{
"date": "2025-11-18",
"appliances": [
{
"appliance_id": "...",
"appliance_type": "hvac",
"name": "Living Room AC",
"schedule": {
"intervals": [0, 1, "...", 47],
"high_temps": [74.0, "..."],
"low_temps": [70.0, "..."],
"setpoint_temps": [72.0, "..."],
"temp_trajectory": [72.1, "..."]
},
"savings_pct": 18.5,
"source": "optimization",
"entities": { "entity_id": "climate.thermostat" }
}
]
}

Typically 1–5 seconds. Worst case is bounded by the HVAC optimizer’s 28-second budget plus a couple of fast non-HVAC runs. Show an “Optimizing…” overlay while the request is in flight.

  • Right after the user changes constraints, comfort bands, or optimization_mode and expects to see the impact immediately.
  • After saving a custom rate curve via PUT /api/v1/rates.

For the regular daily fetch, use GET /api/v1/schedule or GET /api/v1/schedules — they read the most recent persisted row without triggering a recompute.

StatusDetailCause
401"Not authenticated"Missing or invalid token
503"Database unavailable"Supabase not reachable