1use std::sync::Arc;
6
7use mabi_core::{
8 device::BoxedDevice, DeviceConfig, DeviceFactory, FactoryRegistry, Protocol,
9 Result as CoreResult,
10};
11
12use crate::address::{GroupAddress, IndividualAddress};
13use crate::config::{GroupObjectConfig, KnxDeviceConfig};
14use crate::device::{KnxDevice, KnxDeviceBuilder};
15use crate::dpt::{DptId, DptRegistry, DptValue};
16use crate::error::KnxError;
17
18pub struct KnxDeviceFactory {
20 dpt_registry: Arc<DptRegistry>,
21}
22
23impl KnxDeviceFactory {
24 pub fn new() -> Self {
26 Self {
27 dpt_registry: Arc::new(DptRegistry::new()),
28 }
29 }
30
31 pub fn with_registry(registry: Arc<DptRegistry>) -> Self {
33 Self {
34 dpt_registry: registry,
35 }
36 }
37
38 pub fn create_from_config(&self, config: KnxDeviceConfig) -> CoreResult<KnxDevice> {
40 let mut builder = KnxDeviceBuilder::new(&config.id, &config.name)
41 .individual_address(config.individual_address)
42 .description(&config.description)
43 .dpt_registry(self.dpt_registry.clone());
44
45 for go_config in &config.group_objects {
47 let address: GroupAddress = go_config
48 .address
49 .parse()
50 .map_err(|e: KnxError| mabi_core::Error::Protocol(e.to_string()))?;
51
52 let dpt_id: DptId = go_config
53 .dpt
54 .parse()
55 .map_err(|e: KnxError| mabi_core::Error::Protocol(e.to_string()))?;
56
57 if let Some(ref json_value) = go_config.initial_value {
59 let dpt_value = parse_json_to_dpt(json_value, &dpt_id)?;
60 builder =
61 builder.group_object_with_value(address, &go_config.name, dpt_id, dpt_value);
62 } else {
63 builder = builder.group_object(address, &go_config.name, dpt_id);
64 }
65 }
66
67 builder
68 .build()
69 .map_err(|e| mabi_core::Error::Protocol(e.to_string()))
70 }
71
72 pub fn create_simple(
74 &self,
75 id: &str,
76 name: &str,
77 individual_address: IndividualAddress,
78 ) -> KnxDevice {
79 KnxDeviceBuilder::new(id, name)
80 .individual_address(individual_address)
81 .dpt_registry(self.dpt_registry.clone())
82 .build()
83 .expect("Simple device creation should not fail")
84 }
85}
86
87impl Default for KnxDeviceFactory {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93impl DeviceFactory for KnxDeviceFactory {
94 fn protocol(&self) -> Protocol {
95 Protocol::KnxIp
96 }
97
98 fn create(&self, config: DeviceConfig) -> CoreResult<BoxedDevice> {
99 let individual_address = config
101 .metadata
102 .get("individual_address")
103 .and_then(|s| s.parse().ok())
104 .unwrap_or_else(|| IndividualAddress::new(1, 1, 1));
105
106 let mut builder = KnxDeviceBuilder::new(&config.id, &config.name)
107 .individual_address(individual_address)
108 .description(&config.description)
109 .dpt_registry(self.dpt_registry.clone());
110
111 if let Some(group_objects_json) = config.metadata.get("group_objects") {
113 if let Ok(objects) = serde_json::from_str::<Vec<GroupObjectConfig>>(group_objects_json)
114 {
115 for go in objects {
116 if let (Ok(addr), Ok(dpt)) =
117 (go.address.parse::<GroupAddress>(), go.dpt.parse::<DptId>())
118 {
119 builder = builder.group_object(addr, &go.name, dpt);
120 }
121 }
122 }
123 }
124
125 let device = builder
126 .build()
127 .map_err(|e| mabi_core::Error::Protocol(e.to_string()))?;
128
129 Ok(Box::new(device))
130 }
131}
132
133fn parse_json_to_dpt(json: &serde_json::Value, dpt_id: &DptId) -> CoreResult<DptValue> {
135 match dpt_id.main {
136 1 => {
137 let b = json
139 .as_bool()
140 .ok_or_else(|| mabi_core::Error::Config("Expected boolean".into()))?;
141 Ok(DptValue::Bool(b))
142 }
143 5 | 6 => {
144 let n = json
146 .as_i64()
147 .ok_or_else(|| mabi_core::Error::Config("Expected integer".into()))?;
148 if dpt_id.main == 5 {
149 Ok(DptValue::U8(n as u8))
150 } else {
151 Ok(DptValue::I8(n as i8))
152 }
153 }
154 7 | 8 => {
155 let n = json
157 .as_i64()
158 .ok_or_else(|| mabi_core::Error::Config("Expected integer".into()))?;
159 if dpt_id.main == 7 {
160 Ok(DptValue::U16(n as u16))
161 } else {
162 Ok(DptValue::I16(n as i16))
163 }
164 }
165 9 => {
166 let f = json
168 .as_f64()
169 .ok_or_else(|| mabi_core::Error::Config("Expected number".into()))?;
170 Ok(DptValue::F16(f as f32))
171 }
172 12 | 13 => {
173 let n = json
175 .as_i64()
176 .ok_or_else(|| mabi_core::Error::Config("Expected integer".into()))?;
177 if dpt_id.main == 12 {
178 Ok(DptValue::U32(n as u32))
179 } else {
180 Ok(DptValue::I32(n as i32))
181 }
182 }
183 14 => {
184 let f = json
186 .as_f64()
187 .ok_or_else(|| mabi_core::Error::Config("Expected number".into()))?;
188 Ok(DptValue::F32(f as f32))
189 }
190 16 => {
191 let s = json
193 .as_str()
194 .ok_or_else(|| mabi_core::Error::Config("Expected string".into()))?;
195 Ok(DptValue::String(s.to_string()))
196 }
197 _ => {
198 if let Some(b) = json.as_bool() {
200 Ok(DptValue::Bool(b))
201 } else if let Some(n) = json.as_i64() {
202 Ok(DptValue::I32(n as i32))
203 } else if let Some(f) = json.as_f64() {
204 Ok(DptValue::F32(f as f32))
205 } else if let Some(s) = json.as_str() {
206 Ok(DptValue::String(s.to_string()))
207 } else {
208 Err(mabi_core::Error::Config(format!(
209 "Cannot parse value for DPT {}",
210 dpt_id
211 )))
212 }
213 }
214 }
215}
216
217pub fn register_knx_factory(registry: &FactoryRegistry) -> CoreResult<()> {
219 registry.register(KnxDeviceFactory::new())
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use crate::config::GroupObjectFlagsConfig;
226
227 #[test]
228 fn test_factory_create_from_config() {
229 let factory = KnxDeviceFactory::new();
230
231 let config = KnxDeviceConfig {
232 id: "knx-1".to_string(),
233 name: "Living Room Controller".to_string(),
234 description: "Controls living room lights".to_string(),
235 individual_address: IndividualAddress::new(1, 2, 3),
236 group_objects: vec![
237 GroupObjectConfig {
238 address: "1/0/1".to_string(),
239 name: "Main Light".to_string(),
240 dpt: "1.001".to_string(),
241 flags: GroupObjectFlagsConfig::default(),
242 initial_value: Some(serde_json::json!(false)),
243 },
244 GroupObjectConfig {
245 address: "1/0/2".to_string(),
246 name: "Dimmer".to_string(),
247 dpt: "5.001".to_string(),
248 flags: GroupObjectFlagsConfig::default(),
249 initial_value: Some(serde_json::json!(50)),
250 },
251 ],
252 tick_interval_ms: 100,
253 };
254
255 let device = factory.create_from_config(config).unwrap();
256 assert_eq!(device.individual_address().to_string(), "1.2.3");
257 }
258
259 #[test]
260 fn test_factory_create_simple() {
261 let factory = KnxDeviceFactory::new();
262 let device = factory.create_simple("test", "Test Device", IndividualAddress::new(1, 1, 1));
263 assert_eq!(device.id(), "test");
264 }
265
266 #[test]
267 fn test_factory_trait() {
268 let factory = KnxDeviceFactory::new();
269 assert_eq!(factory.protocol(), Protocol::KnxIp);
270 }
271}