matc/clusters/codec/
admin_commissioning_cluster.rs

1//! Matter TLV encoders and decoders for Administrator Commissioning Cluster
2//! Cluster ID: 0x003C
3//!
4//! This file is automatically generated from AdminCommissioningCluster.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Enum definitions
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum CommissioningWindowStatus {
18    /// Commissioning window not open
19    Windownotopen = 0,
20    /// An Enhanced Commissioning Method window is open
21    Enhancedwindowopen = 1,
22    /// A Basic Commissioning Method window is open
23    Basicwindowopen = 2,
24}
25
26impl CommissioningWindowStatus {
27    /// Convert from u8 value
28    pub fn from_u8(value: u8) -> Option<Self> {
29        match value {
30            0 => Some(CommissioningWindowStatus::Windownotopen),
31            1 => Some(CommissioningWindowStatus::Enhancedwindowopen),
32            2 => Some(CommissioningWindowStatus::Basicwindowopen),
33            _ => None,
34        }
35    }
36
37    /// Convert to u8 value
38    pub fn to_u8(self) -> u8 {
39        self as u8
40    }
41}
42
43impl From<CommissioningWindowStatus> for u8 {
44    fn from(val: CommissioningWindowStatus) -> Self {
45        val as u8
46    }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
50#[repr(u8)]
51pub enum StatusCode {
52    /// Could not be completed because another commissioning is in progress
53    Busy = 2,
54    /// Provided PAKE parameters were incorrectly formatted or otherwise invalid
55    Pakeparametererror = 3,
56    /// No commissioning window was currently open
57    Windownotopen = 4,
58}
59
60impl StatusCode {
61    /// Convert from u8 value
62    pub fn from_u8(value: u8) -> Option<Self> {
63        match value {
64            2 => Some(StatusCode::Busy),
65            3 => Some(StatusCode::Pakeparametererror),
66            4 => Some(StatusCode::Windownotopen),
67            _ => None,
68        }
69    }
70
71    /// Convert to u8 value
72    pub fn to_u8(self) -> u8 {
73        self as u8
74    }
75}
76
77impl From<StatusCode> for u8 {
78    fn from(val: StatusCode) -> Self {
79        val as u8
80    }
81}
82
83// Command encoders
84
85/// Encode OpenCommissioningWindow command (0x00)
86pub fn encode_open_commissioning_window(commissioning_timeout: u16, pake_passcode_verifier: Vec<u8>, discriminator: u16, iterations: u32, salt: Vec<u8>) -> anyhow::Result<Vec<u8>> {
87    let tlv = tlv::TlvItemEnc {
88        tag: 0,
89        value: tlv::TlvItemValueEnc::StructInvisible(vec![
90        (0, tlv::TlvItemValueEnc::UInt16(commissioning_timeout)).into(),
91        (1, tlv::TlvItemValueEnc::OctetString(pake_passcode_verifier)).into(),
92        (2, tlv::TlvItemValueEnc::UInt16(discriminator)).into(),
93        (3, tlv::TlvItemValueEnc::UInt32(iterations)).into(),
94        (4, tlv::TlvItemValueEnc::OctetString(salt)).into(),
95        ]),
96    };
97    Ok(tlv.encode()?)
98}
99
100/// Encode OpenBasicCommissioningWindow command (0x01)
101pub fn encode_open_basic_commissioning_window(commissioning_timeout: u16) -> anyhow::Result<Vec<u8>> {
102    let tlv = tlv::TlvItemEnc {
103        tag: 0,
104        value: tlv::TlvItemValueEnc::StructInvisible(vec![
105        (0, tlv::TlvItemValueEnc::UInt16(commissioning_timeout)).into(),
106        ]),
107    };
108    Ok(tlv.encode()?)
109}
110
111// Attribute decoders
112
113/// Decode WindowStatus attribute (0x0000)
114pub fn decode_window_status(inp: &tlv::TlvItemValue) -> anyhow::Result<CommissioningWindowStatus> {
115    if let tlv::TlvItemValue::Int(v) = inp {
116        CommissioningWindowStatus::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
117    } else {
118        Err(anyhow::anyhow!("Expected Integer"))
119    }
120}
121
122/// Decode AdminFabricIndex attribute (0x0001)
123pub fn decode_admin_fabric_index(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
124    if let tlv::TlvItemValue::Int(v) = inp {
125        Ok(Some(*v as u8))
126    } else {
127        Ok(None)
128    }
129}
130
131/// Decode AdminVendorId attribute (0x0002)
132pub fn decode_admin_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
133    if let tlv::TlvItemValue::Int(v) = inp {
134        Ok(Some(*v as u16))
135    } else {
136        Ok(None)
137    }
138}
139
140
141// JSON dispatcher function
142
143/// Decode attribute value and return as JSON string
144///
145/// # Parameters
146/// * `cluster_id` - The cluster identifier
147/// * `attribute_id` - The attribute identifier
148/// * `tlv_value` - The TLV value to decode
149///
150/// # Returns
151/// JSON string representation of the decoded value or error
152pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
153    // Verify this is the correct cluster
154    if cluster_id != 0x003C {
155        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x003C, got {}\"}}", cluster_id);
156    }
157
158    match attribute_id {
159        0x0000 => {
160            match decode_window_status(tlv_value) {
161                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
162                Err(e) => format!("{{\"error\": \"{}\"}}", e),
163            }
164        }
165        0x0001 => {
166            match decode_admin_fabric_index(tlv_value) {
167                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
168                Err(e) => format!("{{\"error\": \"{}\"}}", e),
169            }
170        }
171        0x0002 => {
172            match decode_admin_vendor_id(tlv_value) {
173                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
174                Err(e) => format!("{{\"error\": \"{}\"}}", e),
175            }
176        }
177        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
178    }
179}
180
181/// Get list of all attributes supported by this cluster
182///
183/// # Returns
184/// Vector of tuples containing (attribute_id, attribute_name)
185pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
186    vec![
187        (0x0000, "WindowStatus"),
188        (0x0001, "AdminFabricIndex"),
189        (0x0002, "AdminVendorId"),
190    ]
191}
192
193// Command listing
194
195pub fn get_command_list() -> Vec<(u32, &'static str)> {
196    vec![
197        (0x00, "OpenCommissioningWindow"),
198        (0x01, "OpenBasicCommissioningWindow"),
199        (0x02, "RevokeCommissioning"),
200    ]
201}
202
203pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
204    match cmd_id {
205        0x00 => Some("OpenCommissioningWindow"),
206        0x01 => Some("OpenBasicCommissioningWindow"),
207        0x02 => Some("RevokeCommissioning"),
208        _ => None,
209    }
210}
211
212pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
213    match cmd_id {
214        0x00 => Some(vec![
215            crate::clusters::codec::CommandField { tag: 0, name: "commissioning_timeout", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
216            crate::clusters::codec::CommandField { tag: 1, name: "pake_passcode_verifier", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
217            crate::clusters::codec::CommandField { tag: 2, name: "discriminator", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
218            crate::clusters::codec::CommandField { tag: 3, name: "iterations", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
219            crate::clusters::codec::CommandField { tag: 4, name: "salt", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
220        ]),
221        0x01 => Some(vec![
222            crate::clusters::codec::CommandField { tag: 0, name: "commissioning_timeout", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
223        ]),
224        0x02 => Some(vec![]),
225        _ => None,
226    }
227}
228
229pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
230    match cmd_id {
231        0x00 => {
232        let commissioning_timeout = crate::clusters::codec::json_util::get_u16(args, "commissioning_timeout")?;
233        let pake_passcode_verifier = crate::clusters::codec::json_util::get_octstr(args, "pake_passcode_verifier")?;
234        let discriminator = crate::clusters::codec::json_util::get_u16(args, "discriminator")?;
235        let iterations = crate::clusters::codec::json_util::get_u32(args, "iterations")?;
236        let salt = crate::clusters::codec::json_util::get_octstr(args, "salt")?;
237        encode_open_commissioning_window(commissioning_timeout, pake_passcode_verifier, discriminator, iterations, salt)
238        }
239        0x01 => {
240        let commissioning_timeout = crate::clusters::codec::json_util::get_u16(args, "commissioning_timeout")?;
241        encode_open_basic_commissioning_window(commissioning_timeout)
242        }
243        0x02 => Ok(vec![]),
244        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
245    }
246}
247
248// Typed facade (invokes + reads)
249
250/// Invoke `OpenCommissioningWindow` command on cluster `Administrator Commissioning`.
251pub async fn open_commissioning_window(conn: &crate::controller::Connection, endpoint: u16, commissioning_timeout: u16, pake_passcode_verifier: Vec<u8>, discriminator: u16, iterations: u32, salt: Vec<u8>) -> anyhow::Result<()> {
252    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_ADMINISTRATOR_COMMISSIONING, crate::clusters::defs::CLUSTER_ADMINISTRATOR_COMMISSIONING_CMD_ID_OPENCOMMISSIONINGWINDOW, &encode_open_commissioning_window(commissioning_timeout, pake_passcode_verifier, discriminator, iterations, salt)?).await?;
253    Ok(())
254}
255
256/// Invoke `OpenBasicCommissioningWindow` command on cluster `Administrator Commissioning`.
257pub async fn open_basic_commissioning_window(conn: &crate::controller::Connection, endpoint: u16, commissioning_timeout: u16) -> anyhow::Result<()> {
258    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_ADMINISTRATOR_COMMISSIONING, crate::clusters::defs::CLUSTER_ADMINISTRATOR_COMMISSIONING_CMD_ID_OPENBASICCOMMISSIONINGWINDOW, &encode_open_basic_commissioning_window(commissioning_timeout)?).await?;
259    Ok(())
260}
261
262/// Invoke `RevokeCommissioning` command on cluster `Administrator Commissioning`.
263pub async fn revoke_commissioning(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
264    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_ADMINISTRATOR_COMMISSIONING, crate::clusters::defs::CLUSTER_ADMINISTRATOR_COMMISSIONING_CMD_ID_REVOKECOMMISSIONING, &[]).await?;
265    Ok(())
266}
267
268/// Read `WindowStatus` attribute from cluster `Administrator Commissioning`.
269pub async fn read_window_status(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CommissioningWindowStatus> {
270    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ADMINISTRATOR_COMMISSIONING, crate::clusters::defs::CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_WINDOWSTATUS).await?;
271    decode_window_status(&tlv)
272}
273
274/// Read `AdminFabricIndex` attribute from cluster `Administrator Commissioning`.
275pub async fn read_admin_fabric_index(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
276    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ADMINISTRATOR_COMMISSIONING, crate::clusters::defs::CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_ADMINFABRICINDEX).await?;
277    decode_admin_fabric_index(&tlv)
278}
279
280/// Read `AdminVendorId` attribute from cluster `Administrator Commissioning`.
281pub async fn read_admin_vendor_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u16>> {
282    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ADMINISTRATOR_COMMISSIONING, crate::clusters::defs::CLUSTER_ADMINISTRATOR_COMMISSIONING_ATTR_ID_ADMINVENDORID).await?;
283    decode_admin_vendor_id(&tlv)
284}
285