1use std::sync::Arc;
6
7use mabi_core::{
8 DeviceConfig, DeviceFactory, FactoryRegistry, Protocol,
9 Result as CoreResult,
10 device::BoxedDevice,
11};
12
13use crate::address::{GroupAddress, IndividualAddress};
14use crate::config::{GroupObjectConfig, KnxDeviceConfig};
15use crate::device::{KnxDevice, KnxDeviceBuilder};
16use crate::dpt::{DptId, DptRegistry, DptValue};
17use crate::error::KnxError;
18
19pub struct KnxDeviceFactory {
21 dpt_registry: Arc<DptRegistry>,
22}
23
24impl KnxDeviceFactory {
25 pub fn new() -> Self {
27 Self {
28 dpt_registry: Arc::new(DptRegistry::new()),
29 }
30 }
31
32 pub fn with_registry(registry: Arc<DptRegistry>) -> Self {
34 Self {
35 dpt_registry: registry,
36 }
37 }
38
39 pub fn create_from_config(&self, config: KnxDeviceConfig) -> CoreResult<KnxDevice> {
41 let mut builder = KnxDeviceBuilder::new(&config.id, &config.name)
42 .individual_address(config.individual_address)
43 .description(&config.description)
44 .dpt_registry(self.dpt_registry.clone());
45
46 for go_config in &config.group_objects {
48 let address: GroupAddress = go_config
49 .address
50 .parse()
51 .map_err(|e: KnxError| mabi_core::Error::Protocol(e.to_string()))?;
52
53 let dpt_id: DptId = go_config
54 .dpt
55 .parse()
56 .map_err(|e: KnxError| mabi_core::Error::Protocol(e.to_string()))?;
57
58 if let Some(ref json_value) = go_config.initial_value {
60 let dpt_value = parse_json_to_dpt(json_value, &dpt_id)?;
61 builder = 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)) = (go.address.parse::<GroupAddress>(), go.dpt.parse::<DptId>()) {
117 builder = builder.group_object(addr, &go.name, dpt);
118 }
119 }
120 }
121 }
122
123 let device = builder
124 .build()
125 .map_err(|e| mabi_core::Error::Protocol(e.to_string()))?;
126
127 Ok(Box::new(device))
128 }
129}
130
131fn parse_json_to_dpt(json: &serde_json::Value, dpt_id: &DptId) -> CoreResult<DptValue> {
133 match dpt_id.main {
134 1 => {
135 let b = json
137 .as_bool()
138 .ok_or_else(|| mabi_core::Error::Config("Expected boolean".into()))?;
139 Ok(DptValue::Bool(b))
140 }
141 5 | 6 => {
142 let n = json
144 .as_i64()
145 .ok_or_else(|| mabi_core::Error::Config("Expected integer".into()))?;
146 if dpt_id.main == 5 {
147 Ok(DptValue::U8(n as u8))
148 } else {
149 Ok(DptValue::I8(n as i8))
150 }
151 }
152 7 | 8 => {
153 let n = json
155 .as_i64()
156 .ok_or_else(|| mabi_core::Error::Config("Expected integer".into()))?;
157 if dpt_id.main == 7 {
158 Ok(DptValue::U16(n as u16))
159 } else {
160 Ok(DptValue::I16(n as i16))
161 }
162 }
163 9 => {
164 let f = json
166 .as_f64()
167 .ok_or_else(|| mabi_core::Error::Config("Expected number".into()))?;
168 Ok(DptValue::F16(f as f32))
169 }
170 12 | 13 => {
171 let n = json
173 .as_i64()
174 .ok_or_else(|| mabi_core::Error::Config("Expected integer".into()))?;
175 if dpt_id.main == 12 {
176 Ok(DptValue::U32(n as u32))
177 } else {
178 Ok(DptValue::I32(n as i32))
179 }
180 }
181 14 => {
182 let f = json
184 .as_f64()
185 .ok_or_else(|| mabi_core::Error::Config("Expected number".into()))?;
186 Ok(DptValue::F32(f as f32))
187 }
188 16 => {
189 let s = json
191 .as_str()
192 .ok_or_else(|| mabi_core::Error::Config("Expected string".into()))?;
193 Ok(DptValue::String(s.to_string()))
194 }
195 _ => {
196 if let Some(b) = json.as_bool() {
198 Ok(DptValue::Bool(b))
199 } else if let Some(n) = json.as_i64() {
200 Ok(DptValue::I32(n as i32))
201 } else if let Some(f) = json.as_f64() {
202 Ok(DptValue::F32(f as f32))
203 } else if let Some(s) = json.as_str() {
204 Ok(DptValue::String(s.to_string()))
205 } else {
206 Err(mabi_core::Error::Config(format!(
207 "Cannot parse value for DPT {}",
208 dpt_id
209 )))
210 }
211 }
212 }
213}
214
215pub fn register_knx_factory(registry: &FactoryRegistry) -> CoreResult<()> {
217 registry.register(KnxDeviceFactory::new())
218}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223 use crate::config::GroupObjectFlagsConfig;
224
225 #[test]
226 fn test_factory_create_from_config() {
227 let factory = KnxDeviceFactory::new();
228
229 let config = KnxDeviceConfig {
230 id: "knx-1".to_string(),
231 name: "Living Room Controller".to_string(),
232 description: "Controls living room lights".to_string(),
233 individual_address: IndividualAddress::new(1, 2, 3),
234 group_objects: vec![
235 GroupObjectConfig {
236 address: "1/0/1".to_string(),
237 name: "Main Light".to_string(),
238 dpt: "1.001".to_string(),
239 flags: GroupObjectFlagsConfig::default(),
240 initial_value: Some(serde_json::json!(false)),
241 },
242 GroupObjectConfig {
243 address: "1/0/2".to_string(),
244 name: "Dimmer".to_string(),
245 dpt: "5.001".to_string(),
246 flags: GroupObjectFlagsConfig::default(),
247 initial_value: Some(serde_json::json!(50)),
248 },
249 ],
250 tick_interval_ms: 100,
251 };
252
253 let device = factory.create_from_config(config).unwrap();
254 assert_eq!(device.individual_address().to_string(), "1.2.3");
255 }
256
257 #[test]
258 fn test_factory_create_simple() {
259 let factory = KnxDeviceFactory::new();
260 let device = factory.create_simple("test", "Test Device", IndividualAddress::new(1, 1, 1));
261 assert_eq!(device.id(), "test");
262 }
263
264 #[test]
265 fn test_factory_trait() {
266 let factory = KnxDeviceFactory::new();
267 assert_eq!(factory.protocol(), Protocol::KnxIp);
268 }
269}