Improving our Solar Battery Savings

Last month, I analysed the performance of our solar install and found that, whilst our Solar battery was generating daily savings, it would very likely never save enough to offset its purchase cost.

There were a number of factors involved, but one of the bigger ones was the battery wasn't always being sufficiently charged, with our average max daily charge level being 72%. On sunny days, the battery gets a full charge but, British weather being what it is, there are plenty of days dragging that average down.

As I noted at the time, Solar isn't the only source from which the battery can be charged: there's also the option of charging from the grid (ideally when prices are low).

So, in the month since, that's exactly what I've done.

In this post, I'm going to describe how I've configured things, analyse the impact of the change and also talk about some changes that my electricity supplier (Octopus) has recently made.


Configuration

It had originally been my intention to build automation to consume pricing information and dynamically control when the battery should charge: there's a wealth of information out there on how to control a Solis Inverter from HomeAssistant.

However, as soon as I tried to set this up, I ran into a fundamental issue: all of the setup guides and tools rely on older data-sticks.

My inverter (a Solis RHI-3.6K-48ES-EG) came with a 3rd generation stick (model S3-WIFI-ST) which, unlike older counterparts, does not expose Modbus locally. As a result, tools like solismod and pysolarman cannot work with them.

There is actually a guide to getting things working using a rs485 splitter but I've not tried it yet (in fact, I only actually found it whilst double checking the links above as part of drafting this post).

However, Soliscloud has an interface which allows you to manually set the registers on your Inverter. It's not enabled by default so access needs to be requested and, even once granted, there's no API acces, but it does do what it says on the tin.

The navigation interface is quite simplistic:

Screenshot of the top level menu of the Soliscloud Remote Control interface

Solis still seem to be working on improving it, as several things have moved around/changed since I first started playing with it.

The default mode is Self-consumption (basically, prioritise serving household demand over export revenue). Within that menu there are some additional options

Screenshot of the Self-Use menu of the Soliscloud Remote Control interface. There are multiple buttons including Time of Use Switch and Charge and Discharge

The Charge and Discharge button opens a side pane which allows charge times and rates to be configured

Screenshot of the Self-Use menu of the Soliscloud Remote Control interface

