Making my water heater smart
A solar water heater that worked great in summer but fell apart in winter pushed me to automate the whole thing.
Our house came with a two-way system to heat the water we use for things like showering and washing the dishes. But so far, it has been far from smart. It’s changing today, once and for all.
How it used to be
The system as we got it when we bought the house is composed by three main elements:
- A water tank;
- An electric coil; and
- A solar panel;
During the summer, the solar panel alone is more than enough to heat the water to temperatures we’re not even comfortable with. That’s great because it allows for everyone to take a shower when we most need it as well as clean anything that needs cleaning, doing the dishes and everything else that’s necessary. It really has plenty of hot water for a whole family.
As the water flows outside the water tank, new fresh water goes in. And this is where my first gripe with this whole system comes in. I’m no expert in this area, but from an energy efficiency point of view, it makes no sense to spend hours heating a 250 liter water tank only to see the temperature drop as soon as you start pulling hot water, because new cold water is flowing in.
We’re never fully taking advantage of whatever system heats the water, because if we take out 50 liters from the tank, another 50 liters are going in, and the hot water is going to turn colder fast.
I also understand that from a physics point of view, one can’t just take water out and do nothing. Because pressure would build up inside the tank to very uncomfortable levels. So with this kind of system, I believe we have no way around it. Perhaps having an air valve that would let air in instead of water to release the pressure? I don’t know… Just thinking out loud, really.
But while this system works great during the summer—when the electric coil isn’t even needed—the colder months are a different story.
Preparing for the winter
As the summer fades away and the winter approaches, a ritual we got used to at home was going to the electrical panel and switching on the breaker for the electric coil.
At the time we bought the house, we got suggested that this coil could be on all the time. It never felt quite right to me. Again, I’m no expert, but leaving a 2800W device on all the time could translate to unprecedented electrical bills for us. Something we never looked up to.
But one thing is for sure! Not only is there not enough sun light during the colder months to heat the water through the solar panel alone, there’s also a much colder air mass around the water tank, getting warmer by the temperature from the hot water.
And yes, the energy flows from hot to cold.
Meaning, it is the hot water that is releasing energy to the cold air mass. Not the other way around.
To prevent this coil from being on all the time, we installed a simple clock breaker in the panel. And by “we” I mean, my dad. Because if there’s anything I’m not comfortable at all with in this world, it’s electricity. Don’t ask me why because I also couldn’t answer.
With this clock in place, we could configure specific times of the day where the coil would be on so that we would have hot water and prevent hot bills.
It’s not just the sun
Although the sun is crucial for this three-part system to work properly, it’s not the only factor that can leave us without hot water.
Another one, and a very much obvious one, is cloud coverage.
Imagine it’s June. As usual, we have the clock breaker in the panel turned off by then, because we expect sunny days in June. But for some reason there’s a cloudy day. If we don’t expect it and forget to turn on the breaker, we most likely will not have hot water for that day.
So, although this clock breaker helps a lot, it’s not perfect.
But we felt ok with these very few exceptions and carried on with this system for a few years. This autumn, we noticed the coil wasn’t heating up the water. We still had some sunlight in the beginning, but the water was lukewarm at best.
We called the technician in, because there’s no way I’m going to climb a 20 m high makeshift ladder that happens to be older than me, just to check what’s going on in the roof—where this whole system is.
Turns out, the coil was fine. The clock breaker failed! It’s something that shouldn’t happen. Something that rarely happens. But apparently it does happen. So he replaced the clock breaker with the original one with no clock—just on or off.
Which means we were back at square one.
This time though, we’re invested in Home Assistant. So naturally, my next step was finding a Shelly device I could connect to the breaker to dynamically turn the coil on or off.
A smarter solution
The Shelly 1PM Gen 4 sounded perfect for me. I knew the coil itself needs as much as 3000W and 230V. The 1PM supports 16A at 240V. I don’t know much about electricity. But I do know that amps * volts = watts.
Meaning, the 1PM supports up to 3680W at 230V. Since the coil itself needs 3000W, the 1PM works fine!
And this Gen 4 device, just like any other Gen 4 from Shelly, supports Zigbee. Which for me is a big plus, because I already have a Zigbee network—quite a robust one too—that is independent from the devices that actually need access to the internet.
I could also use WiFi, but since I would need to connect them to a specific SSID, which only allows a specific set of Mac addresses, it would be a bit more cumbersome to install. And from my experience, WiFi devices are far more inconsistent than mains powered Zigbee ones.
Let’s automate it
Now that the 1PM is installed—and since it’s a Power Measurement device I can check how much it’s consuming which also tells me if the device is indeed working as expected or not—I can set up some automations that will make my life easier.
You see, ever since we went back to the original breaker, I had to remember to turn on the breaker when I got up and turn off when I went to bed. Unsurprisingly, I not always did.
For this, our dear friend ChatGPT was an invaluable help. Instead of lurking for forums and subreddits for hours, I could just talk to it back and forth and come up with a solution that seems robust enough for our use case.
The sun
Arguably, the most important aspect of the automation responsible for turning the coil on, is the sun. But what exactly about it? Home Assistant comes with a sun integration anyone can use. There are plenty of entities available.
The sensor.sun_solar_elevation entity tells me the current sun elevation. The keyword there is “current”.
What I have in mind is checking the sun elevation for the day and decide whether or not I should turn on the coil. So the current value serves me of very little in this scenario. I need a forecast.
Unfortunately, there’s no forecast for such a value under the sun device.
So with the help of ChatGPT I created a template sensor.sun_max_elevation_for_today with the following template:
{% set latitude = 41.15 %} {# For Porto #}
{% set today = now().timetuple().tm_yday %}
{% set declination = 23.44 * sin( (360/365 * (284 + today)) * 3.14159265359 / 180 ) %}
{{ 90 - latitude + declination | round(1) }}
For instance, I’m writing this at Dec 16th and this template would return 25.5°.
That’s great! But the sun is only one of the factors!
The clouds
For the cloud coverage value I’m relying on the AstroWeather integration. After configuring it for your location you will find a sensor.astroweather_home_deepsky_forecast_today.
This is a percentage value that tells you how covered the sky is with clouds. I’m considering that a value above 30% is too cloudy for my solar panel. You can adjust that however you see fit.
The switch
With the above data, I set up an easy to glance-at template binary sensor called binary_sensor.water_heater_should_be with the following template:
{% set sun_low = states('sensor.sun_max_elevation_for_today') | float(0) < 45 %}
{% set clouds_high = states('sensor.astroweather_home_deepsky_forecast_today') | float(0) > 30 %}
{{ sun_low or clouds_high }}
As you can see, if the sun elevation is going to be below 45° or the cloud coverage is going to be above 30%, the water heater (the coil) should be turned on.
The automation
alias: "@05_or_16"
description: ""
triggers:
- trigger: time
at: "05:00:00"
weekday:
- mon
- tue
- wed
- thu
- fri
- sun
- sat
- trigger: time
at: "16:00:00"
weekday:
- mon
- tue
- wed
- thu
- fri
- sat
- sun
conditions:
- condition: state
entity_id: binary_sensor.water_heater_should_be
state:
- "on"
actions:
- action: switch.turn_on
metadata: {}
target:
entity_id: switch.water_heater
data: {}
mode: single
The above automation is going to run at 05:00 and 16:00. More on that later.
When it runs, the first thing it does is checking if the water heater should be on—that’s the binary sensor defined above.
If that’s the case, it switches the water heater on—the Shelly 1PM.
I had more logic there to notify us when this runs so that we know the water is heating, but prevent notifying when we’re still sleeping. It makes the automation far more complex and for this example, it’s just not worth it.
Turning the heater off
alias: "@water_hot"
description: ""
triggers:
- trigger: state
entity_id:
- switch.water_heater
to:
- "on"
for:
hours: 4
minutes: 0
seconds: 0
conditions: []
actions:
- action: switch.turn_off
metadata: {}
target:
entity_id: switch.water_heater
data: {}
mode: single
For our house, I decided that having the heater on for 4 hours is enough for the 250 liter tank to heat up. I had this feeling. But lacked the data.
Now, thanks to the power measurement capabilities of the 1PM, I also have the data.
This morning, the heater turned on at 05:00 as expected. At 07:23 the built-in thermostat was already cutting the power off, meaning the water was plenty hot already—I believe it’s set for 70° C. It consumed between 2800–3000W while it was on.
At 08:32 it went back on, consuming around the same power for roughly another 10 minutes. And then at 09:00 as expected, the automation turned the heater off.
So, in total, the heater was consuming power for around 2h30 of the whole 4h period the heater was on. Not bad! Also relevant is the outside temperature, which for today was around 8° C during the morning. As this value goes down, the amount of time the heater will need to be on will naturally increase.
The whole idea behind switching the heater on at 05:00 and again at 16:00 is so that we can A) have hot water in the morning, B) hot water for the dishes at breakfast/lunch and C) hot water at the end of the day for showers and dishes.
Leaving it on for the whole day, could potentially translate to higher costs, although we know that the built-in thermostat would cut the power off occasionally throughout the day as the water becomes hot enough.
With a setup like this, we could also benefit from some potential sunlight throughout the day to heat the water, even if just a little bit. Might just be enough to keep it hot for a longer period.
Takeaways
This setup didn’t reinvent our water heater, but it made it predictable, cheaper to run, and far less annoying. Instead of guessing or manually flipping breakers, the system now adapts to the season and the weather, giving us hot water when we actually need it. Here’s a quick rundown of how I did it:
- Automated the boring manual switches;
- Used sun and cloud data to make decisions;
- One smart relay controls the whole coil;
- Measured power to know what’s actually happening;
- Hot water ready when we need it, no babysitting required;