1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, serde::Serialize)]
16pub struct AmbientContextType {
17
18}
19
20#[derive(Debug, serde::Serialize)]
21pub struct HoldTimeLimits {
22 pub hold_time_min: Option<u16>,
23 pub hold_time_max: Option<u16>,
24 pub hold_time_default: Option<u16>,
25}
26
27#[derive(Debug, serde::Serialize)]
28pub struct ObjectCountConfig {
29 pub object_count_threshold: Option<u16>,
30}
31
32#[derive(Debug, serde::Serialize)]
33pub struct PredictedActivity {
34 pub start_timestamp: Option<u64>,
35 pub end_timestamp: Option<u64>,
36 pub crowd_detected: Option<bool>,
37 pub crowd_count: Option<u8>,
38 pub confidence: Option<u8>,
39}
40
41pub fn decode_human_activity_detected(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
45 if let tlv::TlvItemValue::Bool(v) = inp {
46 Ok(*v)
47 } else {
48 Err(anyhow::anyhow!("Expected Bool"))
49 }
50}
51
52pub fn decode_object_identified(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
54 if let tlv::TlvItemValue::Bool(v) = inp {
55 Ok(*v)
56 } else {
57 Err(anyhow::anyhow!("Expected Bool"))
58 }
59}
60
61pub fn decode_audio_context_detected(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
63 if let tlv::TlvItemValue::Bool(v) = inp {
64 Ok(*v)
65 } else {
66 Err(anyhow::anyhow!("Expected Bool"))
67 }
68}
69
70pub fn decode_ambient_context_type(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<AmbientContextType>> {
72 let mut res = Vec::new();
73 if let tlv::TlvItemValue::List(v) = inp {
74 for _item in v {
75 res.push(AmbientContextType {
76
77 });
78 }
79 }
80 Ok(res)
81}
82
83pub fn decode_ambient_context_type_supported(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
85 let mut res = Vec::new();
86 if let tlv::TlvItemValue::List(v) = inp {
87 for item in v {
88 if let tlv::TlvItemValue::Int(i) = &item.value {
89 res.push(*i as u8);
90 }
91 }
92 }
93 Ok(res)
94}
95
96pub fn decode_object_count_reached(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
98 if let tlv::TlvItemValue::Bool(v) = inp {
99 Ok(*v)
100 } else {
101 Err(anyhow::anyhow!("Expected Bool"))
102 }
103}
104
105pub fn decode_object_count_config(inp: &tlv::TlvItemValue) -> anyhow::Result<ObjectCountConfig> {
107 if let tlv::TlvItemValue::List(_fields) = inp {
108 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
110 Ok(ObjectCountConfig {
111 object_count_threshold: item.get_int(&[1]).map(|v| v as u16),
112 })
113 } else {
114 Err(anyhow::anyhow!("Expected struct fields"))
115 }
116}
117
118pub fn decode_object_count(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
120 if let tlv::TlvItemValue::Int(v) = inp {
121 Ok(*v as u16)
122 } else {
123 Err(anyhow::anyhow!("Expected UInt16"))
124 }
125}
126
127pub fn decode_simultaneous_detection_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
129 if let tlv::TlvItemValue::Int(v) = inp {
130 Ok(*v as u8)
131 } else {
132 Err(anyhow::anyhow!("Expected UInt8"))
133 }
134}
135
136pub fn decode_hold_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
138 if let tlv::TlvItemValue::Int(v) = inp {
139 Ok(*v as u16)
140 } else {
141 Err(anyhow::anyhow!("Expected UInt16"))
142 }
143}
144
145pub fn decode_hold_time_limits(inp: &tlv::TlvItemValue) -> anyhow::Result<HoldTimeLimits> {
147 if let tlv::TlvItemValue::List(_fields) = inp {
148 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
150 Ok(HoldTimeLimits {
151 hold_time_min: item.get_int(&[0]).map(|v| v as u16),
152 hold_time_max: item.get_int(&[1]).map(|v| v as u16),
153 hold_time_default: item.get_int(&[2]).map(|v| v as u16),
154 })
155 } else {
156 Err(anyhow::anyhow!("Expected struct fields"))
157 }
158}
159
160pub fn decode_predicted_activity(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<PredictedActivity>> {
162 let mut res = Vec::new();
163 if let tlv::TlvItemValue::List(v) = inp {
164 for item in v {
165 res.push(PredictedActivity {
166 start_timestamp: item.get_int(&[0]),
167 end_timestamp: item.get_int(&[1]),
168 crowd_detected: item.get_bool(&[3]),
169 crowd_count: item.get_int(&[4]).map(|v| v as u8),
170 confidence: item.get_int(&[5]).map(|v| v as u8),
171 });
172 }
173 }
174 Ok(res)
175}
176
177
178pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
190 if ![0x0431].contains(&cluster_id) {
192 return format!("{{\"error\": \"Invalid cluster ID. Expected [0x0431], got {}\"}}", cluster_id);
193 }
194
195 match attribute_id {
196 0x0000 => {
197 match decode_human_activity_detected(tlv_value) {
198 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
199 Err(e) => format!("{{\"error\": \"{}\"}}", e),
200 }
201 }
202 0x0001 => {
203 match decode_object_identified(tlv_value) {
204 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
205 Err(e) => format!("{{\"error\": \"{}\"}}", e),
206 }
207 }
208 0x0002 => {
209 match decode_audio_context_detected(tlv_value) {
210 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
211 Err(e) => format!("{{\"error\": \"{}\"}}", e),
212 }
213 }
214 0x0003 => {
215 match decode_ambient_context_type(tlv_value) {
216 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
217 Err(e) => format!("{{\"error\": \"{}\"}}", e),
218 }
219 }
220 0x0004 => {
221 match decode_ambient_context_type_supported(tlv_value) {
222 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
223 Err(e) => format!("{{\"error\": \"{}\"}}", e),
224 }
225 }
226 0x0005 => {
227 match decode_object_count_reached(tlv_value) {
228 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
229 Err(e) => format!("{{\"error\": \"{}\"}}", e),
230 }
231 }
232 0x0006 => {
233 match decode_object_count_config(tlv_value) {
234 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
235 Err(e) => format!("{{\"error\": \"{}\"}}", e),
236 }
237 }
238 0x0007 => {
239 match decode_object_count(tlv_value) {
240 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
241 Err(e) => format!("{{\"error\": \"{}\"}}", e),
242 }
243 }
244 0x0008 => {
245 match decode_simultaneous_detection_limit(tlv_value) {
246 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
247 Err(e) => format!("{{\"error\": \"{}\"}}", e),
248 }
249 }
250 0x0009 => {
251 match decode_hold_time(tlv_value) {
252 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
253 Err(e) => format!("{{\"error\": \"{}\"}}", e),
254 }
255 }
256 0x000A => {
257 match decode_hold_time_limits(tlv_value) {
258 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
259 Err(e) => format!("{{\"error\": \"{}\"}}", e),
260 }
261 }
262 0x000B => {
263 match decode_predicted_activity(tlv_value) {
264 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
265 Err(e) => format!("{{\"error\": \"{}\"}}", e),
266 }
267 }
268 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
269 }
270}
271
272pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
277 vec![
278 (0x0000, "HumanActivityDetected"),
279 (0x0001, "ObjectIdentified"),
280 (0x0002, "AudioContextDetected"),
281 (0x0003, "AmbientContextType"),
282 (0x0004, "AmbientContextTypeSupported"),
283 (0x0005, "ObjectCountReached"),
284 (0x0006, "ObjectCountConfig"),
285 (0x0007, "ObjectCount"),
286 (0x0008, "SimultaneousDetectionLimit"),
287 (0x0009, "HoldTime"),
288 (0x000A, "HoldTimeLimits"),
289 (0x000B, "PredictedActivity"),
290 ]
291}
292
293pub async fn read_human_activity_detected(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
297 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_HUMANACTIVITYDETECTED).await?;
298 decode_human_activity_detected(&tlv)
299}
300
301pub async fn read_object_identified(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
303 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_OBJECTIDENTIFIED).await?;
304 decode_object_identified(&tlv)
305}
306
307pub async fn read_audio_context_detected(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
309 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_AUDIOCONTEXTDETECTED).await?;
310 decode_audio_context_detected(&tlv)
311}
312
313pub async fn read_ambient_context_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<AmbientContextType>> {
315 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_AMBIENTCONTEXTTYPE).await?;
316 decode_ambient_context_type(&tlv)
317}
318
319pub async fn read_ambient_context_type_supported(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<u8>> {
321 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_AMBIENTCONTEXTTYPESUPPORTED).await?;
322 decode_ambient_context_type_supported(&tlv)
323}
324
325pub async fn read_object_count_reached(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
327 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_OBJECTCOUNTREACHED).await?;
328 decode_object_count_reached(&tlv)
329}
330
331pub async fn read_object_count_config(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ObjectCountConfig> {
333 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_OBJECTCOUNTCONFIG).await?;
334 decode_object_count_config(&tlv)
335}
336
337pub async fn read_object_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
339 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_OBJECTCOUNT).await?;
340 decode_object_count(&tlv)
341}
342
343pub async fn read_simultaneous_detection_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
345 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_SIMULTANEOUSDETECTIONLIMIT).await?;
346 decode_simultaneous_detection_limit(&tlv)
347}
348
349pub async fn read_hold_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
351 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_HOLDTIME).await?;
352 decode_hold_time(&tlv)
353}
354
355pub async fn read_hold_time_limits(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<HoldTimeLimits> {
357 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_HOLDTIMELIMITS).await?;
358 decode_hold_time_limits(&tlv)
359}
360
361pub async fn read_predicted_activity(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<PredictedActivity>> {
363 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_AMBIENT_CONTEXT_SENSING, crate::clusters::defs::CLUSTER_AMBIENT_CONTEXT_SENSING_ATTR_ID_PREDICTEDACTIVITY).await?;
364 decode_predicted_activity(&tlv)
365}
366
367#[derive(Debug, serde::Serialize)]
368pub struct AmbientContextDetectStartedEvent {
369 pub ambient_context_detected: Option<AmbientContextType>,
370 pub object_count_reached: Option<bool>,
371 pub object_count: Option<u16>,
372}
373
374#[derive(Debug, serde::Serialize)]
375pub struct AmbientContextDetectEndedEvent {
376 pub event_start_time: Option<u8>,
377}
378
379pub fn decode_ambient_context_detect_started_event(inp: &tlv::TlvItemValue) -> anyhow::Result<AmbientContextDetectStartedEvent> {
383 if let tlv::TlvItemValue::List(_fields) = inp {
384 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
385 Ok(AmbientContextDetectStartedEvent {
386 ambient_context_detected: {
387 if let Some(nested_tlv) = item.get(&[0]) {
388 if let tlv::TlvItemValue::List(_) = nested_tlv {
389 let _nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
390 Some(AmbientContextType {
391
392 })
393 } else {
394 None
395 }
396 } else {
397 None
398 }
399 },
400 object_count_reached: item.get_bool(&[1]),
401 object_count: item.get_int(&[2]).map(|v| v as u16),
402 })
403 } else {
404 Err(anyhow::anyhow!("Expected struct fields"))
405 }
406}
407
408pub fn decode_ambient_context_detect_ended_event(inp: &tlv::TlvItemValue) -> anyhow::Result<AmbientContextDetectEndedEvent> {
410 if let tlv::TlvItemValue::List(_fields) = inp {
411 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
412 Ok(AmbientContextDetectEndedEvent {
413 event_start_time: item.get_int(&[0]).map(|v| v as u8),
414 })
415 } else {
416 Err(anyhow::anyhow!("Expected struct fields"))
417 }
418}
419
420
421pub fn decode_event_json(cluster_id: u32, event_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
425 if ![0x0431].contains(&cluster_id) {
426 return format!("{{\"error\": \"Invalid cluster ID. Expected [0x0431], got {}\"}}", cluster_id);
427 }
428
429 match event_id {
430 0x00 => {
431 match decode_ambient_context_detect_started_event(tlv_value) {
432 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
433 Err(e) => format!("{{\"error\": \"{}\"}}", e),
434 }
435 }
436 0x01 => {
437 match decode_ambient_context_detect_ended_event(tlv_value) {
438 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
439 Err(e) => format!("{{\"error\": \"{}\"}}", e),
440 }
441 }
442 _ => format!("{{\"error\": \"Unknown event ID: {}\"}}", event_id),
443 }
444}
445
446pub fn get_event_list() -> Vec<(u32, &'static str)> {
451 vec![
452 (0x00, "AmbientContextDetectStarted"),
453 (0x01, "AmbientContextDetectEnded"),
454 ]
455}
456