matc/clusters/codec/
messages.rs

1//! Matter TLV encoders and decoders for Messages Cluster
2//! Cluster ID: 0x0097
3//!
4//! This file is automatically generated from Messages.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Enum definitions
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum FutureMessagePreference {
16    /// Similar messages are allowed
17    Allowed = 0,
18    /// Similar messages should be sent more often
19    Increased = 1,
20    /// Similar messages should be sent less often
21    Reduced = 2,
22    /// Similar messages should not be sent
23    Disallowed = 3,
24    /// No further messages should be sent
25    Banned = 4,
26}
27
28impl FutureMessagePreference {
29    /// Convert from u8 value
30    pub fn from_u8(value: u8) -> Option<Self> {
31        match value {
32            0 => Some(FutureMessagePreference::Allowed),
33            1 => Some(FutureMessagePreference::Increased),
34            2 => Some(FutureMessagePreference::Reduced),
35            3 => Some(FutureMessagePreference::Disallowed),
36            4 => Some(FutureMessagePreference::Banned),
37            _ => None,
38        }
39    }
40
41    /// Convert to u8 value
42    pub fn to_u8(self) -> u8 {
43        self as u8
44    }
45}
46
47impl From<FutureMessagePreference> for u8 {
48    fn from(val: FutureMessagePreference) -> Self {
49        val as u8
50    }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
54#[repr(u8)]
55pub enum MessagePriority {
56    /// Message to be transferred with a low level of importance
57    Low = 0,
58    /// Message to be transferred with a medium level of importance
59    Medium = 1,
60    /// Message to be transferred with a high level of importance
61    High = 2,
62    /// Message to be transferred with a critical level of importance
63    Critical = 3,
64}
65
66impl MessagePriority {
67    /// Convert from u8 value
68    pub fn from_u8(value: u8) -> Option<Self> {
69        match value {
70            0 => Some(MessagePriority::Low),
71            1 => Some(MessagePriority::Medium),
72            2 => Some(MessagePriority::High),
73            3 => Some(MessagePriority::Critical),
74            _ => None,
75        }
76    }
77
78    /// Convert to u8 value
79    pub fn to_u8(self) -> u8 {
80        self as u8
81    }
82}
83
84impl From<MessagePriority> for u8 {
85    fn from(val: MessagePriority) -> Self {
86        val as u8
87    }
88}
89
90// Bitmap definitions
91
92/// MessageControl bitmap type
93pub type MessageControl = u8;
94
95/// Constants for MessageControl
96pub mod messagecontrol {
97    /// Message requires confirmation from user
98    pub const CONFIRMATION_REQUIRED: u8 = 0x01;
99    /// Message requires response from user
100    pub const RESPONSE_REQUIRED: u8 = 0x02;
101    /// Message supports reply message from user
102    pub const REPLY_MESSAGE: u8 = 0x04;
103    /// Message has already been confirmed
104    pub const MESSAGE_CONFIRMED: u8 = 0x08;
105    /// Message required PIN/password protection
106    pub const MESSAGE_PROTECTED: u8 = 0x10;
107}
108
109// Struct definitions
110
111#[derive(Debug, serde::Serialize)]
112pub struct MessageResponseOption {
113    pub message_response_id: Option<u32>,
114    pub label: Option<String>,
115}
116
117#[derive(Debug, serde::Serialize)]
118pub struct Message {
119    pub message_id: Option<u8>,
120    pub priority: Option<MessagePriority>,
121    pub message_control: Option<MessageControl>,
122    pub start_time: Option<u64>,
123    pub duration: Option<u64>,
124    pub message_text: Option<String>,
125    pub responses: Option<Vec<MessageResponseOption>>,
126}
127
128// Command encoders
129
130/// Encode PresentMessagesRequest command (0x00)
131pub fn encode_present_messages_request(message_id: u8, priority: MessagePriority, message_control: MessageControl, start_time: Option<u64>, duration: Option<u64>, message_text: String, responses: Vec<MessageResponseOption>) -> anyhow::Result<Vec<u8>> {
132    let tlv = tlv::TlvItemEnc {
133        tag: 0,
134        value: tlv::TlvItemValueEnc::StructInvisible(vec![
135        (0, tlv::TlvItemValueEnc::UInt8(message_id)).into(),
136        (1, tlv::TlvItemValueEnc::UInt8(priority.to_u8())).into(),
137        (2, tlv::TlvItemValueEnc::UInt8(message_control)).into(),
138        (3, tlv::TlvItemValueEnc::UInt64(start_time.unwrap_or(0))).into(),
139        (4, tlv::TlvItemValueEnc::UInt64(duration.unwrap_or(0))).into(),
140        (5, tlv::TlvItemValueEnc::String(message_text)).into(),
141        (6, tlv::TlvItemValueEnc::Array(responses.into_iter().map(|v| {
142                    let mut fields = Vec::new();
143                    if let Some(x) = v.message_response_id { fields.push((0, tlv::TlvItemValueEnc::UInt32(x)).into()); }
144                    if let Some(x) = v.label { fields.push((1, tlv::TlvItemValueEnc::String(x.clone())).into()); }
145                    (0, tlv::TlvItemValueEnc::StructAnon(fields)).into()
146                }).collect())).into(),
147        ]),
148    };
149    Ok(tlv.encode()?)
150}
151
152/// Encode CancelMessagesRequest command (0x01)
153pub fn encode_cancel_messages_request(message_i_ds: Vec<u8>) -> anyhow::Result<Vec<u8>> {
154    let tlv = tlv::TlvItemEnc {
155        tag: 0,
156        value: tlv::TlvItemValueEnc::StructInvisible(vec![
157        (0, tlv::TlvItemValueEnc::StructAnon(message_i_ds.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
158        ]),
159    };
160    Ok(tlv.encode()?)
161}
162
163// Attribute decoders
164
165/// Decode Messages attribute (0x0000)
166pub fn decode_messages(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Message>> {
167    let mut res = Vec::new();
168    if let tlv::TlvItemValue::List(v) = inp {
169        for item in v {
170            res.push(Message {
171                message_id: item.get_int(&[0]).map(|v| v as u8),
172                priority: item.get_int(&[1]).and_then(|v| MessagePriority::from_u8(v as u8)),
173                message_control: item.get_int(&[2]).map(|v| v as u8),
174                start_time: item.get_int(&[3]),
175                duration: item.get_int(&[4]),
176                message_text: item.get_string_owned(&[5]),
177                responses: {
178                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
179                        let mut items = Vec::new();
180                        for list_item in l {
181                            items.push(MessageResponseOption {
182                message_response_id: list_item.get_int(&[0]).map(|v| v as u32),
183                label: list_item.get_string_owned(&[1]),
184                            });
185                        }
186                        Some(items)
187                    } else {
188                        None
189                    }
190                },
191            });
192        }
193    }
194    Ok(res)
195}
196
197/// Decode ActiveMessageIDs attribute (0x0001)
198pub fn decode_active_message_i_ds(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
199    let mut res = Vec::new();
200    if let tlv::TlvItemValue::List(v) = inp {
201        for item in v {
202            if let tlv::TlvItemValue::Int(i) = &item.value {
203                res.push(*i as u8);
204            }
205        }
206    }
207    Ok(res)
208}
209
210
211// JSON dispatcher function
212
213/// Decode attribute value and return as JSON string
214///
215/// # Parameters
216/// * `cluster_id` - The cluster identifier
217/// * `attribute_id` - The attribute identifier
218/// * `tlv_value` - The TLV value to decode
219///
220/// # Returns
221/// JSON string representation of the decoded value or error
222pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
223    // Verify this is the correct cluster
224    if cluster_id != 0x0097 {
225        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0097, got {}\"}}", cluster_id);
226    }
227
228    match attribute_id {
229        0x0000 => {
230            match decode_messages(tlv_value) {
231                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
232                Err(e) => format!("{{\"error\": \"{}\"}}", e),
233            }
234        }
235        0x0001 => {
236            match decode_active_message_i_ds(tlv_value) {
237                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
238                Err(e) => format!("{{\"error\": \"{}\"}}", e),
239            }
240        }
241        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
242    }
243}
244
245/// Get list of all attributes supported by this cluster
246///
247/// # Returns
248/// Vector of tuples containing (attribute_id, attribute_name)
249pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
250    vec![
251        (0x0000, "Messages"),
252        (0x0001, "ActiveMessageIDs"),
253    ]
254}
255
256#[derive(Debug, serde::Serialize)]
257pub struct MessageQueuedEvent {
258    pub message_id: Option<u8>,
259}
260
261#[derive(Debug, serde::Serialize)]
262pub struct MessagePresentedEvent {
263    pub message_id: Option<u8>,
264}
265
266#[derive(Debug, serde::Serialize)]
267pub struct MessageCompleteEvent {
268    pub message_id: Option<u8>,
269    pub response_id: Option<u32>,
270    pub reply: Option<String>,
271    pub future_messages_preference: Option<FutureMessagePreference>,
272}
273
274// Event decoders
275
276/// Decode MessageQueued event (0x00, priority: info)
277pub fn decode_message_queued_event(inp: &tlv::TlvItemValue) -> anyhow::Result<MessageQueuedEvent> {
278    if let tlv::TlvItemValue::List(_fields) = inp {
279        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
280        Ok(MessageQueuedEvent {
281                                message_id: item.get_int(&[0]).map(|v| v as u8),
282        })
283    } else {
284        Err(anyhow::anyhow!("Expected struct fields"))
285    }
286}
287
288/// Decode MessagePresented event (0x01, priority: info)
289pub fn decode_message_presented_event(inp: &tlv::TlvItemValue) -> anyhow::Result<MessagePresentedEvent> {
290    if let tlv::TlvItemValue::List(_fields) = inp {
291        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
292        Ok(MessagePresentedEvent {
293                                message_id: item.get_int(&[0]).map(|v| v as u8),
294        })
295    } else {
296        Err(anyhow::anyhow!("Expected struct fields"))
297    }
298}
299
300/// Decode MessageComplete event (0x02, priority: info)
301pub fn decode_message_complete_event(inp: &tlv::TlvItemValue) -> anyhow::Result<MessageCompleteEvent> {
302    if let tlv::TlvItemValue::List(_fields) = inp {
303        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
304        Ok(MessageCompleteEvent {
305                                message_id: item.get_int(&[0]).map(|v| v as u8),
306                                response_id: item.get_int(&[1]).map(|v| v as u32),
307                                reply: item.get_string_owned(&[2]),
308                                future_messages_preference: item.get_int(&[3]).and_then(|v| FutureMessagePreference::from_u8(v as u8)),
309        })
310    } else {
311        Err(anyhow::anyhow!("Expected struct fields"))
312    }
313}
314