Skip to content

Fix/feedthrough Kirchhoff derivation#138

Merged
cayossarian merged 6 commits intomainfrom
fix/feedthrough-kirchhoff-derivation
Apr 20, 2026
Merged

Fix/feedthrough Kirchhoff derivation#138
cayossarian merged 6 commits intomainfrom
fix/feedthrough-kirchhoff-derivation

Conversation

@cayossarian
Copy link
Copy Markdown
Member

No description provided.

The panel's native energy.ebus.device.lugs.downstream active-power
carries a systematic ~400-550 W offset and its imported-energy counter
can emit non-monotonic (including negative) cumulative values, making
both readings unusable for either instantaneous power or lifetime
energy accounting.

Main meter and per-branch readings remain accurate, so apply the
energy-balance identity at the main bus:

    P_main = P_feedthrough + Σ(branches, load-perspective)
    => P_feedthrough = P_main − Σ(branches)

Feedthrough power/energy are now derived at snapshot build time in
HomieDeviceConsumer._build_snapshot and mirrored in the dirty-circuit
rebuild path. The synthesized PV virtual circuit carries the correct
load-perspective sign so it participates safely; unmapped tab entries
contribute zero. Per-phase currents (l1/l2) continue to be read from
the downstream-lugs node — those readings are orthogonal to the
active-power / energy-counter defects.

No public interface change: field names and types are unchanged;
only the values' source shifts.

Version bumped to 2.6.3.
scripts/validate_lug_derivation/ compares the panel's native
downstream-lugs readings against the v1 REST API readings against a
Kirchhoff-derived value (main − Σcircuits), using both
span-panel-api==1.1.15 (for v1 REST) and the current workspace
library (for v2 MQTT) in parallel ephemeral environments driven by
uv run.

Used to diagnose the feedthrough power/energy defect on MQTT v2 and
to confirm that the Kirchhoff derivation produces physically-
consistent results across both APIs. See v1-only "Unmapped Tab"
circuits vs v2-only "Commissioned PV System" virtual circuit: both
represent the same physical PV in opposite sign conventions, which
the partitioning logic in compare.py accounts for.

A gitignore rule for scripts/validate_lug_derivation/run_local.sh
keeps a credentialed driver script out of git — users copy and
edit that template with their own host / v1 token / v2 passphrase.
@cayossarian cayossarian requested a review from Copilot April 20, 2026 19:04
@cayossarian cayossarian force-pushed the fix/feedthrough-kirchhoff-derivation branch from c0aede3 to be0b49a Compare April 20, 2026 19:09
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the MQTT/Homie (v2) snapshot construction to compute “feedthrough” from an energy-balance/Kirchhoff-style derivation (main meter minus sum of circuit snapshots), and bumps the package version with supporting tests and validation scripts.

Changes:

  • Derive feedthrough power/energy from upstream-lugs (main) minus Σ(circuits) in HomieDeviceConsumer, including the dirty-circuit rebuild path.
  • Update MQTT/Homie tests to validate the new derivation behavior and ensure downstream-lugs power/energy are ignored.
  • Add validation scripts to capture/compare v1 vs v2 snapshots and bump version/changelog entries.

Reviewed changes

Copilot reviewed 7 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/span_panel_api/mqtt/homie.py Adds _derive_feedthrough() and applies it in full and partial snapshot rebuild paths; stops reading downstream-lugs power/energy.
tests/test_mqtt_homie.py Replaces downstream-lugs→feedthrough assertions with derivation-based expectations; adjusts generic-lugs test to validate downstream current fields.
scripts/validate_lug_derivation/v1_reader.py New helper to capture v1 REST snapshots for comparison.
scripts/validate_lug_derivation/v2_reader.py New helper to capture v2 MQTT snapshots from the current workspace install.
scripts/validate_lug_derivation/compare.py New script to run both readers and print side-by-side comparisons (including derived feedthrough).
pyproject.toml Bumps project version to 2.6.3.
uv.lock Updates locked version metadata for editable span-panel-api to 2.6.3.
CHANGELOG.md Adds 2.6.3 entry documenting the feedthrough derivation change.
.gitignore Ignores a local credentialed runner script for the validation workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/span_panel_api/mqtt/homie.py Outdated
Comment thread src/span_panel_api/mqtt/homie.py
Per-direction energy derivation (main.consumed - Σcircuit.consumed,
and likewise for produced) is mathematically unsound when branches
flow bidirectionally. The classic case is PV self-consumption on the
main panel: Σ(branch.consumed) can exceed main.consumed even when the
net balance is valid, so the naive subtraction emits negative
cumulative feedthrough counters.

_derive_feedthrough now derives the net-energy identity

    feedthrough_net = (main.consumed - main.produced) - Σ(branch.net)

and splits it into non-negative consumed / produced components. Added
a PV-self-consumption regression test.

Also clarified field_metadata.py: the downstream-lugs entries for
feedthrough power/energy are retained only to inherit unit/datatype
from the Homie schema; the runtime values are derived.

Addresses PR #138 review feedback.
… fix

The library now derives feedthrough via Kirchhoff, so downstream
consumers no longer see the firmware defect. But the SPAN API is in
beta and carries no version signal — we need to detect empirically
when SPAN ships the fix upstream (tracked at
spanio/SPAN-API-Client-Docs#13).

v2_reader.py now reaches into the MQTT accumulator to capture the raw
downstream-lugs active-power / imported-energy / exported-energy
values alongside the library's derived snapshot (same-repo diagnostic
access via _homie._acc).

compare.py displays the raw values with delta-vs-derived and flags:
  - "upstream defect present" when |raw active-power - derived| > 100 W
  - "upstream defect MAY be fixed" when the delta < 50 W (confirm
    over sustained samples)
  - "upstream imported-energy counter still broken" when raw < 0

Live sample at time of writing: firmware active-power offset
~400-450 W vs Kirchhoff — tracking signal works.
@cayossarian cayossarian merged commit fa5ff0d into main Apr 20, 2026
6 checks passed
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.

2 participants