Repository navigation
fix(inverter): enable Enable_Charge_Target before writing a GivTCP discharge target - #4542
Closed
chalfontchubby wants to merge 1 commit into
Closed
chalfontchubby wants to merge 1 commit into
chalfontchubby wants to merge 1 commit into
Conversation
…scharge target (#4517) adjust_force_export() decided a discharge-target write was needed based on rest_readDischargeTarget() alone, but on some inverters GivTCP reports each write as successful while it never actually sticks - Control.Enable_Charge_Target stays off, so the value is written but the inverter doesn't treat it as authoritative, and Predbat sees a permanent mismatch and rewrites every cycle indefinitely. adjust_battery_target() already calls rest_enableChargeTarget(True) before writing a charge target for exactly this reason (documented: without it the inverter ignores the target). Mirror that call for the discharge target too. No-ops wherever it's already enabled, which is the common case. Whether every rest_v3 inverter actually has this register at all is unconfirmed, so this is deliberately hardened for the case it's wrong: - If enabling itself fails, skip the discharge-target write rather than also attempting one already known to be doomed - a genuinely unsupported inverter retries one REST endpoint per cycle instead of two. - After DISCHARGE_TARGET_ENABLE_MAX_CYCLE_FAILURES consecutive cycles where enabling has never once succeeded, stop attempting either endpoint entirely rather than retrying forever, and surface it via record_status so the reduced safety margin (no inverter-side reserve backstop during force export) is visible, not just logged. Resets naturally on restart and on any genuine success, so a working register never gets written off, and a regression (worked before, now failing) is flagged distinctly rather than silently treated the same as never-supported. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Aug 15, 2026
Closed
Collaborator
Author
|
Approach taken had diverged (into try the writes, back off ofter failing a number of times) - so the pr description was invalid. But replaced with an inverter type check to gate the writes. |
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
Follow-up to #4517/#4518, for the case #4518 explicitly doesn't fix (a REST-v3 inverter where
Control.Discharge_Target_SOC_1is entirely absent, so the caller falls through to the slowerraw.invertorfield with no change in behaviour).Working from a reporter's real
REST_Response.txtandGIVTCP_Logs.log:Control.Enable_Charge_Targetreads"disable", and GivTCP's own log shows"Setting Discharge Target 1 was a success"repeatedly - the write itself is genuinely reaching the inverter and being acknowledged, but doesn't persist, soadjust_force_export()sees a permanent mismatch and rewrites every single cycle.adjust_battery_target()already callsrest_enableChargeTarget(True)before writing a charge target ("without it the inverter ignores the target") - that call was never mirrored on the discharge-target side. This PR does that.Not confirmed as the root cause - correlational, from comparing against a second, unrelated working sample (#4421) where the pairing is the opposite (
Enable_Charge_Target: enable+Discharge_Target_SOC_1present). Every hardware-identifying field GivTCP exposes (model/Invertor_Type,device_type_code,num_mppt, and firmware version, which differs only trivially) is identical between the two samples - so this isn't a generation/model distinction we could gate on statically even if we wanted to; the only thing that differs isEnable_Charge_Targetitself.Deliberately hardened for the case this theory is wrong:
rest_enableChargeTarget(True)itself fails, the discharge-target write is skipped rather than also attempted - a genuinely unsupported inverter retries one REST endpoint per cycle instead of two.DISCHARGE_TARGET_ENABLE_MAX_CYCLE_FAILURESconsecutive cycles where enabling has never once succeeded, stop attempting either endpoint entirely and surface it viarecord_status(the inverter loses its hardware-side reserve backstop during force export, not just a noisy log). Resets on restart and on any genuine success, and a regression (worked before, now failing) is flagged distinctly rather than being silently written off as unsupported.Posted as draft specifically to ask for a live test before this goes anywhere near merge - it's unconfirmed and the person who can confirm it is the original reporter.
Test plan
test_inverter.py, each confirmed to fail without its corresponding fix and pass with it./run_all --quickpasses./run_pre_commitpasses🤖 Generated with Claude Code