metering/lib.rs
1//! German energy metering domain library.
2//!
3//! A **standalone**, **pure** library for meter data calculations required by
4//! BDEW MaKo, MessZV, GasGVV, and EnWG. Zero I/O, no async, no float money.
5//!
6//! This crate supersedes the `meter-quality` crate, which has been folded in.
7//!
8//! # Modules
9//!
10//! | Module | Contents |
11//! |---|---|
12//! | [`interval`] | `MeterInterval`, `Sparte`, `QualityFlag`, `demand_kw()` |
13//! | [`conversion`] | Gas m³ → kWh_Hs (§24 GasGVV / DVGW G 685) |
14//! | [`aggregation`] | Billing period: `arbeitsmenge_kwh`, `spitzenleistung_kw`, HT/NT |
15//! | [`classification`] | SLP/RLM/iMSys detection, interval length |
16//! | [`imbalance`] | Mehr-/Mindermengensaldo (§27 MessZV, compute_imbalance) |
17//! | [`quality`] | Hampel-filter quality scoring (M7), `score_intervals_raw` for f64 |
18//!
19//! # Quick start — billing period
20//!
21//! ```rust
22//! use metering::{MeterInterval, QualityFlag, aggregate, AggregationConfig};
23//! use rust_decimal::Decimal;
24//! use time::macros::datetime;
25//!
26//! let iv = MeterInterval {
27//! from: datetime!(2026-06-01 0:00 UTC),
28//! to: datetime!(2026-06-01 0:15 UTC),
29//! value_kwh: Decimal::from_str_exact("2.345").unwrap(),
30//! quality: QualityFlag::Measured,
31//! obis_code: None,
32//! };
33//! let period = aggregate(&[iv], AggregationConfig::rlm_strom());
34//! assert!(period.arbeitsmenge_kwh > Decimal::ZERO);
35//! ```
36//!
37//! # Quick start — Gas m³ → kWh_Hs
38//!
39//! ```rust
40//! use metering::gas_m3_to_kwh_hs;
41//! use rust_decimal::Decimal;
42//!
43//! let kwh = gas_m3_to_kwh_hs(
44//! Decimal::from(100u32),
45//! Decimal::from_str_exact("10.55").unwrap(),
46//! Decimal::from_str_exact("0.9764").unwrap(),
47//! );
48//! assert!(kwh > Decimal::from(1000u32));
49//! ```
50//!
51//! # Quick start — quality scoring (f64 API, e.g. from DB)
52//!
53//! ```rust
54//! use metering::{score_intervals_raw, QualityGrade};
55//!
56//! let values = vec![2.3_f64, 2.4, 2.3, 2.5, 2.2, 2.4, 2.3];
57//! let grade = score_intervals_raw(&values, 3, 3.0);
58//! assert_eq!(grade, QualityGrade::A);
59//! ```
60#![deny(unsafe_code)]
61#![warn(missing_docs)]
62
63pub mod aggregation;
64pub mod classification;
65pub mod conversion;
66pub mod imbalance;
67pub mod interval;
68pub mod quality;
69
70// ── Re-exports ────────────────────────────────────────────────────────────────
71
72pub use aggregation::{AggregationConfig, BillingPeriod, HtNtSplit, aggregate};
73pub use classification::{IntervalLengthClass, Messtyp, classify_messtyp, detect_interval_length};
74pub use conversion::{GasConversionParams, gas_m3_to_kwh_hs, normalize_interval_to_kwh};
75pub use imbalance::{ImbalanceSaldo, compute_imbalance};
76pub use interval::{MeterInterval, QualityFlag, Sparte};
77pub use quality::{
78 QualityConfig, QualityGrade, QualityReport, hampel_filter, score_intervals, score_intervals_raw,
79};