• Have you tried out dark mode?! Scroll to the bottom of any page to find a sun or moon icon to turn dark mode on or off!

diy solar

diy solar

Victron ESS Mode 3 Implementation and Exported Grid Power

ricardocello

Watching and Learning
Joined
Apr 4, 2023
Messages
4,045
Location
Virginia, USA
I realize the audience for this topic is relatively small, but for those not in the Victron ecosystem, it will demonstrate the enormous flexibility that Victron builds into their products.

Victron ESS Mode 3 allows someone to implement their own power control loop to completely take over what the Multiplus or Quattros are doing in real time via a very simple setpoint: How much power should be imported or exported at the input of the inverters?

See https://www.victronenergy.com/live/ess:ess_mode_2_and_3
Power to/from AC-input = Power to/from battery + Power to/from AC-output

Why Am I Doing This?
  • Because I want the system to require as little human interaction as possible to self-adapt to the changing seasons and daylight savings time changes.
  • Because I want to see firsthand why grid-parallel ESS systems cannot prevent undesirable export to the grid when large loads shut off.
  • Because I think I can do it better than Victron, at least for my use cases.
  • Because I enjoy embedded software development and control systems.
It sounds simple, but there are so many use cases and behavior oddities in what people might want their systems to do (and when) that it took me a week to get it mostly right. I will continue testing this week, and will no doubt find more issues. I will consider posting it on GitHub after it is running without any known issues.
 
Last edited:
Code:
# Implements a custom ESS Mode 3 Control Loop.
# This implementation is specific to the ricardocello Victron ESS configuration.
#
# Interesting Features
#
# The Daily Schedule is programmed to handle every day with minimal interaction other than the target minimum SoC
# at which to start the day. The schedule is built around sunrise and sunset times, so it is unaffected by
# seasons changing (including Daylight Saving Time).
#
# The current Daily Schedule has these actions:
#
# (1) Starting four hours before sunrise, the batteries are discharged to the ESS Minimum SoC using Critical Loads.
#     Any PV power that becomes available also powers the Critical Loads, which will slightly reduce
#     the battery discharge rate. This should be sufficient time to discharge the batteries down to 10% from 50% SoC.
#
# (2) Starting one hour after sunrise, solar power is used to power all loads. Grid usage is minimized to the
#     grid setpoint value in Watts. If there is insufficient solar to power all the loads, grid power is used.
#     This keeps the battery SoC increasing monotonically throughout the day. If there is excess solar power available,
#     it is used to charge the batteries. When the battery SoC reaches 80%, the battery is also used to power the
#     loads, helping to prevent the SoC from reaching 100%. As the solar power decreases such that it is again
#     insufficient to power all loads, the battery SoC will be held at 80%.
#
# (3) Starting in the afternoon (70% of the solar day completed), the battery is maintained at a 50% SoC.
#     If the SoC is above 50%, the battery is used to power the Critical Loads until it reaches 50% SoC.
#     If the SoC is below 50% due to a really cloudy day, grid is used to bring the battery SoC back up to 50%.
#     This is to guarantee the battery availability during the critical dinner time hours, especially in the summer.
#
# (4) Starting one hour after sunset, the battery is maintained at a 50% SoC as above. However, when the
#     SoC reaches 50%, the inverter and charger are disabled to save considerable idle power overnight (passthru mode).
#     This also disables solar power, but since it is dark, it does not matter. This continues through to the next day.
#
# The user can switch between Optimized, Keep Batteries Charged, and this External Control Mode 3 implementation
# by using the console GUI. When one of the ESS Mode 2 modes is active, the custom Mode 3 implementation idles.
# If the user changes the Minimum SoC value in the GUI, it will be passed on to the Mode 3 implementation when
# External Control is reselected. This is convenient for making a real-time setting change.
# If a Daily Schedule is running, it will be restarted to ensure consistency.
#
# The AllLoadsPV state handles the atypical use-case of applying maximum PV power to loads during the day.
# This is to help avoid filling a battery bank with insufficient capacity and for efficiency.
#
# There is a 400-500 W/sec built-in limitation in the inverter firmware (800-1000 W/sec for split-phase 240V loads).
# Although the Grid Meter and control loop run at 10 Hz, response time to a setpoint change appears to be 0.5 seconds.
# These limitations will cause exported power to be sent to the grid when large loads switch off.
#
# L1 and L2 have independent exponential filters for the power setpoints, with dynamic switching of time constants
# to help minimize inadvertent exporting of power to the grid. This also prevents undesired feeding back on one leg
# to the utility transformer, which should increase efficiency. The time constants have been carefully tuned to
# minimize grid feedback. This also balances the L1/L2 difference from the grid, eliminating the inefficiency of
# sending power back to the utility transformer on the Neutral line.
#
# See https://www.victronenergy.com/live/ess:ess_mode_2_and_3
 
Code:
class State(Enum):
    # This External Control custom ESS implementation is always in one of the following states:
    Undefined = 0           # State is initially undefined at startup
    Mode2 = 1               # Normal ESS Mode 2 system operation (not externally controlled Mode 3)
    Idle = 2                # Inverter and charger are disabled (grid pass-thru)
    Charging = 3            # Grid and available PV are used to charge the battery up to a target SoC
    Discharging = 4         # Critical Loads are used to discharge the battery down to a target SoC
    Maintaining = 5         # Charge or discharge as needed to reach a target SoC

    # CriticalLoadsPV
    # PV is sent to the Critical Loads only, with excess PV power charging the batteries.
    # Grid covers the remainder of the power needs, but does not charge the batteries.
    CriticalLoadsPV = 6

    # AllLoadsPV
    # PV is sent to all loads first, with any excess PV power charging the batteries.
    # Grid covers the remainder of the power needs, but does not charge the batteries.
    # When SoC is above 80%, battery power is used before grid power to cover the remainder of
    # the loads in an attempt to keep the battery from reaching 100% SoC.
    AllLoadsPV = 7
 
I also use ESS mode 3. It allows me to combine several parts of my electrical system to complement each other (solar, battery, grid).
However be aware of some not so nice "features":
- Victron ESS (in Multiplus-II) is quite slow, and also overshoots. This makes finding usable control loop parameters quite the journey...
- Victron Multiplus-II ESS is also somewhat coarse, like >+-20W difference between set and actual value. In a typical home that is +-10%!
- ESS needs a special software module, that is incompatible with some of the other features of the Multiplus.
 
- ESS needs a special software module, that is incompatible with some of the other features of the Multiplus.
Are you referring to the Assistant you need to load on the inverters?

Also worth noting, for those of us in the US at least, ESS, strictly speaking, isn't something that is usable in the sense that Victron doesn't have US grid codes, and interconnecting with only Victron is not something that I think one can do in most jurisdictions.

I use it on one of my systems I know is 'safe' (it's fed by another inverter) to maintain a certain state of charge and/or automate things I'd otherwise need to do in Node Red. While I could do that (and might), this was more easy button. For now.
 
Are you referring to the Assistant you need to load on the inverters?
I only know this for my location (Germany). Victron Multiplus-II is certified for Grid ESS (you still need an ok from your utility).
If you want to use ESS functions, you have to load an additional software module in "VEConfigure". That disables some other functions. E.g. you can no longer have UPS (grid backup).
I do not know if this behaviour is specific to my local grid code.
 
I also use ESS mode 3. It allows me to combine several parts of my electrical system to complement each other (solar, battery, grid).
(y)
However be aware of some not so nice "features":
- Victron ESS (in Multiplus-II) is quite slow, and also overshoots. This makes finding usable control loop parameters quite the journey...
Yes! Not only does it take 0.5 seconds for the setpoint to do anything, but the 800-1000 W/sec limit is painful (Grid Code Other).
I’ve been told it is worse for certain Grid Codes like Germany.

I’ve got a stable loop now, tested it with small loads and huge loads (6 kW) switching on and off.
My grid meter (EM540) runs at near 10 Hz.

- Victron Multiplus-II ESS is also somewhat coarse, like >+-20W difference between set and actual value. In a typical home that is +-10%!
Yes! The output power measurement on critical loads resolution is like 20W.
My grid meter is super accurate, but all of the coarseness adds up quickly.
 
I only know this for my location (Germany). Victron Multiplus-II is certified for Grid ESS (you still need an ok from your utility).
If you want to use ESS functions, you have to load an additional software module in "VEConfigure". That disables some other functions. E.g. you can no longer have UPS (grid backup).
I do not know if this behaviour is specific to my local grid code.
Right, the ESS Assistant disables certain things. My grid backup is working fine, however.
I did add some capacitors near the DC inputs to my Quattros.
 
OK, I've put some Grid Export monitoring and logging into the control loop.

The EM530 grid meter appears to be running at 7-8 Hz, depending on the Cerbo (it is capable of 10 Hz).
Every continuous run of negative grid power values (i.e., unintended exporting) is logged as an event, and statistics are generated.
My grid setpoint is 100W import.

I'm storing the following for each event:
  • Starting Timestamp
  • Duration (seconds)
  • Total Energy Exported (Wh)
  • Maximum Exported Power (W)
The summary statistics for the list of events generated at the end of the day will include:
  • Total duration of all grid exporting for the day (seconds)
  • Total energy of all grid exporting for the day (Wh)
  • Maximum event duration (seconds)
  • Maximum event energy export (Wh)
  • Maximum measured exported power (W)
Log files are produced every day.
This is as closely as I can monitor unintended grid export with the equipment I have.
7-8 Hz reveals lots more than 1 Hz, and is way better than every minute, or 5 minutes.
I'll run it for a few days and post the results later.

Here is what a very brief export looks like (note the two negative grid values for a fraction of a second)).
The spinning wheel meter just appears to stop completely, this export is way too small to be visible.

