Automate a Heat Pump Water Heater with Real‑Time Electricity Prices
Use live electricity prices to run your heat pump water heater when power is cheapest, without sacrificing comfort. Learn the setup, safety guardrails, and a Home Assistant example you can copy today.
- Shift hot water heating to the cheapest hours automatically using real-time prices
- Keep showers hot with smart guardrails for temperature and runtime
- Build it in Home Assistant with price sensors, schedules, and safety checks
If you have a heat pump water heater, you already own a quiet money-saving machine. Heat pumps move heat instead of creating it, slashing energy use compared to resistance elements. But there’s an even bigger win hiding in plain sight: water tanks store heat. That makes them ideal for time-shifting energy use to the cheapest hours of the day. With live electricity prices, you can preheat water when power is cheap and coast through peaks—without anyone at home noticing.
This guide shows how to automate a heat pump water heater against real-time electricity prices (think Octopus Agile in the UK, Nord Pool in much of Europe, or any hourly tariff). You’ll learn what hardware and data you need, how to design guardrails that protect comfort and equipment, and how to implement a practical setup in Home Assistant. Even if you don’t have a smart-ready tank, a simple smart switch and temperature sensor can get you surprisingly far.
Why price-based control fits heat pump water heaters
Heat pump water heaters (HPWHs) shine because their coefficient of performance (COP) often falls between 2 and 4. That means they deliver 2–4 times more heat than the electricity they consume. When you align that efficiency with low-priced hours, you stack two savings: better thermodynamics and a cheaper tariff.
Unlike most space heating, domestic hot water is a forgiving load. You don’t need exact timing—just a hot tank before showers and chores. That flexibility is priceless when electricity prices spike for a couple of hours or plunge when the grid is windy at night. By preheating a bit above your normal setpoint during low-price windows, you can drift through expensive periods with minimal or no heating.
There’s also a comfort angle. Modern HPWHs ramp up gently and are quiet enough for overnight operation. With smart guardrails—minimum temperature thresholds, maximum preheat limits, and a daily runtime floor—you can keep comfort stable while saving in the background.
What you need
You can start simple and add precision over time. Here’s a typical stack that works for most homes:
- Heat pump water heater with a controllable interface: native Wi‑Fi/API, a smart plug or relay controlling power, or a smart thermostat/contactor input.
- Live or day-ahead electricity prices from your supplier or market feed (e.g., Octopus Agile, Nord Pool, or a utility API).
- A smart home hub or automation platform. Home Assistant is ideal due to mature energy integrations and templates.
- Temperature visibility: onboard tank sensor via integration, or an add-on probe (e.g., a DS18B20 strapped to the outlet line with thermal paste and insulation).
- Optional but recommended: a flow or occupancy signal to anticipate hot water demand (e.g., bathroom motion in the morning), and a power meter to track actual consumption.
If your HPWH exposes modes (Heat Pump, Hybrid, Boost), you can map modes to price tiers. If you only control on/off power, you can still shift runtime safely, but you’ll rely more on minimum-temperature guardrails.
How the automation works
At its core, price-based control ranks the next 24 hours by cost and fits your water heating into the cheapest slices while obeying comfort rules. The logic is simple but powerful:
- Define comfort windows: when hot water must be ready (e.g., 6–8 AM and 6–9 PM).
- Use day-ahead/hourly prices to find low-cost hours before those windows.
- Preheat to a slightly higher setpoint during cheap hours, then coast.
- Apply guardrails: minimum tank temperature, maximum setpoint, and a daily minimum runtime to maintain hygiene and performance.
Here are typical guardrails that keep comfort predictable:
| Setting | Guardrail | Typical Value | Why it matters |
|---|---|---|---|
| Minimum tank temperature | Don’t allow heat off below | 46–50 °C (115–122 °F) | Prevents cold showers; protects against rapid bacteria growth; keeps recovery time short. |
| Maximum preheat setpoint | Cap boosted target | 55–58 °C (131–136 °F) | Avoids scald risk and excessive standby losses while still storing extra heat for peaks. |
| Daily runtime minimum | Guarantee base run | 60–120 min/day | Ensures at least one full heat cycle on abnormally high-price days; supports hygiene. |
| Legionella cycle | Weekly high-temp | 60 °C+ (140 °F) for 30–60 min | Manufacturer-recommended disinfection. Schedule in a reasonably priced period. |
| Demand hints | Morning/evening boost | Pre-run 30–60 min before | Anticipates showers/dishwashing so comfort isn’t price-dependent at the last minute. |
Most of the savings come from shifting the bulk of heating to the bottom 6–10 cheapest hours per day. Even if prices don’t vary wildly in your region, you still cut emissions by aligning with renewable-heavy windows and reduce strain on the grid.
Step-by-step: a Home Assistant blueprint you can adapt
The following pattern uses built-in integrations and simple templates. It works whether you have a native HPWH integration (set modes and temperatures) or a smart switch controlling power. Replace entity IDs to match your setup.
Step 1: Bring in electricity prices.
Use your regional integration (e.g., Nord Pool, Octopus Agile) to expose an hourly price sensor like sensor.electricity_price. Many integrations also provide today’s and tomorrow’s price arrays and thresholds (average, min, max).
Step 2: Create a binary sensor for “cheap right now.”
Define “cheap” as below a percentile of the next 24 hours or below a fixed threshold. Percentile works better across seasons.
{% raw %}
# Example: template binary_sensor in configuration.yaml
binary_sensor:
- platform: template
sensors:
hpwh_price_is_low:
friendly_name: "HPWH price is low"
value_template: >-
{% set current = states('sensor.electricity_price') | float(0) %}
{% set forecast = state_attr('sensor.electricity_price', 'prices_next_24h') or [] %}
{% set sorted = forecast | map(attribute='value') | list | sort %}
{% set idx = (sorted | count * 0.30) | int(0) %}
{% set p30 = sorted[idx] if sorted else current %}
{{ current <= p30 }}
{% endraw %}
If your integration doesn’t expose a ready-made array, you can use an automation to cache prices every hour or choose a fixed threshold like “cheaper than 0.15 €/kWh.”
Step 3: Identify comfort windows.
Use the Scheduler integration or a simple input boolean that turns on during key times. For example, create schedule.morning_shower (6:00–8:00) and schedule.evening_peak (18:00–21:00). These windows ask for a preheat starting 30–60 minutes before.
Step 4: Build the control logic.
We’ll combine three signals: low price, approaching comfort window, and minimum tank temperature. If your HPWH supports setpoint control, we’ll raise the target during cheap periods. If it’s just on/off, we’ll allow runtime during cheap hours and enforce a minimum temperature.
{% raw %}
automation:
- alias: "HPWH: Preheat on cheap prices"
trigger:
- platform: state
entity_id: binary_sensor.hpwh_price_is_low
to: "on"
- platform: time_pattern
minutes: "/15"
condition:
- condition: numeric_state
entity_id: sensor.tank_temp
below: 58 # don't exceed max preheat setpoint
action:
- choose:
- conditions:
- condition: state
entity_id: binary_sensor.hpwh_price_is_low
state: "on"
sequence:
- service: water_heater.set_temperature
target:
entity_id: water_heater.hpwh
data:
temperature: 56
- service: water_heater.set_operation_mode
target:
entity_id: water_heater.hpwh
data:
operation_mode: "heat_pump"
{% endraw %}
For on/off control via a smart plug, replace the service calls with switch.turn_on and gate by temperature.
{% raw %}
- alias: "HPWH: Turn on when cheap and below comfort temp"
trigger:
- platform: state
entity_id: binary_sensor.hpwh_price_is_low
to: "on"
- platform: numeric_state
entity_id: sensor.tank_temp
below: 49
condition:
- condition: state
entity_id: binary_sensor.hpwh_price_is_low
state: "on"
action:
- service: switch.turn_on
target:
entity_id: switch.hpwh_power
{% endraw %}
Step 5: Ensure comfort before busy times.
Create a preheat offset for your morning/evening windows so the tank is already hot even if prices are high. This is your comfort guarantee.
{% raw %}
- alias: "HPWH: Preheat before morning showers"
trigger:
- platform: time
at: "05:30:00" # 30–60 min before the window
condition: []
action:
- choose:
- conditions:
- condition: numeric_state
entity_id: sensor.tank_temp
below: 50
sequence:
- service: switch.turn_on
target:
entity_id: switch.hpwh_power
{% endraw %}
Step 6: Add safety guardrails.
You want guarantees for a daily minimum runtime and a weekly high-temperature cycle. These override prices when necessary.
{% raw %}
- alias: "HPWH: Daily runtime minimum"
trigger:
- platform: time
at: "22:00:00"
action:
- condition: template
value_template: "{{ states('sensor.hpwh_run_minutes_today') | int(0) < 60 }}"
- service: switch.turn_on
target:
entity_id: switch.hpwh_power
- delay: "01:00:00"
- service: switch.turn_off
target:
entity_id: switch.hpwh_power
- alias: "HPWH: Weekly legionella cycle"
trigger:
- platform: time
at: "14:00:00"
- platform: time_pattern
weeks: "/1"
weekday: "sun"
action:
- service: water_heater.set_temperature
target:
entity_id: water_heater.hpwh
data:
temperature: 60
- delay: "00:45:00"
- service: water_heater.set_temperature
target:
entity_id: water_heater.hpwh
data:
temperature: 54
{% endraw %}
Step 7: Monitor and tune.
Add a simple dashboard card that shows today’s price curve, tank temperature, run minutes, and whether the automation is currently allowed to run. After a week, adjust thresholds so you skim more cheap hours without flirting with cold showers.
Tuning tips that pay off quickly:
- Start modest: preheat cap at 55–56 °C, minimum temp 48–49 °C. Increase only if you experience discomfort.
- Prefer “percentile cheap” over “price below X,” so the system adapts to seasonal shifts.
- Briefly allow resistance “boost” only when absolutely needed (e.g., tank below 45 °C before a demand window).
- Measure standby loss: if the tank cools quickly, reduce preheat margin or add insulation to exposed pipes.
- Use occupancy cues: a bathroom PIR in the early morning is a powerful hint to run even when prices aren’t perfect.
What if your HPWH lacks smart controls? A heavy-duty, UL/CE-rated smart relay (or a plug if within rating) can cycle power within safe bounds. Many HPWHs remember their last mode after power is restored, so a timed power cut can stop or start heating cleanly. Always check manufacturer guidance and electrical codes, and use a certified electrician for high-load circuits.
What about households with variable hot water demand? You can add a “demand score” that blends motion near bathrooms, dishwasher or laundry events, and recent draw (drop in tank temp). Use that score to bias the price threshold: lower the cheapness bar when demand is likely, so the tank starts earlier.
For households on static tariffs, the same logic still reduces emissions: schedule preheat for hours with high wind or solar penetration, often overnight or midday. If your utility offers a carbon intensity feed, you can swap the price signal for grams CO₂/kWh and call it “greenest-hour heating.”
Finally, don’t forget maintenance. A weekly high-temp cycle reduces bacterial risk. Many HPWHs have built-in anti-legionella functions; expose and schedule those via integration instead of rolling your own if possible.
Going further: whole-home orchestration
Once you see savings from the tank, it’s natural to coordinate other flexible loads:
- EV charging: target the bottom quartile of prices, but protect a departure time and minimum range.
- Laundry and dishwashers: auto-start within a cheap window after you load them; use a “latest end time” override.
- Space heating/cooling: preheat or precool within comfort bands in well-insulated rooms.
- Solar-aware scheduling: when PV is producing, prefer self-consumption; fall back to price-based control when it’s cloudy.
- Grid services: in some regions, enroll in demand response or virtual power plant programs for extra rewards.
As your orchestration grows, prevent conflicts with a simple “power budget” helper. For example, if the EV is drawing 7 kW and your service limit is tight, defer the water heater unless it’s in a guaranteed comfort window. Home Assistant’s Energy dashboard and power sensors make this coordination easier than you might expect.
No. A native integration is nice, but many people start with a heavy-duty smart relay or plug to control power. If your model keeps its last mode after power loss, you can pause and resume heating safely. For finer control and telemetry (temperature, COP, error codes), a manufacturer API or third-party add-on board is worth the upgrade.
No. A native integration is nice, but many people start with a heavy-duty smart relay or plug to control power. If your model keeps its last mode after power loss, you can pause and resume heating safely. For finer control and telemetry (temperature, COP, error codes), a manufacturer API or third-party add-on board is worth the upgrade.
Not if you apply guardrails. Keep a minimum tank temperature (for example 48–50 °C), preheat before known demand windows, and allow an override when the tank gets unexpectedly cold. Most households won’t notice the difference—except on the bill.
Not if you apply guardrails. Keep a minimum tank temperature (for example 48–50 °C), preheat before known demand windows, and allow an override when the tank gets unexpectedly cold. Most households won’t notice the difference—except on the bill.
It depends on your tariff spread and usage. In regions with strong hourly swings, shifting 70–90% of runtime into the cheapest third of hours can trim water heating costs by 15–40%. Add the heat pump’s inherent efficiency and you’re stacking savings on savings. Your mileage varies; track a baseline week, then compare.
It depends on your tariff spread and usage. In regions with strong hourly swings, shifting 70–90% of runtime into the cheapest third of hours can trim water heating costs by 15–40%. Add the heat pump’s inherent efficiency and you’re stacking savings on savings. Your mileage varies; track a baseline week, then compare.
Follow manufacturer guidance. Avoid rapid on/off cycling by using minimum run/stop times and let the unit complete normal cycles. If you have an official integration, prefer mode and setpoint changes over cutting power. For hard-switch control, limit changes to a few per day and use a soft start delay after power restore if available.
Follow manufacturer guidance. Avoid rapid on/off cycling by using minimum run/stop times and let the unit complete normal cycles. If you have an official integration, prefer mode and setpoint changes over cutting power. For hard-switch control, limit changes to a few per day and use a soft start delay after power restore if available.
Often, yes. If the unit is on a standard plug and well within a smart plug’s rated load, you can automate without altering wiring. Where hardwiring is involved, coordinate with your landlord and a licensed electrician. You can still use price-based reminders to time showers, dishwashing, and laundry for cheap periods.
Often, yes. If the unit is on a standard plug and well within a smart plug’s rated load, you can automate without altering wiring. Where hardwiring is involved, coordinate with your landlord and a licensed electrician. You can still use price-based reminders to time showers, dishwashing, and laundry for cheap periods.