It's worth noting here that, to a certain extent, it doesn't really matter what you enter as a charge rate (as long as it's not too low): the Battery Management System (BMS) will not allow the battery to charge faster than it's capable of. Still, it is better to err on the side of caution in case that ever changes.

The changes made here, though, will have absolutely no impact until the schedule is enabled.

On the Self-Use menu is a button labelled Time of Use Switch. Anything ending in Switch is essentially a boolean - you turn it on, or off. In this case, the switch defines whether the Charge/Discharge schedule is observed or not.


Adjusting Time of Use

In my previous post, one of the mitigations that I suggested was adjusting settings so that energy would only be drawn from the battery when most valuable (i.e. at peak times). The idea being that any energy remaining after peak would be carried forward into the next day's peak rather than trickling away overnight.

I did look into doing this, but unfortunately the inverter's settings don't quite work that way:

  • If you set the Discharge Current field to 0 and specify a time range, the battery will not discharge during that time (good!)
  • However, it will also consider it a discharge period and will therefore also not charge the battery (boooo!)

So, although you can technically set the battery to only discharge at certain times it probably won't have any charge to discharge in the first place.

In fiddling around to get this working, I learnt a few things about the Solis Inverter's scheduling:

  • If you set a charge period, the battery will charge at that rate, taking energy from the grid to top-up whatever the panels are delivering
  • If you set a discharge period, the battery will constantly discharge at the specified rate, exporting energy to grid if there's insufficient household demand to consume it (this took me by surprise, resulting in me accidentally dumping a battery load to grid shortly before peak time started).
  • There isn't a way (other than setting a discharge period), within Self-use to tell the inverter not to charge the battery from the panels
  • If you switch to Grid Feedback Priority the meaning of the schedule changes. The battery will not be charged from the panels unless there's a charge period defined.

In effect, Self-Use mode means the tooling only really allows you to influence how the battery interacts with the grid: when should it charge from it, when should it discharge to it? This is actually quite logical given that the mode is supposed to try and ensure that consumption primarily uses locally generated energy but it can be a little restrictive.


Routine Schedule

With no ability to dynamically shift the charging schedule based on price, I needed to choose a timerange that would generally see low prices.

The obvious choice for this, of course, was in the small hours of the night, so I set an appropriate schedule:

Screenshot of the time-of-use pane. I have set the inverter to charge the battery between 2am and 4am

The next night, the battery charged as it should. Except, of course, that charge was long gone by the time we reached peak (in fact, it was gone before I even got out of bed).

I messed around with settings for a bit, but ultimately found that there isn't a way to configure things so that that charge is maintained until peak (at least, not if we want it to also be topped up by the panels).

Helpfully though, it's not just the morning that prices are lower: there are a good few hours in the afternoon (where Solar farms are presumably picking up the slack) with lower pricing too:

Screenshot of an Octopus pricing graph, the afternoon is much cheaper than 4pm onwards

So, I updated the configuration so that we charge the battery from 12pm to just before peak time starts:

Screenshot of battery schedule, it'll charge between 1200 and 1545

This carries an additional benefit: the battery will have had an entire morning of Solar charging, so we'll only use the grid for whatever's necessary to top the battery up (of course, if import prices drop below export value we'll need to re-assess that).


Impact on Charge Levels

The change didn't have as significant an impact on the average charge level as I'd been expecting:

from(bucket: "Systemstats/rp_720d")
  |> range(start: 2023-08-14T00:00:00Z)
  |> filter(fn: (r) => r["_measurement"] == "solar_inverter")
  |> filter(fn: (r) => r["_field"] == "batteryPowerPerc")
  |> keep(columns: ["_time", "_field", "_value"])
  |> aggregateWindow(every: 1d, fn: max, createEmpty: false)
  |> mean()

Screenshot of battery schedule, it'll charge between 1200 and 1545

However, on closer inspection, this average is pulled down by a handful of particularly overcast days, where the only charge that the battery got was from the grid.

If we instead look at the proportion of days where the battery was charged to at least 65% (i.e. enough to see us through even a busier peak):

from(bucket: "Systemstats/rp_720d")
  |> range(start: v.timeRangeStart, stop: v.timeRangeStop)
  |> filter(fn: (r) => r["_measurement"] == "solar_inverter")
  |> filter(fn: (r) => r["_field"] == "batteryPowerPerc")
  |> keep(columns: ["_time", "_field", "_value"])
  |> aggregateWindow(every: 1d, fn: max, createEmpty: false)
  |> map(fn: (r) => ({r with 
       _field: if r._value > 65.0 then "full" else "partial",
       _value: 1
       }))
  |> sum()

We can see that the difference is quite pronounced:

Screenshot of pie charts showing how many days the battery failed to reach 65% charge before the change was made and after.

Prior to the change, nearly 31% of days didn't result in the battery reaching a 65% charge level (yay British weather...). Since the change was made, that number has dropped to just 6%.

The difference is even more pronounced if a 45% charge threshold is used: partial charges then account for 20% before and 1% after the change.


Impact on Savings

The introduction of the afternoon charge schedule led to a fairly significant change in daily savings rates (the change was made at the red line):

Screenshot of daily battery savings. After the change, the daily savings tend to be higher, but there are more negatives

(If you're wondering about those earlier multi-pound savings, they're explained here and, unfortunately, are not repeatable).

The change had two outcomes:

  • Savings, when realised, tended to be higher than before
  • Negative savings have occurred more frequently

Negative savings occur when the total financial value (i.e. the cost of import from the grid or lost export cost) of the power that we store into the battery is higher than the equivalent import value of the energy when it's discharged.

In the time covered, one of primary determining factors seems to be whether or not we use the oven in the evening: If we instead cook with the airfryer (or a gas hob), we don't draw enough energy at peak time. The battery's charge is then released gradually over the course of the night when prices are lower, leading to negative savings.

So, just as in my last analysis, there is a perverse incentive to use less energy efficient appliances in the evening in order to help drive the numbers up.

Of course, no-one actually benefits from improving those figures in that way: using extra energy unnecessarily is still a net loss and is an example of the sort of thinking that ultimately leads to trying to burn tyres in order to improve the efficiency of burning coal to generate Cryptocurrency.

A crypto-bro sits holding a Bitcoin amongst fires made of coal and tyres. Generated using Bings AI image creator, which probably explains why he has a third hand

Utterly crazy.

Anyway... despite those days with negative savings, the average daily saving has increased to £0.152 (from £0.125). Whilst that change is only a few pence, it still represents a 21% increase in the average daily saving.

At that rate, the battery will have paid itself off in... yeah, let's not go there.

If we can eliminate negative-savings days (don't you just love a magic wand?), then the average saving becomes 0.29 a day. That roughly halves the break even time (but still leaves it many times the battery's rated lifetime)


Getting Free Electricity

Our energy tariff is Octopus Agile, which sometimes sees prices drop very low (or even become negative). Unfortunately, though, that's not really happened at all since I updated the charge schedule.

However, we're now enrolled in a new Octopus scheme: Power-Ups.

Screenshot of the Octopus page on powerups, showing the areas that it's currently active in

With power-ups, we occasionally get periods where our electricity is free despite the Agile price not being 0. The idea behind the scheme is to show the local network operators that excess renewable energy can be consumed and discourage them from switching off green generation when surpluses are expected.

With the electricity being free, it obviously makes sense to charge the battery from the grid rather than from solar, helping drive up that day's savings.

In order to account for these in my stats, I created a new field - override_price - which allows me to override the reported agile unit cost with a simple curl

curl \
-d 'octopus_pricing,tariff_direction=import,charge_type=usage-charge,payment_method=None,reason=misc/solar#6 override_price=0.0 1692365400000000000' \
"http://192.168.3.96:8086/write?db=Systemstats"`

This sets the cost to 0.0p/kWh for that 30 minute slot.

The following query allows us to look at when there have been power-ups and how much time they covered:

SELECT
   count("override_price") * 30 as "minutes"  
FROM "Systemstats"."autogen"."octopus_pricing" 
WHERE $timeFilter 
GROUP BY time(1d) fill(null)

Screenshot of graph showing when powerups have occurred. There have been 4 since the scheme started on Aug 14

As you might expect, the impact that Power-up periods have had on battery savings has been pretty positive (relevant days have been marked with red dots):

Screenshot of graph showing battery saving values with red dots marking the days where power-ups were present. Savings are pretty good on each of the days

There are a number of factors that have played into savings performance so far, but the primary one is striking a balance between Solar and grid charging.

The maximum rate at which the battery can charge is limited, so it's simply not possible to take the battery from empty to full in 2 hours: this means that it's important to let the battery charge from solar during the morning because otherwise there likely won't be enough charge to cover peak.

Conversely, it also doesn't make sense to put too much Solar energy into the battery, because then we won't be able to fully utilise the free grid power.

To complicate matters, the battery's maximum charge rate is influenced by things like temperature, so there is an inavoidable element of guesswork involved in scheduling charges.

I found that the key lies in not relying solely on the Soliscloud schedules and instead switching things around manually:

  • Set a schedule to charge from grid during the power up (so far that's been 1400 - 1600)
  • In the morning, let the battery charge from Solar until it's at about 47% (on some days we reached that by 1030)
  • Toggle off the Time of Use Switch and then switch the inverter to Feedback Grid Priority mode (so that it'll start exporting rather than charging the battery)
  • Just before the start of the power-up, switch back to Self-Use and toggle Time of Use back on so that the battery charges from grid

This approach, of course, relies on me being available at the right times to switch things around. But, it also leads to much higher export volumes (and therefore revenue)

Screenshot of graph showing system export volume. Power up days are marked with red dots and are generally much higher

In effect, each exported kWh becomes worth double what it would otherwise have been.

  • Rather than storing 1 kWh, we export it (export revenue makes balance +15p)
  • During the power-up period, we replace it using free grid power, stored in the battery (balance remains +15p)
  • We later discharge and consume it at the prevailing import price (assuming 30p/kWh, balance becomes +45p)

The power-up allows us to claim the export value, avoiding loss of opportunity cost (which, as I wrote last time, is a major contributor to the low savings rate), but still realise a full kWh's worth of savings during peak time.

Although that level of gain couldn't exist without the battery, it isn't fully accounted for in the battery savings figures - to see the true benefit of the approach we need to look at the total system savings figure instead:

Screenshot of graph showing system savings. Power up days are marked with red dots and are generally much higher

As a rule, the days with power-ups outperformed their adjacent days. The exception is the 18th of August: not only was the weather crap, it was my first spin at configuring the inverter to take advantage of a power-up and I ballsed it up a bit.

It's worth noting too, that the Power-Ups also delivered non-solar savings that aren't accounted for in these graphs: we shifted some of our load to the Power-up window and so were able to run the washing machine etc for free.

The result is that our consumption costs were reduced by at least sixty pence a day:

Screenshot of graph showing savings derived through Octopus power ups

The grid, for it's part, gets an additional supply of green energy (our exports) at times of lower supply, without needing to spin down green generation capacity.


Further Improvements

A couple of days ago, I made an additional change to the schedule.

Although, much lower than the evening peak, there is a pricing peak each morning (coinciding with people getting ready for work etc)

Screenshot of graph showing octopus pricing, there's a small peak each morning before prices drop again for the afternoon

At that time in the morning, our panels are active, but far from operating at their best, so it seems to makes sense to take a small overnight charge to help shave the morning peak.

Screenshot of battery schedule, it is now configured to charge 1200-1545 and 0315-0545

The savings, if any, will likely be a few pence at most but that's still actually a reasonable percentage improvement on the battery's daily value. It'll also, likely, be higher in Winter when our panels start generating later in the day.


Conclusion

Battery break-even, obviously, is still decades away. But, given that there is no way to un-purchase the battery, any additional savings that the battery can generate are still welcome, not least because it helps lower our energy bills. If I were being smart, I could probably find a way to invest those savings so that their growth could contribute further towards achieving break-even.

Because our day-to-day activities vary, there's an element of risk in charging the battery (whether from grid or solar): the battery's ability to unlock savings is quite reliant on whether or not we'll demand sufficient energy at peak time.

That could potentially be mitigated by limiting battery discharge to certain periods, but it's not something that's currently possible with this inverter (or at least, not without significant trade-offs).

Somewhat unsurprisingly, the best way to unlock additional battery savings is to use the battery more. Ensuring that the battery has at least enough charge to survive peak usage has helped drive savings up by about 20%.

The introduction of Octopus Power-Ups has also proven beneficial, allowing the system to derive a reasonable amount of additional value. The benefit will, very likely, be less during Winter as we won't be able to export anywhere near the same amount of energy, conversely though, our batteries will likely be in more need of a grid charge.

My work on this, clearly, isn't yet done.

First, I need to see what benefit (if any) we gain from shaving that morning peak.

Once I've got meaningful stats on that, the next step is likely going to be to look at adding a rs485 switch in to the mix so that I can potentially start to automate.

With automation in place, I'll be more able to

  • Avoid running up negative savings: on days where we routinely don't use the oven, the automation can disable (or perhaps just reduce) the scheduled grid charge.
  • Ensure a sensible charge level on cloudy days: weather forecasting can be used to define whether we're likely to need a prolonged grid charge to cope with peak
  • Automate switching between Self-Use and Grid-Priority, allowing me finer control over when the battery charges and discharges

I don't believe that we'll ever reach the point that buying the battery won't have been a financial mistake, but given that we've got it, I do think there's still some scope for milking additional savings out of it. Particularly as the rest of the system is currently over-performing enough that it should offset the cost of the battery relatively quickly.