Flow: count generation meters as sources (grid + solar → house)
ci / build-test (push) Successful in 1m14s
ci / build-test (push) Successful in 1m14s
A meter's flow value is now its throughput — consumption OR generation output —
so a generation meter (solar) acts as a source that can feed downstream meters.
Setting a load meter's upstream to {grid, solar} now splits its consumption
across both proportionally, and the remainder under the sources (grid + solar −
load) surfaces as "Other" = export + battery/inverter losses. Negative values
(savings/balance virtuals) are clamped to 0 (a ribbon can't be negative). The
per-type KPI is relabelled "Top-level throughput" since it now spans generation.
Test: Generation_meter_counts_as_source (grid 75 + solar-gen 30 → house 40 →
28.57/11.43 split, 65 remainder). 69 Core + 48 Integration = 117 green.
Live-verified: electricity flow now shows Solar 1/2 as source nodes.
Claude-Session: https://claude.ai/code/session_01Lz2RqAsnQhetqWNoCDfexK
This commit is contained in:
@@ -33,12 +33,16 @@ public sealed class FlowService(IDbContextFactory<MeterVaultDbContext> contextFa
|
||||
var fromUtc = ToUtc(from);
|
||||
var toUtc = ToUtc(to);
|
||||
|
||||
// A meter's flow value is its throughput: consumption OR generation output — so a generation
|
||||
// meter (solar) can act as a source feeding downstream meters (grid + solar → house). A meter
|
||||
// is normally one kind, so summing both kinds is that meter's flow. Negatives (savings/balance
|
||||
// virtual meters) are clamped to 0 — a flow ribbon can't be negative.
|
||||
var sums = await db.Consumption.AsNoTracking()
|
||||
.Where(c => c.Time >= fromUtc && c.Time < toUtc && c.Kind == ConsumptionKind.Consumption)
|
||||
.Where(c => c.Time >= fromUtc && c.Time < toUtc)
|
||||
.GroupBy(c => c.MeterId)
|
||||
.Select(g => new { MeterId = g.Key, Total = g.Sum(x => x.Amount) })
|
||||
.ToListAsync(cancellationToken).ConfigureAwait(false);
|
||||
var value = sums.Where(s => meterIds.Contains(s.MeterId)).ToDictionary(s => s.MeterId, s => s.Total);
|
||||
var value = sums.Where(s => meterIds.Contains(s.MeterId)).ToDictionary(s => s.MeterId, s => Math.Max(0, s.Total));
|
||||
double V(int id) => value.GetValueOrDefault(id);
|
||||
|
||||
var links = await db.MeterLinks.AsNoTracking()
|
||||
|
||||
Reference in New Issue
Block a user