Skip to content

Schedule

The schedule endpoint returns today’s optimized temperature plan for an HVAC unit. 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)

ParamRequiredNotes
appliance_idConditionalUUID of the HVAC unit whose schedule to return. Required (returns 400) when the account has 2+ HVAC units — otherwise the endpoint can’t tell which one you mean. Single-HVAC accounts may omit it; it resolves to their only HVAC.
Terminal window
curl "https://api.hungrymachines.io/api/v1/schedule?appliance_id=a1b2c3d4-..." \
-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 — the thermostat never sees this value.
schedule.low_tempsfloat[48]Per-interval lower comfort bound (°F). Display-only.
schedule.setpoint_tempsfloat[48] | nullThe 48-element command to apply to the thermostat at each 30-min boundary, regardless of HVAC mode. null on source: "defaults" and on legacy rows — fall back to (high_temps[i] + low_temps[i]) / 2.
schedule.temp_trajectoryfloat[48] | nullPredicted indoor-temperature line for charting. Display-only. null on defaults / legacy rows.
modestring"cool", "heat", "auto", or "off"
estimated_savings_pctfloatDisplay-only estimated % savings vs. a naive fixed-setpoint thermostat
model_confidencefloat | nullDisplay-only learning-confidence indicator in [0, 1] — higher means the schedule is based on more-established learning. null while on defaults. Treat it as a progress signal; don’t interpret the exact value.
generated_atstringWhen the schedule was produced (UTC ISO 8601)
stalebooleanOnly present (and true) when returning a prior day’s schedule because none was produced 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

Slot 0 begins at local midnight (the account’s configured timezone). Compute the current interval as interval = hour * 2 + (1 if minute >= 30 else 0) using local time.

If no schedule was produced today, the most recent available one is returned with stale: true:

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

Before Hungry Machines has learned enough about the home, 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 when your client starts and once a day (after the overnight run).
  2. Cache the response locally.
  3. Every 30 minutes, look up the current interval idx and apply setpoint_temps[idx]. If setpoint_temps is null, apply the midpoint of high_temps[idx] and low_temps[idx].
StatusDetailCause
400"User has multiple HVAC appliances; pass appliance_id to disambiguate."2+ HVAC units and no appliance_id supplied
401"Not authenticated"Missing or invalid token

Recompute schedules synchronously for the account and return the fresh result. Built for “user just hit Save on a constraint editor — show the new chart now” flows. The response is the same shape as GET /api/v1/schedules (all appliances at once), plus a results array reporting each appliance’s outcome for this run.

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, plus results:

{
"date": "2025-11-18",
"appliances": ["<same entries as GET /api/v1/schedules>"],
"results": [
{ "appliance_id": "uuid-1", "appliance_type": "hvac", "name": "Office AC", "status": "ok" },
{ "appliance_id": "uuid-2", "appliance_type": "hvac", "name": "Front AC", "status": "failed", "detail": "weather fetch failed" }
]
}

results[].status values:

ValueMeaning
okA fresh schedule was produced for this appliance.
failedThis appliance did not re-optimize; detail carries a short reason. Its previous schedule is still in appliances. Tell the user it didn’t update.
calibratingA one-time warm-up is active for this HVAC; constraint changes won’t reflect on its chart until it completes.
forecastSolar — nothing to schedule.
observeDehumidifier — data-collection only.
skippedUnknown appliance type.

Account-level early exits (no profile, weather fetch failed, optimization_mode == "off") return an empty results array with the previous appliances entries.

Typically 1–5 seconds. 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 stored row without triggering a recompute.

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