Skip to content

Preferences

The preferences endpoints let you configure your comfort settings and optimization mode. These values control how aggressively the optimizer shifts energy usage.

These are account-level preferences. For a home with more than one HVAC, each unit also has its own per-HVAC preferences with the same shape. Planning for a unit follows these account-level values until that unit’s own preferences are saved, and the account-level values stay authoritative for account-scope fields.

See also Rates for the electricity rate curve the optimizer saves against.

Auth: Required (Bearer JWT)

Terminal window
curl https://api.hungrymachines.io/api/v1/preferences \
-H "Authorization: Bearer YOUR_TOKEN"
{
"base_temperature": 72.0,
"savings_level": 1,
"time_away": "08:00",
"time_home": "17:00",
"optimization_mode": "cool",
"hourly_high_temps_f": null,
"hourly_low_temps_f": null,
"optimize_hvac_fan": false,
"optimize_hvac_mode": false,
"optimization_enabled": true,
"newsletter_opt_in": true,
"spike_guard_enabled": true,
"max_concurrent_appliances": null,
"power_cap_kw": null,
"base_load_reserve_kw": 0.0,
"demand_charge_usd_per_kw": null,
"demand_window_start": null,
"demand_window_end": null
}

If the user hasn’t set preferences yet, defaults are returned.

Field Type Default Description
base_temperature float 72.0 Desired temperature (°F)
savings_level integer 1 1 = tight, 2 = moderate, 3 = aggressive. Stored and returned; it does not change the default comfort band. To widen or narrow comfort, set the two hourly arrays.
time_away string "08:00" When you typically leave home (HH:MM, 24-hour). Stored and returned; it does not change the default comfort band.
time_home string "17:00" When you typically return home (HH:MM, 24-hour). Stored and returned; it does not change the default comfort band.
optimization_mode string "cool" "cool", "heat", "auto", or "off"
hourly_high_temps_f array[float] | null null Optional 24-element per-hour upper comfort bound (°F). When set, the two hourly arrays are the comfort band. When null, the default band applies.
hourly_low_temps_f array[float] | null null Optional 24-element per-hour lower comfort bound (°F). Must be set together with hourly_high_temps_f.
optimize_hvac_fan boolean false Opt-in: also emit a per-slot fan-speed schedule.
optimize_hvac_mode boolean false Opt-in: also emit a per-slot HVAC-mode schedule.
optimization_enabled boolean true Master pause switch. When false, clients must stop applying schedules entirely until re-enabled. Schedules are still computed, so re-enabling takes effect at the next half-hour boundary.
newsletter_opt_in boolean true Newsletter membership. Changing only this field does not trigger a schedule recompute.
spike_guard_enabled boolean true Automatically avoid real-time price spikes on plans that support it. Your comfort range always applies. Turn off any time.
max_concurrent_appliances integer | null null Limit how many appliances (EV charger, home battery, water heater, etc.) may run at the same time. null = no limit.
power_cap_kw float | null null A whole-home power ceiling (kW) the planner respects. null = no cap.
base_load_reserve_kw float 0.0 Power (kW) always reserved for everyday always-on draw before the planner spends the rest of power_cap_kw.
demand_charge_usd_per_kw float | null null Your utility’s demand charge rate ($/kW), if any, so the planner avoids a new monthly peak. null = no demand charge.
demand_window_start string | null null HH:MM start of the hours your demand charge applies. null with demand_window_end also null = all day.
demand_window_end string | null null HH:MM end of the hours your demand charge applies.

Without an explicit override, every home gets the same default band, set only by base_temperature and optimization_mode. At a base of 72 °F in cool mode it is 70–73 °F for hours 0–7 and 22–23, and 67–78 °F for hours 8–21. A different base shifts both bounds by the same amount, and heat mode mirrors the shape so the wider side is below the base. savings_level, time_away and time_home do not change it. See default bands below to preview the exact per-hour values.

If you want different per-hour bounds — for example, a tighter band during occupied hours and a wider band overnight — submit hourly_high_temps_f and hourly_low_temps_f together.

  • Both arrays must be set together, or both must be null to clear the override and return to the default band. Always send both in the same request.
  • Each array is exactly 24 values, indexed 0 (midnight) through 23 (11 PM local time).
  • Each value must be in [50, 90] °F.
  • For every hour i, hourly_low_temps_f[i] < hourly_high_temps_f[i].
  • When the override is set, the explicit bounds apply at every hour.

Example: tighter [68, 74] band from 8 AM through 9 PM, wider [64, 78] band overnight.

{
"hourly_high_temps_f": [78, 78, 78, 78, 78, 78, 78, 78, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 78, 78],
"hourly_low_temps_f": [64, 64, 64, 64, 64, 64, 64, 64, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 64, 64]
}

Auth: Required (Bearer JWT)

