1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum Color {
18 Black = 0,
20 Navy = 1,
22 Green = 2,
24 Teal = 3,
26 Maroon = 4,
28 Purple = 5,
30 Olive = 6,
32 Gray = 7,
34 Blue = 8,
36 Lime = 9,
38 Aqua = 10,
40 Red = 11,
42 Fuchsia = 12,
44 Yellow = 13,
46 White = 14,
48 Nickel = 15,
50 Chrome = 16,
52 Brass = 17,
54 Copper = 18,
56 Silver = 19,
58 Gold = 20,
60}
61
62impl Color {
63 pub fn from_u8(value: u8) -> Option<Self> {
65 match value {
66 0 => Some(Color::Black),
67 1 => Some(Color::Navy),
68 2 => Some(Color::Green),
69 3 => Some(Color::Teal),
70 4 => Some(Color::Maroon),
71 5 => Some(Color::Purple),
72 6 => Some(Color::Olive),
73 7 => Some(Color::Gray),
74 8 => Some(Color::Blue),
75 9 => Some(Color::Lime),
76 10 => Some(Color::Aqua),
77 11 => Some(Color::Red),
78 12 => Some(Color::Fuchsia),
79 13 => Some(Color::Yellow),
80 14 => Some(Color::White),
81 15 => Some(Color::Nickel),
82 16 => Some(Color::Chrome),
83 17 => Some(Color::Brass),
84 18 => Some(Color::Copper),
85 19 => Some(Color::Silver),
86 20 => Some(Color::Gold),
87 _ => None,
88 }
89 }
90
91 pub fn to_u8(self) -> u8 {
93 self as u8
94 }
95}
96
97impl From<Color> for u8 {
98 fn from(val: Color) -> Self {
99 val as u8
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
104#[repr(u8)]
105pub enum ProductFinish {
106 Other = 0,
108 Matte = 1,
110 Satin = 2,
112 Polished = 3,
114 Rugged = 4,
116 Fabric = 5,
118}
119
120impl ProductFinish {
121 pub fn from_u8(value: u8) -> Option<Self> {
123 match value {
124 0 => Some(ProductFinish::Other),
125 1 => Some(ProductFinish::Matte),
126 2 => Some(ProductFinish::Satin),
127 3 => Some(ProductFinish::Polished),
128 4 => Some(ProductFinish::Rugged),
129 5 => Some(ProductFinish::Fabric),
130 _ => None,
131 }
132 }
133
134 pub fn to_u8(self) -> u8 {
136 self as u8
137 }
138}
139
140impl From<ProductFinish> for u8 {
141 fn from(val: ProductFinish) -> Self {
142 val as u8
143 }
144}
145
146#[derive(Debug, serde::Serialize)]
149pub struct CapabilityMinima {
150 pub case_sessions_per_fabric: Option<u16>,
151 pub subscriptions_per_fabric: Option<u16>,
152 pub simultaneous_invocations_supported: Option<u16>,
153 pub simultaneous_writes_supported: Option<u16>,
154 pub read_paths_supported: Option<u16>,
155 pub subscribe_paths_supported: Option<u16>,
156}
157
158#[derive(Debug, serde::Serialize)]
159pub struct ProductAppearance {
160 pub finish: Option<ProductFinish>,
161 pub primary_color: Option<Color>,
162}
163
164pub fn decode_data_model_revision(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
168 if let tlv::TlvItemValue::Int(v) = inp {
169 Ok(*v as u16)
170 } else {
171 Err(anyhow::anyhow!("Expected UInt16"))
172 }
173}
174
175pub fn decode_vendor_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
177 if let tlv::TlvItemValue::String(v) = inp {
178 Ok(v.clone())
179 } else {
180 Err(anyhow::anyhow!("Expected String"))
181 }
182}
183
184pub fn decode_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
186 if let tlv::TlvItemValue::Int(v) = inp {
187 Ok(*v as u16)
188 } else {
189 Err(anyhow::anyhow!("Expected UInt16"))
190 }
191}
192
193pub fn decode_product_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
195 if let tlv::TlvItemValue::String(v) = inp {
196 Ok(v.clone())
197 } else {
198 Err(anyhow::anyhow!("Expected String"))
199 }
200}
201
202pub fn decode_product_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
204 if let tlv::TlvItemValue::Int(v) = inp {
205 Ok(*v as u16)
206 } else {
207 Err(anyhow::anyhow!("Expected UInt16"))
208 }
209}
210
211pub fn decode_node_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
213 if let tlv::TlvItemValue::String(v) = inp {
214 Ok(v.clone())
215 } else {
216 Err(anyhow::anyhow!("Expected String"))
217 }
218}
219
220pub fn decode_location(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
222 if let tlv::TlvItemValue::String(v) = inp {
223 Ok(v.clone())
224 } else {
225 Err(anyhow::anyhow!("Expected String"))
226 }
227}
228
229pub fn decode_hardware_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
231 if let tlv::TlvItemValue::Int(v) = inp {
232 Ok(*v as u16)
233 } else {
234 Err(anyhow::anyhow!("Expected UInt16"))
235 }
236}
237
238pub fn decode_hardware_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
240 if let tlv::TlvItemValue::String(v) = inp {
241 Ok(v.clone())
242 } else {
243 Err(anyhow::anyhow!("Expected String"))
244 }
245}
246
247pub fn decode_software_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
249 if let tlv::TlvItemValue::Int(v) = inp {
250 Ok(*v as u32)
251 } else {
252 Err(anyhow::anyhow!("Expected UInt32"))
253 }
254}
255
256pub fn decode_software_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
258 if let tlv::TlvItemValue::String(v) = inp {
259 Ok(v.clone())
260 } else {
261 Err(anyhow::anyhow!("Expected String"))
262 }
263}
264
265pub fn decode_manufacturing_date(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
267 if let tlv::TlvItemValue::String(v) = inp {
268 Ok(v.clone())
269 } else {
270 Err(anyhow::anyhow!("Expected String"))
271 }
272}
273
274pub fn decode_part_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
276 if let tlv::TlvItemValue::String(v) = inp {
277 Ok(v.clone())
278 } else {
279 Err(anyhow::anyhow!("Expected String"))
280 }
281}
282
283pub fn decode_product_url(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
285 if let tlv::TlvItemValue::String(v) = inp {
286 Ok(v.clone())
287 } else {
288 Err(anyhow::anyhow!("Expected String"))
289 }
290}
291
292pub fn decode_product_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
294 if let tlv::TlvItemValue::String(v) = inp {
295 Ok(v.clone())
296 } else {
297 Err(anyhow::anyhow!("Expected String"))
298 }
299}
300
301pub fn decode_serial_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
303 if let tlv::TlvItemValue::String(v) = inp {
304 Ok(v.clone())
305 } else {
306 Err(anyhow::anyhow!("Expected String"))
307 }
308}
309
310pub fn decode_local_config_disabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
312 if let tlv::TlvItemValue::Bool(v) = inp {
313 Ok(*v)
314 } else {
315 Err(anyhow::anyhow!("Expected Bool"))
316 }
317}
318
319pub fn decode_reachable(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
321 if let tlv::TlvItemValue::Bool(v) = inp {
322 Ok(*v)
323 } else {
324 Err(anyhow::anyhow!("Expected Bool"))
325 }
326}
327
328pub fn decode_unique_id(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
330 if let tlv::TlvItemValue::String(v) = inp {
331 Ok(v.clone())
332 } else {
333 Err(anyhow::anyhow!("Expected String"))
334 }
335}
336
337pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
339 if let tlv::TlvItemValue::List(_fields) = inp {
340 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
342 Ok(CapabilityMinima {
343 case_sessions_per_fabric: item.get_int(&[0]).map(|v| v as u16),
344 subscriptions_per_fabric: item.get_int(&[1]).map(|v| v as u16),
345 simultaneous_invocations_supported: item.get_int(&[2]).map(|v| v as u16),
346 simultaneous_writes_supported: item.get_int(&[3]).map(|v| v as u16),
347 read_paths_supported: item.get_int(&[4]).map(|v| v as u16),
348 subscribe_paths_supported: item.get_int(&[5]).map(|v| v as u16),
349 })
350 } else {
351 Err(anyhow::anyhow!("Expected struct fields"))
352 }
353}
354
355pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
357 if let tlv::TlvItemValue::List(_fields) = inp {
358 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
360 Ok(ProductAppearance {
361 finish: item.get_int(&[0]).and_then(|v| ProductFinish::from_u8(v as u8)),
362 primary_color: item.get_int(&[1]).and_then(|v| Color::from_u8(v as u8)),
363 })
364 } else {
365 Err(anyhow::anyhow!("Expected struct fields"))
366 }
367}
368
369pub fn decode_specification_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
371 if let tlv::TlvItemValue::Int(v) = inp {
372 Ok(*v as u32)
373 } else {
374 Err(anyhow::anyhow!("Expected UInt32"))
375 }
376}
377
378pub fn decode_max_paths_per_invoke(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
380 if let tlv::TlvItemValue::Int(v) = inp {
381 Ok(*v as u16)
382 } else {
383 Err(anyhow::anyhow!("Expected UInt16"))
384 }
385}
386
387pub fn decode_configuration_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
389 if let tlv::TlvItemValue::Int(v) = inp {
390 Ok(*v as u32)
391 } else {
392 Err(anyhow::anyhow!("Expected UInt32"))
393 }
394}
395
396
397pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
409 if cluster_id != 0x0028 {
411 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0028, got {}\"}}", cluster_id);
412 }
413
414 match attribute_id {
415 0x0000 => {
416 match decode_data_model_revision(tlv_value) {
417 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
418 Err(e) => format!("{{\"error\": \"{}\"}}", e),
419 }
420 }
421 0x0001 => {
422 match decode_vendor_name(tlv_value) {
423 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
424 Err(e) => format!("{{\"error\": \"{}\"}}", e),
425 }
426 }
427 0x0002 => {
428 match decode_vendor_id(tlv_value) {
429 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
430 Err(e) => format!("{{\"error\": \"{}\"}}", e),
431 }
432 }
433 0x0003 => {
434 match decode_product_name(tlv_value) {
435 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
436 Err(e) => format!("{{\"error\": \"{}\"}}", e),
437 }
438 }
439 0x0004 => {
440 match decode_product_id(tlv_value) {
441 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
442 Err(e) => format!("{{\"error\": \"{}\"}}", e),
443 }
444 }
445 0x0005 => {
446 match decode_node_label(tlv_value) {
447 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
448 Err(e) => format!("{{\"error\": \"{}\"}}", e),
449 }
450 }
451 0x0006 => {
452 match decode_location(tlv_value) {
453 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
454 Err(e) => format!("{{\"error\": \"{}\"}}", e),
455 }
456 }
457 0x0007 => {
458 match decode_hardware_version(tlv_value) {
459 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
460 Err(e) => format!("{{\"error\": \"{}\"}}", e),
461 }
462 }
463 0x0008 => {
464 match decode_hardware_version_string(tlv_value) {
465 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
466 Err(e) => format!("{{\"error\": \"{}\"}}", e),
467 }
468 }
469 0x0009 => {
470 match decode_software_version(tlv_value) {
471 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
472 Err(e) => format!("{{\"error\": \"{}\"}}", e),
473 }
474 }
475 0x000A => {
476 match decode_software_version_string(tlv_value) {
477 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
478 Err(e) => format!("{{\"error\": \"{}\"}}", e),
479 }
480 }
481 0x000B => {
482 match decode_manufacturing_date(tlv_value) {
483 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
484 Err(e) => format!("{{\"error\": \"{}\"}}", e),
485 }
486 }
487 0x000C => {
488 match decode_part_number(tlv_value) {
489 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
490 Err(e) => format!("{{\"error\": \"{}\"}}", e),
491 }
492 }
493 0x000D => {
494 match decode_product_url(tlv_value) {
495 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
496 Err(e) => format!("{{\"error\": \"{}\"}}", e),
497 }
498 }
499 0x000E => {
500 match decode_product_label(tlv_value) {
501 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
502 Err(e) => format!("{{\"error\": \"{}\"}}", e),
503 }
504 }
505 0x000F => {
506 match decode_serial_number(tlv_value) {
507 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
508 Err(e) => format!("{{\"error\": \"{}\"}}", e),
509 }
510 }
511 0x0010 => {
512 match decode_local_config_disabled(tlv_value) {
513 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
514 Err(e) => format!("{{\"error\": \"{}\"}}", e),
515 }
516 }
517 0x0011 => {
518 match decode_reachable(tlv_value) {
519 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
520 Err(e) => format!("{{\"error\": \"{}\"}}", e),
521 }
522 }
523 0x0012 => {
524 match decode_unique_id(tlv_value) {
525 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
526 Err(e) => format!("{{\"error\": \"{}\"}}", e),
527 }
528 }
529 0x0013 => {
530 match decode_capability_minima(tlv_value) {
531 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
532 Err(e) => format!("{{\"error\": \"{}\"}}", e),
533 }
534 }
535 0x0014 => {
536 match decode_product_appearance(tlv_value) {
537 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
538 Err(e) => format!("{{\"error\": \"{}\"}}", e),
539 }
540 }
541 0x0015 => {
542 match decode_specification_version(tlv_value) {
543 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
544 Err(e) => format!("{{\"error\": \"{}\"}}", e),
545 }
546 }
547 0x0016 => {
548 match decode_max_paths_per_invoke(tlv_value) {
549 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
550 Err(e) => format!("{{\"error\": \"{}\"}}", e),
551 }
552 }
553 0x0018 => {
554 match decode_configuration_version(tlv_value) {
555 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
556 Err(e) => format!("{{\"error\": \"{}\"}}", e),
557 }
558 }
559 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
560 }
561}
562
563pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
568 vec![
569 (0x0000, "DataModelRevision"),
570 (0x0001, "VendorName"),
571 (0x0002, "VendorID"),
572 (0x0003, "ProductName"),
573 (0x0004, "ProductID"),
574 (0x0005, "NodeLabel"),
575 (0x0006, "Location"),
576 (0x0007, "HardwareVersion"),
577 (0x0008, "HardwareVersionString"),
578 (0x0009, "SoftwareVersion"),
579 (0x000A, "SoftwareVersionString"),
580 (0x000B, "ManufacturingDate"),
581 (0x000C, "PartNumber"),
582 (0x000D, "ProductURL"),
583 (0x000E, "ProductLabel"),
584 (0x000F, "SerialNumber"),
585 (0x0010, "LocalConfigDisabled"),
586 (0x0011, "Reachable"),
587 (0x0012, "UniqueID"),
588 (0x0013, "CapabilityMinima"),
589 (0x0014, "ProductAppearance"),
590 (0x0015, "SpecificationVersion"),
591 (0x0016, "MaxPathsPerInvoke"),
592 (0x0018, "ConfigurationVersion"),
593 ]
594}
595
596pub async fn read_data_model_revision(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
600 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_DATAMODELREVISION).await?;
601 decode_data_model_revision(&tlv)
602}
603
604pub async fn read_vendor_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
606 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORNAME).await?;
607 decode_vendor_name(&tlv)
608}
609
610pub async fn read_vendor_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
612 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORID).await?;
613 decode_vendor_id(&tlv)
614}
615
616pub async fn read_product_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
618 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTNAME).await?;
619 decode_product_name(&tlv)
620}
621
622pub async fn read_product_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
624 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTID).await?;
625 decode_product_id(&tlv)
626}
627
628pub async fn read_node_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
630 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_NODELABEL).await?;
631 decode_node_label(&tlv)
632}
633
634pub async fn read_location(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
636 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCATION).await?;
637 decode_location(&tlv)
638}
639
640pub async fn read_hardware_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
642 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSION).await?;
643 decode_hardware_version(&tlv)
644}
645
646pub async fn read_hardware_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
648 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSIONSTRING).await?;
649 decode_hardware_version_string(&tlv)
650}
651
652pub async fn read_software_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
654 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSION).await?;
655 decode_software_version(&tlv)
656}
657
658pub async fn read_software_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
660 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSIONSTRING).await?;
661 decode_software_version_string(&tlv)
662}
663
664pub async fn read_manufacturing_date(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
666 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_MANUFACTURINGDATE).await?;
667 decode_manufacturing_date(&tlv)
668}
669
670pub async fn read_part_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
672 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PARTNUMBER).await?;
673 decode_part_number(&tlv)
674}
675
676pub async fn read_product_url(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
678 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTURL).await?;
679 decode_product_url(&tlv)
680}
681
682pub async fn read_product_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
684 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTLABEL).await?;
685 decode_product_label(&tlv)
686}
687
688pub async fn read_serial_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
690 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SERIALNUMBER).await?;
691 decode_serial_number(&tlv)
692}
693
694pub async fn read_local_config_disabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
696 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCALCONFIGDISABLED).await?;
697 decode_local_config_disabled(&tlv)
698}
699
700pub async fn read_reachable(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
702 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_REACHABLE).await?;
703 decode_reachable(&tlv)
704}
705
706pub async fn read_unique_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
708 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_UNIQUEID).await?;
709 decode_unique_id(&tlv)
710}
711
712pub async fn read_capability_minima(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CapabilityMinima> {
714 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_CAPABILITYMINIMA).await?;
715 decode_capability_minima(&tlv)
716}
717
718pub async fn read_product_appearance(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ProductAppearance> {
720 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTAPPEARANCE).await?;
721 decode_product_appearance(&tlv)
722}
723
724pub async fn read_specification_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
726 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SPECIFICATIONVERSION).await?;
727 decode_specification_version(&tlv)
728}
729
730pub async fn read_max_paths_per_invoke(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
732 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_MAXPATHSPERINVOKE).await?;
733 decode_max_paths_per_invoke(&tlv)
734}
735
736pub async fn read_configuration_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
738 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_CONFIGURATIONVERSION).await?;
739 decode_configuration_version(&tlv)
740}
741
742#[derive(Debug, serde::Serialize)]
743pub struct StartUpEvent {
744 pub software_version: Option<u32>,
745}
746
747#[derive(Debug, serde::Serialize)]
748pub struct LeaveEvent {
749 pub fabric_index: Option<u8>,
750}
751
752#[derive(Debug, serde::Serialize)]
753pub struct ReachableChangedEvent {
754 pub reachable_new_value: Option<bool>,
755}
756
757pub fn decode_start_up_event(inp: &tlv::TlvItemValue) -> anyhow::Result<StartUpEvent> {
761 if let tlv::TlvItemValue::List(_fields) = inp {
762 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
763 Ok(StartUpEvent {
764 software_version: item.get_int(&[0]).map(|v| v as u32),
765 })
766 } else {
767 Err(anyhow::anyhow!("Expected struct fields"))
768 }
769}
770
771pub fn decode_leave_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LeaveEvent> {
773 if let tlv::TlvItemValue::List(_fields) = inp {
774 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
775 Ok(LeaveEvent {
776 fabric_index: item.get_int(&[0]).map(|v| v as u8),
777 })
778 } else {
779 Err(anyhow::anyhow!("Expected struct fields"))
780 }
781}
782
783pub fn decode_reachable_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ReachableChangedEvent> {
785 if let tlv::TlvItemValue::List(_fields) = inp {
786 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
787 Ok(ReachableChangedEvent {
788 reachable_new_value: item.get_bool(&[0]),
789 })
790 } else {
791 Err(anyhow::anyhow!("Expected struct fields"))
792 }
793}
794
795
796pub fn decode_event_json(cluster_id: u32, event_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
800 if cluster_id != 0x0028 {
801 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0028, got {}\"}}", cluster_id);
802 }
803
804 match event_id {
805 0x00 => {
806 match decode_start_up_event(tlv_value) {
807 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
808 Err(e) => format!("{{\"error\": \"{}\"}}", e),
809 }
810 }
811 0x01 => "{}".to_string(),
812 0x02 => {
813 match decode_leave_event(tlv_value) {
814 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
815 Err(e) => format!("{{\"error\": \"{}\"}}", e),
816 }
817 }
818 0x03 => {
819 match decode_reachable_changed_event(tlv_value) {
820 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
821 Err(e) => format!("{{\"error\": \"{}\"}}", e),
822 }
823 }
824 _ => format!("{{\"error\": \"Unknown event ID: {}\"}}", event_id),
825 }
826}
827
828pub fn get_event_list() -> Vec<(u32, &'static str)> {
833 vec![
834 (0x00, "StartUp"),
835 (0x01, "ShutDown"),
836 (0x02, "Leave"),
837 (0x03, "ReachableChanged"),
838 ]
839}
840