The instant_rate mode existed in the enum but had no normalizer, so normalizing a power/flow sensor threw NotSupportedException. InstantRateNormalizer integrates the rate over time (trapezoidal, attributed to each interval's end reading); a per-hour rate in the meter's unit yields the consumption unit (kW->kWh, L/h->L). Registered in the engine; meter editor shows a mode hint. +4 Core tests. Claude-Session: https://claude.ai/code/session_01Kib2MniVFbD95fkgLgBBnB
122 lines
2.8 KiB
C#
122 lines
2.8 KiB
C#
namespace MeterVault.Core.Domain;
|
||
|
||
/// <summary>
|
||
/// How a meter's raw readings become normalized consumption (SDD §5.2).
|
||
/// Stored as text in the database via a value converter.
|
||
/// </summary>
|
||
public enum MeterMode
|
||
{
|
||
/// <summary>Monotonic register (electricity house/grid/EV, water). Consumption = Δ register, with swaps/resets.</summary>
|
||
CumulativeCounter,
|
||
|
||
/// <summary>Monotonic generation register (PV). Δ register → generation.</summary>
|
||
GenerationCounter,
|
||
|
||
/// <summary>Cumulative operating hours (burner). Δ hours × rate (fixed or empirical) → consumption.</summary>
|
||
RuntimeCounter,
|
||
|
||
/// <summary>Tank/bottle with deliveries + level. Deliveries add; usage from level-Δ and/or runtime×rate; forecast to empty.</summary>
|
||
ConsumableBalance,
|
||
|
||
/// <summary>Source already reports increments. The value is the increment.</summary>
|
||
DirectDelta,
|
||
|
||
/// <summary>Power/flow sensor. Consumption = rate integrated over time (trapezoidal).</summary>
|
||
InstantRate,
|
||
|
||
/// <summary>Computed from other meters via a user-defined expression.</summary>
|
||
Virtual,
|
||
}
|
||
|
||
/// <summary>Whether a normalized amount is drawn (consumption) or produced (generation).</summary>
|
||
public enum ConsumptionKind : short
|
||
{
|
||
Consumption = 0,
|
||
Generation = 1,
|
||
}
|
||
|
||
/// <summary>Provenance/confidence of a reading or consumption row.</summary>
|
||
public enum ReadingQuality : short
|
||
{
|
||
Measured = 0,
|
||
Estimated = 1,
|
||
Manual = 2,
|
||
Imported = 3,
|
||
Interpolated = 4,
|
||
}
|
||
|
||
/// <summary>Bitmask annotations on a reading/consumption delta.</summary>
|
||
[Flags]
|
||
public enum ReadingFlags
|
||
{
|
||
None = 0,
|
||
CounterReset = 1,
|
||
MeterSwap = 2,
|
||
Anomaly = 4,
|
||
}
|
||
|
||
/// <summary>Discrete meter lifecycle/correction events (SDD meter_event.event_type).</summary>
|
||
public enum MeterEventType
|
||
{
|
||
MeterSwap,
|
||
CounterReset,
|
||
Delivery,
|
||
TankLevel,
|
||
Correction,
|
||
Note,
|
||
}
|
||
|
||
/// <summary>Where a meter_source pulls values from.</summary>
|
||
public enum SourceType
|
||
{
|
||
Mqtt,
|
||
Tasmota,
|
||
HomeAssistant,
|
||
Manual,
|
||
Import,
|
||
Virtual,
|
||
}
|
||
|
||
/// <summary>What kind of quantity a source reports (drives normalization).</summary>
|
||
public enum SourceValueKind
|
||
{
|
||
Register,
|
||
Delta,
|
||
Rate,
|
||
Level,
|
||
Runtime,
|
||
}
|
||
|
||
/// <summary>Scope a tariff applies to.</summary>
|
||
public enum TariffScope
|
||
{
|
||
Global,
|
||
EnergyType,
|
||
Meter,
|
||
}
|
||
|
||
/// <summary>Which price component a tariff row carries.</summary>
|
||
public enum TariffComponent
|
||
{
|
||
UnitPrice,
|
||
BasePrice,
|
||
FeedIn,
|
||
Bonus,
|
||
Discount,
|
||
Tax,
|
||
}
|
||
|
||
/// <summary>How a tank's runtime→consumption rate is derived.</summary>
|
||
public enum TankRateMode
|
||
{
|
||
Fixed,
|
||
Empirical,
|
||
}
|
||
|
||
/// <summary>Type of an ingestion endpoint (broker / HA connection).</summary>
|
||
public enum EndpointType
|
||
{
|
||
MqttBroker,
|
||
HomeAssistant,
|
||
}
|