Repository navigation
feat(sigenergy): model the grid export limit from the plant's backfeed limit - #5681
Conversation
…d limit The Sigenergy Cloud component already parsed gridMaxBackfeedPowerW from the openapi/change MQTT message but never used it, so Predbat planned exports up to the inverter's AC limit even on a plant capped lower at the grid. Publish it as sensor.<prefix>_sigenergy_<system>_export_limit (W) and wire export_limit to it in automatic_config. Until the plant reports a limit the sensor reads 99999 W (no limit), the same convention the gateway component uses, so behaviour is unchanged for systems that never send one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
springfall2008
left a comment
There was a problem hiding this comment.
Reviewed against live data from a production Sigenergy plant with a 3.68 kW G98 export cap on a 12 kW inverter.
Live data point (partly ticks the "live check" box). The plant's only openapi/change message in 48 hours was:
{'antiReflux': 'on', 'batteryRatedChargePowerW': '13200.0', 'batteryRatedCapabilityWh': '27120.0', 'backupCutOffSOC%': '16.0', 'inverterMaxAbsorptionPowerW': '12000.0', 'peakShavingStatus': 'off', 'stormWatchStatus': 'off', 'batteryRatedDischargePowerW': '14400.0', 'inverterMaxActivePowerW': '12000.0', 'dischargeCutOffSOC%': '0.0', 'chargeCutOffSOC%': '100.0', 'peakShavingCutOffSOC%': '0.0', 'gridMaxBackfeedPowerW': '3680.0', 'inverterMaxApprentPowerVar': '12000.0'}
gridMaxBackfeedPowerW = 3680 matches the site's real cap, and live period messages show grid export pinned at 3.67–3.69 kW during exports. So the field is the right source. Three things before merge, the first a regression:
-
set_argoverwrites a user's ownexport_limit(regression). See the inline comment. Today, a user who has setexport_limitin apps.yaml gets the right plan. After this PR it is silently replaced by the sensor, which reads 99999 after every restart until a change message arrives. On the site above that would have been up to two days of no limit.gecloud.pyalready usesset_arg_auto("export_limit", ..., overwrite=False)for this reason. The SaaS uses exactly this kind of per-instance override as the workaround for capped Sigenergy sites, so they would regress on the next restart. -
The value is lost on restart. One change message in 48 hours is typical, because it only fires when the plant's settings change. A pod restarted at 20:17 had still received none at 20:30. Suggest persisting the last reported backfeed and antiReflux values in the component cache, e.g. a new
SIGENERGY_CACHE_KEYSentry restored inload_cached_data(). Then the 99999 fallback only applies to a plant that has never reported. -
Use
antiReflux. Sigenergy sends an explicit export-limiting flag next to the value ('antiReflux': 'on'above). Suggest:antiReflux == 'off'→ 99999 (no limit), whatevergridMaxBackfeedPowerWsays.antiReflux == 'on'→ usegridMaxBackfeedPowerW, including 0. With limiting switched on, 0 most plausibly means zero export (unverified), which settles the PR's 0 W question. That needs_handle_mqtt_changeto store 0 for this field instead of skipping it withif val:.- Field absent → current behaviour.
Minor: the _handle_mqtt_change docstring example could be replaced with the real payload above, which shows antiReflux.
Not covered by this PR, but worth knowing: the plan series on that site also showed 19–24 kW grid swings, beyond the 12 kW battery rate. A separate issue, not explained by the missing export limit.
springfall2008
left a comment
There was a problem hiding this comment.
Automated comment from the triage bot.
Reviewed head 4aa2c51: 2 findings, both inline, no blocking issues. The wiring itself is correct end to end — verified the new sensor flows through get_arg(required_unit='W') (inverter.py:802-803) into the export-rate caps in prediction (prediction.py:666) and dispatch (execute.py:390-391); that missing/0 → 99999 matches the house "no limit" convention (const.py:110, gateway.py:1419, solis.py:2447); that the three tests exercise real paths (MockSigenergyAPI subclasses SigenergyAPI) and would fail before the change; and the docs line is accurate. No kernel change needed — prediction untouched.
Non-anchor note: the PR's remaining open point (a reported 0 W treated as "no limit") is deliberate, disclosed in the body, and matches existing practice — solis maps a 0 register to 99999 too — so I agree with keeping it.
…he the limit across restarts PR #5681 review: - automatic_config binds export_limit with set_arg_auto(overwrite=False), so an export_limit set in apps.yaml is no longer replaced by the sensor's 99999 fallback. - antiReflux "off" means no limit; "on" uses gridMaxBackfeedPowerW including 0 W (zero export); without the flag the old behaviour is kept. The fields are merged per message into a new grid_export dict instead of systems, so a 0 W backfeed is no longer dropped and a partial change message can't wipe them. - grid_export is a new cache key restored by load_cached_data() and rewritten every poll, since the cache expires after a day and change messages can be further apart than that. - The _handle_mqtt_change docstring example is now the live payload. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Summary
The Sigenergy Cloud component already parsed
gridMaxBackfeedPowerWfrom theopenapi/changeMQTT message intosystems[id]["gridMaxBackfeedPower"], but nothing read it.automatic_configwiredinverter_limitand neverexport_limit, so on a plant whose grid connection is capped below the inverter's AC limit (e.g. 5 kW backfeed on a 12 kW inverter), Predbat planned exports the plant can't deliver._get_export_limit_w()returns the backfeed limit in W, or 99999 when the plant hasn't reported one. That is the same "no limit" convention the gateway component uses.publish_system_entitiespublishessensor.<prefix>_sigenergy_<system>_export_limit(W,device_class: power).automatic_configsetsexport_limitto those sensors, one per system.docs/components.md: a note on where the limit comes from and the 99999 fallback.Things to check
gridMaxBackfeedPowerWonly comes in anopenapi/changemessage. Until one arrives after a restart, the sensor reads 99999 W and exports are capped byinverter_limitalone. That is the same as before this PR, so it's no regression, but the limit may not be applied straight after startup. It isn't restored from the cache._handle_mqtt_changealready skips zero values (if val:), and I've kept that. Without a spec I can't tell whether 0 means "zero export" or "not configured". Treating it as zero export would stop all export planning if it actually means "not configured", which is worse than leaving things as they are.maxSellPoweris still not sent in battery commands. This PR only changes what Predbat plans, not how the inverter is commanded.Test plan
publish_export_limit(an MQTT change message flows through to a 5000 W sensor),publish_export_limit_unknown(99999 fallback), and anexport_limitassertion inautomatic_config. All three failed before the change../run_all --test sigenergy: 122 pass./run_all --quick: all pass🤖 Generated with Claude Code