Just my luck, I move into a house with solar panels, just when the energy market breaks. Just about every day, electricity generation prices go negative when the sun is out, then skyrocket when it’s down.

Screenshot of solar feedin tarrif at negative 8c per kWh.
Grid to my house: 7c/kWh 😁 My house to the grid: -8c/kWh 😭

Charged if you do, charged if you don’t. Any power I use costs me 7c/kWh, while any power I export also costs me 8 c/kWh. The magic of the free market. The price difference is thanks to distribution companies having monopolies on the powerlines. They charge per day of use, plus per kWh of usage, cos why not double dip your customers!

So our free market is already utterly warped by geographic monopolies of distribution companies. But the problems continue. Each day as solar generation goes up, people’s energy demand also drops as they are running off the solar and selling the excess. You get that double whammy of increased supply, decreased demand. It’s so extreme that prices go negative. Something that’s meant to be a rare occurrence is casually just happening on the daily now.

Big picture this might be a great sign. Are we done with solar? We seem to have way more than we need, surely these negative prices mean fossil fuel generators are being kicked off the grid?

lol nah.

Prices are negative even with only 63% renewables. Coal generators continue to run all day every day. Since they can’t turn off, they can only ramp down so far. It turns out tonnes of burning coal just sorta keeps burning even if you stop shoving more in. So in the middle of the day, they are generating about half of the electricity that’s close to overloading the grid. This limits the penetration of renewables, with large scale solar and wind stopping to avoid the negative prices.

The Market demands I turn my solar off

So now I’ve got to turn my solar panels off to avoid paying extra on my power bill. With them going full blast, I’m being charged ~40 cents each day. That’s $12 a month, or 17% of my typical bill. Doing this is hard to Google since it goes by different names; curtailment, dynamic power reduction, demand response. Turns out this is only recently a consideration in solar inverter installations. For decades people have been installing gigawatts of solar panels on people’s roofs, on the assumption that it’ll never actually impact the grid. So absolutely nothing was setup or mandated to curtail power output in response to grid overload.

Lucky for me I’ve got a recentish Fronius inverter with WiFi, so I can configure it over the network. Best to use their app Solar.start to setup and connect the inverter. Once connected you can use their other app or just visit the inverter’s IP address for a dashboard and settings menu.

Mod MY bus?

While there are plenty of options in the web UI, there’s no straightforward “Stop output” button. There’s also multiple Fronius web APIs but they are read only for data logging. The real control is in the Modbus interface. Handily it supports Modbus over TCP, so we can access it via WiFi too.

Screenshot of Fronius Modbus Settings page, with tcp checked, and Inverter control via Modbus checked

Keep in mind that Modbus is completely unsecure. Anything on your network can send commands, no password, username, key, or token required. That ‘Restrict the control’ checkbox makes less writable/controllable, it does not enable authentication unfortunately. This setup is extra dangerous since malicious actors can send a series of dangerous commands that could physically damage the inverter. Heck, you yourself can easy send wrong commands that damage the inverter by mistake. Hopefully one day in the future there’s a better way to do this.

Once Modbus is enabled we can say goodbye to Fronius interfaces, since it uses the industry standard SunSpec v2. Here you’ll google how to talk Modbus, and get a whole bunch of EE documentation about binary flags and checksums. Skip to SunSpec and it’ll still be telling you about offsets and byte types. Don’t worry about any of that, there is already a great official python library!

Even with the block offsets abstracted away, there’s a fair bit to SunSpec, since it’s meant for a whole bunch of device types and uses. Let’s see what we need to simply control the inverter’s power output.

# Load the library
import sunspec2.modbus.client as client

# Create device object to represent the inverter
# slave_id: set to 1, it's a Modbus thing to specify devices on non-TCP Modbus connections.
# ipaddr: The inverter's IP on your LAN.
# ipport: TCP port number in inverter's Modbus config page.
d = client.SunSpecModbusClientDeviceTCP(slave_id=1, ipaddr='192.168.1.35', ipport=502)

# This will work out what type of device it's talking to and configure stuff for you.
d.scan()

d.models is a dict listing all the device types discovered in the scan, in both SunSpec model ID number and name.

print(d.models.keys())
#output:
dict_keys([1, 'common', 111, 'inverter', 120, 'nameplate', 121, 'settings', 122, 'status', 123, 'controls', 160, 'mppt'])

My inverter shows up as multiple devices, really just different features exposed in different specifications. We care about the inverter and controls devices.

Let’s read both their current values

d.controls[0].read()
d.inverter[0].read()

# Get current inverter output in Watts
print(d.inverter[0].W.value)
# outputs
3176.0

Now we can read all the values from our device object d. Easiest to explore it’s contents in a interactive python shell.

We can also modify values in the local d object, then write them to the inverter. These are the values to change that control the power generation.

# enable the power output limit control. 0 = off, 1 = on
d.controls[0].WMaxLim_Ena.value = 1

# Desired output power as a percentage of system's maximum.
# Percentage is multiplied by 100 for precise control.
# Eg 10000 = 100%, 5000 = 50%
d.controls[0].WMaxLimPct.value = 5000

# Now update the inverter with these new values
d.controls[0].write()

# It's customary to read after writing to check everything's gucci
d.controls[0].read()

Because SunSpec is a generic specification, you can’t directly specify wattage, since the range would be different for each inverter model.

There are actually more values that control the timing of the change in power, described in this video. My example keeps it simple and will immediately set the desired value when you call write().

Playing the market

I’ve already got a raspberry pi checking energy price with a python script, so I just needed to add some logic for the inverter.

if amberdata["solar"] < 0:
  # Set output to 8%
	d.controls[0].WMaxLimPct.value = 800
	d.controls[0].WMaxLim_Ena.value = 1
	d.controls[0].write()
else:
  # Set output to 100%
	d.controls[0].WMaxLimPct.value = 10000
	d.controls[0].WMaxLim_Ena.value = 0
	d.controls[0].write()

8% ends up being ~280W, which is enough to cover my house’s background power usage. If I had a power meter I could try to match consumption better.

Screenshot of graph showing Solar feed in price and generation over a day.

Here’s a warmer day that had prices increase in the arvo as people turned on their air cons. Thanks to my script I avoided the negative prices but still made 13 cents between 4-7pm. Most days the price is negative whenever the sun is out at all.

You can barely see the blue bars, which is my consumption from the grid. It’s not too big a deal so far, since I’m lowering output exactly when prices are low. May need to make something smarter for when the air con is going. Imagine how amazing a battery would be to take advantage of this price volatility.

What’s the rest of the country gonna do?

Setting this up is fun for me, but surely we can’t expect every household to do the same? Ultimately power companies need to control this stuff. In other countries there are programs for the power company to set up their own control solution, and pay you with credits on your bill. This has existed for reducing consumption for decades. The same programs can be extended to curtail solar generation when unneeded too.

Australia is very late to the party for this stuff. Trial programs since 2017 to set up demand response are only used by “customer types interested in engaging with technology (e.g. middle-aged men, ‘retired engineers’)” Actual quote. Page 10. In South Australia they’ve resorted to increasing supply voltage in individual substations to trip dumb inverter’s safety features and disconnect themselves. Which is absolutely wild.

We really need coal generators to decommission and make room on the grid. You know, that thing scientists said to do 50 years ago. Arguably 158 years ago. They cost money to run AND their output costs money 10 hours a day.

Graph showing an increase of renewable penetration and potential penetration
We could be hitting 100% renewables if coal generators turned off when needed.

For the last couple of years, renewable penetration into the grid has been lower than potential, with the divide growing. Coal generators aren’t able to get out of the way. I do need to point out that these percentages are for times of peak solar/wind generation and low power demand. We are still a long way off 100% renewables, all day, every day. Check AEMO’s Quarterly Report for way more details.

Of course actually making use of the excess solar during the day would be way better. The financial incentive for more batteries on the grid is greater than ever. They can quickly and easily soak up the sunshine and cover nighttime demand. Leveraging current price fluctuations they can pay for themselves quickly. Or even pump excess solar into opportunistic hydrogen generation, mine bitcoin, anything, it’s better than free power, it’s power you get paid to use!

It’s a big problem to figure out grid scale solutions to all this. It’s also exciting that household scale solutions are within the grasp of ‘middle-aged men and retired engineers’. Solar panels and batteries to power a house are cheaper than ever. A raspberry pi and a lil python script can decimate power bills. This chap managed a $-830 monthly power bill