matc/clusters/codec/
network_commissioning_cluster.rs

1//! Generated Matter TLV encoders and decoders for Network Commissioning Cluster
2//! Cluster ID: 0x0031
3//! 
4//! This file is automatically generated from NetworkCommissioningCluster.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Struct definitions
12
13#[derive(Debug, serde::Serialize)]
14pub struct NetworkInfo {
15    pub network_id: Option<Vec<u8>>,
16    pub connected: Option<bool>,
17}
18
19#[derive(Debug, serde::Serialize)]
20pub struct ThreadInterfaceScanResult {
21    pub pan_id: Option<u16>,
22    pub extended_pan_id: Option<u64>,
23    pub network_name: Option<String>,
24    pub channel: Option<u16>,
25    pub version: Option<u8>,
26    pub extended_address: Option<u8>,
27    pub rssi: Option<i8>,
28    pub lqi: Option<u8>,
29}
30
31#[derive(Debug, serde::Serialize)]
32pub struct WiFiInterfaceScanResult {
33    pub security: Option<u8>,
34    pub ssid: Option<Vec<u8>>,
35    pub bssid: Option<Vec<u8>>,
36    pub channel: Option<u16>,
37    pub wifi_band: Option<u8>,
38    pub rssi: Option<i8>,
39}
40
41// Command encoders
42
43/// Encode ScanNetworks command (0x00)
44pub fn encode_scan_networks(ssid: Option<Vec<u8>>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
45    let tlv = tlv::TlvItemEnc {
46        tag: 0,
47        value: tlv::TlvItemValueEnc::StructInvisible(vec![
48        (0, tlv::TlvItemValueEnc::OctetString(ssid.unwrap_or_default())).into(),
49        (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
50        ]),
51    };
52    Ok(tlv.encode()?)
53}
54
55/// Encode AddOrUpdateWiFiNetwork command (0x02)
56pub fn encode_add_or_update_wifi_network(ssid: Vec<u8>, credentials: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
57    let tlv = tlv::TlvItemEnc {
58        tag: 0,
59        value: tlv::TlvItemValueEnc::StructInvisible(vec![
60        (0, tlv::TlvItemValueEnc::OctetString(ssid)).into(),
61        (1, tlv::TlvItemValueEnc::OctetString(credentials)).into(),
62        (2, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
63        ]),
64    };
65    Ok(tlv.encode()?)
66}
67
68/// Encode AddOrUpdateThreadNetwork command (0x03)
69pub fn encode_add_or_update_thread_network(operational_dataset: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
70    let tlv = tlv::TlvItemEnc {
71        tag: 0,
72        value: tlv::TlvItemValueEnc::StructInvisible(vec![
73        (0, tlv::TlvItemValueEnc::OctetString(operational_dataset)).into(),
74        (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
75        ]),
76    };
77    Ok(tlv.encode()?)
78}
79
80/// Encode RemoveNetwork command (0x04)
81pub fn encode_remove_network(network_id: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
82    let tlv = tlv::TlvItemEnc {
83        tag: 0,
84        value: tlv::TlvItemValueEnc::StructInvisible(vec![
85        (0, tlv::TlvItemValueEnc::OctetString(network_id)).into(),
86        (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
87        ]),
88    };
89    Ok(tlv.encode()?)
90}
91
92/// Encode ConnectNetwork command (0x06)
93pub fn encode_connect_network(network_id: Vec<u8>, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
94    let tlv = tlv::TlvItemEnc {
95        tag: 0,
96        value: tlv::TlvItemValueEnc::StructInvisible(vec![
97        (0, tlv::TlvItemValueEnc::OctetString(network_id)).into(),
98        (1, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
99        ]),
100    };
101    Ok(tlv.encode()?)
102}
103
104/// Encode ReorderNetwork command (0x08)
105pub fn encode_reorder_network(network_id: Vec<u8>, network_index: u8, breadcrumb: u64) -> anyhow::Result<Vec<u8>> {
106    let tlv = tlv::TlvItemEnc {
107        tag: 0,
108        value: tlv::TlvItemValueEnc::StructInvisible(vec![
109        (0, tlv::TlvItemValueEnc::OctetString(network_id)).into(),
110        (1, tlv::TlvItemValueEnc::UInt8(network_index)).into(),
111        (2, tlv::TlvItemValueEnc::UInt64(breadcrumb)).into(),
112        ]),
113    };
114    Ok(tlv.encode()?)
115}
116
117// Attribute decoders
118
119/// Decode MaxNetworks attribute (0x0000)
120pub fn decode_max_networks(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
121    if let tlv::TlvItemValue::Int(v) = inp {
122        Ok(*v as u8)
123    } else {
124        Err(anyhow::anyhow!("Expected Integer"))
125    }
126}
127
128/// Decode Networks attribute (0x0001)
129pub fn decode_networks(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkInfo>> {
130    let mut res = Vec::new();
131    if let tlv::TlvItemValue::List(v) = inp {
132        for item in v {
133            res.push(NetworkInfo {
134                network_id: item.get_octet_string_owned(&[0]),
135                connected: item.get_bool(&[1]),
136            });
137        }
138    }
139    Ok(res)
140}
141
142/// Decode ScanMaxTimeSeconds attribute (0x0002)
143pub fn decode_scan_max_time_seconds(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
144    if let tlv::TlvItemValue::Int(v) = inp {
145        Ok(*v as u8)
146    } else {
147        Err(anyhow::anyhow!("Expected Integer"))
148    }
149}
150
151/// Decode ConnectMaxTimeSeconds attribute (0x0003)
152pub fn decode_connect_max_time_seconds(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
153    if let tlv::TlvItemValue::Int(v) = inp {
154        Ok(*v as u8)
155    } else {
156        Err(anyhow::anyhow!("Expected Integer"))
157    }
158}
159
160/// Decode InterfaceEnabled attribute (0x0004)
161pub fn decode_interface_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
162    if let tlv::TlvItemValue::Bool(v) = inp {
163        Ok(*v)
164    } else {
165        Err(anyhow::anyhow!("Expected Bool"))
166    }
167}
168
169/// Decode LastNetworkingStatus attribute (0x0005)
170pub fn decode_last_networking_status(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
171    if let tlv::TlvItemValue::Int(v) = inp {
172        Ok(Some(*v as u8))
173    } else {
174        Ok(None)
175    }
176}
177
178/// Decode LastNetworkID attribute (0x0006)
179pub fn decode_last_network_id(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
180    if let tlv::TlvItemValue::OctetString(v) = inp {
181        Ok(Some(v.clone()))
182    } else {
183        Ok(None)
184    }
185}
186
187/// Decode LastConnectErrorValue attribute (0x0007)
188pub fn decode_last_connect_error_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i32>> {
189    if let tlv::TlvItemValue::Int(v) = inp {
190        Ok(Some(*v as i32))
191    } else {
192        Ok(None)
193    }
194}
195
196/// Decode SupportedWiFiBands attribute (0x0008)
197pub fn decode_supported_wifi_bands(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
198    let mut res = Vec::new();
199    if let tlv::TlvItemValue::List(v) = inp {
200        for item in v {
201            if let tlv::TlvItemValue::Int(i) = &item.value {
202                res.push(*i as u8);
203            }
204        }
205    }
206    Ok(res)
207}
208
209/// Decode SupportedThreadFeatures attribute (0x0009)
210pub fn decode_supported_thread_features(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
211    if let tlv::TlvItemValue::Int(v) = inp {
212        Ok(*v as u8)
213    } else {
214        Err(anyhow::anyhow!("Expected Integer"))
215    }
216}
217
218/// Decode ThreadVersion attribute (0x000A)
219pub fn decode_thread_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
220    if let tlv::TlvItemValue::Int(v) = inp {
221        Ok(*v as u16)
222    } else {
223        Err(anyhow::anyhow!("Expected Integer"))
224    }
225}
226
227
228// JSON dispatcher function
229
230/// Decode attribute value and return as JSON string
231/// 
232/// # Parameters
233/// * `cluster_id` - The cluster identifier
234/// * `attribute_id` - The attribute identifier
235/// * `tlv_value` - The TLV value to decode
236/// 
237/// # Returns
238/// JSON string representation of the decoded value or error
239pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
240    // Verify this is the correct cluster
241    if cluster_id != 0x0031 {
242        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0031, got {}\"}}", cluster_id);
243    }
244    
245    match attribute_id {
246        0x0000 => {
247            match decode_max_networks(tlv_value) {
248                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
249                Err(e) => format!("{{\"error\": \"{}\"}}", e),
250            }
251        }
252        0x0001 => {
253            match decode_networks(tlv_value) {
254                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
255                Err(e) => format!("{{\"error\": \"{}\"}}", e),
256            }
257        }
258        0x0002 => {
259            match decode_scan_max_time_seconds(tlv_value) {
260                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
261                Err(e) => format!("{{\"error\": \"{}\"}}", e),
262            }
263        }
264        0x0003 => {
265            match decode_connect_max_time_seconds(tlv_value) {
266                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
267                Err(e) => format!("{{\"error\": \"{}\"}}", e),
268            }
269        }
270        0x0004 => {
271            match decode_interface_enabled(tlv_value) {
272                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
273                Err(e) => format!("{{\"error\": \"{}\"}}", e),
274            }
275        }
276        0x0005 => {
277            match decode_last_networking_status(tlv_value) {
278                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
279                Err(e) => format!("{{\"error\": \"{}\"}}", e),
280            }
281        }
282        0x0006 => {
283            match decode_last_network_id(tlv_value) {
284                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
285                Err(e) => format!("{{\"error\": \"{}\"}}", e),
286            }
287        }
288        0x0007 => {
289            match decode_last_connect_error_value(tlv_value) {
290                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
291                Err(e) => format!("{{\"error\": \"{}\"}}", e),
292            }
293        }
294        0x0008 => {
295            match decode_supported_wifi_bands(tlv_value) {
296                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
297                Err(e) => format!("{{\"error\": \"{}\"}}", e),
298            }
299        }
300        0x0009 => {
301            match decode_supported_thread_features(tlv_value) {
302                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
303                Err(e) => format!("{{\"error\": \"{}\"}}", e),
304            }
305        }
306        0x000A => {
307            match decode_thread_version(tlv_value) {
308                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
309                Err(e) => format!("{{\"error\": \"{}\"}}", e),
310            }
311        }
312        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
313    }
314}
315
316/// Get list of all attributes supported by this cluster
317/// 
318/// # Returns
319/// Vector of tuples containing (attribute_id, attribute_name)
320pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
321    vec![
322        (0x0000, "MaxNetworks"),
323        (0x0001, "Networks"),
324        (0x0002, "ScanMaxTimeSeconds"),
325        (0x0003, "ConnectMaxTimeSeconds"),
326        (0x0004, "InterfaceEnabled"),
327        (0x0005, "LastNetworkingStatus"),
328        (0x0006, "LastNetworkID"),
329        (0x0007, "LastConnectErrorValue"),
330        (0x0008, "SupportedWiFiBands"),
331        (0x0009, "SupportedThreadFeatures"),
332        (0x000A, "ThreadVersion"),
333    ]
334}
335