Skip to main content

matc/clusters/codec/
bridged_device_basic_information_cluster.rs

1//! Matter TLV encoders and decoders for Bridged Device Basic Information Cluster
2//! Cluster ID: 0x0039
3//!
4//! This file is automatically generated from BridgedDeviceBasicInformationCluster.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// Command encoders
165
166/// Encode KeepActive command (0x80)
167pub fn encode_keep_active(stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<Vec<u8>> {
168    let tlv = tlv::TlvItemEnc {
169        tag: 0,
170        value: tlv::TlvItemValueEnc::StructInvisible(vec![
171        (0, tlv::TlvItemValueEnc::UInt32(stay_active_duration)).into(),
172        (1, tlv::TlvItemValueEnc::UInt32(timeout_ms)).into(),
173        ]),
174    };
175    Ok(tlv.encode()?)
176}
177
178// Attribute decoders
179
180/// Decode DataModelRevision attribute (0x0000)
181pub fn decode_data_model_revision(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 VendorName attribute (0x0001)
190pub fn decode_vendor_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 VendorID attribute (0x0002)
199pub fn decode_vendor_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 ProductName attribute (0x0003)
208pub fn decode_product_name(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 ProductID attribute (0x0004)
217pub fn decode_product_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
218    if let tlv::TlvItemValue::Int(v) = inp {
219        Ok(*v as u16)
220    } else {
221        Err(anyhow::anyhow!("Expected UInt16"))
222    }
223}
224
225/// Decode NodeLabel attribute (0x0005)
226pub fn decode_node_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
227    if let tlv::TlvItemValue::String(v) = inp {
228        Ok(v.clone())
229    } else {
230        Err(anyhow::anyhow!("Expected String"))
231    }
232}
233
234/// Decode Location attribute (0x0006)
235pub fn decode_location(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 HardwareVersion attribute (0x0007)
244pub fn decode_hardware_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
245    if let tlv::TlvItemValue::Int(v) = inp {
246        Ok(*v as u16)
247    } else {
248        Err(anyhow::anyhow!("Expected UInt16"))
249    }
250}
251
252/// Decode HardwareVersionString attribute (0x0008)
253pub fn decode_hardware_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 SoftwareVersion attribute (0x0009)
262pub fn decode_software_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
263    if let tlv::TlvItemValue::Int(v) = inp {
264        Ok(*v as u32)
265    } else {
266        Err(anyhow::anyhow!("Expected UInt32"))
267    }
268}
269
270/// Decode SoftwareVersionString attribute (0x000A)
271pub fn decode_software_version_string(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 ManufacturingDate attribute (0x000B)
280pub fn decode_manufacturing_date(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 PartNumber attribute (0x000C)
289pub fn decode_part_number(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 ProductURL attribute (0x000D)
298pub fn decode_product_url(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 ProductLabel attribute (0x000E)
307pub fn decode_product_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
308    if let tlv::TlvItemValue::String(v) = inp {
309        Ok(v.clone())
310    } else {
311        Err(anyhow::anyhow!("Expected String"))
312    }
313}
314
315/// Decode SerialNumber attribute (0x000F)
316pub fn decode_serial_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
317    if let tlv::TlvItemValue::String(v) = inp {
318        Ok(v.clone())
319    } else {
320        Err(anyhow::anyhow!("Expected String"))
321    }
322}
323
324/// Decode LocalConfigDisabled attribute (0x0010)
325pub fn decode_local_config_disabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
326    if let tlv::TlvItemValue::Bool(v) = inp {
327        Ok(*v)
328    } else {
329        Err(anyhow::anyhow!("Expected Bool"))
330    }
331}
332
333/// Decode Reachable attribute (0x0011)
334pub fn decode_reachable(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
335    if let tlv::TlvItemValue::Bool(v) = inp {
336        Ok(*v)
337    } else {
338        Err(anyhow::anyhow!("Expected Bool"))
339    }
340}
341
342/// Decode UniqueID attribute (0x0012)
343pub fn decode_unique_id(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
344    if let tlv::TlvItemValue::String(v) = inp {
345        Ok(v.clone())
346    } else {
347        Err(anyhow::anyhow!("Expected String"))
348    }
349}
350
351/// Decode CapabilityMinima attribute (0x0013)
352pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
353    if let tlv::TlvItemValue::List(_fields) = inp {
354        // Struct with fields
355        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
356        Ok(CapabilityMinima {
357                case_sessions_per_fabric: item.get_int(&[0]).map(|v| v as u16),
358                subscriptions_per_fabric: item.get_int(&[1]).map(|v| v as u16),
359                simultaneous_invocations_supported: item.get_int(&[2]).map(|v| v as u16),
360                simultaneous_writes_supported: item.get_int(&[3]).map(|v| v as u16),
361                read_paths_supported: item.get_int(&[4]).map(|v| v as u16),
362                subscribe_paths_supported: item.get_int(&[5]).map(|v| v as u16),
363        })
364    } else {
365        Err(anyhow::anyhow!("Expected struct fields"))
366    }
367}
368
369/// Decode ProductAppearance attribute (0x0014)
370pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
371    if let tlv::TlvItemValue::List(_fields) = inp {
372        // Struct with fields
373        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
374        Ok(ProductAppearance {
375                finish: item.get_int(&[0]).and_then(|v| ProductFinish::from_u8(v as u8)),
376                primary_color: item.get_int(&[1]).and_then(|v| Color::from_u8(v as u8)),
377        })
378    } else {
379        Err(anyhow::anyhow!("Expected struct fields"))
380    }
381}
382
383/// Decode SpecificationVersion attribute (0x0015)
384pub fn decode_specification_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
385    if let tlv::TlvItemValue::Int(v) = inp {
386        Ok(*v as u32)
387    } else {
388        Err(anyhow::anyhow!("Expected UInt32"))
389    }
390}
391
392/// Decode MaxPathsPerInvoke attribute (0x0016)
393pub fn decode_max_paths_per_invoke(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
394    if let tlv::TlvItemValue::Int(v) = inp {
395        Ok(*v as u16)
396    } else {
397        Err(anyhow::anyhow!("Expected UInt16"))
398    }
399}
400
401/// Decode ConfigurationVersion attribute (0x0018)
402pub fn decode_configuration_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
403    if let tlv::TlvItemValue::Int(v) = inp {
404        Ok(*v as u32)
405    } else {
406        Err(anyhow::anyhow!("Expected UInt32"))
407    }
408}
409
410
411// JSON dispatcher function
412
413/// Decode attribute value and return as JSON string
414///
415/// # Parameters
416/// * `cluster_id` - The cluster identifier
417/// * `attribute_id` - The attribute identifier
418/// * `tlv_value` - The TLV value to decode
419///
420/// # Returns
421/// JSON string representation of the decoded value or error
422pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
423    // Verify this is the correct cluster
424    if cluster_id != 0x0039 {
425        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0039, got {}\"}}", cluster_id);
426    }
427
428    match attribute_id {
429        0x0000 => {
430            match decode_data_model_revision(tlv_value) {
431                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
432                Err(e) => format!("{{\"error\": \"{}\"}}", e),
433            }
434        }
435        0x0001 => {
436            match decode_vendor_name(tlv_value) {
437                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
438                Err(e) => format!("{{\"error\": \"{}\"}}", e),
439            }
440        }
441        0x0002 => {
442            match decode_vendor_id(tlv_value) {
443                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
444                Err(e) => format!("{{\"error\": \"{}\"}}", e),
445            }
446        }
447        0x0003 => {
448            match decode_product_name(tlv_value) {
449                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
450                Err(e) => format!("{{\"error\": \"{}\"}}", e),
451            }
452        }
453        0x0004 => {
454            match decode_product_id(tlv_value) {
455                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
456                Err(e) => format!("{{\"error\": \"{}\"}}", e),
457            }
458        }
459        0x0005 => {
460            match decode_node_label(tlv_value) {
461                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
462                Err(e) => format!("{{\"error\": \"{}\"}}", e),
463            }
464        }
465        0x0006 => {
466            match decode_location(tlv_value) {
467                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
468                Err(e) => format!("{{\"error\": \"{}\"}}", e),
469            }
470        }
471        0x0007 => {
472            match decode_hardware_version(tlv_value) {
473                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
474                Err(e) => format!("{{\"error\": \"{}\"}}", e),
475            }
476        }
477        0x0008 => {
478            match decode_hardware_version_string(tlv_value) {
479                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
480                Err(e) => format!("{{\"error\": \"{}\"}}", e),
481            }
482        }
483        0x0009 => {
484            match decode_software_version(tlv_value) {
485                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
486                Err(e) => format!("{{\"error\": \"{}\"}}", e),
487            }
488        }
489        0x000A => {
490            match decode_software_version_string(tlv_value) {
491                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
492                Err(e) => format!("{{\"error\": \"{}\"}}", e),
493            }
494        }
495        0x000B => {
496            match decode_manufacturing_date(tlv_value) {
497                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
498                Err(e) => format!("{{\"error\": \"{}\"}}", e),
499            }
500        }
501        0x000C => {
502            match decode_part_number(tlv_value) {
503                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
504                Err(e) => format!("{{\"error\": \"{}\"}}", e),
505            }
506        }
507        0x000D => {
508            match decode_product_url(tlv_value) {
509                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
510                Err(e) => format!("{{\"error\": \"{}\"}}", e),
511            }
512        }
513        0x000E => {
514            match decode_product_label(tlv_value) {
515                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
516                Err(e) => format!("{{\"error\": \"{}\"}}", e),
517            }
518        }
519        0x000F => {
520            match decode_serial_number(tlv_value) {
521                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
522                Err(e) => format!("{{\"error\": \"{}\"}}", e),
523            }
524        }
525        0x0010 => {
526            match decode_local_config_disabled(tlv_value) {
527                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
528                Err(e) => format!("{{\"error\": \"{}\"}}", e),
529            }
530        }
531        0x0011 => {
532            match decode_reachable(tlv_value) {
533                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
534                Err(e) => format!("{{\"error\": \"{}\"}}", e),
535            }
536        }
537        0x0012 => {
538            match decode_unique_id(tlv_value) {
539                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
540                Err(e) => format!("{{\"error\": \"{}\"}}", e),
541            }
542        }
543        0x0013 => {
544            match decode_capability_minima(tlv_value) {
545                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
546                Err(e) => format!("{{\"error\": \"{}\"}}", e),
547            }
548        }
549        0x0014 => {
550            match decode_product_appearance(tlv_value) {
551                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
552                Err(e) => format!("{{\"error\": \"{}\"}}", e),
553            }
554        }
555        0x0015 => {
556            match decode_specification_version(tlv_value) {
557                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
558                Err(e) => format!("{{\"error\": \"{}\"}}", e),
559            }
560        }
561        0x0016 => {
562            match decode_max_paths_per_invoke(tlv_value) {
563                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
564                Err(e) => format!("{{\"error\": \"{}\"}}", e),
565            }
566        }
567        0x0018 => {
568            match decode_configuration_version(tlv_value) {
569                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
570                Err(e) => format!("{{\"error\": \"{}\"}}", e),
571            }
572        }
573        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
574    }
575}
576
577/// Get list of all attributes supported by this cluster
578///
579/// # Returns
580/// Vector of tuples containing (attribute_id, attribute_name)
581pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
582    vec![
583        (0x0000, "DataModelRevision"),
584        (0x0001, "VendorName"),
585        (0x0002, "VendorID"),
586        (0x0003, "ProductName"),
587        (0x0004, "ProductID"),
588        (0x0005, "NodeLabel"),
589        (0x0006, "Location"),
590        (0x0007, "HardwareVersion"),
591        (0x0008, "HardwareVersionString"),
592        (0x0009, "SoftwareVersion"),
593        (0x000A, "SoftwareVersionString"),
594        (0x000B, "ManufacturingDate"),
595        (0x000C, "PartNumber"),
596        (0x000D, "ProductURL"),
597        (0x000E, "ProductLabel"),
598        (0x000F, "SerialNumber"),
599        (0x0010, "LocalConfigDisabled"),
600        (0x0011, "Reachable"),
601        (0x0012, "UniqueID"),
602        (0x0013, "CapabilityMinima"),
603        (0x0014, "ProductAppearance"),
604        (0x0015, "SpecificationVersion"),
605        (0x0016, "MaxPathsPerInvoke"),
606        (0x0018, "ConfigurationVersion"),
607    ]
608}
609
610// Command listing
611
612pub fn get_command_list() -> Vec<(u32, &'static str)> {
613    vec![
614        (0x80, "KeepActive"),
615    ]
616}
617
618pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
619    match cmd_id {
620        0x80 => Some("KeepActive"),
621        _ => None,
622    }
623}
624
625pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
626    match cmd_id {
627        0x80 => Some(vec![
628            crate::clusters::codec::CommandField { tag: 0, name: "stay_active_duration", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
629            crate::clusters::codec::CommandField { tag: 1, name: "timeout_ms", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
630        ]),
631        _ => None,
632    }
633}
634
635pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
636    match cmd_id {
637        0x80 => {
638        let stay_active_duration = crate::clusters::codec::json_util::get_u32(args, "stay_active_duration")?;
639        let timeout_ms = crate::clusters::codec::json_util::get_u32(args, "timeout_ms")?;
640        encode_keep_active(stay_active_duration, timeout_ms)
641        }
642        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
643    }
644}
645
646// Typed facade (invokes + reads)
647
648/// Invoke `KeepActive` command on cluster `Bridged Device Basic Information`.
649pub async fn keep_active(conn: &crate::controller::Connection, endpoint: u16, stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<()> {
650    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_CMD_ID_KEEPACTIVE, &encode_keep_active(stay_active_duration, timeout_ms)?).await?;
651    Ok(())
652}
653
654/// Read `DataModelRevision` attribute from cluster `Bridged Device Basic Information`.
655pub async fn read_data_model_revision(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
656    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_DATAMODELREVISION).await?;
657    decode_data_model_revision(&tlv)
658}
659
660/// Read `VendorName` attribute from cluster `Bridged Device Basic Information`.
661pub async fn read_vendor_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
662    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_VENDORNAME).await?;
663    decode_vendor_name(&tlv)
664}
665
666/// Read `VendorID` attribute from cluster `Bridged Device Basic Information`.
667pub async fn read_vendor_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
668    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_VENDORID).await?;
669    decode_vendor_id(&tlv)
670}
671
672/// Read `ProductName` attribute from cluster `Bridged Device Basic Information`.
673pub async fn read_product_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
674    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTNAME).await?;
675    decode_product_name(&tlv)
676}
677
678/// Read `ProductID` attribute from cluster `Bridged Device Basic Information`.
679pub async fn read_product_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
680    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTID).await?;
681    decode_product_id(&tlv)
682}
683
684/// Read `NodeLabel` attribute from cluster `Bridged Device Basic Information`.
685pub async fn read_node_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
686    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_NODELABEL).await?;
687    decode_node_label(&tlv)
688}
689
690/// Read `Location` attribute from cluster `Bridged Device Basic Information`.
691pub async fn read_location(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
692    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_LOCATION).await?;
693    decode_location(&tlv)
694}
695
696/// Read `HardwareVersion` attribute from cluster `Bridged Device Basic Information`.
697pub async fn read_hardware_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
698    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSION).await?;
699    decode_hardware_version(&tlv)
700}
701
702/// Read `HardwareVersionString` attribute from cluster `Bridged Device Basic Information`.
703pub async fn read_hardware_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
704    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSIONSTRING).await?;
705    decode_hardware_version_string(&tlv)
706}
707
708/// Read `SoftwareVersion` attribute from cluster `Bridged Device Basic Information`.
709pub async fn read_software_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
710    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSION).await?;
711    decode_software_version(&tlv)
712}
713
714/// Read `SoftwareVersionString` attribute from cluster `Bridged Device Basic Information`.
715pub async fn read_software_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
716    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSIONSTRING).await?;
717    decode_software_version_string(&tlv)
718}
719
720/// Read `ManufacturingDate` attribute from cluster `Bridged Device Basic Information`.
721pub async fn read_manufacturing_date(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
722    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_MANUFACTURINGDATE).await?;
723    decode_manufacturing_date(&tlv)
724}
725
726/// Read `PartNumber` attribute from cluster `Bridged Device Basic Information`.
727pub async fn read_part_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
728    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PARTNUMBER).await?;
729    decode_part_number(&tlv)
730}
731
732/// Read `ProductURL` attribute from cluster `Bridged Device Basic Information`.
733pub async fn read_product_url(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
734    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTURL).await?;
735    decode_product_url(&tlv)
736}
737
738/// Read `ProductLabel` attribute from cluster `Bridged Device Basic Information`.
739pub async fn read_product_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
740    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTLABEL).await?;
741    decode_product_label(&tlv)
742}
743
744/// Read `SerialNumber` attribute from cluster `Bridged Device Basic Information`.
745pub async fn read_serial_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
746    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SERIALNUMBER).await?;
747    decode_serial_number(&tlv)
748}
749
750/// Read `LocalConfigDisabled` attribute from cluster `Bridged Device Basic Information`.
751pub async fn read_local_config_disabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
752    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_LOCALCONFIGDISABLED).await?;
753    decode_local_config_disabled(&tlv)
754}
755
756/// Read `Reachable` attribute from cluster `Bridged Device Basic Information`.
757pub async fn read_reachable(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
758    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_REACHABLE).await?;
759    decode_reachable(&tlv)
760}
761
762/// Read `UniqueID` attribute from cluster `Bridged Device Basic Information`.
763pub async fn read_unique_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
764    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_UNIQUEID).await?;
765    decode_unique_id(&tlv)
766}
767
768/// Read `CapabilityMinima` attribute from cluster `Bridged Device Basic Information`.
769pub async fn read_capability_minima(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CapabilityMinima> {
770    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_CAPABILITYMINIMA).await?;
771    decode_capability_minima(&tlv)
772}
773
774/// Read `ProductAppearance` attribute from cluster `Bridged Device Basic Information`.
775pub async fn read_product_appearance(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ProductAppearance> {
776    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTAPPEARANCE).await?;
777    decode_product_appearance(&tlv)
778}
779
780/// Read `SpecificationVersion` attribute from cluster `Bridged Device Basic Information`.
781pub async fn read_specification_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
782    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SPECIFICATIONVERSION).await?;
783    decode_specification_version(&tlv)
784}
785
786/// Read `MaxPathsPerInvoke` attribute from cluster `Bridged Device Basic Information`.
787pub async fn read_max_paths_per_invoke(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
788    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_MAXPATHSPERINVOKE).await?;
789    decode_max_paths_per_invoke(&tlv)
790}
791
792/// Read `ConfigurationVersion` attribute from cluster `Bridged Device Basic Information`.
793pub async fn read_configuration_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
794    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_CONFIGURATIONVERSION).await?;
795    decode_configuration_version(&tlv)
796}
797
798#[derive(Debug, serde::Serialize)]
799pub struct StartUpEvent {
800    pub software_version: Option<u32>,
801}
802
803#[derive(Debug, serde::Serialize)]
804pub struct LeaveEvent {
805    pub fabric_index: Option<u8>,
806}
807
808#[derive(Debug, serde::Serialize)]
809pub struct ReachableChangedEvent {
810    pub reachable_new_value: Option<bool>,
811}
812
813#[derive(Debug, serde::Serialize)]
814pub struct ActiveChangedEvent {
815    pub promised_active_duration: Option<u32>,
816}
817
818// Event decoders
819
820/// Decode StartUp event (0x00, priority: critical)
821pub fn decode_start_up_event(inp: &tlv::TlvItemValue) -> anyhow::Result<StartUpEvent> {
822    if let tlv::TlvItemValue::List(_fields) = inp {
823        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
824        Ok(StartUpEvent {
825                                software_version: item.get_int(&[0]).map(|v| v as u32),
826        })
827    } else {
828        Err(anyhow::anyhow!("Expected struct fields"))
829    }
830}
831
832/// Decode Leave event (0x02, priority: info)
833pub fn decode_leave_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LeaveEvent> {
834    if let tlv::TlvItemValue::List(_fields) = inp {
835        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
836        Ok(LeaveEvent {
837                                fabric_index: item.get_int(&[0]).map(|v| v as u8),
838        })
839    } else {
840        Err(anyhow::anyhow!("Expected struct fields"))
841    }
842}
843
844/// Decode ReachableChanged event (0x03, priority: info)
845pub fn decode_reachable_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ReachableChangedEvent> {
846    if let tlv::TlvItemValue::List(_fields) = inp {
847        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
848        Ok(ReachableChangedEvent {
849                                reachable_new_value: item.get_bool(&[0]),
850        })
851    } else {
852        Err(anyhow::anyhow!("Expected struct fields"))
853    }
854}
855
856/// Decode ActiveChanged event (0x80, priority: info)
857pub fn decode_active_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ActiveChangedEvent> {
858    if let tlv::TlvItemValue::List(_fields) = inp {
859        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
860        Ok(ActiveChangedEvent {
861                                promised_active_duration: item.get_int(&[0]).map(|v| v as u32),
862        })
863    } else {
864        Err(anyhow::anyhow!("Expected struct fields"))
865    }
866}
867
868
869// Event JSON dispatcher
870
871/// Decode event value and return as JSON string
872pub fn decode_event_json(cluster_id: u32, event_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
873    if cluster_id != 0x0039 {
874        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0039, got {}\"}}", cluster_id);
875    }
876
877    match event_id {
878        0x00 => {
879            match decode_start_up_event(tlv_value) {
880                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
881                Err(e) => format!("{{\"error\": \"{}\"}}", e),
882            }
883        }
884        0x01 => "{}".to_string(),
885        0x02 => {
886            match decode_leave_event(tlv_value) {
887                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
888                Err(e) => format!("{{\"error\": \"{}\"}}", e),
889            }
890        }
891        0x03 => {
892            match decode_reachable_changed_event(tlv_value) {
893                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
894                Err(e) => format!("{{\"error\": \"{}\"}}", e),
895            }
896        }
897        0x80 => {
898            match decode_active_changed_event(tlv_value) {
899                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
900                Err(e) => format!("{{\"error\": \"{}\"}}", e),
901            }
902        }
903        _ => format!("{{\"error\": \"Unknown event ID: {}\"}}", event_id),
904    }
905}
906
907/// Get list of all events supported by this cluster
908///
909/// # Returns
910/// Vector of tuples containing (event_id, event_name)
911pub fn get_event_list() -> Vec<(u32, &'static str)> {
912    vec![
913        (0x00, "StartUp"),
914        (0x01, "ShutDown"),
915        (0x02, "Leave"),
916        (0x03, "ReachableChanged"),
917        (0x80, "ActiveChanged"),
918    ]
919}
920