fix(inverter): stop re-committing a stable export window every cycle (Solis) - #4711
Open
chalfontchubby wants to merge 3 commits into
Open
fix(inverter): stop re-committing a stable export window every cycle (Solis)#4711chalfontchubby wants to merge 3 commits into
chalfontchubby wants to merge 3 commits into
Conversation
…changed Addresses #2328. press_and_poll_button()'s "separate buttons" fallback (charge_update_button/discharge_update_button, used by e.g. some Solis and SolaX SX4 configs instead of a single combined button) pressed both buttons on every call, regardless of which side actually needed updating - a charge-only window change also pressed the unrelated discharge button, and vice versa. rszemeti's report showed exactly this: both update_charge_times and update_discharge_times pressed together even when the charge window's own start/end times were provably unchanged (every underlying write correctly logged "No write needed"). He disabled Predbat after reaching ~75k inverter writes in a year to avoid EEPROM wear. Added a `side` parameter ("charge"/"discharge"/"both", default "both" for any caller not yet updated) and passed the correct side from each of the four call sites (adjust_battery_target, adjust_force_export, disable_charge_window, adjust_charge_window). A single combined button (schedule_write_button or charge_discharge_update_button) is unaffected - there's only one button either way. New test_press_and_poll_button_side_scoping isolates the branching logic by stubbing _press_single_button_and_poll (its own retry/timestamp-polling behaviour is a separate concern), asserting each side presses only its own button. No prior coverage existed for the separate-buttons path at all. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
For H M format inverters the discharge slot-time registers are rewritten on every cycle as a write-reliability workaround (#1529), so changed_start_end is True on every cycle of an unchanged export window. #4000 then used that flag to gate the update button press, which made the button fire every 5 minutes for the whole window. On Solis each press zeroes the timed charge/discharge current registers, so the inverter stops exporting until something restores them (#4709). The same flag also triggers the 30 second GivTCP settle sleep in adjust_inverter_mode, and the export-slot notification, on every cycle. Separate "we rewrote the registers" from "the schedule needs committing" and gate the press, the sleep and the notify on the latter. Tracking the last committed schedule keeps a stable window quiet while still committing once after a restart, when nothing has been committed yet - so #4000's own regression test passes unchanged. The extra commit-once safety net is scoped to the H M path; every other format already commits on a real change alone. The register writes themselves are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
press_and_poll_button returns a success flag that was being discarded, so a failed button press was still recorded in last_export_schedule_committed and never retried - the schedule would sit uncommitted until it happened to change on its own. The behaviour being replaced retried implicitly, because changed_start_end fired every cycle. Gating on the real result keeps that retry without bringing back the every-cycle press. Same failure shape as the known call_service_template issue, where a service call is marked done before its success is checked. Co-Authored-By: Claude Opus 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.
Fixes #4709
Problem
On Solis
GS_fb00(solax_modbus), pressing the charge/discharge update button zeroes the timed charge/discharge current registers. The reporter measured the current register being knocked to 0 A at:xx:22on every 5-minute boundary throughout an active export window, stopping export until something restored it.The cause is in
adjust_force_export. ForH Mtime format the discharge slot-time registers are rewritten unconditionally every cycle — a deliberate write-reliability workaround from #1529. #4000 then reused that same "we wrote something" flag (changed_start_end) to decide whether to press the update button, so the button fired every cycle even when the window had not changed.#4000's stated premise was that
adjust_charge_window"always re-writes time entities for H M format → button press fires every cycle". The write half is correct; the button-press half is not — the charge side's press is gated on a plain dirty check and always has been. So the every-cycle press was never symmetric with anything.The same flag also gates the 30 second GivTCP settle sleep in
adjust_inverter_modeand the export-slot notification, both of which were therefore firing every cycle too.Fix
Separate "we rewrote the registers" from "the schedule needs committing", and gate the press, the sleep and the notify on the latter.
Tracking the last committed schedule keeps a stable window quiet while still committing once after a restart, when nothing has been committed yet — so #4000's own regression test passes unchanged. The commit-once safety net is scoped to the
H Mpath; every other format already commits on a real change alone.A commit is only recorded once it has actually succeeded.
press_and_poll_buttonreturns a success flag, and discarding it would mean a failed press was recorded as done and never retried — the schedule sitting uncommitted until it happened to change on its own. The behaviour being replaced retried implicitly, becausechanged_start_endfired every cycle, so gating on the real result preserves that retry without bringing back the every-cycle press. (Same failure shape as the knowncall_service_templateissue, where a service call is marked done before its success is checked.)The register writes themselves are untouched.
Also fixes idle-cycle presses on plain
GSBeyond the export window, this PR also stops a second symptom that only came to light during triage of #4712.
GS(pre-FB00 Solis) ischarge_time_format: "H M", sochanged_start_endis set unconditionally there too — which means on currentmainit presses the update button on every idle cycle as well, all day, not just during export. Droppingchanged_start_endfrom the commit condition fixes that. Measured over four idleadjust_force_export(False)calls:GS_fb00and the cloud types reach the same press by a second, independent route (aNonetime comparison) which this PR does not touch — that is #4712, fixed by #4713 stacked on top of this one.Also included
press_and_poll_buttonnow presses only the side that changed. Where separatecharge_update_button/discharge_update_buttonentities are configured, both were pressed whenever either side had something to send — unchanged since the original split-button support. Halves the presses for those users; no effect on the combined-button setups the Solis template ships by default. This was written for #2328 and parked as too small to be worth landing alone.Commits
9a3a0e23press_and_poll_buttononly presses the button(s) that changedbe3d225f4499357cTesting
4499357c.adjust_force_export1passes unchanged, which is what pins the GE path's behaviour.--quicksuite green.Not yet confirmed against a live install — logs requested on #4709.
🤖 Generated with Claude Code