Is Our Hot Tub Thermal Cover Worth The Cost?
<img class="introimage" itemprop="image" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/more_efficient.jpg" style="display: none"/><div>
<p>This year, we bought an <a href="https://www.bentasker.co.uk/posts/blog/house-stuff/automating-our-hottub-with-home-assistant.html">inflatable hot tub</a>, which has a 2kW heating element.</p>
<p>Warming the tub wasn't too bad in summer: energy prices were lower and our solar panels supplied a good chunk of the power.</p>
<p>Winter, of course, has been another matter. Not only is energy more expensive, but the lower ambient temperature means that the heater needs to kick in more frequently to help maintain even our "idle" temperature of 20°C (chosen to strike a balance between energy usage and warm up time).</p>
<p>The tub isn't <em>just</em> an inflatable rubber ring, it has a thermally lined outer layer (BestWay call the material <a href="https://www.bestwaystore.co.uk/blogs/all/energysense">EnergySense</a> and claim that it increases efficiency by 40%). Similar material is used in the lid and the tub also sits on a sheet of interlocking foam tiles. </p>
<p>So there's already <em>some</em> level of insulation.</p>
<p>All the same, though, the tub has been consuming <em>quite a lot</em> of energy on the days that we have it warm.</p>
<p>Adding a thermal cover, on the face of it, seemed like a no-brainer: </p>
<pre><code class="language-text">additional insulation = reduced heat loss
reduced heat loss = lower running cost
</code></pre>
<p>The catch though, is the <em>price</em>. Lay-z-spa, for example, want <a href="https://www.lay-z-spa.co.uk/hot-tub-thermal-covers.html">over £100</a> for even a small cover, though <a href="https://www.therange.co.uk/outdoor-living/pools-and-hot-tubs/hot-tub-covers/cleverspa-thermal-cover-for-hot-tubs/">unbranded covers</a> are cheaper.</p>
<!-- TEASER_END -->
<hr/>
<h4 id="claimed-energy-efficiency">Claimed Energy Efficiency</h4>
<p>Lay-z-spa claim that their cover can deliver <em>up to</em> 40% more efficiency, which seems bold.</p>
<p>Not wanting to spend £140 on this experiment, though, I went for the non-branded option at £64.99.</p>
<p>The box that it arrived in made an even bolder claim:</p>
<p><img alt="Photo of the cover's box, which claims it can be up to 50% more energy efficient" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/more_efficient.jpg"/></p>
<p>Presumably, in order to actually achieve that level of improvement, you'd need to have been running an un-insulated tub, with no lid, out in the wind.</p>
<hr/>
<h4 id="previous-energy-use">Previous Energy Use</h4>
<p>The hot-tub's power supply isn't independently metered, so it's not possible to get an exact read of energy consumption. </p>
<p>However, because I have the <a href="https://github.com/cdpuk/ha-bestway">HomeAssistant integration</a> set up, I do have a record of heater state, so it's possible to approximate energy usage by combining time active with the heater's rating (it has a single 2kW element):</p>
<pre><code class="language-flux">import "contrib/tomhollingworth/events"
from(bucket: "home_assistant/autogen")
|> range(start: v.timeRangeStart)
|> filter(fn: (r) => r._measurement == "climate.spa_thermostat"
and r._field == "hvac_action_str")
|> events.duration(unit: 1s)
|> filter(fn: (r) => r._value == "heating")
|> map(fn: (r) => ({ r with
// 2.03 is heater plus pump
_value: (float(v: r.duration) / 3600.0) * 2.03
}))
|> aggregateWindow(every: 1d, fn: sum)
</code></pre>
<p>This generates a graph showing energy consumption per day</p>
<p><img alt="Graph showing energy usage per day" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/usage_before.png"/></p>
<p>You can see when the tub is being brought out of idle and up to temperature, consuming <em>nearly 25kWh</em> in the process. By way of comparison, our normal daily household consumption is between 20 and 30 kWh so heating the tub pretty much <em>doubles</em> our usage.</p>
<p>The usage calculations can be combined with <a href="https://www.bentasker.co.uk/posts/blog/house-stuff/writing-octopus-pricing-and-usage-into-influxdb-with-telegraf.html">Octopus pricing information</a> to arrive at a cost per day:</p>
<pre><code class="language-flux">import "contrib/tomhollingworth/events"
usage = from(bucket: "hottub")
|> range(start: v.timeRangeStart)
|> filter(fn: (r) => r._measurement == "climate.spa_thermostat"
and r._field == "hvac_action_str")
|> events.duration(unit: 1s)
|> filter(fn: (r) => r._value == "heating")
|> map(fn: (r) => ({ r with
// 2.03 is heater plus pump
_value: (float(v: r.duration) / 3600.0) * 2.03
}))
|> aggregateWindow(every: 30m, fn: sum)
pricing = from(bucket: "Systemstats")
|> range(start: v.timeRangeStart)
|> filter(fn: (r) => r._measurement == "octopus_pricing")
|> filter(fn: (r) => r.charge_type == "usage-charge"
and r.tariff_direction != "EXPORT")
|> filter(fn: (r) => r._field == "cost_inc_vat")
|> aggregateWindow(every: 30m, fn: mean)
join(tables: {t1: usage, t2: pricing}, on: ["_time"])
// Calculate cost based on grid price at the time
|> map(fn: (r) =>({
_time: r._time,
_value: (r._value_t1 * r._value_t2) / 100.0,
_field: "usage_cost"
}))
|> aggregateWindow(every: 1d, fn: sum)
</code></pre>
<p><img alt="Daily energy cost of running the hottub" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/cost.png"/></p>
<p>I regretted creating this graph almost as soon as I saw it... <em>ouch</em>.</p>
<p>Unfortunately, this graph isn't <em>particularly</em> useful for comparison: we're on a variable price tariff, so it would be misleading to try and draw conclusions from the total spent because the underlying prices can vary quite significantly.</p>
<hr/>
<h4 id="rate-of-temperature-change">Rate of Temperature Change</h4>
<p>Assuming that it helps at all, the additional insulation provided by a cover helps by reducing the rate that heat escapes the tub.</p>
<p>So the other thing that I needed to look at was the average hourly change in temperature.</p>
<p>Decreases:</p>
<pre><code class="language-sql">SELECT mean("temperature_change")
FROM (
SELECT
derivative(mean("current_temperature"), 1h) AS "temperature_change"
FROM "hottub"."autogen"."climate.spa_thermostat"
WHERE time > now() - 30d
GROUP BY time(1h)
FILL(null)
)
WHERE "temperature_change" < 0
GROUP BY time(1h)
</code></pre>
<p><img alt="Graph showing the average hourly drop in temperature across the prior 30 days" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/temperature_decrease.png"/></p>
<p>The graph for temperature increases is generated using much the same query, just with the final conditional swapped</p>
<pre><code class="language-sql">SELECT mean("temperature_change")
FROM (
SELECT
derivative(mean("current_temperature"), 1h) AS "temperature_change"
FROM "hottub"."autogen"."climate.spa_thermostat"
WHERE time > now() - 30d
GROUP BY time(1h)
FILL(null)
)
WHERE "temperature_change" > 0
GROUP BY time(1h)
</code></pre>
<p><img alt="Graph showing increases over time" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/temperature_increase.png"/></p>
<p>Reducing each of these to aggregates gets us the following figures:</p>
<table>
<thead><tr>
<th></th>
<th><strong>Min °C</strong></th>
<th><strong>Mean °C</strong></th>
<th><strong>Max °C</strong></th>
</tr></thead>
<tbody>
<tr>
<td><strong>Drop</strong></td>
<td>0.0161</td>
<td>0.451</td>
<td>1.5</td>
</tr>
<tr>
<td><strong>Rise</strong></td>
<td>0.0185</td>
<td>1.04</td>
<td>2.54</td>
</tr>
</tbody>
</table>
<hr/>
<h4 id="fitting-the-cover">Fitting The Cover</h4>
<p>The cover seems to be pretty good quality - in terms of material and thickness, it feels like a moderately good sleeping bag.</p>
<p>It's got a rectangular panel which can be unzipped to allow for connections to an external pump:</p>
<p><img alt="Photo of the hot-tub with cover on, there's a rectangular gap to allow for pipes to the pump and heat unit" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/hot_tub_with_cover.jpg"/></p>
<p>One thing that I was concerned about was puddling. </p>
<p>The rain sometimes blows in and collects on the tub's lid - that's annoying but quite easily dealt with when lifting a flat rigid lid. The new cover is more like a blanket though, and I didn't fancy getting splashed with cold, manky water when trying to take it off.</p>
<p>It's only the outermost edge which is really exposed to the rain, so I placed a plastic storage box just back from it before placing the cover on in the hope that most of the rain would then run down the side of it and off the tub.</p>
<p>This does mean that there will have been a little more air under the cover than if it were flat against the lid.</p>
<hr/>
<h4 id="impact-cooling">Impact: Cooling</h4>
<p>The impact on the rate of cooling is quite visible in the temperature graph:</p>
<p><img alt="Graph showing water termperature. Once the cover is fitted, the rate of cooling is definitely slower" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/decrease_with_cover.png"/></p>
<p>Before the cover was fitted, the tub would often reach the idle temperature of 20°C. The little spikes indicate that the thermostat was sometimes clicking back on to help maintain that temperature.</p>
<p>The cool down period after the cover was fitted, though, didn't reach idle, so the next heating period started from 23°C rather than 20°C</p>
<p>Because it takes a known amount of energy to heat 1L of water, we can work out roughly what energy this might save:</p>
<pre><code>1_litre = 3C x 4.18 kilojoule = 12.54kj
600l = 12.54kj * 600l = 7524kj
kwh = 7524 kj / 3600 = 2.09kWh
</code></pre>
<p>So, that extra few degrees <em>should</em> have shaved about <code>2 kWh</code> off the heater's energy usage. That's not a <em>huge</em> amount, but it's still about 8% of the first day's warm.</p>
<p>If we overlay the decrease graph onto water temperature we can see that the rate of decrease <em>was</em> generally more gentle with the cover, although there's not <em>much</em> change when the water is warmest.</p>
<p><img alt="Graph showing rate of decrease, overlaid onto water termperatures. Decreases don't spike as much once the cover has been fitted." src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/decrease_v_temp.png"/></p>
<p>So, although there is an impact on the rate of cooling, it's quite modest and only really occurs when the water's cooler.</p>
<hr/>
<h4 id="impact-warming">Impact: Warming</h4>
<p>Our best potential for financial savings occur when the tub is being warmed - it's all very well it cooling more slowly, but I'm not going to be climbing into the thing whether it's 20°C or 23°C. An increased rate of warming, though, would mean that we need to burn less energy to warm the tub back up.</p>
<p>But, have these savings been realised?</p>
<p>If we overlay rate of temperature increase onto the temperature graph:</p>
<p><img alt="Graph with rate of increase overlaid against water temperature" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/increase_v_temp.png"/></p>
<p>There's very little difference at all.</p>
<p>In fact, if we swap the overlay to show maximum increase</p>
<pre><code class="language-sql">SELECT max("temperature_change")
FROM (
SELECT
derivative(max("current_temperature"), 1h) AS "temperature_change"
FROM "hottub"."autogen"."climate.spa_thermostat"
WHERE time > now() - 30d
GROUP BY time(1h)
FILL(null)
)
WHERE "temperature_change" > 0
GROUP BY time(1h)
</code></pre>
<p>We can see that, with the exception of one point, there is <em>no difference</em>:</p>
<p><img alt="Graph showing the maximum hourly temperature increase" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/temp_vs_max_increase.png"/></p>
<p>That one jump of 3°C is <em>probably</em> anomalous and the result of reduced flow through the filter (more on that below).</p>
<hr/>
<h4 id="impact-energy-consumption">Impact: Energy Consumption</h4>
<p>The entire aim of using a cover is to reduce energy consumption. The tub may not appear to have been warming any faster, but perhaps there are some marginal energy gains?</p>
<p>If there are, they are <em>extremely</em> minimal:</p>
<p><img alt="Graph showing daily energy consumption of the tub" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/energy_usage.png"/></p>
<p>In fact, if we look at a graph showing heater state we can see that there really isn't that much difference in time spent active when warming back up:</p>
<p><img alt="Chart showing the state of the heater over the last 30 days. The pattern is much the same before and after the cover was fitted" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/heater_state.png"/></p>
<p>Note: the random seeming spikes are the heater clicking on as a result of
<a href="https://www.bentasker.co.uk/posts/blog/house-stuff/automating-our-hottub-with-home-assistant.html#automation">my automation for Plunge Pricing</a>.</p>
<p>However, if we look at the energy consumed on days where the heater simply has to maintain 38°C, there <em>does</em> appear to be a reduction:</p>
<p><img alt="Graph showing energy usage when the heater simply has to maintain 38c rather than reach it" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/idling_usage_extra_day.png"/></p>
<p>Before the cover was added, the average daily usage was <code>8.32 kWh</code>. Afterwards, it was <code>5.94 kWh</code>, yielding a saving of <code>2.38 kWh</code> a day. Of course, we're only in that maintenance state for 2 days, so the weekly saving is <code>4.76 kWh</code> a week.</p>
<hr/>
<h4 id="savings">Savings</h4>
<p>We should try and convert that saving into money so that we can work out when savings would break even with the cover's purchase price.</p>
<p>To do that, we need to know what energy prices look like when the tub is heating:</p>
<pre><code class="language-flux">import "contrib/tomhollingworth/events"
usage = from(bucket: "hottub")
|> range(start: v.timeRangeStart)
|> filter(fn: (r) => r._measurement == "climate.spa_thermostat"
and r._field == "hvac_action_str")
|> events.duration(unit: 1s)
|> filter(fn: (r) => r._value == "heating")
|> map(fn: (r) => ({ r with
// 2.03 is heater plus pump
_value: (float(v: r.duration) / 3600.0) * 2.03
}))
|> aggregateWindow(every: 30m, fn: sum)
pricing = from(bucket: "Systemstats")
|> range(start: v.timeRangeStart)
|> filter(fn: (r) => r._measurement == "octopus_pricing")
|> filter(fn: (r) => r.charge_type == "usage-charge"
and r.tariff_direction != "EXPORT")
|> filter(fn: (r) => r._field == "cost_inc_vat")
|> aggregateWindow(every: 30m, fn: mean)
// Join the two so we only get prices at times
// that the heater was active
join(tables: {t1: usage, t2: pricing}, on: ["_time"])
|> filter(fn: (r) => exists r._value_t1)
|> map(fn: (r) =>({
_time: r._time,
_value: r._value_t2,
_field: "unit_cost"
}))
// Exclude plunge pricing
|> filter(fn: (r) => r._value > 0)
</code></pre>
<p>By bolting different aggregates onto the end, we can arrive at the following unit prices and potential savings (based on <code>4.76 kWh</code> a week)</p>
<table>
<thead><tr>
<th></th>
<th><strong>Price</strong></th>
<th>Savings</th>
</tr></thead>
<tbody>
<tr>
<td><strong>Min</strong></td>
<td>0.221</td>
<td>1.05196</td>
</tr>
<tr>
<td><strong>Mean</strong></td>
<td>20.7</td>
<td>98.532</td>
</tr>
<tr>
<td><strong>Max</strong></td>
<td>94.8</td>
<td>451.248</td>
</tr>
</tbody>
</table>
<p>Note: that max value is horrifying, I should probably set up an automation to turn the heater off when prices are that high.</p>
<p>Assuming that that's all we manage to save, the payback time for a £64.99 cover is therefore</p>
<table>
<thead><tr>
<th></th>
<th></th>
</tr></thead>
<tbody>
<tr>
<td><strong>Min</strong></td>
<td>118 Years</td>
</tr>
<tr>
<td><strong>Mean</strong></td>
<td>1 Year 3 months</td>
</tr>
<tr>
<td><strong>Max</strong></td>
<td>14 Weeks</td>
</tr>
</tbody>
</table>
<p>Prices either side of a plunge pricing session are generally quite low, so I wondered whether they were skewing the mean price and re-ran the query, excluding any price below <code>£0.10/kWh</code>. Unfortunately, the mean only shifted to <code>£0.23/kWh</code> which would still give a payback time of 1 year 1 month.</p>
<p>Although that's not horrific, it's far from a given that the cover will survive being exposed to the elements for long enough. The real break-even period will <em>probably</em> be longer too as the average price is lower in Summer.</p>
<hr/>
<h4 id="external-influences">External Influences</h4>
<p>There are a few things which make direct comparison harder and less reliable.</p>
<h5 id="the-weather">The weather</h5>
<p>The hot tub is sat outside and the average ambient temperature has been lower over the last couple of weeks.</p>
<p><img alt="Graph showing the temperature measured by my weather station. Although it hasn't dipped as low, the average temperature has been lower" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/weather_temperature.png"/></p>
<p>However, whilst this will have increased the rate at which we lose heat, it <em>shouldn't</em> be enough to almost completely offset the gains of having a cover - I'd expect most of the impact to occur at peak and at idle.</p>
<h5 id="the-filter">The Filter</h5>
<p>The tub's pump pulls water into the heater via a pleated paper filter. Over time, that filter scales up and starts to clog, reducing the rate at which water is pulled through.</p>
<p>This can have quite an impact on heat circulation: it reduces the amount of pressure behind the newly warmed water and so doesn't push it as far into the tub. This reduced rate of mixing can lead to cool spots forming.</p>
<h5 id="usage">Usage</h5>
<p>Unsurprisingly, taking the lid off and exposing the surface of a 38°C body of water to 5°C air allows for an increased rate of heat loss.</p>
<p>It's not as visible in graphs covering a week, but if we compare consecutive days, we can see the heater kicking in:</p>
<p><img alt="Graph showing heater state over 2 days. I had a quick dip around 10pm Friday and the heater kicked in part way through" src="https://www.bentasker.co.uk/images/BlogItems/hottub_cover/heater_detailed.png"/></p>
<p>As a result of the tub being used, the heater ran for about 40 minutes, causing about <code>1.33 kWh</code> of additional consumption.</p>
<h5 id="the-inconvenience">The inconvenience</h5>
<p>So far, I've been good at putting the cover back on. However, it really is quite inconvenient to fit properly. That inconvenience is only really amplified by the fact that hot tubs need regular maintenance (water quality checks, dropping new chlorine tablets in etc). </p>
<p>Given how often the cover needs to be disturbed, it'd be quite easy to start rationalising not putting it back on "because we'll probably use the tub tomorrow anyway".</p>
<hr/>
<h4 id="conclusion">Conclusion</h4>
<p>It looks unlikely that the cover will lead to enough savings to offset it's purchase price in a meaningful time frame.</p>
<p>It bears noting, though, that I <strong>did</strong> cheap out. It is quite possible that a Lay-z-spa cover is more efficient, but I think it's unlikely that it would change the outcome: given the additional cost, it'd need to be <em>twice</em> as efficient just to break even with the cover that I did buy.</p>
<p>I don't think that this is necessarily a reflection of the efficiency of thermal covers as a whole, so much as a reflection of just how efficient our tub <em>already was</em>: adding the additional layer only seems to have saved us about 3°C of cooling <em>over the course of a week</em>, far less than I was expecting.</p>
<p>I <em>suspect</em> that the cover might get a less well insulated tub toward the level of efficiency that ours already achieves. The name "EnergySense" might grate on my nerves, but it seems it probably does do what they claim.</p>
<p>During warmup, regardless of the level of insulation, the heater ultimately has to warm 600 litres of water from 20°C to 38°C, which is always going to demand a reasonable chunk of energy.</p>
<p>Although not huge, there <em>do</em> seem to be savings on the days that the tub is simply maintaining temperatures. At a little over a year, the break-even point is a little further out than I'd like, but not unachievable <em>especially</em> as we (unsurprisingly) see better savings on the days where the tub doesn't end up being used.</p>
</div>
New #Blog: Is Our Hot Tub Thermal Cover Worth The Cost?
Author: Ben Tasker
www.bentasker.co.uk/posts/blog/house-stuff/w...
#analysis #electrical #hottub #housestuff #influxql
0
0
0
0