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}
153
154#[derive(Debug, serde::Serialize)]
155pub struct ProductAppearance {
156 pub finish: Option<ProductFinish>,
157 pub primary_color: Option<Color>,
158}
159
160pub fn decode_data_model_revision(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
164 if let tlv::TlvItemValue::Int(v) = inp {
165 Ok(*v as u16)
166 } else {
167 Err(anyhow::anyhow!("Expected UInt16"))
168 }
169}
170
171pub fn decode_vendor_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
173 if let tlv::TlvItemValue::String(v) = inp {
174 Ok(v.clone())
175 } else {
176 Err(anyhow::anyhow!("Expected String"))
177 }
178}
179
180pub fn decode_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
182 if let tlv::TlvItemValue::Int(v) = inp {
183 Ok(*v as u16)
184 } else {
185 Err(anyhow::anyhow!("Expected UInt16"))
186 }
187}
188
189pub fn decode_product_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
191 if let tlv::TlvItemValue::String(v) = inp {
192 Ok(v.clone())
193 } else {
194 Err(anyhow::anyhow!("Expected String"))
195 }
196}
197
198pub fn decode_product_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
200 if let tlv::TlvItemValue::Int(v) = inp {
201 Ok(*v as u16)
202 } else {
203 Err(anyhow::anyhow!("Expected UInt16"))
204 }
205}
206
207pub fn decode_node_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
209 if let tlv::TlvItemValue::String(v) = inp {
210 Ok(v.clone())
211 } else {
212 Err(anyhow::anyhow!("Expected String"))
213 }
214}
215
216pub fn decode_location(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
218 if let tlv::TlvItemValue::String(v) = inp {
219 Ok(v.clone())
220 } else {
221 Err(anyhow::anyhow!("Expected String"))
222 }
223}
224
225pub fn decode_hardware_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
227 if let tlv::TlvItemValue::Int(v) = inp {
228 Ok(*v as u16)
229 } else {
230 Err(anyhow::anyhow!("Expected UInt16"))
231 }
232}
233
234pub fn decode_hardware_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
236 if let tlv::TlvItemValue::String(v) = inp {
237 Ok(v.clone())
238 } else {
239 Err(anyhow::anyhow!("Expected String"))
240 }
241}
242
243pub fn decode_software_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
245 if let tlv::TlvItemValue::Int(v) = inp {
246 Ok(*v as u32)
247 } else {
248 Err(anyhow::anyhow!("Expected UInt32"))
249 }
250}
251
252pub fn decode_software_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
254 if let tlv::TlvItemValue::String(v) = inp {
255 Ok(v.clone())
256 } else {
257 Err(anyhow::anyhow!("Expected String"))
258 }
259}
260
261pub fn decode_manufacturing_date(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
263 if let tlv::TlvItemValue::String(v) = inp {
264 Ok(v.clone())
265 } else {
266 Err(anyhow::anyhow!("Expected String"))
267 }
268}
269
270pub fn decode_part_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
272 if let tlv::TlvItemValue::String(v) = inp {
273 Ok(v.clone())
274 } else {
275 Err(anyhow::anyhow!("Expected String"))
276 }
277}
278
279pub fn decode_product_url(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
281 if let tlv::TlvItemValue::String(v) = inp {
282 Ok(v.clone())
283 } else {
284 Err(anyhow::anyhow!("Expected String"))
285 }
286}
287
288pub fn decode_product_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
290 if let tlv::TlvItemValue::String(v) = inp {
291 Ok(v.clone())
292 } else {
293 Err(anyhow::anyhow!("Expected String"))
294 }
295}
296
297pub fn decode_serial_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
299 if let tlv::TlvItemValue::String(v) = inp {
300 Ok(v.clone())
301 } else {
302 Err(anyhow::anyhow!("Expected String"))
303 }
304}
305
306pub fn decode_local_config_disabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
308 if let tlv::TlvItemValue::Bool(v) = inp {
309 Ok(*v)
310 } else {
311 Err(anyhow::anyhow!("Expected Bool"))
312 }
313}
314
315pub fn decode_reachable(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
317 if let tlv::TlvItemValue::Bool(v) = inp {
318 Ok(*v)
319 } else {
320 Err(anyhow::anyhow!("Expected Bool"))
321 }
322}
323
324pub fn decode_unique_id(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
326 if let tlv::TlvItemValue::String(v) = inp {
327 Ok(v.clone())
328 } else {
329 Err(anyhow::anyhow!("Expected String"))
330 }
331}
332
333pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
335 if let tlv::TlvItemValue::List(_fields) = inp {
336 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
338 Ok(CapabilityMinima {
339 case_sessions_per_fabric: item.get_int(&[0]).map(|v| v as u16),
340 subscriptions_per_fabric: item.get_int(&[1]).map(|v| v as u16),
341 })
342 } else {
343 Err(anyhow::anyhow!("Expected struct fields"))
344 }
345}
346
347pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
349 if let tlv::TlvItemValue::List(_fields) = inp {
350 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
352 Ok(ProductAppearance {
353 finish: item.get_int(&[0]).and_then(|v| ProductFinish::from_u8(v as u8)),
354 primary_color: item.get_int(&[1]).and_then(|v| Color::from_u8(v as u8)),
355 })
356 } else {
357 Err(anyhow::anyhow!("Expected struct fields"))
358 }
359}
360
361pub fn decode_specification_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
363 if let tlv::TlvItemValue::Int(v) = inp {
364 Ok(*v as u32)
365 } else {
366 Err(anyhow::anyhow!("Expected UInt32"))
367 }
368}
369
370pub fn decode_max_paths_per_invoke(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
372 if let tlv::TlvItemValue::Int(v) = inp {
373 Ok(*v as u16)
374 } else {
375 Err(anyhow::anyhow!("Expected UInt16"))
376 }
377}
378
379pub fn decode_configuration_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
381 if let tlv::TlvItemValue::Int(v) = inp {
382 Ok(*v as u32)
383 } else {
384 Err(anyhow::anyhow!("Expected UInt32"))
385 }
386}
387
388
389pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
401 if cluster_id != 0x0028 {
403 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0028, got {}\"}}", cluster_id);
404 }
405
406 match attribute_id {
407 0x0000 => {
408 match decode_data_model_revision(tlv_value) {
409 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
410 Err(e) => format!("{{\"error\": \"{}\"}}", e),
411 }
412 }
413 0x0001 => {
414 match decode_vendor_name(tlv_value) {
415 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
416 Err(e) => format!("{{\"error\": \"{}\"}}", e),
417 }
418 }
419 0x0002 => {
420 match decode_vendor_id(tlv_value) {
421 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
422 Err(e) => format!("{{\"error\": \"{}\"}}", e),
423 }
424 }
425 0x0003 => {
426 match decode_product_name(tlv_value) {
427 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
428 Err(e) => format!("{{\"error\": \"{}\"}}", e),
429 }
430 }
431 0x0004 => {
432 match decode_product_id(tlv_value) {
433 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
434 Err(e) => format!("{{\"error\": \"{}\"}}", e),
435 }
436 }
437 0x0005 => {
438 match decode_node_label(tlv_value) {
439 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
440 Err(e) => format!("{{\"error\": \"{}\"}}", e),
441 }
442 }
443 0x0006 => {
444 match decode_location(tlv_value) {
445 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
446 Err(e) => format!("{{\"error\": \"{}\"}}", e),
447 }
448 }
449 0x0007 => {
450 match decode_hardware_version(tlv_value) {
451 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
452 Err(e) => format!("{{\"error\": \"{}\"}}", e),
453 }
454 }
455 0x0008 => {
456 match decode_hardware_version_string(tlv_value) {
457 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
458 Err(e) => format!("{{\"error\": \"{}\"}}", e),
459 }
460 }
461 0x0009 => {
462 match decode_software_version(tlv_value) {
463 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
464 Err(e) => format!("{{\"error\": \"{}\"}}", e),
465 }
466 }
467 0x000A => {
468 match decode_software_version_string(tlv_value) {
469 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
470 Err(e) => format!("{{\"error\": \"{}\"}}", e),
471 }
472 }
473 0x000B => {
474 match decode_manufacturing_date(tlv_value) {
475 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
476 Err(e) => format!("{{\"error\": \"{}\"}}", e),
477 }
478 }
479 0x000C => {
480 match decode_part_number(tlv_value) {
481 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
482 Err(e) => format!("{{\"error\": \"{}\"}}", e),
483 }
484 }
485 0x000D => {
486 match decode_product_url(tlv_value) {
487 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
488 Err(e) => format!("{{\"error\": \"{}\"}}", e),
489 }
490 }
491 0x000E => {
492 match decode_product_label(tlv_value) {
493 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
494 Err(e) => format!("{{\"error\": \"{}\"}}", e),
495 }
496 }
497 0x000F => {
498 match decode_serial_number(tlv_value) {
499 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
500 Err(e) => format!("{{\"error\": \"{}\"}}", e),
501 }
502 }
503 0x0010 => {
504 match decode_local_config_disabled(tlv_value) {
505 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
506 Err(e) => format!("{{\"error\": \"{}\"}}", e),
507 }
508 }
509 0x0011 => {
510 match decode_reachable(tlv_value) {
511 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
512 Err(e) => format!("{{\"error\": \"{}\"}}", e),
513 }
514 }
515 0x0012 => {
516 match decode_unique_id(tlv_value) {
517 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
518 Err(e) => format!("{{\"error\": \"{}\"}}", e),
519 }
520 }
521 0x0013 => {
522 match decode_capability_minima(tlv_value) {
523 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
524 Err(e) => format!("{{\"error\": \"{}\"}}", e),
525 }
526 }
527 0x0014 => {
528 match decode_product_appearance(tlv_value) {
529 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
530 Err(e) => format!("{{\"error\": \"{}\"}}", e),
531 }
532 }
533 0x0015 => {
534 match decode_specification_version(tlv_value) {
535 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
536 Err(e) => format!("{{\"error\": \"{}\"}}", e),
537 }
538 }
539 0x0016 => {
540 match decode_max_paths_per_invoke(tlv_value) {
541 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
542 Err(e) => format!("{{\"error\": \"{}\"}}", e),
543 }
544 }
545 0x0018 => {
546 match decode_configuration_version(tlv_value) {
547 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
548 Err(e) => format!("{{\"error\": \"{}\"}}", e),
549 }
550 }
551 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
552 }
553}
554
555pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
560 vec![
561 (0x0000, "DataModelRevision"),
562 (0x0001, "VendorName"),
563 (0x0002, "VendorID"),
564 (0x0003, "ProductName"),
565 (0x0004, "ProductID"),
566 (0x0005, "NodeLabel"),
567 (0x0006, "Location"),
568 (0x0007, "HardwareVersion"),
569 (0x0008, "HardwareVersionString"),
570 (0x0009, "SoftwareVersion"),
571 (0x000A, "SoftwareVersionString"),
572 (0x000B, "ManufacturingDate"),
573 (0x000C, "PartNumber"),
574 (0x000D, "ProductURL"),
575 (0x000E, "ProductLabel"),
576 (0x000F, "SerialNumber"),
577 (0x0010, "LocalConfigDisabled"),
578 (0x0011, "Reachable"),
579 (0x0012, "UniqueID"),
580 (0x0013, "CapabilityMinima"),
581 (0x0014, "ProductAppearance"),
582 (0x0015, "SpecificationVersion"),
583 (0x0016, "MaxPathsPerInvoke"),
584 (0x0018, "ConfigurationVersion"),
585 ]
586}
587
588pub async fn read_data_model_revision(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
592 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_DATAMODELREVISION).await?;
593 decode_data_model_revision(&tlv)
594}
595
596pub async fn read_vendor_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
598 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORNAME).await?;
599 decode_vendor_name(&tlv)
600}
601
602pub async fn read_vendor_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
604 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_VENDORID).await?;
605 decode_vendor_id(&tlv)
606}
607
608pub async fn read_product_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
610 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTNAME).await?;
611 decode_product_name(&tlv)
612}
613
614pub async fn read_product_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
616 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTID).await?;
617 decode_product_id(&tlv)
618}
619
620pub async fn read_node_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
622 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_NODELABEL).await?;
623 decode_node_label(&tlv)
624}
625
626pub async fn read_location(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
628 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCATION).await?;
629 decode_location(&tlv)
630}
631
632pub async fn read_hardware_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
634 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSION).await?;
635 decode_hardware_version(&tlv)
636}
637
638pub async fn read_hardware_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
640 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSIONSTRING).await?;
641 decode_hardware_version_string(&tlv)
642}
643
644pub async fn read_software_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
646 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSION).await?;
647 decode_software_version(&tlv)
648}
649
650pub async fn read_software_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
652 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSIONSTRING).await?;
653 decode_software_version_string(&tlv)
654}
655
656pub async fn read_manufacturing_date(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
658 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_MANUFACTURINGDATE).await?;
659 decode_manufacturing_date(&tlv)
660}
661
662pub async fn read_part_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
664 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PARTNUMBER).await?;
665 decode_part_number(&tlv)
666}
667
668pub async fn read_product_url(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
670 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTURL).await?;
671 decode_product_url(&tlv)
672}
673
674pub async fn read_product_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
676 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTLABEL).await?;
677 decode_product_label(&tlv)
678}
679
680pub async fn read_serial_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
682 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SERIALNUMBER).await?;
683 decode_serial_number(&tlv)
684}
685
686pub async fn read_local_config_disabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
688 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_LOCALCONFIGDISABLED).await?;
689 decode_local_config_disabled(&tlv)
690}
691
692pub async fn read_reachable(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
694 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_REACHABLE).await?;
695 decode_reachable(&tlv)
696}
697
698pub async fn read_unique_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
700 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_UNIQUEID).await?;
701 decode_unique_id(&tlv)
702}
703
704pub async fn read_capability_minima(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CapabilityMinima> {
706 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_CAPABILITYMINIMA).await?;
707 decode_capability_minima(&tlv)
708}
709
710pub async fn read_product_appearance(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ProductAppearance> {
712 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_PRODUCTAPPEARANCE).await?;
713 decode_product_appearance(&tlv)
714}
715
716pub async fn read_specification_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
718 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_SPECIFICATIONVERSION).await?;
719 decode_specification_version(&tlv)
720}
721
722pub async fn read_max_paths_per_invoke(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
724 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_MAXPATHSPERINVOKE).await?;
725 decode_max_paths_per_invoke(&tlv)
726}
727
728pub async fn read_configuration_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
730 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BASIC_INFORMATION_ATTR_ID_CONFIGURATIONVERSION).await?;
731 decode_configuration_version(&tlv)
732}
733
734#[derive(Debug, serde::Serialize)]
735pub struct StartUpEvent {
736 pub software_version: Option<u32>,
737}
738
739#[derive(Debug, serde::Serialize)]
740pub struct LeaveEvent {
741 pub fabric_index: Option<u8>,
742}
743
744#[derive(Debug, serde::Serialize)]
745pub struct ReachableChangedEvent {
746 pub reachable_new_value: Option<bool>,
747}
748
749pub fn decode_start_up_event(inp: &tlv::TlvItemValue) -> anyhow::Result<StartUpEvent> {
753 if let tlv::TlvItemValue::List(_fields) = inp {
754 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
755 Ok(StartUpEvent {
756 software_version: item.get_int(&[0]).map(|v| v as u32),
757 })
758 } else {
759 Err(anyhow::anyhow!("Expected struct fields"))
760 }
761}
762
763pub fn decode_leave_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LeaveEvent> {
765 if let tlv::TlvItemValue::List(_fields) = inp {
766 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
767 Ok(LeaveEvent {
768 fabric_index: item.get_int(&[0]).map(|v| v as u8),
769 })
770 } else {
771 Err(anyhow::anyhow!("Expected struct fields"))
772 }
773}
774
775pub fn decode_reachable_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ReachableChangedEvent> {
777 if let tlv::TlvItemValue::List(_fields) = inp {
778 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
779 Ok(ReachableChangedEvent {
780 reachable_new_value: item.get_bool(&[0]),
781 })
782 } else {
783 Err(anyhow::anyhow!("Expected struct fields"))
784 }
785}
786