matc/clusters/codec/
joint_fabric_datastore_cluster.rs

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