Fix Sigenergy Cloud PV power key and MQTT-vs-REST field clobbering - #4755
Merged
Conversation
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>
Closed
7 tasks
Contributor
There was a problem hiding this comment.
🟡 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
realtimeInfoparsing to read PV power via a fallback chain (pVPower→pvTotalPower→pvPower). - Update MQTT
openapi/periodhandling to preserve previously-knownenergy_flow/system_statusvalues 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 |
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>
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.
Two independent bugs in the Sigenergy Cloud (openapi/MQTT) component, both root-caused from the reporter's logs on #4663.
1.
pv_powerpermanently stuck at 0WThe
realtimeInfoREST payload spells the fieldpVPower(capital V) - inconsistent withpvEnergyDaily/pvTotalPoweralongside it, and with the MQTT period topic's"PV power".fetch_energy_flow_from_realtimereadpvPower, 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:
pVPower→pvTotalPower→pvPower.pVPoweris primary because across three consecutive samples in the log it tracked the string-derived power (4.26 → 4.33 → 4.67 kW) whilepvTotalPowerlagged flat at 4.38.2. SoC resets to 0% within minutes of restart, forcing a mid-export replan
_handle_mqtt_periodrebuildsenergy_flowwholesale 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", sostorageSOC%(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_statusvalue 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
KeyErroron the first genuinely absent field, which is itself confirmation the guard is load-bearing rather than cosmetic../run_all --quickand pre-commit green, re-run after rebasing onto current main.Notes for review
🤖 Generated with Claude Code