Skip to content

Fix Sigenergy Cloud PV power key and MQTT-vs-REST field clobbering - #4755

Merged
springfall2008 merged 1 commit into
mainfrom
fix/sigenergy-cloud-pv-and-soc-4663
Aug 27, 2026
Merged

Fix Sigenergy Cloud PV power key and MQTT-vs-REST field clobbering#4755
springfall2008 merged 1 commit into
mainfrom
fix/sigenergy-cloud-pv-and-soc-4663

Conversation

@chalfontchubby

Copy link
Copy Markdown
Collaborator

Two independent bugs in the Sigenergy Cloud (openapi/MQTT) component, both root-caused from the reporter's logs on #4663.

1. pv_power permanently stuck at 0W

The realtimeInfo REST payload spells the field pVPower (capital V) - inconsistent with pvEnergyDaily/pvTotalPower alongside it, and with the MQTT period topic's "PV power". fetch_energy_flow_from_realtime read pvPower, which never matched, so PV silently defaulted to 0 forever.

That is exactly the reporter's "physically impossible" power-flow diagram: battery charging hard while PV reads 0.

Fixed with a fallback chain: pVPowerpvTotalPowerpvPower. pVPower is primary because across three consecutive samples in the log it tracked the string-derived power (4.26 → 4.33 → 4.67 kW) while pvTotalPower lagged flat at 4.38.

2. SoC resets to 0% within minutes of restart, forcing a mid-export replan

_handle_mqtt_period rebuilds energy_flow wholesale from a raw dict merged across period messages (added in #4172, so a field that stops changing isn't re-read as 0). That merge only helps once a field has been seen at least once.

This reporter's period messages carry only "PV power", so storageSOC% (and battery/grid power) were never present in the merged state, defaulted to 0, and overwrote the good values the REST poll had already fetched. The log confirms the sequence: 30.84kWh/85% from REST → an MQTT period message reporting SOC 0% → a 0.0kWh/0% status two minutes later.

Fixed by falling back to the previous energy_flow/system_status value for any field this system has never reported, rather than defaulting to 0.

Tests

New regression test for the never-reported-field case, both with and without a prior REST value. Verified failing without the fix - without the guard it throws KeyError on the first genuinely absent field, which is itself confirmation the guard is load-bearing rather than cosmetic.

./run_all --quick and pre-commit green, re-run after rebasing onto current main.

Notes for review

  • Not dogfooded live. This is the Cloud (openapi/MQTT) component, not the local Modbus integration my own Sigenergy system uses, so I have no way to exercise it directly.
  • ## Sigenergy Cloud integration: pv_power entity permanently stuck at 0W, no restart clears it #4663 is closed - the reporter closed it themselves after moving to the Modbus Sigenstor integration, which sidesteps this component entirely. Both bugs are still present on main, so this is referenced as context rather than as a fix-closes; anyone else on the Cloud component will still hit them.

🤖 Generated with Claude Code

Fixes #4663. Two independent bugs against the Sigenergy Cloud (openapi/MQTT)
integration, both root-caused from the reporter's own logs.

1. pv_power stuck at 0W. The realtimeInfo REST endpoint's raw payload spells
   the field "pVPower" (capital V) - inconsistent with pvEnergyDaily/
   pvTotalPower alongside it, and with the MQTT period topic's "PV power".
   fetch_energy_flow_from_realtime read "pvPower", which never matched, so PV
   silently defaulted to 0 forever - exactly the reporter's "physically
   impossible" power-flow diagram (battery charging hard, PV showing 0).
   Fixed with a fallback chain (pVPower, then pvTotalPower, then pvPower).
   pVPower chosen as primary: across three consecutive samples in the log it
   tracked the string-derived power (4.26 -> 4.33 -> 4.67kW) while
   pvTotalPower lagged flat at 4.38.

2. SoC resets to 0% within minutes of restart, forcing a mid-export replan.
   _handle_mqtt_period rebuilds energy_flow wholesale from a raw dict merged
   across period messages (added in #4172 so a field that stops changing
   isn't re-read as 0). That merge only helps once a field has been seen at
   least once - this reporter's period messages carry only "PV power", so
   storageSOC% (and battery/grid power) were never present in the merged
   state, defaulted to 0, and overwrote the good values the REST poll had
   already fetched. Log confirms the sequence: 30.84kWh/85% from REST,
   MQTT period message reporting SOC 0%, then a 0.0kWh/0% status two
   minutes later. Fixed by falling back to the previous energy_flow/
   system_status value for any field this system has never reported, rather
   than defaulting to 0.

Not dogfooded live: this is the Cloud (openapi/MQTT) component, not the local
Modbus integration Rik's own Sigenergy system uses, so there's no way to
exercise it directly here.

Tests: new regression test for the never-reported-field case (both with and
without a prior REST value), verified failing without the fix - without the
guard it throws KeyError on the first genuinely-absent field, which is itself
confirmation the guard is load-bearing, not just cosmetic. Full run_pre_commit
green.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The REST-side PV key fallback (pVPower/pvTotalPower) is not covered by a regression test in the newly added test block, which risks the original PV=0W bug recurring undetected.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Fixes two Sigenergy Cloud (OpenAPI + MQTT) data-integrity bugs that could (a) pin PV power to 0W due to a mis-cased REST field name and (b) let sparse MQTT period messages overwrite previously-correct REST-derived fields (notably SoC) with fabricated zeros.

Changes:

  • Update REST realtimeInfo parsing to read PV power via a fallback chain (pVPowerpvTotalPowerpvPower).
  • Update MQTT openapi/period handling to preserve previously-known energy_flow / system_status values when a field has never been reported by that system.
  • Add a regression test covering the “never reported field” MQTT clobbering scenario and register it in the Sigenergy test suite.
File summaries
File Description
apps/predbat/sigenergy.py Fixes PV power key parsing from REST and prevents MQTT sparse updates from zeroing never-reported fields.
apps/predbat/tests/test_sigenergy.py Adds regression coverage for the MQTT never-reported-field scenario and wires it into run_sigenergy_tests.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +1552 to +1560
# With nothing previously known either, an absent field is still 0 rather than raising
api2 = MockSigenergyAPI()
api2._handle_mqtt_period("SYS2", {"PV power": "1000.0"})
flow2 = api2.energy_flow.get("SYS2", {})
if flow2["batterySoc"] != 0.0:
print("ERROR: batterySoc with no prior value should default to 0, got {}".format(flow2["batterySoc"]))
failed = True

return failed
@springfall2008
springfall2008 merged commit d21052e into main Aug 27, 2026
3 checks passed
@springfall2008
springfall2008 deleted the fix/sigenergy-cloud-pv-and-soc-4663 branch August 27, 2026 07:48
chalfontchubby added a commit to chalfontchubby/batpred that referenced this pull request Aug 28, 2026
…008#4663/springfall2008#4755

Copilot flagged this on springfall2008#4755 after merge: the PR fixed two independent bugs
(REST pVPower key + MQTT never-reported-field clobbering) but only the second
got a regression test. The existing fetch_inverter_realtime test used a fake
response keyed "pvPower" - the natural-looking spelling the original bug
actually read - so it would keep passing even if the pVPower fallback chain
regressed back to reading the wrong key.

Verified the new test fails against the pre-springfall2008#4755 behavior (asserts "got 0.0"
for the primary pVPower case) and passes with the fallback chain restored.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants