matc/clusters/codec/
basic_information_cluster.rs

1//! Matter TLV encoders and decoders for Basic Information Cluster
2//! Cluster ID: 0x0028
3//!
4//! This file is automatically generated from BasicInformationCluster.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Enum definitions
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum Color {
18    /// Approximately RGB #000000.
19    Black = 0,
20    /// Approximately RGB #000080.
21    Navy = 1,
22    /// Approximately RGB #008000.
23    Green = 2,
24    /// Approximately RGB #008080.
25    Teal = 3,
26    /// Approximately RGB #800000.
27    Maroon = 4,
28    /// Approximately RGB #800080.
29    Purple = 5,
30    /// Approximately RGB #808000.
31    Olive = 6,
32    /// Approximately RGB #808080.
33    Gray = 7,
34    /// Approximately RGB #0000FF.
35    Blue = 8,
36    /// Approximately RGB #00FF00.
37    Lime = 9,
38    /// Approximately RGB #00FFFF.
39    Aqua = 10,
40    /// Approximately RGB #FF0000.
41    Red = 11,
42    /// Approximately RGB #FF00FF.
43    Fuchsia = 12,
44    /// Approximately RGB #FFFF00.
45    Yellow = 13,
46    /// Approximately RGB #FFFFFF.
47    White = 14,
48    /// Typical hardware "Nickel" color.
49    Nickel = 15,
50    /// Typical hardware "Chrome" color.
51    Chrome = 16,
52    /// Typical hardware "Brass" color.
53    Brass = 17,
54    /// Typical hardware "Copper" color.
55    Copper = 18,
56    /// Typical hardware "Silver" color.
57    Silver = 19,
58    /// Typical hardware "Gold" color.
59    Gold = 20,
60}
61
62impl Color {
63    /// Convert from u8 value
64    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    /// Convert to u8 value
92    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    /// Product has some other finish not listed below.
107    Other = 0,
108    /// Product has a matte finish.
109    Matte = 1,
110    /// Product has a satin finish.
111    Satin = 2,
112    /// Product has a polished or shiny finish.
113    Polished = 3,
114    /// Product has a rugged finish.
115    Rugged = 4,
116    /// Product has a fabric finish.
117    Fabric = 5,
118}
119
120impl ProductFinish {
121    /// Convert from u8 value
122    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    /// Convert to u8 value
135    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// Struct definitions
147
148#[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
160// Attribute decoders
161
162/// Decode DataModelRevision attribute (0x0000)
163pub 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
171/// Decode VendorName attribute (0x0001)
172pub 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
180/// Decode VendorID attribute (0x0002)
181pub 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
189/// Decode ProductName attribute (0x0003)
190pub 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
198/// Decode ProductID attribute (0x0004)
199pub 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
207/// Decode NodeLabel attribute (0x0005)
208pub 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
216/// Decode Location attribute (0x0006)
217pub 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
225/// Decode HardwareVersion attribute (0x0007)
226pub 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
234/// Decode HardwareVersionString attribute (0x0008)
235pub 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
243/// Decode SoftwareVersion attribute (0x0009)
244pub 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
252/// Decode SoftwareVersionString attribute (0x000A)
253pub 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
261/// Decode ManufacturingDate attribute (0x000B)
262pub 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
270/// Decode PartNumber attribute (0x000C)
271pub 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
279/// Decode ProductURL attribute (0x000D)
280pub 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
288/// Decode ProductLabel attribute (0x000E)
289pub 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
297/// Decode SerialNumber attribute (0x000F)
298pub 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
306/// Decode LocalConfigDisabled attribute (0x0010)
307pub 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
315/// Decode Reachable attribute (0x0011)
316pub 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
324/// Decode UniqueID attribute (0x0012)
325pub 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
333/// Decode CapabilityMinima attribute (0x0013)
334pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
335    if let tlv::TlvItemValue::List(_fields) = inp {
336        // Struct with fields
337        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
347/// Decode ProductAppearance attribute (0x0014)
348pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
349    if let tlv::TlvItemValue::List(_fields) = inp {
350        // Struct with fields
351        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
361/// Decode SpecificationVersion attribute (0x0015)
362pub 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
370/// Decode MaxPathsPerInvoke attribute (0x0016)
371pub 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
379/// Decode ConfigurationVersion attribute (0x0018)
380pub 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
389// JSON dispatcher function
390
391/// Decode attribute value and return as JSON string
392///
393/// # Parameters
394/// * `cluster_id` - The cluster identifier
395/// * `attribute_id` - The attribute identifier
396/// * `tlv_value` - The TLV value to decode
397///
398/// # Returns
399/// JSON string representation of the decoded value or error
400pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
401    // Verify this is the correct cluster
402    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
555/// Get list of all attributes supported by this cluster
556///
557/// # Returns
558/// Vector of tuples containing (attribute_id, attribute_name)
559pub 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
588// Typed facade (invokes + reads)
589
590/// Read `DataModelRevision` attribute from cluster `Basic Information`.
591pub 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
596/// Read `VendorName` attribute from cluster `Basic Information`.
597pub 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
602/// Read `VendorID` attribute from cluster `Basic Information`.
603pub 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
608/// Read `ProductName` attribute from cluster `Basic Information`.
609pub 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
614/// Read `ProductID` attribute from cluster `Basic Information`.
615pub 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
620/// Read `NodeLabel` attribute from cluster `Basic Information`.
621pub 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
626/// Read `Location` attribute from cluster `Basic Information`.
627pub 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
632/// Read `HardwareVersion` attribute from cluster `Basic Information`.
633pub 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
638/// Read `HardwareVersionString` attribute from cluster `Basic Information`.
639pub 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
644/// Read `SoftwareVersion` attribute from cluster `Basic Information`.
645pub 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
650/// Read `SoftwareVersionString` attribute from cluster `Basic Information`.
651pub 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
656/// Read `ManufacturingDate` attribute from cluster `Basic Information`.
657pub 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
662/// Read `PartNumber` attribute from cluster `Basic Information`.
663pub 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
668/// Read `ProductURL` attribute from cluster `Basic Information`.
669pub 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
674/// Read `ProductLabel` attribute from cluster `Basic Information`.
675pub 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
680/// Read `SerialNumber` attribute from cluster `Basic Information`.
681pub 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
686/// Read `LocalConfigDisabled` attribute from cluster `Basic Information`.
687pub 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
692/// Read `Reachable` attribute from cluster `Basic Information`.
693pub 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
698/// Read `UniqueID` attribute from cluster `Basic Information`.
699pub 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
704/// Read `CapabilityMinima` attribute from cluster `Basic Information`.
705pub 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
710/// Read `ProductAppearance` attribute from cluster `Basic Information`.
711pub 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
716/// Read `SpecificationVersion` attribute from cluster `Basic Information`.
717pub 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
722/// Read `MaxPathsPerInvoke` attribute from cluster `Basic Information`.
723pub 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
728/// Read `ConfigurationVersion` attribute from cluster `Basic Information`.
729pub 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
749// Event decoders
750
751/// Decode StartUp event (0x00, priority: critical)
752pub 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
763/// Decode Leave event (0x02, priority: info)
764pub 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
775/// Decode ReachableChanged event (0x03, priority: info)
776pub 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