Skip to content

Fix sticky reserve floor on inverters without managed reserve SOC (e.g. SolisCloud) - #3709

Merged
springfall2008 merged 3 commits into
mainfrom
copilot/fix-soliscloud-battery-soc-calculation
Apr 3, 2026
Merged

springfall2008 merged 3 commits into
mainfrom
copilot/fix-soliscloud-battery-soc-calculation

Conversation

Copilot AI commented Mar 31, 2026 •

Copy link
Copy Markdown
Contributor

On inverters where inv_has_reserve_soc = False (e.g. SolisCloud), the battery plan would permanently show a floor at whatever reserve value Predbat had last written — even after set_reserve_min was lowered — because reserve_percent was set from the inverter-reported reserve_percent_current (the elevated/sticky value) rather than reserve_min.

Mechanism: charge-freeze logic calls adjust_reserve(soc_percent + 1) → writes e.g. 80% to the reserve entity → freeze ends → reserve_percent is still read back as 80% from the inverter → plan is forever floored at 80% even though set_reserve_min is 4%.

Changes

  • inverter.py — __init__(): Extended the condition that sets reserve_percent = reserve_min to also cover inverters where inv_has_reserve_soc = False (i.e. Predbat does not manage the reserve entity). Previously only inverters with inv_has_reserve_soc = True and set_reserve_enable = True used reserve_min as the planning floor.

    # Before — non-managed inverters always used the inverter-reported value as planning floor
    if self.base.set_reserve_enable and self.inv_has_reserve_soc:
    
    # After — non-managed inverters (e.g. SolisCloud) also use reserve_min as the planning floor
    if (self.base.set_reserve_enable and self.inv_has_reserve_soc) or not self.inv_has_reserve_soc:
  • tests/test_inverter.py: Updated test_adjust_reserve() to also set inv.reserve_min (now relevant to the planning floor logic). Added reserve_percent parameter to allow testing scenarios where reserve_percent and reserve_min differ.

…dd warning log

Agent-Logs-Url: https://github.com/springfall2008/batpred/sessions/e08373e6-d20f-4e46-8a22-9372b56b5bdb

Co-authored-by: springfall2008 <48591903+springfall2008@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix battery SoC calculation issue in SolisCloud integration Fix sticky reserve floor on inverters without managed reserve SOC (e.g. SolisCloud) Mar 31, 2026
Copilot AI requested a review from springfall2008 March 31, 2026 08:30

@CraigCallender CraigCallender 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.

LGTM

@CraigCallender CraigCallender 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.

LGTM

Comment thread apps/predbat/inverter.py Outdated
@@ -476,6 +476,14 @@ def __init__(self, base, id=0, quiet=False, rest_postCommand=None, rest_getData=

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I'm wondering if this should be:

if (self.base.set_reserve_enable and self.inv_has_reserve_soc) or not self.inv_has_reserve_soc

Then the other change isn't required?

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@copilot Is there a simpler fix?

inverter.py line 475 could be:

if (self.base.set_reserve_enable and self.inv_has_reserve_soc) or not self.inv_has_reserve_soc

And then the other change might not be required?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 5caa936. Changed the condition to (self.base.set_reserve_enable and self.inv_has_reserve_soc) or not self.inv_has_reserve_soc, which means non-managed inverters (like SolisCloud) always use reserve_min as the planning floor. The adjust_reserve() change and the warning log were both reverted since they're no longer needed.

…n-managed inverters

Agent-Logs-Url: https://github.com/springfall2008/batpred/sessions/afdc9cdf-fc4f-4025-b656-02c2eba79ced

Co-authored-by: springfall2008 <48591903+springfall2008@users.noreply.github.com>

Copilot AI commented Apr 3, 2026

Copy link
Copy Markdown
Contributor Author

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/springfall2008/batpred/contents/apps/predbat
    • Triggering command: /home/REDACTED/work/batpred/batpred/coverage/venv/bin/python3 python3 ../apps/predbat/unit_test.py --test inverter (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from springfall2008 April 3, 2026 09:17
@springfall2008
springfall2008 marked this pull request as ready for review April 3, 2026 12:49
Copilot AI review requested due to automatic review settings April 3, 2026 12:49

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.

Pull request overview

Fixes a reserve “sticky floor” issue for inverter types that don’t support managed reserve SoC (e.g. SolisCloud), where planning/clamping could remain pinned to an elevated inverter-reported reserve value even after set_reserve_min is lowered.

Changes:

  • Update Inverter.__init__() to use reserve_min as the planning/clamp floor when inv_has_reserve_soc is False.
  • Extend the inverter reserve adjustment test helper to allow simulating reserve_percent differing from reserve_min and set inv.reserve_min explicitly.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
apps/predbat/inverter.py Adjusts how reserve_percent (planning/clamp floor) is derived for inverters without managed reserve SoC.
apps/predbat/tests/test_inverter.py Updates test_adjust_reserve helper to support scenarios where reserve_percent and reserve_min differ.

Comment thread apps/predbat/inverter.py
Comment on lines 474 to 478
self.base.log("Reserve min: {}%, battery_min: {}%".format(self.reserve_min, dp0(battery_min_soc)))
if self.base.set_reserve_enable and self.inv_has_reserve_soc:
if (self.base.set_reserve_enable and self.inv_has_reserve_soc) or not self.inv_has_reserve_soc:
self.reserve_percent = self.reserve_min
else:
self.reserve_percent = self.reserve_percent_current

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

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

The behavior change to set reserve_percent = reserve_min when inv_has_reserve_soc is False isn’t currently covered by a unit test. In apps/predbat/tests/test_inverter.py, all existing inverter instantiations use inverter_type=["GE"] (managed reserve), so this regression-prone path (e.g. inverter_type="SolisCloud" with a high/stale reserve sensor) isn’t asserted. Please add a test that constructs an inverter with inv_has_reserve_soc=False and verifies reserve_percent (and thus adjust_reserve’s clamp floor) follows set_reserve_min rather than the current sensor value.

Copilot uses AI. Check for mistakes.
@springfall2008
springfall2008 merged commit 4258585 into main Apr 3, 2026
5 checks passed
@springfall2008
springfall2008 deleted the copilot/fix-soliscloud-battery-soc-calculation branch April 3, 2026 12:53
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.

SolisCloud: Plan Never Shows Battery SoC Drop Below 80%

4 participants