1use serde::{Deserialize, Serialize};
6
7use crate::enums::{DeviceCategory, DeviceType};
8use crate::traits::{Bo4eMeta, Bo4eObject};
9
10#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
30#[serde(rename_all = "camelCase")]
31pub struct Device {
32 #[serde(flatten)]
34 pub meta: Bo4eMeta,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub device_id: Option<String>,
39
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub serial_number: Option<String>,
43
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub device_category: Option<DeviceCategory>,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub device_type: Option<DeviceType>,
51
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub manufacturer: Option<String>,
55
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub model: Option<String>,
59
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub manufacturing_year: Option<i32>,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub installation_date: Option<chrono::DateTime<chrono::Utc>>,
67
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub removal_date: Option<chrono::DateTime<chrono::Utc>>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub firmware_version: Option<String>,
75
76 #[serde(skip_serializing_if = "Option::is_none")]
78 pub description: Option<String>,
79
80 #[serde(skip_serializing_if = "Option::is_none")]
82 pub metering_location_id: Option<String>,
83}
84
85impl Bo4eObject for Device {
86 fn type_name_german() -> &'static str {
87 "Geraet"
88 }
89
90 fn type_name_english() -> &'static str {
91 "Device"
92 }
93
94 fn meta(&self) -> &Bo4eMeta {
95 &self.meta
96 }
97
98 fn meta_mut(&mut self) -> &mut Bo4eMeta {
99 &mut self.meta
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_device_creation() {
109 let device = Device {
110 device_id: Some("DEV001".to_string()),
111 device_category: Some(DeviceCategory::MeteringDevice),
112 ..Default::default()
113 };
114
115 assert_eq!(device.device_id, Some("DEV001".to_string()));
116 }
117
118 #[test]
119 fn test_serialize() {
120 let device = Device {
121 meta: Bo4eMeta::with_type("Geraet"),
122 device_id: Some("DEV001".to_string()),
123 ..Default::default()
124 };
125
126 let json = serde_json::to_string(&device).unwrap();
127 assert!(json.contains(r#""_typ":"Geraet""#));
128 }
129
130 #[test]
131 fn test_roundtrip() {
132 let device = Device {
133 meta: Bo4eMeta::with_type("Geraet"),
134 device_id: Some("DEV001".to_string()),
135 serial_number: Some("SN123456".to_string()),
136 device_category: Some(DeviceCategory::MeteringDevice),
137 manufacturer: Some("Acme Corp".to_string()),
138 manufacturing_year: Some(2023),
139 ..Default::default()
140 };
141
142 let json = serde_json::to_string(&device).unwrap();
143 let parsed: Device = serde_json::from_str(&json).unwrap();
144 assert_eq!(device, parsed);
145 }
146
147 #[test]
148 fn test_bo4e_object_impl() {
149 assert_eq!(Device::type_name_german(), "Geraet");
150 assert_eq!(Device::type_name_english(), "Device");
151 }
152}