bo4e_core/com/
load_curve_data.rs

1//! Load curve data (Lastkurvendaten) component.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::enums::Unit;
7use crate::traits::{Bo4eMeta, Bo4eObject};
8
9/// Load curve data containing power measurements over time.
10///
11/// German: Lastkurvendaten
12///
13/// # Example
14///
15/// ```rust
16/// use bo4e_core::com::LoadCurveData;
17/// use bo4e_core::enums::Unit;
18/// use chrono::Utc;
19///
20/// let data = LoadCurveData {
21///     timestamp: Some(Utc::now()),
22///     power_value: Some(125.5),
23///     power_unit: Some(Unit::Kilowatt),
24///     interval_minutes: Some(15),
25///     ..Default::default()
26/// };
27/// ```
28#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct LoadCurveData {
31    /// BO4E metadata
32    #[serde(flatten)]
33    pub meta: Bo4eMeta,
34
35    /// Timestamp of the measurement (Zeitpunkt)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    pub timestamp: Option<DateTime<Utc>>,
38
39    /// Power value (Leistungswert)
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub power_value: Option<f64>,
42
43    /// Unit of power measurement (Leistungseinheit)
44    #[serde(skip_serializing_if = "Option::is_none")]
45    pub power_unit: Option<Unit>,
46
47    /// Energy value for the interval (Energiewert)
48    #[serde(skip_serializing_if = "Option::is_none")]
49    pub energy_value: Option<f64>,
50
51    /// Unit of energy measurement (Energieeinheit)
52    #[serde(skip_serializing_if = "Option::is_none")]
53    pub energy_unit: Option<Unit>,
54
55    /// Interval duration in minutes (Intervalllaenge)
56    #[serde(skip_serializing_if = "Option::is_none")]
57    pub interval_minutes: Option<i32>,
58
59    /// OBIS code (OBIS-Kennzahl)
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub obis_code: Option<String>,
62
63    /// Measurement location ID (Messlokations-ID)
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub measurement_location_id: Option<String>,
66}
67
68impl Bo4eObject for LoadCurveData {
69    fn type_name_german() -> &'static str {
70        "Lastkurvendaten"
71    }
72
73    fn type_name_english() -> &'static str {
74        "LoadCurveData"
75    }
76
77    fn meta(&self) -> &Bo4eMeta {
78        &self.meta
79    }
80
81    fn meta_mut(&mut self) -> &mut Bo4eMeta {
82        &mut self.meta
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use chrono::TimeZone;
90
91    #[test]
92    fn test_load_curve_data() {
93        let data = LoadCurveData {
94            timestamp: Some(Utc.with_ymd_and_hms(2024, 1, 15, 12, 15, 0).unwrap()),
95            power_value: Some(125.5),
96            power_unit: Some(Unit::Kilowatt),
97            interval_minutes: Some(15),
98            ..Default::default()
99        };
100
101        let json = serde_json::to_string(&data).unwrap();
102        assert!(json.contains("125.5"));
103        assert!(json.contains("15"));
104    }
105
106    #[test]
107    fn test_with_energy() {
108        let data = LoadCurveData {
109            timestamp: Some(Utc::now()),
110            power_value: Some(100.0),
111            power_unit: Some(Unit::Kilowatt),
112            energy_value: Some(25.0),
113            energy_unit: Some(Unit::KilowattHour),
114            interval_minutes: Some(15),
115            ..Default::default()
116        };
117
118        let json = serde_json::to_string(&data).unwrap();
119        assert!(json.contains("100"));
120        assert!(json.contains("25"));
121    }
122
123    #[test]
124    fn test_roundtrip() {
125        let data = LoadCurveData {
126            timestamp: Some(Utc::now()),
127            power_value: Some(999.99),
128            power_unit: Some(Unit::Kilowatt),
129            obis_code: Some("1-0:1.4.0".to_string()),
130            ..Default::default()
131        };
132
133        let json = serde_json::to_string(&data).unwrap();
134        let parsed: LoadCurveData = serde_json::from_str(&json).unwrap();
135        assert_eq!(data.power_value, parsed.power_value);
136        assert_eq!(data.obis_code, parsed.obis_code);
137    }
138
139    #[test]
140    fn test_bo4e_object_impl() {
141        assert_eq!(LoadCurveData::type_name_german(), "Lastkurvendaten");
142        assert_eq!(LoadCurveData::type_name_english(), "LoadCurveData");
143    }
144}