Skip to main content

bo4e_core/com/
profile_data.rs

1//! Profile data (Profildaten) component.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::enums::Unit;
7use crate::traits::{Bo4eMeta, Bo4eObject};
8
9/// Profile data for standard load profiles or individual consumption profiles.
10///
11/// German: Profildaten
12///
13/// # Example
14///
15/// ```rust
16/// use bo4e_core::com::ProfileData;
17/// use chrono::Utc;
18///
19/// let profile = ProfileData {
20///     profile_type: Some("H0".to_string()),
21///     timestamp: Some(Utc::now()),
22///     value: Some(0.000125),
23///     ..Default::default()
24/// };
25/// ```
26#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
27#[cfg_attr(feature = "json-schema", derive(schemars::JsonSchema))]
28#[cfg_attr(feature = "json-schema", schemars(rename = "Profildaten"))]
29#[serde(rename_all = "camelCase")]
30pub struct ProfileData {
31    /// BO4E metadata
32    #[serde(flatten)]
33    pub meta: Bo4eMeta,
34
35    /// Profile type/identifier (Profiltyp)
36    #[serde(skip_serializing_if = "Option::is_none")]
37    #[cfg_attr(feature = "json-schema", schemars(rename = "profiltyp"))]
38    pub profile_type: Option<String>,
39
40    /// Timestamp of the profile value (Zeitpunkt)
41    #[serde(skip_serializing_if = "Option::is_none")]
42    #[cfg_attr(feature = "json-schema", schemars(rename = "zeitpunkt"))]
43    pub timestamp: Option<DateTime<Utc>>,
44
45    /// Profile value (Profilwert)
46    #[serde(skip_serializing_if = "Option::is_none")]
47    #[cfg_attr(feature = "json-schema", schemars(rename = "profilwert"))]
48    pub value: Option<f64>,
49
50    /// Unit of the profile value (Einheit)
51    #[serde(skip_serializing_if = "Option::is_none")]
52    #[cfg_attr(feature = "json-schema", schemars(rename = "einheit"))]
53    pub unit: Option<Unit>,
54
55    /// Profile name (Profilname)
56    #[serde(skip_serializing_if = "Option::is_none")]
57    #[cfg_attr(feature = "json-schema", schemars(rename = "profilname"))]
58    pub profile_name: Option<String>,
59
60    /// Profile version (Profilversion)
61    #[serde(skip_serializing_if = "Option::is_none")]
62    #[cfg_attr(feature = "json-schema", schemars(rename = "profilversion"))]
63    pub profile_version: Option<String>,
64
65    /// Temperature zone (Temperaturzone)
66    #[serde(skip_serializing_if = "Option::is_none")]
67    #[cfg_attr(feature = "json-schema", schemars(rename = "temperaturzone"))]
68    pub temperature_zone: Option<String>,
69}
70
71impl Bo4eObject for ProfileData {
72    fn type_name_german() -> &'static str {
73        "Profildaten"
74    }
75
76    fn type_name_english() -> &'static str {
77        "ProfileData"
78    }
79
80    fn meta(&self) -> &Bo4eMeta {
81        &self.meta
82    }
83
84    fn meta_mut(&mut self) -> &mut Bo4eMeta {
85        &mut self.meta
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92    use chrono::TimeZone;
93
94    #[test]
95    fn test_profile_data() {
96        let profile = ProfileData {
97            profile_type: Some("H0".to_string()),
98            timestamp: Some(Utc.with_ymd_and_hms(2024, 1, 15, 12, 15, 0).unwrap()),
99            value: Some(0.000125),
100            profile_name: Some("Haushalt".to_string()),
101            ..Default::default()
102        };
103
104        let json = serde_json::to_string(&profile).unwrap();
105        assert!(json.contains("H0"));
106        assert!(json.contains("0.000125"));
107    }
108
109    #[test]
110    fn test_business_profile() {
111        let profile = ProfileData {
112            profile_type: Some("G0".to_string()),
113            profile_name: Some("Gewerbe allgemein".to_string()),
114            profile_version: Some("2024-01".to_string()),
115            temperature_zone: Some("TZ1".to_string()),
116            ..Default::default()
117        };
118
119        let json = serde_json::to_string(&profile).unwrap();
120        assert!(json.contains("G0"));
121        assert!(json.contains("TZ1"));
122    }
123
124    #[test]
125    fn test_roundtrip() {
126        let profile = ProfileData {
127            profile_type: Some("L0".to_string()),
128            value: Some(0.000089),
129            ..Default::default()
130        };
131
132        let json = serde_json::to_string(&profile).unwrap();
133        let parsed: ProfileData = serde_json::from_str(&json).unwrap();
134        assert_eq!(profile, parsed);
135    }
136
137    #[test]
138    fn test_bo4e_object_impl() {
139        assert_eq!(ProfileData::type_name_german(), "Profildaten");
140        assert_eq!(ProfileData::type_name_english(), "ProfileData");
141    }
142}