Skip to main content

matc/clusters/codec/
joint_fabric_datastore_cluster.rs

1//! Matter TLV encoders and decoders for Joint Fabric Datastore Cluster
2//! Cluster IDs: 0x0752
3//!
4//! This file is automatically generated from JointFabricDatastoreCluster.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Import serialization helpers for octet strings
14use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16// Enum definitions
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum DatastoreAccessControlEntryAuthMode {
21    /// Passcode authenticated session
22    Pase = 1,
23    /// Certificate authenticated session
24    Case = 2,
25    /// Group authenticated session
26    Group = 3,
27}
28
29impl DatastoreAccessControlEntryAuthMode {
30    /// Convert from u8 value
31    pub fn from_u8(value: u8) -> Option<Self> {
32        match value {
33            1 => Some(DatastoreAccessControlEntryAuthMode::Pase),
34            2 => Some(DatastoreAccessControlEntryAuthMode::Case),
35            3 => Some(DatastoreAccessControlEntryAuthMode::Group),
36            _ => None,
37        }
38    }
39
40    /// Convert to u8 value
41    pub fn to_u8(self) -> u8 {
42        self as u8
43    }
44}
45
46impl From<DatastoreAccessControlEntryAuthMode> for u8 {
47    fn from(val: DatastoreAccessControlEntryAuthMode) -> Self {
48        val as u8
49    }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
53#[repr(u8)]
54pub enum DatastoreAccessControlEntryPrivilege {
55    /// Can read and observe all (except Access Control Cluster)
56    View = 1,
57    /// View privileges, and can perform the primary function of this Node (except Access Control Cluster)
58    Operate = 3,
59    /// Operate privileges, and can modify persistent configuration of this Node (except Access Control Cluster)
60    Manage = 4,
61    /// Manage privileges, and can observe and modify the Access Control Cluster
62    Administer = 5,
63}
64
65impl DatastoreAccessControlEntryPrivilege {
66    /// Convert from u8 value
67    pub fn from_u8(value: u8) -> Option<Self> {
68        match value {
69            1 => Some(DatastoreAccessControlEntryPrivilege::View),
70            3 => Some(DatastoreAccessControlEntryPrivilege::Operate),
71            4 => Some(DatastoreAccessControlEntryPrivilege::Manage),
72            5 => Some(DatastoreAccessControlEntryPrivilege::Administer),
73            _ => None,
74        }
75    }
76
77    /// Convert to u8 value
78    pub fn to_u8(self) -> u8 {
79        self as u8
80    }
81}
82
83impl From<DatastoreAccessControlEntryPrivilege> for u8 {
84    fn from(val: DatastoreAccessControlEntryPrivilege) -> Self {
85        val as u8
86    }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
90#[repr(u8)]
91pub enum DatastoreGroupKeyMulticastPolicy {
92    /// Indicates filtering of multicast messages for a specific Group ID
93    Pergroupid = 0,
94    /// Indicates not filtering of multicast messages
95    Allnodes = 1,
96}
97
98impl DatastoreGroupKeyMulticastPolicy {
99    /// Convert from u8 value
100    pub fn from_u8(value: u8) -> Option<Self> {
101        match value {
102            0 => Some(DatastoreGroupKeyMulticastPolicy::Pergroupid),
103            1 => Some(DatastoreGroupKeyMulticastPolicy::Allnodes),
104            _ => None,
105        }
106    }
107
108    /// Convert to u8 value
109    pub fn to_u8(self) -> u8 {
110        self as u8
111    }
112}
113
114impl From<DatastoreGroupKeyMulticastPolicy> for u8 {
115    fn from(val: DatastoreGroupKeyMulticastPolicy) -> Self {
116        val as u8
117    }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
121#[repr(u8)]
122pub enum DatastoreGroupKeySecurityPolicy {
123    /// Message counter synchronization using trust-first
124    Trustfirst = 0,
125}
126
127impl DatastoreGroupKeySecurityPolicy {
128    /// Convert from u8 value
129    pub fn from_u8(value: u8) -> Option<Self> {
130        match value {
131            0 => Some(DatastoreGroupKeySecurityPolicy::Trustfirst),
132            _ => None,
133        }
134    }
135
136    /// Convert to u8 value
137    pub fn to_u8(self) -> u8 {
138        self as u8
139    }
140}
141
142impl From<DatastoreGroupKeySecurityPolicy> for u8 {
143    fn from(val: DatastoreGroupKeySecurityPolicy) -> Self {
144        val as u8
145    }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
149#[repr(u8)]
150pub enum DatastoreState {
151    /// Target device operation is pending
152    Pending = 0,
153    /// Target device operation has been committed
154    Committed = 1,
155    /// Target device delete operation is pending
156    Deletepending = 2,
157    /// Target device operation has failed
158    Commitfailed = 3,
159}
160
161impl DatastoreState {
162    /// Convert from u8 value
163    pub fn from_u8(value: u8) -> Option<Self> {
164        match value {
165            0 => Some(DatastoreState::Pending),
166            1 => Some(DatastoreState::Committed),
167            2 => Some(DatastoreState::Deletepending),
168            3 => Some(DatastoreState::Commitfailed),
169            _ => None,
170        }
171    }
172
173    /// Convert to u8 value
174    pub fn to_u8(self) -> u8 {
175        self as u8
176    }
177}
178
179impl From<DatastoreState> for u8 {
180    fn from(val: DatastoreState) -> Self {
181        val as u8
182    }
183}
184
185// Struct definitions
186
187#[derive(Debug, serde::Serialize)]
188pub struct DatastoreACLEntry {
189    pub node_id: Option<u64>,
190    pub list_id: Option<u16>,
191    pub acl_entry: Option<DatastoreAccessControlEntry>,
192    pub status_entry: Option<DatastoreStatusEntry>,
193}
194
195#[derive(Debug, serde::Serialize)]
196pub struct DatastoreAccessControlEntry {
197    pub privilege: Option<DatastoreAccessControlEntryPrivilege>,
198    pub auth_mode: Option<DatastoreAccessControlEntryAuthMode>,
199    pub subjects: Option<Vec<u64>>,
200    pub targets: Option<Vec<DatastoreAccessControlTarget>>,
201}
202
203#[derive(Debug, serde::Serialize)]
204pub struct DatastoreAccessControlTarget {
205    pub cluster: Option<u32>,
206    pub endpoint: Option<u16>,
207    pub device_type: Option<u32>,
208}
209
210#[derive(Debug, serde::Serialize)]
211pub struct DatastoreAdministratorInformationEntry {
212    pub node_id: Option<u64>,
213    pub friendly_name: Option<String>,
214    pub vendor_id: Option<u16>,
215    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
216    pub icac: Option<Vec<u8>>,
217}
218
219#[derive(Debug, serde::Serialize)]
220pub struct DatastoreBindingTarget {
221    pub node: Option<u64>,
222    pub group: Option<u16>,
223    pub endpoint: Option<u16>,
224    pub cluster: Option<u32>,
225}
226
227#[derive(Debug, serde::Serialize)]
228pub struct DatastoreEndpointBindingEntry {
229    pub node_id: Option<u64>,
230    pub endpoint_id: Option<u16>,
231    pub list_id: Option<u16>,
232    pub binding: Option<DatastoreBindingTarget>,
233    pub status_entry: Option<DatastoreStatusEntry>,
234}
235
236#[derive(Debug, serde::Serialize)]
237pub struct DatastoreEndpointEntry {
238    pub endpoint_id: Option<u16>,
239    pub node_id: Option<u64>,
240    pub friendly_name: Option<String>,
241}
242
243#[derive(Debug, serde::Serialize)]
244pub struct DatastoreEndpointGroupIDEntry {
245    pub node_id: Option<u64>,
246    pub endpoint_id: Option<u16>,
247    pub group_id: Option<u16>,
248    pub status_entry: Option<DatastoreStatusEntry>,
249}
250
251#[derive(Debug, serde::Serialize)]
252pub struct DatastoreGroupInformationEntry {
253    pub group_id: Option<u64>,
254    pub friendly_name: Option<String>,
255    pub group_key_set_id: Option<u16>,
256    pub group_cat: Option<u16>,
257    pub group_cat_version: Option<u16>,
258    pub group_permission: Option<DatastoreAccessControlEntryPrivilege>,
259}
260
261#[derive(Debug, serde::Serialize)]
262pub struct DatastoreGroupKeySet {
263    pub group_key_set_id: Option<u16>,
264    pub group_key_security_policy: Option<DatastoreGroupKeySecurityPolicy>,
265    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
266    pub epoch_key0: Option<Vec<u8>>,
267    pub epoch_start_time0: Option<u64>,
268    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
269    pub epoch_key1: Option<Vec<u8>>,
270    pub epoch_start_time1: Option<u64>,
271    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
272    pub epoch_key2: Option<Vec<u8>>,
273    pub epoch_start_time2: Option<u64>,
274    pub group_key_multicast_policy: Option<DatastoreGroupKeyMulticastPolicy>,
275}
276
277#[derive(Debug, serde::Serialize)]
278pub struct DatastoreNodeInformationEntry {
279    pub node_id: Option<u64>,
280    pub friendly_name: Option<String>,
281    pub commissioning_status_entry: Option<DatastoreStatusEntry>,
282}
283
284#[derive(Debug, serde::Serialize)]
285pub struct DatastoreNodeKeySetEntry {
286    pub node_id: Option<u64>,
287    pub group_key_set_id: Option<u16>,
288    pub status_entry: Option<DatastoreStatusEntry>,
289}
290
291#[derive(Debug, serde::Serialize)]
292pub struct DatastoreStatusEntry {
293    pub state: Option<DatastoreState>,
294    pub update_timestamp: Option<u64>,
295    pub failure_code: Option<u8>,
296}
297
298// Command encoders
299
300/// Encode AddKeySet command (0x00)
301pub fn encode_add_key_set(group_key_set: DatastoreGroupKeySet) -> anyhow::Result<Vec<u8>> {
302            // Encode struct DatastoreGroupKeySetStruct
303            let mut group_key_set_fields = Vec::new();
304            if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
305            if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
306            if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
307            if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
308            if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
309            if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
310            if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
311            if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
312            if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
313    let tlv = tlv::TlvItemEnc {
314        tag: 0,
315        value: tlv::TlvItemValueEnc::StructInvisible(vec![
316        (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
317        ]),
318    };
319    Ok(tlv.encode()?)
320}
321
322/// Encode UpdateKeySet command (0x01)
323pub fn encode_update_key_set(group_key_set: DatastoreGroupKeySet) -> anyhow::Result<Vec<u8>> {
324            // Encode struct DatastoreGroupKeySetStruct
325            let mut group_key_set_fields = Vec::new();
326            if let Some(x) = group_key_set.group_key_set_id { group_key_set_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
327            if let Some(x) = group_key_set.group_key_security_policy { group_key_set_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
328            if let Some(x) = group_key_set.epoch_key0 { group_key_set_fields.push((2, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
329            if let Some(x) = group_key_set.epoch_start_time0 { group_key_set_fields.push((3, tlv::TlvItemValueEnc::UInt64(x)).into()); }
330            if let Some(x) = group_key_set.epoch_key1 { group_key_set_fields.push((4, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
331            if let Some(x) = group_key_set.epoch_start_time1 { group_key_set_fields.push((5, tlv::TlvItemValueEnc::UInt64(x)).into()); }
332            if let Some(x) = group_key_set.epoch_key2 { group_key_set_fields.push((6, tlv::TlvItemValueEnc::OctetString(x.clone())).into()); }
333            if let Some(x) = group_key_set.epoch_start_time2 { group_key_set_fields.push((7, tlv::TlvItemValueEnc::UInt64(x)).into()); }
334            if let Some(x) = group_key_set.group_key_multicast_policy { group_key_set_fields.push((8, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
335    let tlv = tlv::TlvItemEnc {
336        tag: 0,
337        value: tlv::TlvItemValueEnc::StructInvisible(vec![
338        (0, tlv::TlvItemValueEnc::StructInvisible(group_key_set_fields)).into(),
339        ]),
340    };
341    Ok(tlv.encode()?)
342}
343
344/// Encode RemoveKeySet command (0x02)
345pub fn encode_remove_key_set(group_key_set_id: u16) -> anyhow::Result<Vec<u8>> {
346    let tlv = tlv::TlvItemEnc {
347        tag: 0,
348        value: tlv::TlvItemValueEnc::StructInvisible(vec![
349        (0, tlv::TlvItemValueEnc::UInt16(group_key_set_id)).into(),
350        ]),
351    };
352    Ok(tlv.encode()?)
353}
354
355/// Encode AddGroup command (0x03)
356pub fn encode_add_group(group_id: u16, friendly_name: String, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: DatastoreAccessControlEntryPrivilege) -> anyhow::Result<Vec<u8>> {
357    let tlv = tlv::TlvItemEnc {
358        tag: 0,
359        value: tlv::TlvItemValueEnc::StructInvisible(vec![
360        (0, tlv::TlvItemValueEnc::UInt16(group_id)).into(),
361        (1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
362        (2, tlv::TlvItemValueEnc::UInt16(group_key_set_id.unwrap_or(0))).into(),
363        (3, tlv::TlvItemValueEnc::UInt16(group_cat.unwrap_or(0))).into(),
364        (4, tlv::TlvItemValueEnc::UInt16(group_cat_version.unwrap_or(0))).into(),
365        (5, tlv::TlvItemValueEnc::UInt8(group_permission.to_u8())).into(),
366        ]),
367    };
368    Ok(tlv.encode()?)
369}
370
371/// Encode UpdateGroup command (0x04)
372pub fn encode_update_group(group_id: u16, friendly_name: Option<String>, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: Option<DatastoreAccessControlEntryPrivilege>) -> anyhow::Result<Vec<u8>> {
373    let tlv = tlv::TlvItemEnc {
374        tag: 0,
375        value: tlv::TlvItemValueEnc::StructInvisible(vec![
376        (0, tlv::TlvItemValueEnc::UInt16(group_id)).into(),
377        (1, tlv::TlvItemValueEnc::String(friendly_name.unwrap_or("".to_string()))).into(),
378        (2, tlv::TlvItemValueEnc::UInt16(group_key_set_id.unwrap_or(0))).into(),
379        (3, tlv::TlvItemValueEnc::UInt16(group_cat.unwrap_or(0))).into(),
380        (4, tlv::TlvItemValueEnc::UInt16(group_cat_version.unwrap_or(0))).into(),
381        (5, tlv::TlvItemValueEnc::UInt8(group_permission.map(|e| e.to_u8()).unwrap_or(0))).into(),
382        ]),
383    };
384    Ok(tlv.encode()?)
385}
386
387/// Encode RemoveGroup command (0x05)
388pub fn encode_remove_group(group_id: u16) -> anyhow::Result<Vec<u8>> {
389    let tlv = tlv::TlvItemEnc {
390        tag: 0,
391        value: tlv::TlvItemValueEnc::StructInvisible(vec![
392        (0, tlv::TlvItemValueEnc::UInt16(group_id)).into(),
393        ]),
394    };
395    Ok(tlv.encode()?)
396}
397
398/// Encode AddAdmin command (0x06)
399pub fn encode_add_admin(node_id: u64, friendly_name: String, vendor_id: u16, icac: Vec<u8>) -> anyhow::Result<Vec<u8>> {
400    let tlv = tlv::TlvItemEnc {
401        tag: 0,
402        value: tlv::TlvItemValueEnc::StructInvisible(vec![
403        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
404        (1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
405        (2, tlv::TlvItemValueEnc::UInt16(vendor_id)).into(),
406        (3, tlv::TlvItemValueEnc::OctetString(icac)).into(),
407        ]),
408    };
409    Ok(tlv.encode()?)
410}
411
412/// Encode UpdateAdmin command (0x07)
413pub fn encode_update_admin(node_id: u64, friendly_name: Option<String>, icac: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
414    let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
415    tlv_fields.push((0, tlv::TlvItemValueEnc::UInt64(node_id)).into());
416    if let Some(x) = friendly_name { tlv_fields.push((1, tlv::TlvItemValueEnc::String(x)).into()); }
417    if let Some(x) = icac { tlv_fields.push((2, tlv::TlvItemValueEnc::OctetString(x)).into()); }
418    let tlv = tlv::TlvItemEnc {
419        tag: 0,
420        value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
421    };
422    Ok(tlv.encode()?)
423}
424
425/// Encode RemoveAdmin command (0x08)
426pub fn encode_remove_admin(node_id: u64) -> anyhow::Result<Vec<u8>> {
427    let tlv = tlv::TlvItemEnc {
428        tag: 0,
429        value: tlv::TlvItemValueEnc::StructInvisible(vec![
430        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
431        ]),
432    };
433    Ok(tlv.encode()?)
434}
435
436/// Encode AddPendingNode command (0x09)
437pub fn encode_add_pending_node(node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
438    let tlv = tlv::TlvItemEnc {
439        tag: 0,
440        value: tlv::TlvItemValueEnc::StructInvisible(vec![
441        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
442        (1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
443        ]),
444    };
445    Ok(tlv.encode()?)
446}
447
448/// Encode RefreshNode command (0x0A)
449pub fn encode_refresh_node(node_id: u64) -> anyhow::Result<Vec<u8>> {
450    let tlv = tlv::TlvItemEnc {
451        tag: 0,
452        value: tlv::TlvItemValueEnc::StructInvisible(vec![
453        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
454        ]),
455    };
456    Ok(tlv.encode()?)
457}
458
459/// Encode UpdateNode command (0x0B)
460pub fn encode_update_node(node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
461    let tlv = tlv::TlvItemEnc {
462        tag: 0,
463        value: tlv::TlvItemValueEnc::StructInvisible(vec![
464        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
465        (1, tlv::TlvItemValueEnc::String(friendly_name)).into(),
466        ]),
467    };
468    Ok(tlv.encode()?)
469}
470
471/// Encode RemoveNode command (0x0C)
472pub fn encode_remove_node(node_id: u64) -> anyhow::Result<Vec<u8>> {
473    let tlv = tlv::TlvItemEnc {
474        tag: 0,
475        value: tlv::TlvItemValueEnc::StructInvisible(vec![
476        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
477        ]),
478    };
479    Ok(tlv.encode()?)
480}
481
482/// Encode UpdateEndpointForNode command (0x0D)
483pub fn encode_update_endpoint_for_node(endpoint_id: u16, node_id: u64, friendly_name: String) -> anyhow::Result<Vec<u8>> {
484    let tlv = tlv::TlvItemEnc {
485        tag: 0,
486        value: tlv::TlvItemValueEnc::StructInvisible(vec![
487        (0, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
488        (1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
489        (2, tlv::TlvItemValueEnc::String(friendly_name)).into(),
490        ]),
491    };
492    Ok(tlv.encode()?)
493}
494
495/// Encode AddGroupIDToEndpointForNode command (0x0E)
496pub fn encode_add_group_id_to_endpoint_for_node(node_id: u64, endpoint_id: u16, group_id: u16) -> anyhow::Result<Vec<u8>> {
497    let tlv = tlv::TlvItemEnc {
498        tag: 0,
499        value: tlv::TlvItemValueEnc::StructInvisible(vec![
500        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
501        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
502        (2, tlv::TlvItemValueEnc::UInt16(group_id)).into(),
503        ]),
504    };
505    Ok(tlv.encode()?)
506}
507
508/// Encode RemoveGroupIDFromEndpointForNode command (0x0F)
509pub fn encode_remove_group_id_from_endpoint_for_node(node_id: u64, endpoint_id: u16, group_id: u16) -> anyhow::Result<Vec<u8>> {
510    let tlv = tlv::TlvItemEnc {
511        tag: 0,
512        value: tlv::TlvItemValueEnc::StructInvisible(vec![
513        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
514        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
515        (2, tlv::TlvItemValueEnc::UInt16(group_id)).into(),
516        ]),
517    };
518    Ok(tlv.encode()?)
519}
520
521/// Encode AddBindingToEndpointForNode command (0x10)
522pub fn encode_add_binding_to_endpoint_for_node(node_id: u64, endpoint_id: u16, binding: DatastoreBindingTarget) -> anyhow::Result<Vec<u8>> {
523            // Encode struct DatastoreBindingTargetStruct
524            let mut binding_fields = Vec::new();
525            if let Some(x) = binding.node { binding_fields.push((1, tlv::TlvItemValueEnc::UInt64(x)).into()); }
526            if let Some(x) = binding.group { binding_fields.push((2, tlv::TlvItemValueEnc::UInt16(x)).into()); }
527            if let Some(x) = binding.endpoint { binding_fields.push((3, tlv::TlvItemValueEnc::UInt16(x)).into()); }
528            if let Some(x) = binding.cluster { binding_fields.push((4, tlv::TlvItemValueEnc::UInt32(x)).into()); }
529    let tlv = tlv::TlvItemEnc {
530        tag: 0,
531        value: tlv::TlvItemValueEnc::StructInvisible(vec![
532        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
533        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
534        (2, tlv::TlvItemValueEnc::StructInvisible(binding_fields)).into(),
535        ]),
536    };
537    Ok(tlv.encode()?)
538}
539
540/// Encode RemoveBindingFromEndpointForNode command (0x11)
541pub fn encode_remove_binding_from_endpoint_for_node(list_id: u16, endpoint_id: u16, node_id: u64) -> anyhow::Result<Vec<u8>> {
542    let tlv = tlv::TlvItemEnc {
543        tag: 0,
544        value: tlv::TlvItemValueEnc::StructInvisible(vec![
545        (0, tlv::TlvItemValueEnc::UInt16(list_id)).into(),
546        (1, tlv::TlvItemValueEnc::UInt16(endpoint_id)).into(),
547        (2, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
548        ]),
549    };
550    Ok(tlv.encode()?)
551}
552
553/// Encode AddACLToNode command (0x12)
554pub fn encode_add_acl_to_node(node_id: u64, acl_entry: DatastoreAccessControlEntry) -> anyhow::Result<Vec<u8>> {
555            // Encode struct DatastoreAccessControlEntryStruct
556            let mut acl_entry_fields = Vec::new();
557            if let Some(x) = acl_entry.privilege { acl_entry_fields.push((1, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
558            if let Some(x) = acl_entry.auth_mode { acl_entry_fields.push((2, tlv::TlvItemValueEnc::UInt8(x.to_u8())).into()); }
559            if let Some(listv) = acl_entry.subjects { acl_entry_fields.push((3, tlv::TlvItemValueEnc::StructAnon(listv.into_iter().map(|x| (0, tlv::TlvItemValueEnc::UInt64(x)).into()).collect())).into()); }
560            if let Some(listv) = acl_entry.targets {
561                let inner_vec: Vec<_> = listv.into_iter().map(|inner| {
562                    let mut nested_fields = Vec::new();
563                        if let Some(x) = inner.cluster { nested_fields.push((0, tlv::TlvItemValueEnc::UInt32(x)).into()); }
564                        if let Some(x) = inner.endpoint { nested_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
565                        if let Some(x) = inner.device_type { nested_fields.push((2, tlv::TlvItemValueEnc::UInt32(x)).into()); }
566                    (0, tlv::TlvItemValueEnc::StructAnon(nested_fields)).into()
567                }).collect();
568                acl_entry_fields.push((4, tlv::TlvItemValueEnc::Array(inner_vec)).into());
569            }
570    let tlv = tlv::TlvItemEnc {
571        tag: 0,
572        value: tlv::TlvItemValueEnc::StructInvisible(vec![
573        (0, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
574        (1, tlv::TlvItemValueEnc::StructInvisible(acl_entry_fields)).into(),
575        ]),
576    };
577    Ok(tlv.encode()?)
578}
579
580/// Encode RemoveACLFromNode command (0x13)
581pub fn encode_remove_acl_from_node(list_id: u16, node_id: u64) -> anyhow::Result<Vec<u8>> {
582    let tlv = tlv::TlvItemEnc {
583        tag: 0,
584        value: tlv::TlvItemValueEnc::StructInvisible(vec![
585        (0, tlv::TlvItemValueEnc::UInt16(list_id)).into(),
586        (1, tlv::TlvItemValueEnc::UInt64(node_id)).into(),
587        ]),
588    };
589    Ok(tlv.encode()?)
590}
591
592// Attribute decoders
593
594/// Decode AnchorRootCA attribute (0x0000)
595pub fn decode_anchor_root_ca(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
596    if let tlv::TlvItemValue::OctetString(v) = inp {
597        Ok(v.clone())
598    } else {
599        Err(anyhow::anyhow!("Expected OctetString"))
600    }
601}
602
603/// Decode AnchorNodeID attribute (0x0001)
604pub fn decode_anchor_node_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
605    if let tlv::TlvItemValue::Int(v) = inp {
606        Ok(*v)
607    } else {
608        Err(anyhow::anyhow!("Expected UInt64"))
609    }
610}
611
612/// Decode AnchorVendorID attribute (0x0002)
613pub fn decode_anchor_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
614    if let tlv::TlvItemValue::Int(v) = inp {
615        Ok(*v as u16)
616    } else {
617        Err(anyhow::anyhow!("Expected UInt16"))
618    }
619}
620
621/// Decode FriendlyName attribute (0x0003)
622pub fn decode_friendly_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
623    if let tlv::TlvItemValue::String(v) = inp {
624        Ok(v.clone())
625    } else {
626        Err(anyhow::anyhow!("Expected String"))
627    }
628}
629
630/// Decode GroupKeySetList attribute (0x0004)
631pub fn decode_group_key_set_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreGroupKeySet>> {
632    let mut res = Vec::new();
633    if let tlv::TlvItemValue::List(v) = inp {
634        for item in v {
635            res.push(DatastoreGroupKeySet {
636                group_key_set_id: item.get_int(&[0]).map(|v| v as u16),
637                group_key_security_policy: item.get_int(&[1]).and_then(|v| DatastoreGroupKeySecurityPolicy::from_u8(v as u8)),
638                epoch_key0: item.get_octet_string_owned(&[2]),
639                epoch_start_time0: item.get_int(&[3]),
640                epoch_key1: item.get_octet_string_owned(&[4]),
641                epoch_start_time1: item.get_int(&[5]),
642                epoch_key2: item.get_octet_string_owned(&[6]),
643                epoch_start_time2: item.get_int(&[7]),
644                group_key_multicast_policy: item.get_int(&[8]).and_then(|v| DatastoreGroupKeyMulticastPolicy::from_u8(v as u8)),
645            });
646        }
647    }
648    Ok(res)
649}
650
651/// Decode GroupList attribute (0x0005)
652pub fn decode_group_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreGroupInformationEntry>> {
653    let mut res = Vec::new();
654    if let tlv::TlvItemValue::List(v) = inp {
655        for item in v {
656            res.push(DatastoreGroupInformationEntry {
657                group_id: item.get_int(&[0]),
658                friendly_name: item.get_string_owned(&[1]),
659                group_key_set_id: item.get_int(&[2]).map(|v| v as u16),
660                group_cat: item.get_int(&[3]).map(|v| v as u16),
661                group_cat_version: item.get_int(&[4]).map(|v| v as u16),
662                group_permission: item.get_int(&[5]).and_then(|v| DatastoreAccessControlEntryPrivilege::from_u8(v as u8)),
663            });
664        }
665    }
666    Ok(res)
667}
668
669/// Decode NodeList attribute (0x0006)
670pub fn decode_node_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreNodeInformationEntry>> {
671    let mut res = Vec::new();
672    if let tlv::TlvItemValue::List(v) = inp {
673        for item in v {
674            res.push(DatastoreNodeInformationEntry {
675                node_id: item.get_int(&[0]),
676                friendly_name: item.get_string_owned(&[1]),
677                commissioning_status_entry: {
678                    if let Some(nested_tlv) = item.get(&[2]) {
679                        if let tlv::TlvItemValue::List(_) = nested_tlv {
680                            let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
681                            Some(DatastoreStatusEntry {
682                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
683                update_timestamp: nested_item.get_int(&[1]),
684                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
685                            })
686                        } else {
687                            None
688                        }
689                    } else {
690                        None
691                    }
692                },
693            });
694        }
695    }
696    Ok(res)
697}
698
699/// Decode AdminList attribute (0x0007)
700pub fn decode_admin_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreAdministratorInformationEntry>> {
701    let mut res = Vec::new();
702    if let tlv::TlvItemValue::List(v) = inp {
703        for item in v {
704            res.push(DatastoreAdministratorInformationEntry {
705                node_id: item.get_int(&[0]),
706                friendly_name: item.get_string_owned(&[1]),
707                vendor_id: item.get_int(&[2]).map(|v| v as u16),
708                icac: item.get_octet_string_owned(&[3]),
709            });
710        }
711    }
712    Ok(res)
713}
714
715/// Decode Status attribute (0x0008)
716pub fn decode_status(inp: &tlv::TlvItemValue) -> anyhow::Result<DatastoreStatusEntry> {
717    if let tlv::TlvItemValue::List(_fields) = inp {
718        // Struct with fields
719        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
720        Ok(DatastoreStatusEntry {
721                state: item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
722                update_timestamp: item.get_int(&[1]),
723                failure_code: item.get_int(&[2]).map(|v| v as u8),
724        })
725    } else {
726        Err(anyhow::anyhow!("Expected struct fields"))
727    }
728}
729
730/// Decode EndpointGroupIDList attribute (0x0009)
731pub fn decode_endpoint_group_id_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointGroupIDEntry>> {
732    let mut res = Vec::new();
733    if let tlv::TlvItemValue::List(v) = inp {
734        for item in v {
735            res.push(DatastoreEndpointGroupIDEntry {
736                node_id: item.get_int(&[0]),
737                endpoint_id: item.get_int(&[1]).map(|v| v as u16),
738                group_id: item.get_int(&[2]).map(|v| v as u16),
739                status_entry: {
740                    if let Some(nested_tlv) = item.get(&[3]) {
741                        if let tlv::TlvItemValue::List(_) = nested_tlv {
742                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
743                            Some(DatastoreStatusEntry {
744                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
745                update_timestamp: nested_item.get_int(&[1]),
746                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
747                            })
748                        } else {
749                            None
750                        }
751                    } else {
752                        None
753                    }
754                },
755            });
756        }
757    }
758    Ok(res)
759}
760
761/// Decode EndpointBindingList attribute (0x000A)
762pub fn decode_endpoint_binding_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointBindingEntry>> {
763    let mut res = Vec::new();
764    if let tlv::TlvItemValue::List(v) = inp {
765        for item in v {
766            res.push(DatastoreEndpointBindingEntry {
767                node_id: item.get_int(&[0]),
768                endpoint_id: item.get_int(&[1]).map(|v| v as u16),
769                list_id: item.get_int(&[2]).map(|v| v as u16),
770                binding: {
771                    if let Some(nested_tlv) = item.get(&[3]) {
772                        if let tlv::TlvItemValue::List(_) = nested_tlv {
773                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
774                            Some(DatastoreBindingTarget {
775                node: nested_item.get_int(&[1]),
776                group: nested_item.get_int(&[2]).map(|v| v as u16),
777                endpoint: nested_item.get_int(&[3]).map(|v| v as u16),
778                cluster: nested_item.get_int(&[4]).map(|v| v as u32),
779                            })
780                        } else {
781                            None
782                        }
783                    } else {
784                        None
785                    }
786                },
787                status_entry: {
788                    if let Some(nested_tlv) = item.get(&[4]) {
789                        if let tlv::TlvItemValue::List(_) = nested_tlv {
790                            let nested_item = tlv::TlvItem { tag: 4, value: nested_tlv.clone() };
791                            Some(DatastoreStatusEntry {
792                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
793                update_timestamp: nested_item.get_int(&[1]),
794                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
795                            })
796                        } else {
797                            None
798                        }
799                    } else {
800                        None
801                    }
802                },
803            });
804        }
805    }
806    Ok(res)
807}
808
809/// Decode NodeKeySetList attribute (0x000B)
810pub fn decode_node_key_set_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreNodeKeySetEntry>> {
811    let mut res = Vec::new();
812    if let tlv::TlvItemValue::List(v) = inp {
813        for item in v {
814            res.push(DatastoreNodeKeySetEntry {
815                node_id: item.get_int(&[0]),
816                group_key_set_id: item.get_int(&[1]).map(|v| v as u16),
817                status_entry: {
818                    if let Some(nested_tlv) = item.get(&[2]) {
819                        if let tlv::TlvItemValue::List(_) = nested_tlv {
820                            let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
821                            Some(DatastoreStatusEntry {
822                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
823                update_timestamp: nested_item.get_int(&[1]),
824                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
825                            })
826                        } else {
827                            None
828                        }
829                    } else {
830                        None
831                    }
832                },
833            });
834        }
835    }
836    Ok(res)
837}
838
839/// Decode NodeACLList attribute (0x000C)
840pub fn decode_node_acl_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreACLEntry>> {
841    let mut res = Vec::new();
842    if let tlv::TlvItemValue::List(v) = inp {
843        for item in v {
844            res.push(DatastoreACLEntry {
845                node_id: item.get_int(&[0]),
846                list_id: item.get_int(&[1]).map(|v| v as u16),
847                acl_entry: {
848                    if let Some(nested_tlv) = item.get(&[2]) {
849                        if let tlv::TlvItemValue::List(_) = nested_tlv {
850                            let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
851                            Some(DatastoreAccessControlEntry {
852                privilege: nested_item.get_int(&[1]).and_then(|v| DatastoreAccessControlEntryPrivilege::from_u8(v as u8)),
853                auth_mode: nested_item.get_int(&[2]).and_then(|v| DatastoreAccessControlEntryAuthMode::from_u8(v as u8)),
854                subjects: {
855                    if let Some(tlv::TlvItemValue::List(l)) = nested_item.get(&[3]) {
856                        let items: Vec<u64> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v) } else { None } }).collect();
857                        Some(items)
858                    } else {
859                        None
860                    }
861                },
862                targets: {
863                    if let Some(tlv::TlvItemValue::List(l)) = nested_item.get(&[4]) {
864                        let mut items = Vec::new();
865                        for list_item in l {
866                            items.push(DatastoreAccessControlTarget {
867                cluster: list_item.get_int(&[0]).map(|v| v as u32),
868                endpoint: list_item.get_int(&[1]).map(|v| v as u16),
869                device_type: list_item.get_int(&[2]).map(|v| v as u32),
870                            });
871                        }
872                        Some(items)
873                    } else {
874                        None
875                    }
876                },
877                            })
878                        } else {
879                            None
880                        }
881                    } else {
882                        None
883                    }
884                },
885                status_entry: {
886                    if let Some(nested_tlv) = item.get(&[3]) {
887                        if let tlv::TlvItemValue::List(_) = nested_tlv {
888                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
889                            Some(DatastoreStatusEntry {
890                state: nested_item.get_int(&[0]).and_then(|v| DatastoreState::from_u8(v as u8)),
891                update_timestamp: nested_item.get_int(&[1]),
892                failure_code: nested_item.get_int(&[2]).map(|v| v as u8),
893                            })
894                        } else {
895                            None
896                        }
897                    } else {
898                        None
899                    }
900                },
901            });
902        }
903    }
904    Ok(res)
905}
906
907/// Decode NodeEndpointList attribute (0x000D)
908pub fn decode_node_endpoint_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DatastoreEndpointEntry>> {
909    let mut res = Vec::new();
910    if let tlv::TlvItemValue::List(v) = inp {
911        for item in v {
912            res.push(DatastoreEndpointEntry {
913                endpoint_id: item.get_int(&[0]).map(|v| v as u16),
914                node_id: item.get_int(&[1]),
915                friendly_name: item.get_string_owned(&[2]),
916            });
917        }
918    }
919    Ok(res)
920}
921
922
923// JSON dispatcher function
924
925/// Decode attribute value and return as JSON string
926///
927/// # Parameters
928/// * `cluster_id` - The cluster identifier
929/// * `attribute_id` - The attribute identifier
930/// * `tlv_value` - The TLV value to decode
931///
932/// # Returns
933/// JSON string representation of the decoded value or error
934pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
935    // Verify this is the correct cluster
936    if ![0x0752].contains(&cluster_id) {
937        return format!("{{\"error\": \"Invalid cluster ID. Expected [0x0752], got {}\"}}", cluster_id);
938    }
939
940    match attribute_id {
941        0x0000 => {
942            match decode_anchor_root_ca(tlv_value) {
943                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
944                Err(e) => format!("{{\"error\": \"{}\"}}", e),
945            }
946        }
947        0x0001 => {
948            match decode_anchor_node_id(tlv_value) {
949                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
950                Err(e) => format!("{{\"error\": \"{}\"}}", e),
951            }
952        }
953        0x0002 => {
954            match decode_anchor_vendor_id(tlv_value) {
955                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
956                Err(e) => format!("{{\"error\": \"{}\"}}", e),
957            }
958        }
959        0x0003 => {
960            match decode_friendly_name(tlv_value) {
961                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
962                Err(e) => format!("{{\"error\": \"{}\"}}", e),
963            }
964        }
965        0x0004 => {
966            match decode_group_key_set_list(tlv_value) {
967                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
968                Err(e) => format!("{{\"error\": \"{}\"}}", e),
969            }
970        }
971        0x0005 => {
972            match decode_group_list(tlv_value) {
973                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
974                Err(e) => format!("{{\"error\": \"{}\"}}", e),
975            }
976        }
977        0x0006 => {
978            match decode_node_list(tlv_value) {
979                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
980                Err(e) => format!("{{\"error\": \"{}\"}}", e),
981            }
982        }
983        0x0007 => {
984            match decode_admin_list(tlv_value) {
985                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
986                Err(e) => format!("{{\"error\": \"{}\"}}", e),
987            }
988        }
989        0x0008 => {
990            match decode_status(tlv_value) {
991                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
992                Err(e) => format!("{{\"error\": \"{}\"}}", e),
993            }
994        }
995        0x0009 => {
996            match decode_endpoint_group_id_list(tlv_value) {
997                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
998                Err(e) => format!("{{\"error\": \"{}\"}}", e),
999            }
1000        }
1001        0x000A => {
1002            match decode_endpoint_binding_list(tlv_value) {
1003                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1004                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1005            }
1006        }
1007        0x000B => {
1008            match decode_node_key_set_list(tlv_value) {
1009                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1010                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1011            }
1012        }
1013        0x000C => {
1014            match decode_node_acl_list(tlv_value) {
1015                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1016                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1017            }
1018        }
1019        0x000D => {
1020            match decode_node_endpoint_list(tlv_value) {
1021                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1022                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1023            }
1024        }
1025        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
1026    }
1027}
1028
1029/// Get list of all attributes supported by this cluster
1030///
1031/// # Returns
1032/// Vector of tuples containing (attribute_id, attribute_name)
1033pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
1034    vec![
1035        (0x0000, "AnchorRootCA"),
1036        (0x0001, "AnchorNodeID"),
1037        (0x0002, "AnchorVendorID"),
1038        (0x0003, "FriendlyName"),
1039        (0x0004, "GroupKeySetList"),
1040        (0x0005, "GroupList"),
1041        (0x0006, "NodeList"),
1042        (0x0007, "AdminList"),
1043        (0x0008, "Status"),
1044        (0x0009, "EndpointGroupIDList"),
1045        (0x000A, "EndpointBindingList"),
1046        (0x000B, "NodeKeySetList"),
1047        (0x000C, "NodeACLList"),
1048        (0x000D, "NodeEndpointList"),
1049    ]
1050}
1051
1052// Command listing
1053
1054pub fn get_command_list() -> Vec<(u32, &'static str)> {
1055    vec![
1056        (0x00, "AddKeySet"),
1057        (0x01, "UpdateKeySet"),
1058        (0x02, "RemoveKeySet"),
1059        (0x03, "AddGroup"),
1060        (0x04, "UpdateGroup"),
1061        (0x05, "RemoveGroup"),
1062        (0x06, "AddAdmin"),
1063        (0x07, "UpdateAdmin"),
1064        (0x08, "RemoveAdmin"),
1065        (0x09, "AddPendingNode"),
1066        (0x0A, "RefreshNode"),
1067        (0x0B, "UpdateNode"),
1068        (0x0C, "RemoveNode"),
1069        (0x0D, "UpdateEndpointForNode"),
1070        (0x0E, "AddGroupIDToEndpointForNode"),
1071        (0x0F, "RemoveGroupIDFromEndpointForNode"),
1072        (0x10, "AddBindingToEndpointForNode"),
1073        (0x11, "RemoveBindingFromEndpointForNode"),
1074        (0x12, "AddACLToNode"),
1075        (0x13, "RemoveACLFromNode"),
1076    ]
1077}
1078
1079pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
1080    match cmd_id {
1081        0x00 => Some("AddKeySet"),
1082        0x01 => Some("UpdateKeySet"),
1083        0x02 => Some("RemoveKeySet"),
1084        0x03 => Some("AddGroup"),
1085        0x04 => Some("UpdateGroup"),
1086        0x05 => Some("RemoveGroup"),
1087        0x06 => Some("AddAdmin"),
1088        0x07 => Some("UpdateAdmin"),
1089        0x08 => Some("RemoveAdmin"),
1090        0x09 => Some("AddPendingNode"),
1091        0x0A => Some("RefreshNode"),
1092        0x0B => Some("UpdateNode"),
1093        0x0C => Some("RemoveNode"),
1094        0x0D => Some("UpdateEndpointForNode"),
1095        0x0E => Some("AddGroupIDToEndpointForNode"),
1096        0x0F => Some("RemoveGroupIDFromEndpointForNode"),
1097        0x10 => Some("AddBindingToEndpointForNode"),
1098        0x11 => Some("RemoveBindingFromEndpointForNode"),
1099        0x12 => Some("AddACLToNode"),
1100        0x13 => Some("RemoveACLFromNode"),
1101        _ => None,
1102    }
1103}
1104
1105pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
1106    match cmd_id {
1107        0x00 => Some(vec![
1108            crate::clusters::codec::CommandField { tag: 0, name: "group_key_set", kind: crate::clusters::codec::FieldKind::Struct { name: "DatastoreGroupKeySetStruct" }, optional: false, nullable: false },
1109        ]),
1110        0x01 => Some(vec![
1111            crate::clusters::codec::CommandField { tag: 0, name: "group_key_set", kind: crate::clusters::codec::FieldKind::Struct { name: "DatastoreGroupKeySetStruct" }, optional: false, nullable: false },
1112        ]),
1113        0x02 => Some(vec![
1114            crate::clusters::codec::CommandField { tag: 0, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1115        ]),
1116        0x03 => Some(vec![
1117            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1118            crate::clusters::codec::CommandField { tag: 1, name: "friendly_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
1119            crate::clusters::codec::CommandField { tag: 2, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
1120            crate::clusters::codec::CommandField { tag: 3, name: "group_cat", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
1121            crate::clusters::codec::CommandField { tag: 4, name: "group_cat_version", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
1122            crate::clusters::codec::CommandField { tag: 5, name: "group_permission", kind: crate::clusters::codec::FieldKind::Enum { name: "DatastoreAccessControlEntryPrivilege", variants: &[(1, "View"), (3, "Operate"), (4, "Manage"), (5, "Administer")] }, optional: false, nullable: false },
1123        ]),
1124        0x04 => Some(vec![
1125            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1126            crate::clusters::codec::CommandField { tag: 1, name: "friendly_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: true },
1127            crate::clusters::codec::CommandField { tag: 2, name: "group_key_set_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
1128            crate::clusters::codec::CommandField { tag: 3, name: "group_cat", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
1129            crate::clusters::codec::CommandField { tag: 4, name: "group_cat_version", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
1130            crate::clusters::codec::CommandField { tag: 5, name: "group_permission", kind: crate::clusters::codec::FieldKind::Enum { name: "DatastoreAccessControlEntryPrivilege", variants: &[(1, "View"), (3, "Operate"), (4, "Manage"), (5, "Administer")] }, optional: false, nullable: true },
1131        ]),
1132        0x05 => Some(vec![
1133            crate::clusters::codec::CommandField { tag: 0, name: "group_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1134        ]),
1135        0x06 => Some(vec![
1136            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1137            crate::clusters::codec::CommandField { tag: 1, name: "friendly_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
1138            crate::clusters::codec::CommandField { tag: 2, name: "vendor_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1139            crate::clusters::codec::CommandField { tag: 3, name: "icac", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
1140        ]),
1141        0x07 => Some(vec![
1142            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1143            crate::clusters::codec::CommandField { tag: 1, name: "friendly_name", kind: crate::clusters::codec::FieldKind::String, optional: true, nullable: false },
1144            crate::clusters::codec::CommandField { tag: 2, name: "icac", kind: crate::clusters::codec::FieldKind::OctetString, optional: true, nullable: false },
1145        ]),
1146        0x08 => Some(vec![
1147            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1148        ]),
1149        0x09 => Some(vec![
1150            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1151            crate::clusters::codec::CommandField { tag: 1, name: "friendly_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
1152        ]),
1153        0x0A => Some(vec![
1154            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1155        ]),
1156        0x0B => Some(vec![
1157            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1158            crate::clusters::codec::CommandField { tag: 1, name: "friendly_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
1159        ]),
1160        0x0C => Some(vec![
1161            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1162        ]),
1163        0x0D => Some(vec![
1164            crate::clusters::codec::CommandField { tag: 0, name: "endpoint_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1165            crate::clusters::codec::CommandField { tag: 1, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1166            crate::clusters::codec::CommandField { tag: 2, name: "friendly_name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
1167        ]),
1168        0x0E => Some(vec![
1169            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1170            crate::clusters::codec::CommandField { tag: 1, name: "endpoint_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1171            crate::clusters::codec::CommandField { tag: 2, name: "group_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1172        ]),
1173        0x0F => Some(vec![
1174            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1175            crate::clusters::codec::CommandField { tag: 1, name: "endpoint_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1176            crate::clusters::codec::CommandField { tag: 2, name: "group_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1177        ]),
1178        0x10 => Some(vec![
1179            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1180            crate::clusters::codec::CommandField { tag: 1, name: "endpoint_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1181            crate::clusters::codec::CommandField { tag: 2, name: "binding", kind: crate::clusters::codec::FieldKind::Struct { name: "DatastoreBindingTargetStruct" }, optional: false, nullable: false },
1182        ]),
1183        0x11 => Some(vec![
1184            crate::clusters::codec::CommandField { tag: 0, name: "list_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1185            crate::clusters::codec::CommandField { tag: 1, name: "endpoint_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1186            crate::clusters::codec::CommandField { tag: 2, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1187        ]),
1188        0x12 => Some(vec![
1189            crate::clusters::codec::CommandField { tag: 0, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1190            crate::clusters::codec::CommandField { tag: 1, name: "acl_entry", kind: crate::clusters::codec::FieldKind::Struct { name: "DatastoreAccessControlEntryStruct" }, optional: false, nullable: false },
1191        ]),
1192        0x13 => Some(vec![
1193            crate::clusters::codec::CommandField { tag: 0, name: "list_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1194            crate::clusters::codec::CommandField { tag: 1, name: "node_id", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
1195        ]),
1196        _ => None,
1197    }
1198}
1199
1200pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
1201    match cmd_id {
1202        0x00 => Err(anyhow::anyhow!("command \"AddKeySet\" has complex args: use raw mode")),
1203        0x01 => Err(anyhow::anyhow!("command \"UpdateKeySet\" has complex args: use raw mode")),
1204        0x02 => {
1205        let group_key_set_id = crate::clusters::codec::json_util::get_u16(args, "group_key_set_id")?;
1206        encode_remove_key_set(group_key_set_id)
1207        }
1208        0x03 => {
1209        let group_id = crate::clusters::codec::json_util::get_u16(args, "group_id")?;
1210        let friendly_name = crate::clusters::codec::json_util::get_string(args, "friendly_name")?;
1211        let group_key_set_id = crate::clusters::codec::json_util::get_opt_u16(args, "group_key_set_id")?;
1212        let group_cat = crate::clusters::codec::json_util::get_opt_u16(args, "group_cat")?;
1213        let group_cat_version = crate::clusters::codec::json_util::get_opt_u16(args, "group_cat_version")?;
1214        let group_permission = {
1215            let n = crate::clusters::codec::json_util::get_u64(args, "group_permission")?;
1216            DatastoreAccessControlEntryPrivilege::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid DatastoreAccessControlEntryPrivilege: {}", n))?
1217        };
1218        encode_add_group(group_id, friendly_name, group_key_set_id, group_cat, group_cat_version, group_permission)
1219        }
1220        0x04 => {
1221        let group_id = crate::clusters::codec::json_util::get_u16(args, "group_id")?;
1222        let friendly_name = crate::clusters::codec::json_util::get_opt_string(args, "friendly_name")?;
1223        let group_key_set_id = crate::clusters::codec::json_util::get_opt_u16(args, "group_key_set_id")?;
1224        let group_cat = crate::clusters::codec::json_util::get_opt_u16(args, "group_cat")?;
1225        let group_cat_version = crate::clusters::codec::json_util::get_opt_u16(args, "group_cat_version")?;
1226        let group_permission = crate::clusters::codec::json_util::get_opt_u64(args, "group_permission")?
1227            .and_then(|n| DatastoreAccessControlEntryPrivilege::from_u8(n as u8));
1228        encode_update_group(group_id, friendly_name, group_key_set_id, group_cat, group_cat_version, group_permission)
1229        }
1230        0x05 => {
1231        let group_id = crate::clusters::codec::json_util::get_u16(args, "group_id")?;
1232        encode_remove_group(group_id)
1233        }
1234        0x06 => {
1235        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1236        let friendly_name = crate::clusters::codec::json_util::get_string(args, "friendly_name")?;
1237        let vendor_id = crate::clusters::codec::json_util::get_u16(args, "vendor_id")?;
1238        let icac = crate::clusters::codec::json_util::get_octstr(args, "icac")?;
1239        encode_add_admin(node_id, friendly_name, vendor_id, icac)
1240        }
1241        0x07 => {
1242        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1243        let friendly_name = crate::clusters::codec::json_util::get_opt_string(args, "friendly_name")?;
1244        let icac = crate::clusters::codec::json_util::get_opt_octstr(args, "icac")?;
1245        encode_update_admin(node_id, friendly_name, icac)
1246        }
1247        0x08 => {
1248        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1249        encode_remove_admin(node_id)
1250        }
1251        0x09 => {
1252        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1253        let friendly_name = crate::clusters::codec::json_util::get_string(args, "friendly_name")?;
1254        encode_add_pending_node(node_id, friendly_name)
1255        }
1256        0x0A => {
1257        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1258        encode_refresh_node(node_id)
1259        }
1260        0x0B => {
1261        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1262        let friendly_name = crate::clusters::codec::json_util::get_string(args, "friendly_name")?;
1263        encode_update_node(node_id, friendly_name)
1264        }
1265        0x0C => {
1266        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1267        encode_remove_node(node_id)
1268        }
1269        0x0D => {
1270        let endpoint_id = crate::clusters::codec::json_util::get_u16(args, "endpoint_id")?;
1271        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1272        let friendly_name = crate::clusters::codec::json_util::get_string(args, "friendly_name")?;
1273        encode_update_endpoint_for_node(endpoint_id, node_id, friendly_name)
1274        }
1275        0x0E => {
1276        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1277        let endpoint_id = crate::clusters::codec::json_util::get_u16(args, "endpoint_id")?;
1278        let group_id = crate::clusters::codec::json_util::get_u16(args, "group_id")?;
1279        encode_add_group_id_to_endpoint_for_node(node_id, endpoint_id, group_id)
1280        }
1281        0x0F => {
1282        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1283        let endpoint_id = crate::clusters::codec::json_util::get_u16(args, "endpoint_id")?;
1284        let group_id = crate::clusters::codec::json_util::get_u16(args, "group_id")?;
1285        encode_remove_group_id_from_endpoint_for_node(node_id, endpoint_id, group_id)
1286        }
1287        0x10 => Err(anyhow::anyhow!("command \"AddBindingToEndpointForNode\" has complex args: use raw mode")),
1288        0x11 => {
1289        let list_id = crate::clusters::codec::json_util::get_u16(args, "list_id")?;
1290        let endpoint_id = crate::clusters::codec::json_util::get_u16(args, "endpoint_id")?;
1291        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1292        encode_remove_binding_from_endpoint_for_node(list_id, endpoint_id, node_id)
1293        }
1294        0x12 => Err(anyhow::anyhow!("command \"AddACLToNode\" has complex args: use raw mode")),
1295        0x13 => {
1296        let list_id = crate::clusters::codec::json_util::get_u16(args, "list_id")?;
1297        let node_id = crate::clusters::codec::json_util::get_u64(args, "node_id")?;
1298        encode_remove_acl_from_node(list_id, node_id)
1299        }
1300        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
1301    }
1302}
1303
1304// Typed facade (invokes + reads)
1305
1306/// Invoke `AddKeySet` command on cluster `Joint Fabric Datastore`.
1307pub async fn add_key_set(conn: &crate::controller::Connection, endpoint: u16, group_key_set: DatastoreGroupKeySet) -> anyhow::Result<()> {
1308    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_ADDKEYSET, &encode_add_key_set(group_key_set)?).await?;
1309    Ok(())
1310}
1311
1312/// Invoke `UpdateKeySet` command on cluster `Joint Fabric Datastore`.
1313pub async fn update_key_set(conn: &crate::controller::Connection, endpoint: u16, group_key_set: DatastoreGroupKeySet) -> anyhow::Result<()> {
1314    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_UPDATEKEYSET, &encode_update_key_set(group_key_set)?).await?;
1315    Ok(())
1316}
1317
1318/// Invoke `RemoveKeySet` command on cluster `Joint Fabric Datastore`.
1319pub async fn remove_key_set(conn: &crate::controller::Connection, endpoint: u16, group_key_set_id: u16) -> anyhow::Result<()> {
1320    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REMOVEKEYSET, &encode_remove_key_set(group_key_set_id)?).await?;
1321    Ok(())
1322}
1323
1324/// Invoke `AddGroup` command on cluster `Joint Fabric Datastore`.
1325pub async fn add_group(conn: &crate::controller::Connection, endpoint: u16, group_id: u16, friendly_name: String, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: DatastoreAccessControlEntryPrivilege) -> anyhow::Result<()> {
1326    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_ADDGROUP, &encode_add_group(group_id, friendly_name, group_key_set_id, group_cat, group_cat_version, group_permission)?).await?;
1327    Ok(())
1328}
1329
1330/// Invoke `UpdateGroup` command on cluster `Joint Fabric Datastore`.
1331pub async fn update_group(conn: &crate::controller::Connection, endpoint: u16, group_id: u16, friendly_name: Option<String>, group_key_set_id: Option<u16>, group_cat: Option<u16>, group_cat_version: Option<u16>, group_permission: Option<DatastoreAccessControlEntryPrivilege>) -> anyhow::Result<()> {
1332    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_UPDATEGROUP, &encode_update_group(group_id, friendly_name, group_key_set_id, group_cat, group_cat_version, group_permission)?).await?;
1333    Ok(())
1334}
1335
1336/// Invoke `RemoveGroup` command on cluster `Joint Fabric Datastore`.
1337pub async fn remove_group(conn: &crate::controller::Connection, endpoint: u16, group_id: u16) -> anyhow::Result<()> {
1338    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REMOVEGROUP, &encode_remove_group(group_id)?).await?;
1339    Ok(())
1340}
1341
1342/// Invoke `AddAdmin` command on cluster `Joint Fabric Datastore`.
1343pub async fn add_admin(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, friendly_name: String, vendor_id: u16, icac: Vec<u8>) -> anyhow::Result<()> {
1344    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_ADDADMIN, &encode_add_admin(node_id, friendly_name, vendor_id, icac)?).await?;
1345    Ok(())
1346}
1347
1348/// Invoke `UpdateAdmin` command on cluster `Joint Fabric Datastore`.
1349pub async fn update_admin(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, friendly_name: Option<String>, icac: Option<Vec<u8>>) -> anyhow::Result<()> {
1350    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_UPDATEADMIN, &encode_update_admin(node_id, friendly_name, icac)?).await?;
1351    Ok(())
1352}
1353
1354/// Invoke `RemoveAdmin` command on cluster `Joint Fabric Datastore`.
1355pub async fn remove_admin(conn: &crate::controller::Connection, endpoint: u16, node_id: u64) -> anyhow::Result<()> {
1356    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REMOVEADMIN, &encode_remove_admin(node_id)?).await?;
1357    Ok(())
1358}
1359
1360/// Invoke `AddPendingNode` command on cluster `Joint Fabric Datastore`.
1361pub async fn add_pending_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, friendly_name: String) -> anyhow::Result<()> {
1362    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_ADDPENDINGNODE, &encode_add_pending_node(node_id, friendly_name)?).await?;
1363    Ok(())
1364}
1365
1366/// Invoke `RefreshNode` command on cluster `Joint Fabric Datastore`.
1367pub async fn refresh_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64) -> anyhow::Result<()> {
1368    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REFRESHNODE, &encode_refresh_node(node_id)?).await?;
1369    Ok(())
1370}
1371
1372/// Invoke `UpdateNode` command on cluster `Joint Fabric Datastore`.
1373pub async fn update_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, friendly_name: String) -> anyhow::Result<()> {
1374    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_UPDATENODE, &encode_update_node(node_id, friendly_name)?).await?;
1375    Ok(())
1376}
1377
1378/// Invoke `RemoveNode` command on cluster `Joint Fabric Datastore`.
1379pub async fn remove_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64) -> anyhow::Result<()> {
1380    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REMOVENODE, &encode_remove_node(node_id)?).await?;
1381    Ok(())
1382}
1383
1384/// Invoke `UpdateEndpointForNode` command on cluster `Joint Fabric Datastore`.
1385pub async fn update_endpoint_for_node(conn: &crate::controller::Connection, endpoint: u16, endpoint_id: u16, node_id: u64, friendly_name: String) -> anyhow::Result<()> {
1386    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_UPDATEENDPOINTFORNODE, &encode_update_endpoint_for_node(endpoint_id, node_id, friendly_name)?).await?;
1387    Ok(())
1388}
1389
1390/// Invoke `AddGroupIDToEndpointForNode` command on cluster `Joint Fabric Datastore`.
1391pub async fn add_group_id_to_endpoint_for_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, endpoint_id: u16, group_id: u16) -> anyhow::Result<()> {
1392    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_ADDGROUPIDTOENDPOINTFORNODE, &encode_add_group_id_to_endpoint_for_node(node_id, endpoint_id, group_id)?).await?;
1393    Ok(())
1394}
1395
1396/// Invoke `RemoveGroupIDFromEndpointForNode` command on cluster `Joint Fabric Datastore`.
1397pub async fn remove_group_id_from_endpoint_for_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, endpoint_id: u16, group_id: u16) -> anyhow::Result<()> {
1398    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REMOVEGROUPIDFROMENDPOINTFORNODE, &encode_remove_group_id_from_endpoint_for_node(node_id, endpoint_id, group_id)?).await?;
1399    Ok(())
1400}
1401
1402/// Invoke `AddBindingToEndpointForNode` command on cluster `Joint Fabric Datastore`.
1403pub async fn add_binding_to_endpoint_for_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, endpoint_id: u16, binding: DatastoreBindingTarget) -> anyhow::Result<()> {
1404    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_ADDBINDINGTOENDPOINTFORNODE, &encode_add_binding_to_endpoint_for_node(node_id, endpoint_id, binding)?).await?;
1405    Ok(())
1406}
1407
1408/// Invoke `RemoveBindingFromEndpointForNode` command on cluster `Joint Fabric Datastore`.
1409pub async fn remove_binding_from_endpoint_for_node(conn: &crate::controller::Connection, endpoint: u16, list_id: u16, endpoint_id: u16, node_id: u64) -> anyhow::Result<()> {
1410    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REMOVEBINDINGFROMENDPOINTFORNODE, &encode_remove_binding_from_endpoint_for_node(list_id, endpoint_id, node_id)?).await?;
1411    Ok(())
1412}
1413
1414/// Invoke `AddACLToNode` command on cluster `Joint Fabric Datastore`.
1415pub async fn add_acl_to_node(conn: &crate::controller::Connection, endpoint: u16, node_id: u64, acl_entry: DatastoreAccessControlEntry) -> anyhow::Result<()> {
1416    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_ADDACLTONODE, &encode_add_acl_to_node(node_id, acl_entry)?).await?;
1417    Ok(())
1418}
1419
1420/// Invoke `RemoveACLFromNode` command on cluster `Joint Fabric Datastore`.
1421pub async fn remove_acl_from_node(conn: &crate::controller::Connection, endpoint: u16, list_id: u16, node_id: u64) -> anyhow::Result<()> {
1422    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_CMD_ID_REMOVEACLFROMNODE, &encode_remove_acl_from_node(list_id, node_id)?).await?;
1423    Ok(())
1424}
1425
1426/// Read `AnchorRootCA` attribute from cluster `Joint Fabric Datastore`.
1427pub async fn read_anchor_root_ca(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<u8>> {
1428    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_ANCHORROOTCA).await?;
1429    decode_anchor_root_ca(&tlv)
1430}
1431
1432/// Read `AnchorNodeID` attribute from cluster `Joint Fabric Datastore`.
1433pub async fn read_anchor_node_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u64> {
1434    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_ANCHORNODEID).await?;
1435    decode_anchor_node_id(&tlv)
1436}
1437
1438/// Read `AnchorVendorID` attribute from cluster `Joint Fabric Datastore`.
1439pub async fn read_anchor_vendor_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
1440    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_ANCHORVENDORID).await?;
1441    decode_anchor_vendor_id(&tlv)
1442}
1443
1444/// Read `FriendlyName` attribute from cluster `Joint Fabric Datastore`.
1445pub async fn read_friendly_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
1446    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_FRIENDLYNAME).await?;
1447    decode_friendly_name(&tlv)
1448}
1449
1450/// Read `GroupKeySetList` attribute from cluster `Joint Fabric Datastore`.
1451pub async fn read_group_key_set_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreGroupKeySet>> {
1452    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_GROUPKEYSETLIST).await?;
1453    decode_group_key_set_list(&tlv)
1454}
1455
1456/// Read `GroupList` attribute from cluster `Joint Fabric Datastore`.
1457pub async fn read_group_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreGroupInformationEntry>> {
1458    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_GROUPLIST).await?;
1459    decode_group_list(&tlv)
1460}
1461
1462/// Read `NodeList` attribute from cluster `Joint Fabric Datastore`.
1463pub async fn read_node_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreNodeInformationEntry>> {
1464    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_NODELIST).await?;
1465    decode_node_list(&tlv)
1466}
1467
1468/// Read `AdminList` attribute from cluster `Joint Fabric Datastore`.
1469pub async fn read_admin_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreAdministratorInformationEntry>> {
1470    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_ADMINLIST).await?;
1471    decode_admin_list(&tlv)
1472}
1473
1474/// Read `Status` attribute from cluster `Joint Fabric Datastore`.
1475pub async fn read_status(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<DatastoreStatusEntry> {
1476    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_STATUS).await?;
1477    decode_status(&tlv)
1478}
1479
1480/// Read `EndpointGroupIDList` attribute from cluster `Joint Fabric Datastore`.
1481pub async fn read_endpoint_group_id_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreEndpointGroupIDEntry>> {
1482    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_ENDPOINTGROUPIDLIST).await?;
1483    decode_endpoint_group_id_list(&tlv)
1484}
1485
1486/// Read `EndpointBindingList` attribute from cluster `Joint Fabric Datastore`.
1487pub async fn read_endpoint_binding_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreEndpointBindingEntry>> {
1488    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_ENDPOINTBINDINGLIST).await?;
1489    decode_endpoint_binding_list(&tlv)
1490}
1491
1492/// Read `NodeKeySetList` attribute from cluster `Joint Fabric Datastore`.
1493pub async fn read_node_key_set_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreNodeKeySetEntry>> {
1494    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_NODEKEYSETLIST).await?;
1495    decode_node_key_set_list(&tlv)
1496}
1497
1498/// Read `NodeACLList` attribute from cluster `Joint Fabric Datastore`.
1499pub async fn read_node_acl_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreACLEntry>> {
1500    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_NODEACLLIST).await?;
1501    decode_node_acl_list(&tlv)
1502}
1503
1504/// Read `NodeEndpointList` attribute from cluster `Joint Fabric Datastore`.
1505pub async fn read_node_endpoint_list(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DatastoreEndpointEntry>> {
1506    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_JOINT_FABRIC_DATASTORE, crate::clusters::defs::CLUSTER_JOINT_FABRIC_DATASTORE_ATTR_ID_NODEENDPOINTLIST).await?;
1507    decode_node_endpoint_list(&tlv)
1508}
1509