Skip to content

fix(inverter): settle before verifying a GivTCP discharge target write - #4492

Merged
springfall2008 merged 2 commits into
mainfrom
fix/discharge-target-rest-race
Aug 12, 2026
Merged

fix(inverter): settle before verifying a GivTCP discharge target write#4492
springfall2008 merged 2 commits into
mainfrom
fix/discharge-target-rest-race

Conversation

@chalfontchubby

Copy link
Copy Markdown
Collaborator

Summary

Fixes #4421 - spurious "REST failed to setExportTarget got 0" warnings even though GivTCP's own log confirms the write succeeded.

rest_setDischargeTarget() POSTs the write, then immediately GETs GivTCP's /runAll status to verify it landed. That status is a separately-cached snapshot, refreshed on GivTCP's own polling cycle rather than synchronously with the POST - reading it back with no delay can catch data from before GivTCP has applied and exposed the change. Traced against multiple reporters' logs on the issue: writes do succeed at inconsistent retry counts (rules out a broken field path, which would fail every time), and GivTCP's own log consistently shows the write landing at the exact moment Predbat reports the failure.

Fix: a short settle delay between the POST and each readback (every attempt, not just between retries).

Test plan

  • New regression test (test_discharge_target_settle_delay in test_inverter.py) simulating the exact race: a stale cached readback followed by the real post-write value, asserting the write is still recognised as successful and that a settle sleep happens before each readback.
  • ./run_all --quick - all passing
  • ./run_pre_commit - clean
  • Would appreciate someone hitting this live testing it - @davemilsom2, @FileGo, @Redding43, @kitenski, any of you able to dogfood this on your setup?

🤖 Generated with Claude Code

GivTCP's runAll status is a separately-cached snapshot refreshed on its own
polling cycle, not synchronously with the setDischargeTarget POST. Reading it
back immediately after the write can catch data from before GivTCP has
applied and exposed the change, reporting a spurious "REST failed to
setExportTarget got 0" even though the write actually succeeded - confirmed
against multiple reporters' logs on #4421, where GivTCP's own log shows the
write landing at the exact moment Predbat reports the failure.

Adds a short settle delay between the POST and each readback in
rest_setDischargeTarget, so a slow-to-update cache isn't misread as a failed
write.
…rge target write

Traced against GivTCP's own source (write.py's setDischargeTarget()):
Control.Discharge_Target_SOC_1 is updated synchronously the moment GivTCP
accepts a write, via updateControlCache(). raw.invertor.discharge_target_soc_1,
which rest_setDischargeTarget() was checking exclusively, is only refreshed by
GivTCP's separate background self_run poll cycle - tens of seconds away on
some installs, not remotely covered by a short settle delay.

Check Control.Discharge_Target_SOC_1 first, falling back to the raw register
only if Control doesn't have the key. The settle delay from the previous
commit is still useful for the much smaller residual window (the physical
inverter itself taking a moment to apply the write).
@springfall2008
springfall2008 merged commit 4bb7841 into main Aug 12, 2026
2 checks passed
@springfall2008
springfall2008 deleted the fix/discharge-target-rest-race branch August 12, 2026 17:17
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.

Reoccurence of #4404 - Warn: Inverter 0 REST failed to setExportTarget when exporting

2 participants