Summary
In VPP control mode (SolaxModbusGrowattController), the LOAD_SUPPORT intent is mapped identically to BATTERY_EXPORT: a fixed, forced discharge percentage via grid_first. It never follows actual household load, causing unnecessary grid imports/exports whenever the schedule's load prediction misses.
Reported independently by @nholmgaard and confirmed/expanded by @ridax67 on #118 (2026-07-28), both testing vanilla b26 on Growatt MIN/inverter hardware.
Root cause (confirmed against source)
_intent_to_vpp() in core/bess/solax_modbus_growatt_controller.py:271-297:
def _intent_to_vpp(self, grid_charge, discharge_rate, block_passive_charging=False):
if grid_charge:
return 100, True
if discharge_rate == 0:
return 0, block_passive_charging
return -discharge_rate, True
LOAD_SUPPORT has discharge_rate > 0 (INTENT_TO_CONTROL["LOAD_SUPPORT"], core/bess/inverter_controller.py:49), so it falls into the last branch — the same branch as BATTERY_EXPORT: VPP remote control stays enabled with a forced negative (grid_first) power percentage.
This is a real divergence from TOU mode, where LOAD_SUPPORT → load_first (core/bess/inverter_controller.py:60-67) — load_first lets the inverter's own control loop follow actual load. VPP mode has no equivalent path: _intent_to_vpp only disables/releases remote control when discharge_rate == 0, never for LOAD_SUPPORT specifically.
User reports
Load support intention commands the discharge rate to a fixed value instead of having it just follow the load. This causes unnecessary imports as well as exports, unless the load prediction is completely accurate (which will never happen)... I think that Load support intention should just release VPP control, then it will work better. — @nholmgaard
I agree that sometimes load first would be better than grid first (whenever there is no PV?) and grid first should only be used for solar export and battery export. — @ridax67
Proposed fix
For LOAD_SUPPORT in VPP mode, release VPP control (disable vpp_remote_control, falling back to inverter self-consumption / load-following) instead of forcing a fixed grid_first discharge rate — mirroring what TOU mode already does with load_first.
Out of scope for this fix: ridax67's adaptive power-tracking-toward-zero-net-grid approach for grid_first is a more advanced closed power control loop idea, tracked separately as future work, not needed for a correct baseline here.
Path to closing
Related: #118
Summary
In VPP control mode (
SolaxModbusGrowattController), theLOAD_SUPPORTintent is mapped identically toBATTERY_EXPORT: a fixed, forced discharge percentage viagrid_first. It never follows actual household load, causing unnecessary grid imports/exports whenever the schedule's load prediction misses.Reported independently by @nholmgaard and confirmed/expanded by @ridax67 on #118 (2026-07-28), both testing vanilla b26 on Growatt MIN/inverter hardware.
Root cause (confirmed against source)
_intent_to_vpp()incore/bess/solax_modbus_growatt_controller.py:271-297:LOAD_SUPPORThasdischarge_rate > 0(INTENT_TO_CONTROL["LOAD_SUPPORT"],core/bess/inverter_controller.py:49), so it falls into the last branch — the same branch asBATTERY_EXPORT: VPP remote control stays enabled with a forced negative (grid_first) power percentage.This is a real divergence from TOU mode, where
LOAD_SUPPORT → load_first(core/bess/inverter_controller.py:60-67) — load_first lets the inverter's own control loop follow actual load. VPP mode has no equivalent path:_intent_to_vpponly disables/releases remote control whendischarge_rate == 0, never forLOAD_SUPPORTspecifically.User reports
Proposed fix
For
LOAD_SUPPORTin VPP mode, release VPP control (disablevpp_remote_control, falling back to inverter self-consumption / load-following) instead of forcing a fixed grid_first discharge rate — mirroring what TOU mode already does withload_first.Out of scope for this fix: ridax67's adaptive power-tracking-toward-zero-net-grid approach for grid_first is a more advanced closed power control loop idea, tracked separately as future work, not needed for a correct baseline here.
Path to closing
Related: #118