1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum FutureMessagePreference {
16 Allowed = 0,
18 Increased = 1,
20 Reduced = 2,
22 Disallowed = 3,
24 Banned = 4,
26}
27
28impl FutureMessagePreference {
29 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 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 Low = 0,
58 Medium = 1,
60 High = 2,
62 Critical = 3,
64}
65
66impl MessagePriority {
67 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 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
90pub type MessageControl = u8;
94
95pub mod messagecontrol {
97 pub const CONFIRMATION_REQUIRED: u8 = 0x01;
99 pub const RESPONSE_REQUIRED: u8 = 0x02;
101 pub const REPLY_MESSAGE: u8 = 0x04;
103 pub const MESSAGE_CONFIRMED: u8 = 0x08;
105 pub const MESSAGE_PROTECTED: u8 = 0x10;
107}
108
109#[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
128pub 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
152pub 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
163pub 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
197pub 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
211pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
223 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
245pub 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
274pub 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
288pub 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
300pub 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