Skip to main content

matc/clusters/codec/
ambient_context_sensing.rs

1//! Matter TLV encoders and decoders for Ambient Context Sensing Cluster
2//! Cluster IDs: 0x0431
3//!
4//! This file is automatically generated from AmbientContextSensing.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 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
41// Attribute decoders
42
43/// Decode HumanActivityDetected attribute (0x0000)
44pub 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
52/// Decode ObjectIdentified attribute (0x0001)
53pub 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
61/// Decode AudioContextDetected attribute (0x0002)
62pub 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
70/// Decode AmbientContextType attribute (0x0003)
71pub 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
83/// Decode AmbientContextTypeSupported attribute (0x0004)
84pub 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
96/// Decode ObjectCountReached attribute (0x0005)
97pub 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
105/// Decode ObjectCountConfig attribute (0x0006)
106pub fn decode_object_count_config(inp: &tlv::TlvItemValue) -> anyhow::Result<ObjectCountConfig> {
107    if let tlv::TlvItemValue::List(_fields) = inp {
108        // Struct with fields
109        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
118/// Decode ObjectCount attribute (0x0007)
119pub 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
127/// Decode SimultaneousDetectionLimit attribute (0x0008)
128pub 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
136/// Decode HoldTime attribute (0x0009)
137pub 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
145/// Decode HoldTimeLimits attribute (0x000A)
146pub fn decode_hold_time_limits(inp: &tlv::TlvItemValue) -> anyhow::Result<HoldTimeLimits> {
147    if let tlv::TlvItemValue::List(_fields) = inp {
148        // Struct with fields
149        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
160/// Decode PredictedActivity attribute (0x000B)
161pub 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
178// JSON dispatcher function
179
180/// Decode attribute value and return as JSON string
181///
182/// # Parameters
183/// * `cluster_id` - The cluster identifier
184/// * `attribute_id` - The attribute identifier
185/// * `tlv_value` - The TLV value to decode
186///
187/// # Returns
188/// JSON string representation of the decoded value or error
189pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
190    // Verify this is the correct cluster
191    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
272/// Get list of all attributes supported by this cluster
273///
274/// # Returns
275/// Vector of tuples containing (attribute_id, attribute_name)
276pub 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
293// Typed facade (invokes + reads)
294
295/// Read `HumanActivityDetected` attribute from cluster `Ambient Context Sensing`.
296pub 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
301/// Read `ObjectIdentified` attribute from cluster `Ambient Context Sensing`.
302pub 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
307/// Read `AudioContextDetected` attribute from cluster `Ambient Context Sensing`.
308pub 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
313/// Read `AmbientContextType` attribute from cluster `Ambient Context Sensing`.
314pub 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
319/// Read `AmbientContextTypeSupported` attribute from cluster `Ambient Context Sensing`.
320pub 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
325/// Read `ObjectCountReached` attribute from cluster `Ambient Context Sensing`.
326pub 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
331/// Read `ObjectCountConfig` attribute from cluster `Ambient Context Sensing`.
332pub 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
337/// Read `ObjectCount` attribute from cluster `Ambient Context Sensing`.
338pub 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
343/// Read `SimultaneousDetectionLimit` attribute from cluster `Ambient Context Sensing`.
344pub 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
349/// Read `HoldTime` attribute from cluster `Ambient Context Sensing`.
350pub 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
355/// Read `HoldTimeLimits` attribute from cluster `Ambient Context Sensing`.
356pub 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
361/// Read `PredictedActivity` attribute from cluster `Ambient Context Sensing`.
362pub 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
379// Event decoders
380
381/// Decode AmbientContextDetectStarted event (0x00, priority: info)
382pub 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
408/// Decode AmbientContextDetectEnded event (0x01, priority: info)
409pub 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
421// Event JSON dispatcher
422
423/// Decode event value and return as JSON string
424pub 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
446/// Get list of all events supported by this cluster
447///
448/// # Returns
449/// Vector of tuples containing (event_id, event_name)
450pub fn get_event_list() -> Vec<(u32, &'static str)> {
451    vec![
452        (0x00, "AmbientContextDetectStarted"),
453        (0x01, "AmbientContextDetectEnded"),
454    ]
455}
456