Code:
2025-09-23 10:37:30.388 [Grid  128 W] [Inverter 1510 W] [Needed   28 W] [PV 4149 W] [Setpoint -626 W]
2025-09-23 10:37:30.507 [Grid  112 W] [Inverter 1510 W] [Needed   12 W] [PV 4149 W] [Setpoint -628 W]
2025-09-23 10:37:30.639 [Grid  128 W] [Inverter 1560 W] [Needed   28 W] [PV 4149 W] [Setpoint -633 W]
2025-09-23 10:37:30.763 [Grid  120 W] [Inverter 1560 W] [Needed   20 W] [PV 4149 W] [Setpoint -637 W]
2025-09-23 10:37:30.878 [Grid  100 W] [Inverter 1560 W] [Needed    0 W] [PV 4149 W] [Setpoint -637 W]
2025-09-23 10:37:31.006 [Grid   80 W] [Inverter 1560 W] [Needed  -20 W] [PV 4149 W] [Setpoint -633 W]
2025-09-23 10:37:31.130 [Grid   64 W] [Inverter 1560 W] [Needed  -36 W] [PV 4124 W] [Setpoint -627 W]
2025-09-23 10:37:31.262 [Grid   20 W] [Inverter 1560 W] [Needed  -80 W] [PV 4124 W] [Setpoint -612 W]
2025-09-23 10:37:31.396 [Grid  -28 W] [Inverter 1560 W] [Needed -128 W] [PV 4124 W] [Setpoint -589 W]
2025-09-23 10:37:31.527 [Grid  -12 W] [Inverter 1560 W] [Needed -112 W] [PV 4124 W] [Setpoint -569 W]
2025-09-23 10:37:31.675 [Grid   12 W] [Inverter 1560 W] [Needed  -88 W] [PV 4124 W] [Setpoint -553 W]
2025-09-23 10:37:31.805 [Grid    8 W] [Inverter 1560 W] [Needed  -92 W] [PV 4124 W] [Setpoint -537 W]
2025-09-23 10:37:31.929 [Grid   24 W] [Inverter 1560 W] [Needed  -76 W] [PV 4124 W] [Setpoint -523 W]
2025-09-23 10:37:32.062 [Grid   24 W] [Inverter 1560 W] [Needed  -76 W] [PV 4090 W] [Setpoint -509 W]
2025-09-23 10:37:32.204 [Grid  108 W] [Inverter 1560 W] [Needed    8 W] [PV 4090 W] [Setpoint -511 W]
2025-09-23 10:37:32.338 [Grid  128 W] [Inverter 1560 W] [Needed   28 W] [PV 4090 W] [Setpoint -516 W]
2025-09-23 10:37:32.463 [Grid  136 W] [Inverter 1560 W] [Needed   36 W] [PV 4090 W] [Setpoint -522 W]
2025-09-23 10:37:32.598 [Grid  144 W] [Inverter 1560 W] [Needed   44 W] [PV 4090 W] [Setpoint -530 W]
2025-09-23 10:37:32.745 [Grid  128 W] [Inverter 1560 W] [Needed   28 W] [PV 4090 W] [Setpoint -535 W]
2025-09-23 10:37:32.885 [Grid  136 W] [Inverter 1560 W] [Needed   36 W] [PV 4090 W] [Setpoint -542 W]
2025-09-23 10:37:33.027 [Grid   68 W] [Inverter 1560 W] [Needed  -32 W] [PV 4090 W] [Setpoint -536 W]
2025-09-23 10:37:33.170 [Grid  104 W] [Inverter 1560 W] [Needed    4 W] [PV 4090 W] [Setpoint -537 W]
 
