matc/clusters/codec/
mode_base.rs

1//! Matter TLV encoders and decoders for Mode Base Cluster
2//! Cluster ID: 0x0000
3//!
4//! This file is automatically generated from ModeBase.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Struct definitions
14
15#[derive(Debug, serde::Serialize)]
16pub struct ModeOption {
17    pub label: Option<String>,
18    pub mode: Option<u8>,
19    pub mode_tags: Option<Vec<ModeTag>>,
20}
21
22#[derive(Debug, serde::Serialize)]
23pub struct ModeTag {
24    pub mfg_code: Option<u16>,
25    pub value: Option<u16>,
26}
27
28// Command encoders
29
30/// Encode ChangeToMode command (0x00)
31pub fn encode_change_to_mode(new_mode: u8) -> anyhow::Result<Vec<u8>> {
32    let tlv = tlv::TlvItemEnc {
33        tag: 0,
34        value: tlv::TlvItemValueEnc::StructInvisible(vec![
35        (0, tlv::TlvItemValueEnc::UInt8(new_mode)).into(),
36        ]),
37    };
38    Ok(tlv.encode()?)
39}
40
41// Attribute decoders
42
43/// Decode SupportedModes attribute (0x0000)
44pub fn decode_supported_modes(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ModeOption>> {
45    let mut res = Vec::new();
46    if let tlv::TlvItemValue::List(v) = inp {
47        for item in v {
48            res.push(ModeOption {
49                label: item.get_string_owned(&[0]),
50                mode: item.get_int(&[1]).map(|v| v as u8),
51                mode_tags: {
52                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
53                        let mut items = Vec::new();
54                        for list_item in l {
55                            items.push(ModeTag {
56                mfg_code: list_item.get_int(&[0]).map(|v| v as u16),
57                value: list_item.get_int(&[1]).map(|v| v as u16),
58                            });
59                        }
60                        Some(items)
61                    } else {
62                        None
63                    }
64                },
65            });
66        }
67    }
68    Ok(res)
69}
70
71/// Decode CurrentMode attribute (0x0001)
72pub fn decode_current_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
73    if let tlv::TlvItemValue::Int(v) = inp {
74        Ok(*v as u8)
75    } else {
76        Err(anyhow::anyhow!("Expected UInt8"))
77    }
78}
79
80/// Decode StartUpMode attribute (0x0002)
81pub fn decode_start_up_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
82    if let tlv::TlvItemValue::Int(v) = inp {
83        Ok(Some(*v as u8))
84    } else {
85        Ok(None)
86    }
87}
88
89/// Decode OnMode attribute (0x0003)
90pub fn decode_on_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
91    if let tlv::TlvItemValue::Int(v) = inp {
92        Ok(Some(*v as u8))
93    } else {
94        Ok(None)
95    }
96}
97
98
99// JSON dispatcher function
100
101/// Decode attribute value and return as JSON string
102///
103/// # Parameters
104/// * `cluster_id` - The cluster identifier
105/// * `attribute_id` - The attribute identifier
106/// * `tlv_value` - The TLV value to decode
107///
108/// # Returns
109/// JSON string representation of the decoded value or error
110pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
111    // Verify this is the correct cluster
112    if cluster_id != 0x0000 {
113        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0000, got {}\"}}", cluster_id);
114    }
115
116    match attribute_id {
117        0x0000 => {
118            match decode_supported_modes(tlv_value) {
119                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
120                Err(e) => format!("{{\"error\": \"{}\"}}", e),
121            }
122        }
123        0x0001 => {
124            match decode_current_mode(tlv_value) {
125                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
126                Err(e) => format!("{{\"error\": \"{}\"}}", e),
127            }
128        }
129        0x0002 => {
130            match decode_start_up_mode(tlv_value) {
131                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
132                Err(e) => format!("{{\"error\": \"{}\"}}", e),
133            }
134        }
135        0x0003 => {
136            match decode_on_mode(tlv_value) {
137                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
138                Err(e) => format!("{{\"error\": \"{}\"}}", e),
139            }
140        }
141        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
142    }
143}
144
145/// Get list of all attributes supported by this cluster
146///
147/// # Returns
148/// Vector of tuples containing (attribute_id, attribute_name)
149pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
150    vec![
151        (0x0000, "SupportedModes"),
152        (0x0001, "CurrentMode"),
153        (0x0002, "StartUpMode"),
154        (0x0003, "OnMode"),
155    ]
156}
157
158// Command listing
159
160pub fn get_command_list() -> Vec<(u32, &'static str)> {
161    vec![
162        (0x00, "ChangeToMode"),
163    ]
164}
165
166pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
167    match cmd_id {
168        0x00 => Some("ChangeToMode"),
169        _ => None,
170    }
171}
172
173pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
174    match cmd_id {
175        0x00 => Some(vec![
176            crate::clusters::codec::CommandField { tag: 0, name: "new_mode", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
177        ]),
178        _ => None,
179    }
180}
181
182pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
183    match cmd_id {
184        0x00 => {
185        let new_mode = crate::clusters::codec::json_util::get_u8(args, "new_mode")?;
186        encode_change_to_mode(new_mode)
187        }
188        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
189    }
190}
191
192#[derive(Debug, serde::Serialize)]
193pub struct ChangeToModeResponse {
194    pub status: Option<u8>,
195    pub status_text: Option<String>,
196}
197
198// Command response decoders
199
200/// Decode ChangeToModeResponse command response (01)
201pub fn decode_change_to_mode_response(inp: &tlv::TlvItemValue) -> anyhow::Result<ChangeToModeResponse> {
202    if let tlv::TlvItemValue::List(_fields) = inp {
203        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
204        Ok(ChangeToModeResponse {
205                status: item.get_int(&[0]).map(|v| v as u8),
206                status_text: item.get_string_owned(&[1]),
207        })
208    } else {
209        Err(anyhow::anyhow!("Expected struct fields"))
210    }
211}
212