bo4e_core/com/
meter_reading.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::enums::{MeasuredValueStatus, ReadingType, Unit};
7use crate::traits::{Bo4eMeta, Bo4eObject};
8
9#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct MeterReading {
31 #[serde(flatten)]
33 pub meta: Bo4eMeta,
34
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub timestamp: Option<DateTime<Utc>>,
38
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub value: Option<f64>,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
45 pub unit: Option<Unit>,
46
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub reading_type: Option<ReadingType>,
50
51 #[serde(skip_serializing_if = "Option::is_none")]
53 pub status: Option<MeasuredValueStatus>,
54
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub obis_code: Option<String>,
58
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub register_id: Option<String>,
62}
63
64impl Bo4eObject for MeterReading {
65 fn type_name_german() -> &'static str {
66 "Zaehlwerksstand"
67 }
68
69 fn type_name_english() -> &'static str {
70 "MeterReading"
71 }
72
73 fn meta(&self) -> &Bo4eMeta {
74 &self.meta
75 }
76
77 fn meta_mut(&mut self) -> &mut Bo4eMeta {
78 &mut self.meta
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use chrono::TimeZone;
86
87 #[test]
88 fn test_meter_reading() {
89 let reading = MeterReading {
90 timestamp: Some(Utc.with_ymd_and_hms(2024, 1, 1, 0, 0, 0).unwrap()),
91 value: Some(12345.67),
92 unit: Some(Unit::KilowattHour),
93 reading_type: Some(ReadingType::RemoteReading),
94 obis_code: Some("1-0:1.8.0".to_string()),
95 ..Default::default()
96 };
97
98 let json = serde_json::to_string(&reading).unwrap();
99 assert!(json.contains("12345.67"));
100 assert!(json.contains("1-0:1.8.0"));
101 }
102
103 #[test]
104 fn test_roundtrip() {
105 let reading = MeterReading {
106 timestamp: Some(Utc::now()),
107 value: Some(999.99),
108 unit: Some(Unit::CubicMeter),
109 ..Default::default()
110 };
111
112 let json = serde_json::to_string(&reading).unwrap();
113 let parsed: MeterReading = serde_json::from_str(&json).unwrap();
114 assert_eq!(reading.value, parsed.value);
115 assert_eq!(reading.unit, parsed.unit);
116 }
117
118 #[test]
119 fn test_bo4e_object_impl() {
120 assert_eq!(MeterReading::type_name_german(), "Zaehlwerksstand");
121 assert_eq!(MeterReading::type_name_english(), "MeterReading");
122 }
123}