bo4e_core/com/
meter_register.rs

1//! Meter register (Zaehlwerk) component.
2
3use serde::{Deserialize, Serialize};
4
5use crate::enums::{EnergyDirection, RegisterType, Unit};
6use crate::traits::{Bo4eMeta, Bo4eObject};
7
8/// A register on a meter that records consumption.
9///
10/// German: Zaehlwerk
11///
12/// # Example
13///
14/// ```rust
15/// use bo4e_core::com::MeterRegister;
16/// use bo4e_core::enums::{EnergyDirection, Unit};
17///
18/// let register = MeterRegister {
19///     obis_code: Some("1-0:1.8.0".to_string()),
20///     energy_direction: Some(EnergyDirection::FeedOut),
21///     unit: Some(Unit::KilowattHour),
22///     ..Default::default()
23/// };
24/// ```
25#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
26#[serde(rename_all = "camelCase")]
27pub struct MeterRegister {
28    /// BO4E metadata
29    #[serde(flatten)]
30    pub meta: Bo4eMeta,
31
32    /// Register number/ID (Zaehlwerkskennung)
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub register_id: Option<String>,
35
36    /// OBIS code (OBIS-Kennzahl)
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub obis_code: Option<String>,
39
40    /// Type of register (Registerart)
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub register_type: Option<RegisterType>,
43
44    /// Direction of energy flow (Energierichtung)
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub energy_direction: Option<EnergyDirection>,
47
48    /// Unit of measurement (Einheit)
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub unit: Option<Unit>,
51
52    /// Number of decimal places (Nachkommastellen)
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub decimal_places: Option<i32>,
55
56    /// Multiplier/transformer ratio (Wandlerfaktor)
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub transformer_ratio: Option<f64>,
59
60    /// Description (Bezeichnung)
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub description: Option<String>,
63}
64
65impl Bo4eObject for MeterRegister {
66    fn type_name_german() -> &'static str {
67        "Zaehlwerk"
68    }
69
70    fn type_name_english() -> &'static str {
71        "MeterRegister"
72    }
73
74    fn meta(&self) -> &Bo4eMeta {
75        &self.meta
76    }
77
78    fn meta_mut(&mut self) -> &mut Bo4eMeta {
79        &mut self.meta
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use super::*;
86
87    #[test]
88    fn test_electricity_register() {
89        let register = MeterRegister {
90            obis_code: Some("1-0:1.8.0".to_string()),
91            energy_direction: Some(EnergyDirection::FeedOut),
92            unit: Some(Unit::KilowattHour),
93            description: Some("Bezug".to_string()),
94            ..Default::default()
95        };
96
97        let json = serde_json::to_string(&register).unwrap();
98        assert!(json.contains("1-0:1.8.0"));
99    }
100
101    #[test]
102    fn test_roundtrip() {
103        let register = MeterRegister {
104            obis_code: Some("1-0:2.8.0".to_string()),
105            energy_direction: Some(EnergyDirection::FeedIn),
106            unit: Some(Unit::KilowattHour),
107            ..Default::default()
108        };
109
110        let json = serde_json::to_string(&register).unwrap();
111        let parsed: MeterRegister = serde_json::from_str(&json).unwrap();
112        assert_eq!(register, parsed);
113    }
114
115    #[test]
116    fn test_bo4e_object_impl() {
117        assert_eq!(MeterRegister::type_name_german(), "Zaehlwerk");
118        assert_eq!(MeterRegister::type_name_english(), "MeterRegister");
119    }
120}