Skip to content

Feature: negative-price PV export curtailment via Growatt export-limit register #269

Description

@johanzander

Background

Raised by @Frank-Leysen in #126 (comment 2026-07-11T13:36:32Z): on his Luminus Dynamic contract, sell/injection price goes negative on sunny midday hours. His HA scripts block grid export when the injection price is <= 0, but BESS's optimizer has no equivalent — when solar surplus exceeds house load plus available battery charge room, the excess is unconditionally exported at whatever the sell price is, including negative.

Root cause (confirmed in code)

core/bess/dp_battery_algorithm.py_state_transition / _compute_reward (STORE and IDLE dispositions, ~lines 192-223 and 294-314): surplus_exported = max(0.0, surplus - solar_to_battery) is computed unconditionally once solar exceeds min(max_charge_power_kw, remaining battery room). The reward term already penalizes this correctly when sell_price < 0 (-grid_exported * current_sell_price becomes a cost), so the DP "wants" to avoid it — but there is no action available to actually avoid it. There is no PV curtailment action anywhere in the DP action space, and no export-limit integration in growatt_sph_controller.py / growatt_min_controller.py.

Hardware capability (confirmed, not yet integrated)

Growatt hybrid inverters (SPH / MOD-XH series, includes Frank's MOD 5000TL3-XH GEN4) support a genuine export-limit / curtailment function via Modbus:

  • Register 201: export limit value (or percentage on some models)
  • Register 202: enable export-limit control

This uses a CT/smart-meter at the grid connection point (e.g. SPM-CT-E) to measure actual export and throttle PV/MPPT production down — it curtails real panel output, not just a grid-meter cap that gets bypassed once the battery is full. One forum report noted a small residual overshoot (~20-50W) even at a 0 W setting, so it isn't perfectly airtight, but it does what's needed here.

Sources:

Open question for Frank: does he have the CT/smart-meter hardware connected/available? This feature is only viable if that's present.

Proposed feature

When forecast sell price for a period is negative (or below a user-configurable floor), and the DP has no better use for the surplus (battery full / no headroom), write the Growatt export-limit register (0 or a configured cap) for that period instead of allowing full-rate export; clear/restore the limit once price is non-negative again. No change to the DP objective is needed — the reward function already penalizes negative-price export correctly; this is purely a new actuation path.

Scope

  • New: export-limit register read/write in the Growatt GEN4 Modbus controller
  • New: per-period decision of when to apply the limit (likely a straightforward "sell_price < 0" check against the existing schedule, not a DP action-space change)
  • Confirm hardware prerequisite (CT/smart-meter) with affected users before committing to implementation

Not a regression — no current version of BESS ever had PV curtailment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions