Sigenergy: make Predbat's ownership of the inverter deliberate (option A for #4454) - #4455
Sigenergy: make Predbat's ownership of the inverter deliberate (option A for #4454)#4455mgazza wants to merge 1 commit into
Conversation
A Sigenergy accepts one controller at a time, and VPP mode (Predbat) and the NorthBound Interface (Axle's VPP dispatch channel) are mutually exclusive. Today Predbat wins that contest by accident: _manage_vpp_registration ran on the 5 minute poll tick and silently switched the system back to VPP, so an Axle dispatch could hold the inverter for up to 5 minutes before being displaced with no indication of what had happened. Observed on a live system on 2026-08-06: mode went to Northbound Integration at 19:35:18 and back to VPP at 19:40:12 — exactly one poll interval — while the log only said "controls skipped until onboard is approved". This keeps Predbat as the owner but makes that a decision rather than a race: - reclaim VPP every minute instead of every 5, so control is never ambiguous for long (set_operating_mode is an MQTT publish and only fires when the mode is wrong, so this costs nothing against the REST rate limit) - log the reclaim explicitly, naming the controller being displaced - stop reporting a contended system as pending_approval. The SaaS UI renders that as an amber "approve this in the Sigenergy app" banner, so every Axle event told the user to go and approve something that needed no approval - expose contended_by on the onboard-status sensor so support can tell contention apart from a real onboarding failure Predbat already ingests Axle sessions as its own export windows, so events still run — under Predbat's plan rather than Axle's dispatch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Customer-impact tracking and fleet scope: Predictive-Cloud-Ltd/predbat-saas#1591 (private). Alternative approach: #4456. |
|
Superseded by #4457. These two were opened as mutually-exclusive alternatives — Predbat keeps the inverter, or Axle does. That framing was wrong. A code review found that this PR's faster reclaim actively defeats the The real either/or was never in the code: it is the policy question of whether #4457 combines both, plus fixes for the three review findings (the stale |
What this does
Keeps Predbat as the owner of a Sigenergy inverter, but makes that a decision rather than a race.
A Sigenergy accepts one controller at a time, and VPP mode (Predbat) and the NorthBound Interface (Axle's dispatch channel) are mutually exclusive. Today
_manage_vpp_registration()runs on the 5-minute poll tick and silently switches the system back to VPP, so an Axle dispatch can hold the inverter for up to 5 minutes before being displaced with no indication of what happened.Observed live on 2026-08-06: mode went to Northbound Integration at 19:35:18 and back to VPP at 19:40:12 — exactly one poll interval — while the log only said "controls skipped until onboard is approved".
Changes
SIGENERGY_VPP_RECLAIM_INTERVAL) instead of every 300s, so control is never ambiguous for long.set_operating_mode()is an MQTT publish and only fires when the mode is actually wrong, so this costs nothing against the REST rate limit. Theonboard_statuscache write stays on the 300s cadence.pending_approval. Downstream UIs render that as an amber "approve this in the Sigenergy app" banner, so every Axle event told the user to approve something needing no approval. A system in NBI is fully onboarded.contended_byon the onboard-status sensor so support can tell contention from a genuine onboarding failure.Predbat already ingests Axle sessions as its own export windows (
load_axle_slot()), so events still run — under Predbat's plan rather than Axle's dispatch.Trade-off
This is the "Predbat always wins" position. It's self-contained and needs no config change, but it does override Axle's schedule on every event. If Axle credits delivery from its own NBI dispatch rather than from meter data, this costs the customer the payment even though the energy flowed. That question is open in #4454.
Tests
4 new tests in
tests/test_sigenergy.py: reclaim-from-third-party, contention-not-pending-approval, reclaim-cadence, and the controls-skipped message. Full Sigenergy suite 72 pass / 0 fail;unit_test.py --quickpasses with 0 failures.run_pre_commitclean (ruff, black, cspell).