docs(inverter-setup): fix Sigenergy Freeze Charging forced-import bug - #4392
Merged
springfall2008 merged 4 commits intoJul 31, 2026
Merged
Conversation
discharge_cut_off_state_of_charge was hardcoded to 100 for Freeze Charging, which is always above current SoC by construction - Sigenergy has confirmed this is a firmware bug: setting this above current SoC makes the inverter actively import from grid to reach it, even with grid_import_limitation at 0. Not a trickle in practice - observed several kW, continuing unattended until the target is reached. Root-caused and fix confirmed via live testing (springfall2008#4375), and independently corroborated in the community setup thread (springfall2008#2077, Sigenergy's own acknowledgement quoted there from Feb 2026). - Pin discharge_cut_off_state_of_charge to current SoC instead of a hardcoded value in the main mode-bridge automation. - Add a second automation that re-pins continuously while Freeze Charging is active, not just on mode change - a long session with house load exceeding solar (the situation Freeze Charging exists for) would otherwise let SoC drift below a stale pin and reopen the same gap. grid_import_limitation is not a reliable backstop against this. - Add an explicit note explaining the firmware bug and why grid_import_limitation alone doesn't fix it. - Fix a pre-existing YAML indentation bug in the docs snippet (automation_sigen_ess_max_charging_limit_input_number_action was nested two spaces too deep, making it a child of the first automation's actions instead of a sibling automation - caught by parsing the snippet directly). Live-tested on real Sigenergy hardware (springfall2008#4375).
…d zone Revises the previous commit in this PR after further review: - Drop the continuous re-pinning automation. It was based on a flawed premise (that SoC drifting down during a long Freeze Charging session needs tracking) - but Freeze Charging's own contract already covers this: any load shortfall is met from grid, not the battery, so SoC can only stay flat or rise while discharge is genuinely prohibited. A one-time pin at freeze-start stays valid for the whole session by construction. Continuous re-pinning actively undermines "frozen" - it relocates the anchor to wherever SoC has already drifted to instead of correcting back to it, so real drift (e.g. inverter standby losses) would never get corrected. - Add a small (1 percentage point) margin to the pinned value. The confirmed firmware mechanism only ever corrects one way (import if SoC reads below target), so ordinary sensor-reading noise around an exact-SoC pin is not self-cancelling - a low reading costs a real (if tiny) import, a high reading costs nothing. The margin absorbs normal jitter without needing to track it. - Apply the same one-time-pin treatment to Freeze Discharging's charge_cut_off_state_of_charge, mirroring the discharge side instead of leaving it hardcoded to 0. This restores what jamiekets independently proposed in springfall2008#2077 back in November 2025 (both sides pinned together) - the version that shipped only kept half of it. Not itself vendor-confirmed the way the discharge side is, but 0 is always below current SoC by the same structural shape as the confirmed bug, and pinning costs nothing (still fully blocks charging either way). A more advanced variant - ratcheting the target up only in response to confirmed solar surplus over each period (using PV/load totals as the trigger, not the SoC reading itself, to avoid noise entirely) - is being tested live but is not included here; docs should stay simple and proven. Noted as a future direction in the text and on springfall2008#4375.
…around safety - Revert charge_cut_off_state_of_charge for Freeze Discharging back to a plain hardcoded 0. The mirrored-bug concern was speculative (never vendor-confirmed the way the discharge-side bug was), and 0 has been in real use across the wider community template for months without anyone reporting the kind of dramatic, easily-noticed symptom a real mirrored bug would produce - not worth the added complexity without evidence. - Add a note explaining why discharge_cut_off's margin is clamped at 0 rather than left to go negative: it's an unsigned 16-bit Modbus register on the wire, and the integration's own write encoding has no guard against a negative value - it would silently wrap around into a huge, nonsensical raw value rather than being rejected.
Live-observed (2026-07-30) that 1pp was more generous than needed. The pin is one-time (set once when Freeze Charging starts, not continuously re-sampled), so the margin only ever has to cover possible imprecision in that single initial reading - not ongoing noise across a session. 0.25pp is enough for that.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
discharge_cut_off_state_of_chargewas hardcoded to 100 for Freeze Charging, which is always above current SoC by construction. Sigenergy have confirmed this is a firmware bug on their side: setting this above current SoC makes the inverter actively import from grid to reach it, even withgrid_import_limitationat 0kW. Not a trickle in practice - observed several kW, continuing unattended until the target is reached (see #4375 for the full live-hardware investigation).discharge_cut_off_state_of_chargeonce, when Freeze Charging starts, to current SoC minus a small (1pp) margin - not a hardcoded value, and not continuously re-pinned.charge_cut_off_state_of_charge(mirrored: current SoC plus a small margin), instead of leaving it hardcoded to 0. Not itself vendor-confirmed the way the discharge side is, but0is always below current SoC by the same structural shape as the confirmed bug - and pinning costs nothing, since it still fully blocks charging either way. This also restores what jamiekets independently proposed in Configure Predbat to control Sigenergy SigenStor inverter #2077 back in November 2025 (both cutoffs pinned together) - the version that made it into the shipped docs only kept half of that.automation_sigen_ess_max_charging_limit_input_number_actionwas nested two spaces too deep, making it a child of the first automation'sactionsinstead of a sibling automation. Caught by parsing the snippet directly with PyYAML.A more advanced variant - ratcheting the target up only in response to confirmed solar surplus over each period (comparing PV/load totals as the trigger, rather than using the SoC reading itself to decide, so it's immune to sensor noise entirely) is being tested live but deliberately not included here - docs should stay simple and proven, not experimental.
Test plan
./run_pre_commit(viacoverage/run_pre_commit) - all hooks passsensor.sigen_plant_battery_state_of_chargeconfirmed to exist and report correctly on live hardwaredischarge_cut_off_state_of_chargeto current SoC) live-tested on real Sigenergy hardware, root cause confirmed via controlled testing - see Sigenergy: Freeze Charging template still forces grid-import at full price (discharge cutoff=100 in Maximum Self Consumption) — related to #2872 #4375Closes #4375