Last edited:
An interesting day measuring undesired grid export power.

I'm running the ESS Mode 3 control loop trying to keep a 100 W grid setpoint using available PV power only.
Grid export can only happen is when there is sufficient PV for the whole house and the 100 W setpoint is reached.
When the grid is supplying more than 100 W, it is much less likely to see any export (except for very very large load drops).

Running from 10:00 to 14:30 produced this:
# Grid Export: [ 611 Events] [ 217.7 sec] [ 9.063 Wh][ 1.915 sec Max] [ 0.692 Wh Max] [2468 W Max]

So a total of 611 events where power was exported to the grid were detected.
The shortest was 0.1 seconds in duration.
The longest was 1.915 seconds in duration.
The total amount of time spent exporting was 217.7 seconds (which is more than I was thinking it would be).
A total of 9 Wh was exported (pretty teeny), and the most that was exported at one time was 0.692 Wh (really teeny).
The maximum power exported was 2468 W. It could have been worse.

Here are the events plotted.

Screenshot 2025-09-23 at 5.36.39 PM.png
 
My ancient spinning-wheel utility meter measures 7.2 Wh per revolution of the aluminum disc.
There are holes every 10% of a revolution, and presumably there is an optical detector counting those as they go by.
Which means the meter can detect every 0.72 Wh that is used (or exported if going backwards).
I do not know if I get billed for the exported power, my guess is yes.

The largest energy event I had was 0.692 Wh, so just less than one optical hole spacing.
Which means the meter never ran backwards for more than one hole.
 
OK, I've been running this ESS Mode 3 implementation for a week with no problems.
Still untested is behavior at near-100% battery SoC, I'm hoping DVCC just keeps doing its thing.

Code is available on Github here:

Note that this is based on my other ModbusTCP code which monitors and logs 1 Hz data in real time.
See the aptly named ess_mode_3.py file.
 
And here is what it looks like on the Console when running (pretty boring).
Note that the PV is powering all of the AC Loads (on the input of the inverter) as well as the Critical Loads (on the output of the inverter).
The remainder of the PV is going to the battery.


ESS Mode 3 PV Consumption 2.gif
 
Here is an example of a 6 kW resistive load shutting off.
You can see the performance of the ESS Mode 3 Control Loop.
It isn't any better or worse than the Victron Mode 2 loop from a timing point of view.

Screenshot 2025-09-28 at 12.21.39 PM.png
 
The ESS Mode 3 implementation is now running natively on the Cerbo GX.
I like it much better than Mode 2 because it does exactly what I want programmatically.

30 seconds after startup, the python script starts executing and automatically switches the ESS Mode to External Control
(which is really now Internal Control :cool: ).

Manually switching back and forth from ESS Mode 2 and Mode 3 works really well.
The only ESS Mode 2 parameter used by the Mode 3 code is the Minimum SoC.
 
Why Am I Doing This?
  • Because I want the system to require as little human interaction as possible to self-adapt to the changing seasons and daylight savings time changes.
I tried Mode3, but in the end Mode2 turned out to be simpler for me. By the way, I’m not using a Cerbo or GX, but a Raspberry Pi, and it has crashed or lost network connection a few times over the past year. So, I thought Mode2 would also be more reliable, since VenusOS would perform continuous measurements and has better safety checks than my script, whereas my script could only run periodically - just to adjust the grid set point or to disable import/export when needed. Maybe internal GX would be more stable and you wouldn’t have to worry about that?
 
I tried Mode3, but in the end Mode2 turned out to be simpler for me. By the way, I’m not using a Cerbo or GX, but a Raspberry Pi, and it has crashed or lost network connection a few times over the past year. So, I thought Mode2 would also be more reliable, since VenusOS would perform continuous measurements and has better safety checks than my script, whereas my script could only run periodically - just to adjust the grid set point or to disable import/export when needed. Maybe internal GX would be more stable and you wouldn’t have to worry about that?
Mode 2 under the hood actually isn't that simple.
Victron put a lot of work into the behavior, and they appear to cover lots of edge cases really well.

Before I went full Mode 3, I actually had a script to dynamically adjust power limits under Mode 2. It worked fine.
However, the Mode 2 scheduler options don't really fit what I am trying to do, and I spent a lot of time trying to make it work for my use case.
Having Mode 3 do exactly what I want and when has actually simplified my life, because I'm not messing around with Mode 2 settings anymore.

The only parameter I adjust now is Minimum SoC.
 
Do you know if it's possible to disable the grid sync with the mode 3?

Reading this it seems that is possible but they also say that it will sync with the grid all the time.
I live in an area with very bad service (long cables) so the voltage is quite inconsistent and I don't want to inject but I would want to have something like DESS working.
 
Do you know if it's possible to disable the grid sync with the mode 3?

Reading this it seems that is possible but they also say that it will sync with the grid all the time.
I live in an area with very bad service (long cables) so the voltage is quite inconsistent and I don't want to inject but I would want to have something like DESS working.

That’s not part of the Mode 3 control as far as I can see.

The Multiplus or Quattro firmware itself monitors the AC Inputs in real time, and makes a determination whether or not the power
is usable by monitoring frequency and voltage.

However, there are “Ignore AC Input” flags you can control.
So if you don’t want grid at a certain time of day, or because its voltage doesn’t meet your logic, you can force it to ignore
the AC input and run from inverter. Keep in mind that it attempts to keep phase lock with the AC if it is there so it can switch back quickly.
 
All my attempts to use the "ignore AC input" feature did not work. Either with the flag on the multi or using nodered.
I've read in forums that the only way of doing it is turning the multiplus into inverter mode but that turns ESS off completely.

The voltages are usually within limits that in my area are (230v +- 10%) but all my lights flicker during dinner time for example when there's high demand. When it does below that the multi disconnects yes but appliances like microwaves for example are way slower to heat with 203 than with 230v
 
All my attempts to use the "ignore AC input" feature did not work. Either with the flag on the multi or using nodered.
I've read in forums that the only way of doing it is turning the multiplus into inverter mode but that turns ESS off completely.
ESS only functions when grid is present. I have not tried the "ignore AC input" flags myself, that is good to know.
When grid is not present, the multiplus/quattro goes into inverter mode, and then none of the ESS settings apply.

The voltages are usually within limits that in my area are (230v +- 10%) but all my lights flicker during dinner time for example when there's high demand. When it does below that the multi disconnects yes but appliances like microwaves for example are way slower to heat with 203 than with 230v
Ok, that makes sense.

You can change the lower voltage threshold to switch over to inverter below say 215V,
but then you might find it switching back and forth between grid and inverter too much.

Another more expensive option is to get a separate DC charger that takes 230V in and puts out 100A at 48V (or whatever your voltage is),
and only run in inverter mode. This double conversion approach is inefficient, but you should never have flickering lights because the
inverter will be putting out clean 230V (assuming you have enough capacity for the whole house).
 
I'm looking into that but Victron don't have a 230vac to 48vdc charger. I would need a multiplus for that.
That's not reasonable for me because I would only use it for 2/3 months each year because I have 48 kwh of battery capacity.
 
I'm looking into that but Victron don't have a 230vac to 48vdc charger. I would need a multiplus for that.
That's not reasonable for me because I would only use it for 2/3 months each year because I have 48 kwh of battery capacity.
In the US, we use these devices (which will also work with 230V / 50Hz), and are way cheaper than a dedicated Multiplus.
You could put a Victron SmartShunt on the output to measure the DC charge current, and thereby integrate it into the Victron world.
You may find similar things in Europe.


 
Thank you!
I'm looking into the used market for victron products I would prefer to stay within the victron ecosystem if possible.

I also have the lynx shunt already so the SoC would be accurate at least.

I'll probably wait a bit more because I'm also noticed that some EV DC chargers are hitting the market right now so I would probably do the necessary changes when and if Victron releases their own. (Will need to buy a new distributor and relocate the trunking...)
 

diy solar

diy solar
Back
Top