1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, serde::Serialize)]
14pub struct CapabilityMinima {
15 pub case_sessions_per_fabric: Option<u16>,
16 pub subscriptions_per_fabric: Option<u16>,
17}
18
19#[derive(Debug, serde::Serialize)]
20pub struct ProductAppearance {
21 pub finish: Option<u8>,
22 pub primary_color: Option<u8>,
23}
24
25pub fn encode_keep_active(stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<Vec<u8>> {
29 let tlv = tlv::TlvItemEnc {
30 tag: 0,
31 value: tlv::TlvItemValueEnc::StructInvisible(vec![
32 (0, tlv::TlvItemValueEnc::UInt32(stay_active_duration)).into(),
33 (1, tlv::TlvItemValueEnc::UInt32(timeout_ms)).into(),
34 ]),
35 };
36 Ok(tlv.encode()?)
37}
38
39pub fn decode_data_model_revision(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
43 if let tlv::TlvItemValue::Int(v) = inp {
44 Ok(*v as u16)
45 } else {
46 Err(anyhow::anyhow!("Expected Integer"))
47 }
48}
49
50pub fn decode_vendor_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
52 if let tlv::TlvItemValue::String(v) = inp {
53 Ok(v.clone())
54 } else {
55 Err(anyhow::anyhow!("Expected String"))
56 }
57}
58
59pub fn decode_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
61 if let tlv::TlvItemValue::Int(v) = inp {
62 Ok(*v as u16)
63 } else {
64 Err(anyhow::anyhow!("Expected Integer"))
65 }
66}
67
68pub fn decode_product_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
70 if let tlv::TlvItemValue::String(v) = inp {
71 Ok(v.clone())
72 } else {
73 Err(anyhow::anyhow!("Expected String"))
74 }
75}
76
77pub fn decode_product_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
79 if let tlv::TlvItemValue::Int(v) = inp {
80 Ok(*v as u16)
81 } else {
82 Err(anyhow::anyhow!("Expected Integer"))
83 }
84}
85
86pub fn decode_node_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
88 if let tlv::TlvItemValue::String(v) = inp {
89 Ok(v.clone())
90 } else {
91 Err(anyhow::anyhow!("Expected String"))
92 }
93}
94
95pub fn decode_location(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
97 if let tlv::TlvItemValue::String(v) = inp {
98 Ok(v.clone())
99 } else {
100 Err(anyhow::anyhow!("Expected String"))
101 }
102}
103
104pub fn decode_hardware_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
106 if let tlv::TlvItemValue::Int(v) = inp {
107 Ok(*v as u16)
108 } else {
109 Err(anyhow::anyhow!("Expected Integer"))
110 }
111}
112
113pub fn decode_hardware_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
115 if let tlv::TlvItemValue::String(v) = inp {
116 Ok(v.clone())
117 } else {
118 Err(anyhow::anyhow!("Expected String"))
119 }
120}
121
122pub fn decode_software_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
124 if let tlv::TlvItemValue::Int(v) = inp {
125 Ok(*v as u32)
126 } else {
127 Err(anyhow::anyhow!("Expected Integer"))
128 }
129}
130
131pub fn decode_software_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
133 if let tlv::TlvItemValue::String(v) = inp {
134 Ok(v.clone())
135 } else {
136 Err(anyhow::anyhow!("Expected String"))
137 }
138}
139
140pub fn decode_manufacturing_date(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
142 if let tlv::TlvItemValue::String(v) = inp {
143 Ok(v.clone())
144 } else {
145 Err(anyhow::anyhow!("Expected String"))
146 }
147}
148
149pub fn decode_part_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
151 if let tlv::TlvItemValue::String(v) = inp {
152 Ok(v.clone())
153 } else {
154 Err(anyhow::anyhow!("Expected String"))
155 }
156}
157
158pub fn decode_product_url(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
160 if let tlv::TlvItemValue::String(v) = inp {
161 Ok(v.clone())
162 } else {
163 Err(anyhow::anyhow!("Expected String"))
164 }
165}
166
167pub fn decode_product_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
169 if let tlv::TlvItemValue::String(v) = inp {
170 Ok(v.clone())
171 } else {
172 Err(anyhow::anyhow!("Expected String"))
173 }
174}
175
176pub fn decode_serial_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
178 if let tlv::TlvItemValue::String(v) = inp {
179 Ok(v.clone())
180 } else {
181 Err(anyhow::anyhow!("Expected String"))
182 }
183}
184
185pub fn decode_local_config_disabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
187 if let tlv::TlvItemValue::Bool(v) = inp {
188 Ok(*v)
189 } else {
190 Err(anyhow::anyhow!("Expected Bool"))
191 }
192}
193
194pub fn decode_reachable(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
196 if let tlv::TlvItemValue::Bool(v) = inp {
197 Ok(*v)
198 } else {
199 Err(anyhow::anyhow!("Expected Bool"))
200 }
201}
202
203pub fn decode_unique_id(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
205 if let tlv::TlvItemValue::String(v) = inp {
206 Ok(v.clone())
207 } else {
208 Err(anyhow::anyhow!("Expected String"))
209 }
210}
211
212pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
214 if let tlv::TlvItemValue::List(_fields) = inp {
215 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
217 Ok(CapabilityMinima {
218 case_sessions_per_fabric: item.get_int(&[0]).map(|v| v as u16),
219 subscriptions_per_fabric: item.get_int(&[1]).map(|v| v as u16),
220 })
221 } else {
222 Err(anyhow::anyhow!("Expected struct fields"))
223 }
224}
225
226pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
228 if let tlv::TlvItemValue::List(_fields) = inp {
229 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
231 Ok(ProductAppearance {
232 finish: item.get_int(&[0]).map(|v| v as u8),
233 primary_color: item.get_int(&[1]).map(|v| v as u8),
234 })
235 } else {
236 Err(anyhow::anyhow!("Expected struct fields"))
237 }
238}
239
240pub fn decode_specification_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
242 if let tlv::TlvItemValue::Int(v) = inp {
243 Ok(*v as u32)
244 } else {
245 Err(anyhow::anyhow!("Expected Integer"))
246 }
247}
248
249pub fn decode_max_paths_per_invoke(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
251 if let tlv::TlvItemValue::Int(v) = inp {
252 Ok(*v as u16)
253 } else {
254 Err(anyhow::anyhow!("Expected Integer"))
255 }
256}
257
258pub fn decode_configuration_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
260 if let tlv::TlvItemValue::Int(v) = inp {
261 Ok(*v as u32)
262 } else {
263 Err(anyhow::anyhow!("Expected Integer"))
264 }
265}
266
267
268pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
280 if cluster_id != 0x0039 {
282 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0039, got {}\"}}", cluster_id);
283 }
284
285 match attribute_id {
286 0x0000 => {
287 match decode_data_model_revision(tlv_value) {
288 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
289 Err(e) => format!("{{\"error\": \"{}\"}}", e),
290 }
291 }
292 0x0001 => {
293 match decode_vendor_name(tlv_value) {
294 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
295 Err(e) => format!("{{\"error\": \"{}\"}}", e),
296 }
297 }
298 0x0002 => {
299 match decode_vendor_id(tlv_value) {
300 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
301 Err(e) => format!("{{\"error\": \"{}\"}}", e),
302 }
303 }
304 0x0003 => {
305 match decode_product_name(tlv_value) {
306 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
307 Err(e) => format!("{{\"error\": \"{}\"}}", e),
308 }
309 }
310 0x0004 => {
311 match decode_product_id(tlv_value) {
312 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
313 Err(e) => format!("{{\"error\": \"{}\"}}", e),
314 }
315 }
316 0x0005 => {
317 match decode_node_label(tlv_value) {
318 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
319 Err(e) => format!("{{\"error\": \"{}\"}}", e),
320 }
321 }
322 0x0006 => {
323 match decode_location(tlv_value) {
324 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
325 Err(e) => format!("{{\"error\": \"{}\"}}", e),
326 }
327 }
328 0x0007 => {
329 match decode_hardware_version(tlv_value) {
330 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
331 Err(e) => format!("{{\"error\": \"{}\"}}", e),
332 }
333 }
334 0x0008 => {
335 match decode_hardware_version_string(tlv_value) {
336 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
337 Err(e) => format!("{{\"error\": \"{}\"}}", e),
338 }
339 }
340 0x0009 => {
341 match decode_software_version(tlv_value) {
342 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
343 Err(e) => format!("{{\"error\": \"{}\"}}", e),
344 }
345 }
346 0x000A => {
347 match decode_software_version_string(tlv_value) {
348 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
349 Err(e) => format!("{{\"error\": \"{}\"}}", e),
350 }
351 }
352 0x000B => {
353 match decode_manufacturing_date(tlv_value) {
354 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
355 Err(e) => format!("{{\"error\": \"{}\"}}", e),
356 }
357 }
358 0x000C => {
359 match decode_part_number(tlv_value) {
360 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
361 Err(e) => format!("{{\"error\": \"{}\"}}", e),
362 }
363 }
364 0x000D => {
365 match decode_product_url(tlv_value) {
366 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
367 Err(e) => format!("{{\"error\": \"{}\"}}", e),
368 }
369 }
370 0x000E => {
371 match decode_product_label(tlv_value) {
372 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
373 Err(e) => format!("{{\"error\": \"{}\"}}", e),
374 }
375 }
376 0x000F => {
377 match decode_serial_number(tlv_value) {
378 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
379 Err(e) => format!("{{\"error\": \"{}\"}}", e),
380 }
381 }
382 0x0010 => {
383 match decode_local_config_disabled(tlv_value) {
384 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
385 Err(e) => format!("{{\"error\": \"{}\"}}", e),
386 }
387 }
388 0x0011 => {
389 match decode_reachable(tlv_value) {
390 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
391 Err(e) => format!("{{\"error\": \"{}\"}}", e),
392 }
393 }
394 0x0012 => {
395 match decode_unique_id(tlv_value) {
396 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
397 Err(e) => format!("{{\"error\": \"{}\"}}", e),
398 }
399 }
400 0x0013 => {
401 match decode_capability_minima(tlv_value) {
402 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
403 Err(e) => format!("{{\"error\": \"{}\"}}", e),
404 }
405 }
406 0x0014 => {
407 match decode_product_appearance(tlv_value) {
408 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
409 Err(e) => format!("{{\"error\": \"{}\"}}", e),
410 }
411 }
412 0x0015 => {
413 match decode_specification_version(tlv_value) {
414 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
415 Err(e) => format!("{{\"error\": \"{}\"}}", e),
416 }
417 }
418 0x0016 => {
419 match decode_max_paths_per_invoke(tlv_value) {
420 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
421 Err(e) => format!("{{\"error\": \"{}\"}}", e),
422 }
423 }
424 0x0018 => {
425 match decode_configuration_version(tlv_value) {
426 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
427 Err(e) => format!("{{\"error\": \"{}\"}}", e),
428 }
429 }
430 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
431 }
432}
433
434pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
439 vec![
440 (0x0000, "DataModelRevision"),
441 (0x0001, "VendorName"),
442 (0x0002, "VendorID"),
443 (0x0003, "ProductName"),
444 (0x0004, "ProductID"),
445 (0x0005, "NodeLabel"),
446 (0x0006, "Location"),
447 (0x0007, "HardwareVersion"),
448 (0x0008, "HardwareVersionString"),
449 (0x0009, "SoftwareVersion"),
450 (0x000A, "SoftwareVersionString"),
451 (0x000B, "ManufacturingDate"),
452 (0x000C, "PartNumber"),
453 (0x000D, "ProductURL"),
454 (0x000E, "ProductLabel"),
455 (0x000F, "SerialNumber"),
456 (0x0010, "LocalConfigDisabled"),
457 (0x0011, "Reachable"),
458 (0x0012, "UniqueID"),
459 (0x0013, "CapabilityMinima"),
460 (0x0014, "ProductAppearance"),
461 (0x0015, "SpecificationVersion"),
462 (0x0016, "MaxPathsPerInvoke"),
463 (0x0018, "ConfigurationVersion"),
464 ]
465}
466