Skip to main content

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    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
164// Attribute decoders
165
166/// Decode DataModelRevision attribute (0x0000)
167pub 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
175/// Decode VendorName attribute (0x0001)
176pub 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
184/// Decode VendorID attribute (0x0002)
185pub 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
193/// Decode ProductName attribute (0x0003)
194pub 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
202/// Decode ProductID attribute (0x0004)
203pub 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
211/// Decode NodeLabel attribute (0x0005)
212pub 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
220/// Decode Location attribute (0x0006)
221pub 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
229/// Decode HardwareVersion attribute (0x0007)
230pub 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
238/// Decode HardwareVersionString attribute (0x0008)
239pub 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
247/// Decode SoftwareVersion attribute (0x0009)
248pub 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
256/// Decode SoftwareVersionString attribute (0x000A)
257pub 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
265/// Decode ManufacturingDate attribute (0x000B)
266pub 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
274/// Decode PartNumber attribute (0x000C)
275pub 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
283/// Decode ProductURL attribute (0x000D)
284pub 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
292/// Decode ProductLabel attribute (0x000E)
293pub 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
301/// Decode SerialNumber attribute (0x000F)
302pub 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
310/// Decode LocalConfigDisabled attribute (0x0010)
311pub 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
319/// Decode Reachable attribute (0x0011)
320pub 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
328/// Decode UniqueID attribute (0x0012)
329pub 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
337/// Decode CapabilityMinima attribute (0x0013)
338pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
339    if let tlv::TlvItemValue::List(_fields) = inp {
340        // Struct with fields
341        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
355/// Decode ProductAppearance attribute (0x0014)
356pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
357    if let tlv::TlvItemValue::List(_fields) = inp {
358        // Struct with fields
359        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
369/// Decode SpecificationVersion attribute (0x0015)
370pub 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
378/// Decode MaxPathsPerInvoke attribute (0x0016)
379pub 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
387/// Decode ConfigurationVersion attribute (0x0018)
388pub 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
397// JSON dispatcher function
398
399/// Decode attribute value and return as JSON string
400///
401/// # Parameters
402/// * `cluster_id` - The cluster identifier
403/// * `attribute_id` - The attribute identifier
404/// * `tlv_value` - The TLV value to decode
405///
406/// # Returns
407/// JSON string representation of the decoded value or error
408pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
409    // Verify this is the correct cluster
410    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
563/// Get list of all attributes supported by this cluster
564///
565/// # Returns
566/// Vector of tuples containing (attribute_id, attribute_name)
567pub 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
596// Typed facade (invokes + reads)
597
598/// Read `DataModelRevision` attribute from cluster `Basic Information`.
599pub 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
604/// Read `VendorName` attribute from cluster `Basic Information`.
605pub 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
610/// Read `VendorID` attribute from cluster `Basic Information`.
611pub 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
616/// Read `ProductName` attribute from cluster `Basic Information`.
617pub 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
622/// Read `ProductID` attribute from cluster `Basic Information`.
623pub 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
628/// Read `NodeLabel` attribute from cluster `Basic Information`.
629pub 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
634/// Read `Location` attribute from cluster `Basic Information`.
635pub 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
640/// Read `HardwareVersion` attribute from cluster `Basic Information`.
641pub 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
646/// Read `HardwareVersionString` attribute from cluster `Basic Information`.
647pub 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
652/// Read `SoftwareVersion` attribute from cluster `Basic Information`.
653pub 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
658/// Read `SoftwareVersionString` attribute from cluster `Basic Information`.
659pub 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
664/// Read `ManufacturingDate` attribute from cluster `Basic Information`.
665pub 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
670/// Read `PartNumber` attribute from cluster `Basic Information`.
671pub 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
676/// Read `ProductURL` attribute from cluster `Basic Information`.
677pub 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
682/// Read `ProductLabel` attribute from cluster `Basic Information`.
683pub 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
688/// Read `SerialNumber` attribute from cluster `Basic Information`.
689pub 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
694/// Read `LocalConfigDisabled` attribute from cluster `Basic Information`.
695pub 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
700/// Read `Reachable` attribute from cluster `Basic Information`.
701pub 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
706/// Read `UniqueID` attribute from cluster `Basic Information`.
707pub 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
712/// Read `CapabilityMinima` attribute from cluster `Basic Information`.
713pub 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
718/// Read `ProductAppearance` attribute from cluster `Basic Information`.
719pub 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
724/// Read `SpecificationVersion` attribute from cluster `Basic Information`.
725pub 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
730/// Read `MaxPathsPerInvoke` attribute from cluster `Basic Information`.
731pub 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
736/// Read `ConfigurationVersion` attribute from cluster `Basic Information`.
737pub 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
757// Event decoders
758
759/// Decode StartUp event (0x00, priority: critical)
760pub 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
771/// Decode Leave event (0x02, priority: info)
772pub 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
783/// Decode ReachableChanged event (0x03, priority: info)
784pub 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
796// Event JSON dispatcher
797
798/// Decode event value and return as JSON string
799pub 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
828/// Get list of all events supported by this cluster
829///
830/// # Returns
831/// Vector of tuples containing (event_id, event_name)
832pub 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