template:
- binary_sensor:
- name: Peak hours
state: >
{{ now().weekday() < 5
and 16 <= now().hour < 21 }}
Looks fine in June. Wrong in January, on a holiday, and the week the peak window moves.
ZIP in, current peak / off-peak period out. Home Assistant automations for EV charging, thermostat and HVAC, and loads off the tariff clock — not a hardcoded 4–9 PM that drifts every season.
Home Assistant forums are full of now().hour and schedule helpers. They miss holidays, season flips, DST, and the day the utility refiles the tariff.
template:
- binary_sensor:
- name: Peak hours
state: >
{{ now().weekday() < 5
and 16 <= now().hour < 21 }}
Looks fine in June. Wrong in January, on a holiday, and the week the peak window moves.
automation:
- alias: Charge EV when off-peak
triggers:
- trigger: state
entity_id: binary_sensor.off_peak
to: "on"
The period is a sensor. Automations follow the clock the utility actually bills.
How it works
One REST call. Home Assistant already speaks REST. No custom component or HACS install required.
Any U.S. ZIP, optional street if the ZIP is shared. Residential is the default customer class.
off_peak, on_peak, mid_peak, super_off_peak, or critical_peak — plus when it next changes.
EV charger, thermostat, HVAC, dishwasher, battery reserve, or the Home Assistant Energy dashboard tariff selector.
Install
The YAML recipe — secrets, REST sensors, and boundary-aware automations — is in the docs.
Three blocks: the API key in secrets.yaml (include the word Bearer),
a REST sensor plus templates in configuration.yaml, and automations that refresh
45 seconds after next_change_at then fire on binary_sensor.off_peak.
Swap the ZIP. Reload REST entities and template entities.
sensor.tou_period (live period + next_change_at attribute),
sensor.tou_next_change (timestamp), and
binary_sensor.off_peak (on during off-peak and super-off-peak).
What to automate
Turn the charger on when binary_sensor.off_peak goes on. Hold through super-off-peak. Stop at on-peak.
Drop the thermostat setpoint an hour before next_change_at when the next period is on-peak, then coast.
Delay the dishwasher, washer, and water heater until off-peak. Same binary sensor, different switches.
Charge through off-peak, raise reserve at peak start. Period names only — no ¢/kWh from this API.
Drive the Home Assistant Energy dashboard and utility_meter tariff selects from sensor.tou_period instead of time triggers at 16:00. Pair with an energy monitor or power monitor — this API is the clock, the meter is the kWh.
When sensor.tou_next_change is under an hour away and the current period is off-peak, send a Home Assistant notification to the phone.
A custom Home Assistant component — tou.tools (Time-of-Use) — wraps this exact
flow: API key + ZIP in a config UI, an enum period sensor, an off-peak binary sensor, and a
coordinator that reschedules itself for just after next_change_at.
The REST recipe in the docs is the path that works on any Home Assistant today — no extra component, no HACS or Home Assistant Community Store install. The custom integration is the same sensors without YAML, and it stays inside the free tier by polling only at boundaries. Install from REST; switch later if you want the UI.
The same periods are also an MCP server
at /mcp, if a Home Assistant MCP client or LLM should query them as tools
instead of a REST sensor.
Call GET /api/v1/query/current with your ZIP and rate_plan_id from a REST sensor. Pin the plan on your bill first — a ZIP often has several. results[0].period is then the live period. Automate on that, or on a binary sensor that is on during off-peak and super-off-peak. YAML is in the Home Assistant docs.
No. tou.tools is the timing layer: period names and boundaries. Prices live in riders, baselines, and customer class. Put your own rates on the Home Assistant Energy dashboard or in utility_meter if you need a dollar figure. An energy monitor or power monitor supplies the kWh.
If we have a seeded TOU plan for the utility that serves your ZIP, yes. See coverage. When a ZIP is ambiguous (common in Texas / ERCOT), the API returns every candidate plan instead of guessing — pick the one on your bill, or pass street / city / state.
Refreshing at next_change_at is a handful of calls per day and fits the free plan (500/month, 3 locations). Polling every 15 minutes is ~2,880/month. The REST recipe does the former.
Yes. On a state change of sensor.tou_period, call select.select_option on your meter’s tariff selector. Map off_peak / super_off_peak to your cheap tariff name. Pair with an energy monitor or power monitor for kWh. The Energy dashboard automation in the docs recipe is that mapping.
No credit card. 500 calls/month. Enough for a house if you refresh at next_change_at (a few calls a day).