bo4e_core/bo/
time_series.rs1use serde::{Deserialize, Serialize};
6
7use crate::com::{TimePeriod, TimeSeriesValue};
8use crate::enums::{Division, MeasurementType, Unit};
9use crate::traits::{Bo4eMeta, Bo4eObject};
10
11#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct TimeSeries {
33 #[serde(flatten)]
35 pub meta: Bo4eMeta,
36
37 #[serde(skip_serializing_if = "Option::is_none")]
39 pub time_series_id: Option<String>,
40
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub division: Option<Division>,
44
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub measurement_type: Option<MeasurementType>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
51 pub unit: Option<Unit>,
52
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub validity_period: Option<TimePeriod>,
56
57 #[serde(default, skip_serializing_if = "Vec::is_empty")]
59 pub values: Vec<TimeSeriesValue>,
60
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub market_location_id: Option<String>,
64
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub metering_location_id: Option<String>,
68
69 #[serde(skip_serializing_if = "Option::is_none")]
71 pub description: Option<String>,
72
73 #[serde(skip_serializing_if = "Option::is_none")]
75 pub obis_code: Option<String>,
76
77 #[serde(skip_serializing_if = "Option::is_none")]
79 pub series_version: Option<String>,
80
81 #[serde(skip_serializing_if = "Option::is_none")]
83 pub resolution_minutes: Option<i32>,
84}
85
86impl Bo4eObject for TimeSeries {
87 fn type_name_german() -> &'static str {
88 "Zeitreihe"
89 }
90
91 fn type_name_english() -> &'static str {
92 "TimeSeries"
93 }
94
95 fn meta(&self) -> &Bo4eMeta {
96 &self.meta
97 }
98
99 fn meta_mut(&mut self) -> &mut Bo4eMeta {
100 &mut self.meta
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107
108 #[test]
109 fn test_time_series_creation() {
110 let series = TimeSeries {
111 time_series_id: Some("TS001".to_string()),
112 division: Some(Division::Electricity),
113 ..Default::default()
114 };
115
116 assert_eq!(series.time_series_id, Some("TS001".to_string()));
117 }
118
119 #[test]
120 fn test_serialize() {
121 let series = TimeSeries {
122 meta: Bo4eMeta::with_type("Zeitreihe"),
123 time_series_id: Some("TS001".to_string()),
124 ..Default::default()
125 };
126
127 let json = serde_json::to_string(&series).unwrap();
128 assert!(json.contains(r#""_typ":"Zeitreihe""#));
129 }
130
131 #[test]
132 fn test_roundtrip() {
133 let series = TimeSeries {
134 meta: Bo4eMeta::with_type("Zeitreihe"),
135 time_series_id: Some("TS001".to_string()),
136 division: Some(Division::Electricity),
137 unit: Some(Unit::KilowattHour),
138 resolution_minutes: Some(15),
139 description: Some("Test time series".to_string()),
140 ..Default::default()
141 };
142
143 let json = serde_json::to_string(&series).unwrap();
144 let parsed: TimeSeries = serde_json::from_str(&json).unwrap();
145 assert_eq!(series, parsed);
146 }
147
148 #[test]
149 fn test_bo4e_object_impl() {
150 assert_eq!(TimeSeries::type_name_german(), "Zeitreihe");
151 assert_eq!(TimeSeries::type_name_english(), "TimeSeries");
152 }
153}