Update one or more preference fields. All fields are optional — only the fields you include are changed; others keep their current values. To leave a field unchanged, omit it; send null only for the fields the table below marks as clearable. Any change other than newsletter_opt_in alone triggers a debounced recompute of today’s schedule.

Terminal window
curl -X PUT https://api.hungrymachines.io/api/v1/preferences \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"base_temperature": 73.0,
"savings_level": 2,
"optimization_mode": "auto"
}'

All fields are optional — include only what you want to change.

{
"base_temperature": 73.0,
"savings_level": 2,
"time_away": "07:30",
"time_home": "18:00",
"optimization_mode": "auto"
}
Field Constraints
base_temperature 60.0–85.0 °F
savings_level 1, 2, or 3
time_away HH:MM, 24-hour, 00:00–23:59
time_home HH:MM, 24-hour, 00:00–23:59
optimization_mode "cool", "heat", "auto", "off"
hourly_high_temps_f Exactly 24 finite floats, each in [50, 90] °F
hourly_low_temps_f Exactly 24 finite floats, each in [50, 90] °F
hourly_low_temps_f[i] < hourly_high_temps_f[i] Per-hour lower bound must be strictly less than upper bound
hourly_high_temps_f + hourly_low_temps_f Both fields must be set together (or both null to clear)
optimize_hvac_fan true / false
optimize_hvac_mode true / false
optimization_enabled true / false
newsletter_opt_in true / false
spike_guard_enabled true / false
max_concurrent_appliances Integer >= 1, or null to clear
power_cap_kw Float > 0, or null to clear
base_load_reserve_kw Float >= 0
demand_charge_usd_per_kw Float >= 0, or null to clear
demand_window_start HH:MM, 24-hour, 00:00–23:59, or null
demand_window_end HH:MM, 24-hour, 00:00–23:59, or null

Returns the full preferences object after the update — every field shown under GET, not only the ones you sent. Abbreviated here:

{
"base_temperature": 73.0,
"savings_level": 2,
"time_away": "07:30",
"time_home": "18:00",
"optimization_mode": "auto",
"...": "the remaining GET fields"
}
Status Detail Cause
400 "hourly_high_temps_f and hourly_low_temps_f must be set together or both cleared" Only one of the two arrays was provided as a non-null value
400 "hourly_high_temps_f and hourly_low_temps_f must each have exactly 24 values" Wrong array length
400 "hourly bands at hour <i> must be between 50 and 90 F" Value out of range at hour <i>
400 "hourly bands at hour <i> must be finite numbers between 50 and 90 F" Non-finite value at hour <i>
400 "hourly low must be less than high at hour <i>" hourly_low_temps_f[i] >= hourly_high_temps_f[i]
401 "Not authenticated" Missing or invalid token
422 array detail Any other field out of range or of the wrong type. The entry’s msg names the rule, for example "Value error, base_temperature must be between 60 and 85F". See Errors, Limits & Stability.
503 "Database unavailable" Database not reachable

Preview the default hourly comfort band — the band that applies when no hourly arrays are saved — without saving anything. Use this to build a “Reset to defaults” control that shows what will actually apply, or to render the default band before a user has customized it. The result depends only on base_temperature and optimization_mode.

Auth: Required (Bearer JWT)

Terminal window
curl "https://api.hungrymachines.io/api/v1/preferences/default-bands?base_temperature=72&optimization_mode=cool" \
-H "Authorization: Bearer YOUR_TOKEN"

Every query param is optional — an omitted one falls back to your stored /api/v1/preferences value.

Param Type Validation Falls back to
base_temperature float 60.0–85.0 °F your stored base_temperature
optimization_mode string "cool", "heat", or "auto" your stored optimization_mode
savings_level integer 1, 2, or 3 Accepted for compatibility; does not change the result
time_away string HH:MM Accepted for compatibility; does not change the result
time_home string HH:MM Accepted for compatibility; does not change the result

optimization_mode="auto" resolves to the cool-shaped band for this preview. "off" is not accepted here.

{
"hourly_high_temps_f": [73.0, 73.0, "...(24 values)"],
"hourly_low_temps_f": [70.0, 70.0, "...(24 values)"],
"peak_hours": [13, 21],
"precool_hours": [9, 13]
}

hourly_high_temps_f/hourly_low_temps_f are 24-element arrays, hour 0 = midnight local time — the same shape you’d submit as an hourly override above. peak_hours/precool_hours are fixed [start, end) reference windows in local hours, returned so you can shade the usual expensive hours and the hours before them in a UI without hardcoding them. They do not vary with the query params.

Status Detail Cause
400 "base_temperature must be between 60 and 85F" base_temperature out of range
400 "savings_level must be 1, 2, or 3" savings_level out of range
400 "Time must be in HH:MM format" time_away or time_home malformed
400 "optimization_mode must be cool, heat, or auto" Unknown mode, or "off"
401 "Not authenticated" Missing or invalid token
422 array detail A query value of the wrong type, for example a non-numeric base_temperature