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
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Enum definitions
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum Color {
16    /// Approximately RGB #000000.
17    Black = 0,
18    /// Approximately RGB #000080.
19    Navy = 1,
20    /// Approximately RGB #008000.
21    Green = 2,
22    /// Approximately RGB #008080.
23    Teal = 3,
24    /// Approximately RGB #800000.
25    Maroon = 4,
26    /// Approximately RGB #800080.
27    Purple = 5,
28    /// Approximately RGB #808000.
29    Olive = 6,
30    /// Approximately RGB #808080.
31    Gray = 7,
32    /// Approximately RGB #0000FF.
33    Blue = 8,
34    /// Approximately RGB #00FF00.
35    Lime = 9,
36    /// Approximately RGB #00FFFF.
37    Aqua = 10,
38    /// Approximately RGB #FF0000.
39    Red = 11,
40    /// Approximately RGB #FF00FF.
41    Fuchsia = 12,
42    /// Approximately RGB #FFFF00.
43    Yellow = 13,
44    /// Approximately RGB #FFFFFF.
45    White = 14,
46    /// Typical hardware "Nickel" color.
47    Nickel = 15,
48    /// Typical hardware "Chrome" color.
49    Chrome = 16,
50    /// Typical hardware "Brass" color.
51    Brass = 17,
52    /// Typical hardware "Copper" color.
53    Copper = 18,
54    /// Typical hardware "Silver" color.
55    Silver = 19,
56    /// Typical hardware "Gold" color.
57    Gold = 20,
58}
59
60impl Color {
61    /// Convert from u8 value
62    pub fn from_u8(value: u8) -> Option<Self> {
63        match value {
64            0 => Some(Color::Black),
65            1 => Some(Color::Navy),
66            2 => Some(Color::Green),
67            3 => Some(Color::Teal),
68            4 => Some(Color::Maroon),
69            5 => Some(Color::Purple),
70            6 => Some(Color::Olive),
71            7 => Some(Color::Gray),
72            8 => Some(Color::Blue),
73            9 => Some(Color::Lime),
74            10 => Some(Color::Aqua),
75            11 => Some(Color::Red),
76            12 => Some(Color::Fuchsia),
77            13 => Some(Color::Yellow),
78            14 => Some(Color::White),
79            15 => Some(Color::Nickel),
80            16 => Some(Color::Chrome),
81            17 => Some(Color::Brass),
82            18 => Some(Color::Copper),
83            19 => Some(Color::Silver),
84            20 => Some(Color::Gold),
85            _ => None,
86        }
87    }
88
89    /// Convert to u8 value
90    pub fn to_u8(self) -> u8 {
91        self as u8
92    }
93}
94
95impl From<Color> for u8 {
96    fn from(val: Color) -> Self {
97        val as u8
98    }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
102#[repr(u8)]
103pub enum ProductFinish {
104    /// Product has some other finish not listed below.
105    Other = 0,
106    /// Product has a matte finish.
107    Matte = 1,
108    /// Product has a satin finish.
109    Satin = 2,
110    /// Product has a polished or shiny finish.
111    Polished = 3,
112    /// Product has a rugged finish.
113    Rugged = 4,
114    /// Product has a fabric finish.
115    Fabric = 5,
116}
117
118impl ProductFinish {
119    /// Convert from u8 value
120    pub fn from_u8(value: u8) -> Option<Self> {
121        match value {
122            0 => Some(ProductFinish::Other),
123            1 => Some(ProductFinish::Matte),
124            2 => Some(ProductFinish::Satin),
125            3 => Some(ProductFinish::Polished),
126            4 => Some(ProductFinish::Rugged),
127            5 => Some(ProductFinish::Fabric),
128            _ => None,
129        }
130    }
131
132    /// Convert to u8 value
133    pub fn to_u8(self) -> u8 {
134        self as u8
135    }
136}
137
138impl From<ProductFinish> for u8 {
139    fn from(val: ProductFinish) -> Self {
140        val as u8
141    }
142}
143
144// Struct definitions
145
146#[derive(Debug, serde::Serialize)]
147pub struct CapabilityMinima {
148    pub case_sessions_per_fabric: Option<u16>,
149    pub subscriptions_per_fabric: Option<u16>,
150}
151
152#[derive(Debug, serde::Serialize)]
153pub struct ProductAppearance {
154    pub finish: Option<ProductFinish>,
155    pub primary_color: Option<Color>,
156}
157
158// Command encoders
159
160/// Encode KeepActive command (0x80)
161pub fn encode_keep_active(stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<Vec<u8>> {
162    let tlv = tlv::TlvItemEnc {
163        tag: 0,
164        value: tlv::TlvItemValueEnc::StructInvisible(vec![
165        (0, tlv::TlvItemValueEnc::UInt32(stay_active_duration)).into(),
166        (1, tlv::TlvItemValueEnc::UInt32(timeout_ms)).into(),
167        ]),
168    };
169    Ok(tlv.encode()?)
170}
171
172// Attribute decoders
173
174/// Decode DataModelRevision attribute (0x0000)
175pub fn decode_data_model_revision(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
176    if let tlv::TlvItemValue::Int(v) = inp {
177        Ok(*v as u16)
178    } else {
179        Err(anyhow::anyhow!("Expected UInt16"))
180    }
181}
182
183/// Decode VendorName attribute (0x0001)
184pub fn decode_vendor_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
185    if let tlv::TlvItemValue::String(v) = inp {
186        Ok(v.clone())
187    } else {
188        Err(anyhow::anyhow!("Expected String"))
189    }
190}
191
192/// Decode VendorID attribute (0x0002)
193pub fn decode_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
194    if let tlv::TlvItemValue::Int(v) = inp {
195        Ok(*v as u16)
196    } else {
197        Err(anyhow::anyhow!("Expected UInt16"))
198    }
199}
200
201/// Decode ProductName attribute (0x0003)
202pub fn decode_product_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
203    if let tlv::TlvItemValue::String(v) = inp {
204        Ok(v.clone())
205    } else {
206        Err(anyhow::anyhow!("Expected String"))
207    }
208}
209
210/// Decode ProductID attribute (0x0004)
211pub fn decode_product_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
212    if let tlv::TlvItemValue::Int(v) = inp {
213        Ok(*v as u16)
214    } else {
215        Err(anyhow::anyhow!("Expected UInt16"))
216    }
217}
218
219/// Decode NodeLabel attribute (0x0005)
220pub fn decode_node_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
221    if let tlv::TlvItemValue::String(v) = inp {
222        Ok(v.clone())
223    } else {
224        Err(anyhow::anyhow!("Expected String"))
225    }
226}
227
228/// Decode Location attribute (0x0006)
229pub fn decode_location(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
230    if let tlv::TlvItemValue::String(v) = inp {
231        Ok(v.clone())
232    } else {
233        Err(anyhow::anyhow!("Expected String"))
234    }
235}
236
237/// Decode HardwareVersion attribute (0x0007)
238pub fn decode_hardware_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
239    if let tlv::TlvItemValue::Int(v) = inp {
240        Ok(*v as u16)
241    } else {
242        Err(anyhow::anyhow!("Expected UInt16"))
243    }
244}
245
246/// Decode HardwareVersionString attribute (0x0008)
247pub fn decode_hardware_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
248    if let tlv::TlvItemValue::String(v) = inp {
249        Ok(v.clone())
250    } else {
251        Err(anyhow::anyhow!("Expected String"))
252    }
253}
254
255/// Decode SoftwareVersion attribute (0x0009)
256pub fn decode_software_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
257    if let tlv::TlvItemValue::Int(v) = inp {
258        Ok(*v as u32)
259    } else {
260        Err(anyhow::anyhow!("Expected UInt32"))
261    }
262}
263
264/// Decode SoftwareVersionString attribute (0x000A)
265pub fn decode_software_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
266    if let tlv::TlvItemValue::String(v) = inp {
267        Ok(v.clone())
268    } else {
269        Err(anyhow::anyhow!("Expected String"))
270    }
271}
272
273/// Decode ManufacturingDate attribute (0x000B)
274pub fn decode_manufacturing_date(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
275    if let tlv::TlvItemValue::String(v) = inp {
276        Ok(v.clone())
277    } else {
278        Err(anyhow::anyhow!("Expected String"))
279    }
280}
281
282/// Decode PartNumber attribute (0x000C)
283pub fn decode_part_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
284    if let tlv::TlvItemValue::String(v) = inp {
285        Ok(v.clone())
286    } else {
287        Err(anyhow::anyhow!("Expected String"))
288    }
289}
290
291/// Decode ProductURL attribute (0x000D)
292pub fn decode_product_url(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
293    if let tlv::TlvItemValue::String(v) = inp {
294        Ok(v.clone())
295    } else {
296        Err(anyhow::anyhow!("Expected String"))
297    }
298}
299
300/// Decode ProductLabel attribute (0x000E)
301pub fn decode_product_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
302    if let tlv::TlvItemValue::String(v) = inp {
303        Ok(v.clone())
304    } else {
305        Err(anyhow::anyhow!("Expected String"))
306    }
307}
308
309/// Decode SerialNumber attribute (0x000F)
310pub fn decode_serial_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
311    if let tlv::TlvItemValue::String(v) = inp {
312        Ok(v.clone())
313    } else {
314        Err(anyhow::anyhow!("Expected String"))
315    }
316}
317
318/// Decode LocalConfigDisabled attribute (0x0010)
319pub fn decode_local_config_disabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
320    if let tlv::TlvItemValue::Bool(v) = inp {
321        Ok(*v)
322    } else {
323        Err(anyhow::anyhow!("Expected Bool"))
324    }
325}
326
327/// Decode Reachable attribute (0x0011)
328pub fn decode_reachable(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
329    if let tlv::TlvItemValue::Bool(v) = inp {
330        Ok(*v)
331    } else {
332        Err(anyhow::anyhow!("Expected Bool"))
333    }
334}
335
336/// Decode UniqueID attribute (0x0012)
337pub fn decode_unique_id(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
338    if let tlv::TlvItemValue::String(v) = inp {
339        Ok(v.clone())
340    } else {
341        Err(anyhow::anyhow!("Expected String"))
342    }
343}
344
345/// Decode CapabilityMinima attribute (0x0013)
346pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
347    if let tlv::TlvItemValue::List(_fields) = inp {
348        // Struct with fields
349        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
350        Ok(CapabilityMinima {
351                case_sessions_per_fabric: item.get_int(&[0]).map(|v| v as u16),
352                subscriptions_per_fabric: item.get_int(&[1]).map(|v| v as u16),
353        })
354    } else {
355        Err(anyhow::anyhow!("Expected struct fields"))
356    }
357}
358
359/// Decode ProductAppearance attribute (0x0014)
360pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
361    if let tlv::TlvItemValue::List(_fields) = inp {
362        // Struct with fields
363        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
364        Ok(ProductAppearance {
365                finish: item.get_int(&[0]).and_then(|v| ProductFinish::from_u8(v as u8)),
366                primary_color: item.get_int(&[1]).and_then(|v| Color::from_u8(v as u8)),
367        })
368    } else {
369        Err(anyhow::anyhow!("Expected struct fields"))
370    }
371}
372
373/// Decode SpecificationVersion attribute (0x0015)
374pub fn decode_specification_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
375    if let tlv::TlvItemValue::Int(v) = inp {
376        Ok(*v as u32)
377    } else {
378        Err(anyhow::anyhow!("Expected UInt32"))
379    }
380}
381
382/// Decode MaxPathsPerInvoke attribute (0x0016)
383pub fn decode_max_paths_per_invoke(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
384    if let tlv::TlvItemValue::Int(v) = inp {
385        Ok(*v as u16)
386    } else {
387        Err(anyhow::anyhow!("Expected UInt16"))
388    }
389}
390
391/// Decode ConfigurationVersion attribute (0x0018)
392pub fn decode_configuration_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
393    if let tlv::TlvItemValue::Int(v) = inp {
394        Ok(*v as u32)
395    } else {
396        Err(anyhow::anyhow!("Expected UInt32"))
397    }
398}
399
400
401// JSON dispatcher function
402
403/// Decode attribute value and return as JSON string
404///
405/// # Parameters
406/// * `cluster_id` - The cluster identifier
407/// * `attribute_id` - The attribute identifier
408/// * `tlv_value` - The TLV value to decode
409///
410/// # Returns
411/// JSON string representation of the decoded value or error
412pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
413    // Verify this is the correct cluster
414    if cluster_id != 0x0039 {
415        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0039, got {}\"}}", cluster_id);
416    }
417
418    match attribute_id {
419        0x0000 => {
420            match decode_data_model_revision(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        0x0001 => {
426            match decode_vendor_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        0x0002 => {
432            match decode_vendor_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        0x0003 => {
438            match decode_product_name(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        0x0004 => {
444            match decode_product_id(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        0x0005 => {
450            match decode_node_label(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        0x0006 => {
456            match decode_location(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        0x0007 => {
462            match decode_hardware_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        0x0008 => {
468            match decode_hardware_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        0x0009 => {
474            match decode_software_version(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        0x000A => {
480            match decode_software_version_string(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        0x000B => {
486            match decode_manufacturing_date(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        0x000C => {
492            match decode_part_number(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        0x000D => {
498            match decode_product_url(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        0x000E => {
504            match decode_product_label(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        0x000F => {
510            match decode_serial_number(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        0x0010 => {
516            match decode_local_config_disabled(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        0x0011 => {
522            match decode_reachable(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        0x0012 => {
528            match decode_unique_id(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        0x0013 => {
534            match decode_capability_minima(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        0x0014 => {
540            match decode_product_appearance(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        0x0015 => {
546            match decode_specification_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        0x0016 => {
552            match decode_max_paths_per_invoke(tlv_value) {
553                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
554                Err(e) => format!("{{\"error\": \"{}\"}}", e),
555            }
556        }
557        0x0018 => {
558            match decode_configuration_version(tlv_value) {
559                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
560                Err(e) => format!("{{\"error\": \"{}\"}}", e),
561            }
562        }
563        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
564    }
565}
566
567/// Get list of all attributes supported by this cluster
568///
569/// # Returns
570/// Vector of tuples containing (attribute_id, attribute_name)
571pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
572    vec![
573        (0x0000, "DataModelRevision"),
574        (0x0001, "VendorName"),
575        (0x0002, "VendorID"),
576        (0x0003, "ProductName"),
577        (0x0004, "ProductID"),
578        (0x0005, "NodeLabel"),
579        (0x0006, "Location"),
580        (0x0007, "HardwareVersion"),
581        (0x0008, "HardwareVersionString"),
582        (0x0009, "SoftwareVersion"),
583        (0x000A, "SoftwareVersionString"),
584        (0x000B, "ManufacturingDate"),
585        (0x000C, "PartNumber"),
586        (0x000D, "ProductURL"),
587        (0x000E, "ProductLabel"),
588        (0x000F, "SerialNumber"),
589        (0x0010, "LocalConfigDisabled"),
590        (0x0011, "Reachable"),
591        (0x0012, "UniqueID"),
592        (0x0013, "CapabilityMinima"),
593        (0x0014, "ProductAppearance"),
594        (0x0015, "SpecificationVersion"),
595        (0x0016, "MaxPathsPerInvoke"),
596        (0x0018, "ConfigurationVersion"),
597    ]
598}
599
600#[derive(Debug, serde::Serialize)]
601pub struct StartUpEvent {
602    pub software_version: Option<u32>,
603}
604
605#[derive(Debug, serde::Serialize)]
606pub struct LeaveEvent {
607    pub fabric_index: Option<u8>,
608}
609
610#[derive(Debug, serde::Serialize)]
611pub struct ReachableChangedEvent {
612    pub reachable_new_value: Option<bool>,
613}
614
615#[derive(Debug, serde::Serialize)]
616pub struct ActiveChangedEvent {
617    pub promised_active_duration: Option<u32>,
618}
619
620// Event decoders
621
622/// Decode StartUp event (0x00, priority: critical)
623pub fn decode_start_up_event(inp: &tlv::TlvItemValue) -> anyhow::Result<StartUpEvent> {
624    if let tlv::TlvItemValue::List(_fields) = inp {
625        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
626        Ok(StartUpEvent {
627                                software_version: item.get_int(&[0]).map(|v| v as u32),
628        })
629    } else {
630        Err(anyhow::anyhow!("Expected struct fields"))
631    }
632}
633
634/// Decode Leave event (0x02, priority: info)
635pub fn decode_leave_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LeaveEvent> {
636    if let tlv::TlvItemValue::List(_fields) = inp {
637        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
638        Ok(LeaveEvent {
639                                fabric_index: item.get_int(&[0]).map(|v| v as u8),
640        })
641    } else {
642        Err(anyhow::anyhow!("Expected struct fields"))
643    }
644}
645
646/// Decode ReachableChanged event (0x03, priority: info)
647pub fn decode_reachable_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ReachableChangedEvent> {
648    if let tlv::TlvItemValue::List(_fields) = inp {
649        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
650        Ok(ReachableChangedEvent {
651                                reachable_new_value: item.get_bool(&[0]),
652        })
653    } else {
654        Err(anyhow::anyhow!("Expected struct fields"))
655    }
656}
657
658/// Decode ActiveChanged event (0x80, priority: info)
659pub fn decode_active_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ActiveChangedEvent> {
660    if let tlv::TlvItemValue::List(_fields) = inp {
661        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
662        Ok(ActiveChangedEvent {
663                                promised_active_duration: item.get_int(&[0]).map(|v| v as u32),
664        })
665    } else {
666        Err(anyhow::anyhow!("Expected struct fields"))
667    }
668}
669