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 ClientType {
16 Permanent = 0,
18 Ephemeral = 1,
20}
21
22impl ClientType {
23 pub fn from_u8(value: u8) -> Option<Self> {
25 match value {
26 0 => Some(ClientType::Permanent),
27 1 => Some(ClientType::Ephemeral),
28 _ => None,
29 }
30 }
31
32 pub fn to_u8(self) -> u8 {
34 self as u8
35 }
36}
37
38impl From<ClientType> for u8 {
39 fn from(val: ClientType) -> Self {
40 val as u8
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
45#[repr(u8)]
46pub enum OperatingMode {
47 Sit = 0,
49 Lit = 1,
51}
52
53impl OperatingMode {
54 pub fn from_u8(value: u8) -> Option<Self> {
56 match value {
57 0 => Some(OperatingMode::Sit),
58 1 => Some(OperatingMode::Lit),
59 _ => None,
60 }
61 }
62
63 pub fn to_u8(self) -> u8 {
65 self as u8
66 }
67}
68
69impl From<OperatingMode> for u8 {
70 fn from(val: OperatingMode) -> Self {
71 val as u8
72 }
73}
74
75pub type UserActiveModeTrigger = u32;
79
80pub mod useractivemodetrigger {
82 pub const POWER_CYCLE: u32 = 0x01;
84 pub const SETTINGS_MENU: u32 = 0x02;
86 pub const CUSTOM_INSTRUCTION: u32 = 0x04;
88 pub const DEVICE_MANUAL: u32 = 0x08;
90 pub const ACTUATE_SENSOR: u32 = 0x10;
92 pub const ACTUATE_SENSOR_SECONDS: u32 = 0x20;
94 pub const ACTUATE_SENSOR_TIMES: u32 = 0x40;
96 pub const ACTUATE_SENSOR_LIGHTS_BLINK: u32 = 0x80;
98 pub const RESET_BUTTON: u32 = 0x100;
100 pub const RESET_BUTTON_LIGHTS_BLINK: u32 = 0x200;
102 pub const RESET_BUTTON_SECONDS: u32 = 0x400;
104 pub const RESET_BUTTON_TIMES: u32 = 0x800;
106 pub const SETUP_BUTTON: u32 = 0x1000;
108 pub const SETUP_BUTTON_SECONDS: u32 = 0x2000;
110 pub const SETUP_BUTTON_LIGHTS_BLINK: u32 = 0x4000;
112 pub const SETUP_BUTTON_TIMES: u32 = 0x8000;
114 pub const APP_DEFINED_BUTTON: u32 = 0x10000;
116}
117
118#[derive(Debug, serde::Serialize)]
121pub struct MonitoringRegistration {
122 pub check_in_node_id: Option<u64>,
123 pub monitored_subject: Option<u64>,
124 pub key: Option<u8>,
125 pub client_type: Option<ClientType>,
126}
127
128pub fn encode_register_client(check_in_node_id: u64, monitored_subject: u64, key: Vec<u8>, verification_key: Vec<u8>, client_type: ClientType) -> anyhow::Result<Vec<u8>> {
132 let tlv = tlv::TlvItemEnc {
133 tag: 0,
134 value: tlv::TlvItemValueEnc::StructInvisible(vec![
135 (0, tlv::TlvItemValueEnc::UInt64(check_in_node_id)).into(),
136 (1, tlv::TlvItemValueEnc::UInt64(monitored_subject)).into(),
137 (2, tlv::TlvItemValueEnc::OctetString(key)).into(),
138 (3, tlv::TlvItemValueEnc::OctetString(verification_key)).into(),
139 (4, tlv::TlvItemValueEnc::UInt8(client_type.to_u8())).into(),
140 ]),
141 };
142 Ok(tlv.encode()?)
143}
144
145pub fn encode_unregister_client(check_in_node_id: u64, verification_key: Vec<u8>) -> anyhow::Result<Vec<u8>> {
147 let tlv = tlv::TlvItemEnc {
148 tag: 0,
149 value: tlv::TlvItemValueEnc::StructInvisible(vec![
150 (0, tlv::TlvItemValueEnc::UInt64(check_in_node_id)).into(),
151 (1, tlv::TlvItemValueEnc::OctetString(verification_key)).into(),
152 ]),
153 };
154 Ok(tlv.encode()?)
155}
156
157pub fn encode_stay_active_request(stay_active_duration: u32) -> anyhow::Result<Vec<u8>> {
159 let tlv = tlv::TlvItemEnc {
160 tag: 0,
161 value: tlv::TlvItemValueEnc::StructInvisible(vec![
162 (0, tlv::TlvItemValueEnc::UInt32(stay_active_duration)).into(),
163 ]),
164 };
165 Ok(tlv.encode()?)
166}
167
168pub fn decode_idle_mode_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
172 if let tlv::TlvItemValue::Int(v) = inp {
173 Ok(*v as u32)
174 } else {
175 Err(anyhow::anyhow!("Expected UInt32"))
176 }
177}
178
179pub fn decode_active_mode_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
181 if let tlv::TlvItemValue::Int(v) = inp {
182 Ok(*v as u32)
183 } else {
184 Err(anyhow::anyhow!("Expected UInt32"))
185 }
186}
187
188pub fn decode_active_mode_threshold(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
190 if let tlv::TlvItemValue::Int(v) = inp {
191 Ok(*v as u16)
192 } else {
193 Err(anyhow::anyhow!("Expected UInt16"))
194 }
195}
196
197pub fn decode_registered_clients(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<MonitoringRegistration>> {
199 let mut res = Vec::new();
200 if let tlv::TlvItemValue::List(v) = inp {
201 for item in v {
202 res.push(MonitoringRegistration {
203 check_in_node_id: item.get_int(&[1]),
204 monitored_subject: item.get_int(&[2]),
205 key: item.get_int(&[3]).map(|v| v as u8),
206 client_type: item.get_int(&[4]).and_then(|v| ClientType::from_u8(v as u8)),
207 });
208 }
209 }
210 Ok(res)
211}
212
213pub fn decode_icd_counter(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
215 if let tlv::TlvItemValue::Int(v) = inp {
216 Ok(*v as u32)
217 } else {
218 Err(anyhow::anyhow!("Expected UInt32"))
219 }
220}
221
222pub fn decode_clients_supported_per_fabric(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
224 if let tlv::TlvItemValue::Int(v) = inp {
225 Ok(*v as u16)
226 } else {
227 Err(anyhow::anyhow!("Expected UInt16"))
228 }
229}
230
231pub fn decode_user_active_mode_trigger_hint(inp: &tlv::TlvItemValue) -> anyhow::Result<UserActiveModeTrigger> {
233 if let tlv::TlvItemValue::Int(v) = inp {
234 Ok(*v as u32)
235 } else {
236 Err(anyhow::anyhow!("Expected Integer"))
237 }
238}
239
240pub fn decode_user_active_mode_trigger_instruction(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
242 if let tlv::TlvItemValue::String(v) = inp {
243 Ok(v.clone())
244 } else {
245 Err(anyhow::anyhow!("Expected String"))
246 }
247}
248
249pub fn decode_operating_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<OperatingMode> {
251 if let tlv::TlvItemValue::Int(v) = inp {
252 OperatingMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
253 } else {
254 Err(anyhow::anyhow!("Expected Integer"))
255 }
256}
257
258pub fn decode_maximum_check_in_backoff(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
260 if let tlv::TlvItemValue::Int(v) = inp {
261 Ok(*v as u32)
262 } else {
263 Err(anyhow::anyhow!("Expected UInt32"))
264 }
265}
266
267
268pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
280 if cluster_id != 0x0046 {
282 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0046, got {}\"}}", cluster_id);
283 }
284
285 match attribute_id {
286 0x0000 => {
287 match decode_idle_mode_duration(tlv_value) {
288 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
289 Err(e) => format!("{{\"error\": \"{}\"}}", e),
290 }
291 }
292 0x0001 => {
293 match decode_active_mode_duration(tlv_value) {
294 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
295 Err(e) => format!("{{\"error\": \"{}\"}}", e),
296 }
297 }
298 0x0002 => {
299 match decode_active_mode_threshold(tlv_value) {
300 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
301 Err(e) => format!("{{\"error\": \"{}\"}}", e),
302 }
303 }
304 0x0003 => {
305 match decode_registered_clients(tlv_value) {
306 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
307 Err(e) => format!("{{\"error\": \"{}\"}}", e),
308 }
309 }
310 0x0004 => {
311 match decode_icd_counter(tlv_value) {
312 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
313 Err(e) => format!("{{\"error\": \"{}\"}}", e),
314 }
315 }
316 0x0005 => {
317 match decode_clients_supported_per_fabric(tlv_value) {
318 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
319 Err(e) => format!("{{\"error\": \"{}\"}}", e),
320 }
321 }
322 0x0006 => {
323 match decode_user_active_mode_trigger_hint(tlv_value) {
324 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
325 Err(e) => format!("{{\"error\": \"{}\"}}", e),
326 }
327 }
328 0x0007 => {
329 match decode_user_active_mode_trigger_instruction(tlv_value) {
330 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
331 Err(e) => format!("{{\"error\": \"{}\"}}", e),
332 }
333 }
334 0x0008 => {
335 match decode_operating_mode(tlv_value) {
336 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
337 Err(e) => format!("{{\"error\": \"{}\"}}", e),
338 }
339 }
340 0x0009 => {
341 match decode_maximum_check_in_backoff(tlv_value) {
342 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
343 Err(e) => format!("{{\"error\": \"{}\"}}", e),
344 }
345 }
346 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
347 }
348}
349
350pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
355 vec![
356 (0x0000, "IdleModeDuration"),
357 (0x0001, "ActiveModeDuration"),
358 (0x0002, "ActiveModeThreshold"),
359 (0x0003, "RegisteredClients"),
360 (0x0004, "ICDCounter"),
361 (0x0005, "ClientsSupportedPerFabric"),
362 (0x0006, "UserActiveModeTriggerHint"),
363 (0x0007, "UserActiveModeTriggerInstruction"),
364 (0x0008, "OperatingMode"),
365 (0x0009, "MaximumCheckInBackoff"),
366 ]
367}
368
369#[derive(Debug, serde::Serialize)]
370pub struct RegisterClientResponse {
371 pub icd_counter: Option<u32>,
372}
373
374#[derive(Debug, serde::Serialize)]
375pub struct StayActiveResponse {
376 pub promised_active_duration: Option<u32>,
377}
378
379pub fn decode_register_client_response(inp: &tlv::TlvItemValue) -> anyhow::Result<RegisterClientResponse> {
383 if let tlv::TlvItemValue::List(_fields) = inp {
384 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
385 Ok(RegisterClientResponse {
386 icd_counter: item.get_int(&[0]).map(|v| v as u32),
387 })
388 } else {
389 Err(anyhow::anyhow!("Expected struct fields"))
390 }
391}
392
393pub fn decode_stay_active_response(inp: &tlv::TlvItemValue) -> anyhow::Result<StayActiveResponse> {
395 if let tlv::TlvItemValue::List(_fields) = inp {
396 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
397 Ok(StayActiveResponse {
398 promised_active_duration: item.get_int(&[0]).map(|v| v as u32),
399 })
400 } else {
401 Err(anyhow::anyhow!("Expected struct fields"))
402 }
403}
404