matc/clusters/codec/
service_area.rs

1//! Generated Matter TLV encoders and decoders for Service Area Cluster
2//! Cluster ID: 0x0150
3//! 
4//! This file is automatically generated from ServiceArea.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Struct definitions
12
13#[derive(Debug, serde::Serialize)]
14pub struct AreaInfo {
15    pub location_info: Option<LocationDescriptor>,
16    pub landmark_info: Option<LandmarkInfo>,
17}
18
19#[derive(Debug, serde::Serialize)]
20pub struct Area {
21    pub area_id: Option<u32>,
22    pub map_id: Option<u32>,
23    pub area_info: Option<AreaInfo>,
24}
25
26#[derive(Debug, serde::Serialize)]
27pub struct LandmarkInfo {
28    pub landmark_tag: Option<u8>,
29    pub relative_position_tag: Option<u8>,
30}
31
32#[derive(Debug, serde::Serialize)]
33pub struct Map {
34    pub map_id: Option<u32>,
35    pub name: Option<String>,
36}
37
38#[derive(Debug, serde::Serialize)]
39pub struct Progress {
40    pub area_id: Option<u32>,
41    pub status: Option<u8>,
42    pub total_operational_time: Option<u8>,
43    pub estimated_time: Option<u8>,
44}
45
46#[derive(Debug, serde::Serialize)]
47pub struct LocationDescriptor {
48    pub location_name: Option<String>,
49    pub floor_number: Option<u16>,
50    pub area_type: Option<u8>,
51}
52
53// Command encoders
54
55/// Encode SelectAreas command (0x00)
56pub fn encode_select_areas(new_areas: Vec<u8>) -> anyhow::Result<Vec<u8>> {
57    let tlv = tlv::TlvItemEnc {
58        tag: 0,
59        value: tlv::TlvItemValueEnc::StructInvisible(vec![
60        (0, tlv::TlvItemValueEnc::StructAnon(new_areas.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
61        ]),
62    };
63    Ok(tlv.encode()?)
64}
65
66/// Encode SkipArea command (0x02)
67pub fn encode_skip_area(skipped_area: u32) -> anyhow::Result<Vec<u8>> {
68    let tlv = tlv::TlvItemEnc {
69        tag: 0,
70        value: tlv::TlvItemValueEnc::StructInvisible(vec![
71        (0, tlv::TlvItemValueEnc::UInt32(skipped_area)).into(),
72        ]),
73    };
74    Ok(tlv.encode()?)
75}
76
77// Attribute decoders
78
79/// Decode SupportedAreas attribute (0x0000)
80pub fn decode_supported_areas(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Area>> {
81    let mut res = Vec::new();
82    if let tlv::TlvItemValue::List(v) = inp {
83        for item in v {
84            res.push(Area {
85                area_id: item.get_int(&[0]).map(|v| v as u32),
86                map_id: item.get_int(&[1]).map(|v| v as u32),
87                area_info: {
88                    if let Some(nested_tlv) = item.get(&[2]) {
89                        if let tlv::TlvItemValue::List(_) = nested_tlv {
90                            let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
91                            Some(AreaInfo {
92                location_info: {
93                    if let Some(nested_tlv) = nested_item.get(&[0]) {
94                        if let tlv::TlvItemValue::List(_) = nested_tlv {
95                            let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
96                            Some(LocationDescriptor {
97                location_name: nested_item.get_string_owned(&[0]),
98                floor_number: nested_item.get_int(&[1]).map(|v| v as u16),
99                area_type: nested_item.get_int(&[2]).map(|v| v as u8),
100                            })
101                        } else {
102                            None
103                        }
104                    } else {
105                        None
106                    }
107                },
108                landmark_info: {
109                    if let Some(nested_tlv) = nested_item.get(&[1]) {
110                        if let tlv::TlvItemValue::List(_) = nested_tlv {
111                            let nested_item = tlv::TlvItem { tag: 1, value: nested_tlv.clone() };
112                            Some(LandmarkInfo {
113                landmark_tag: nested_item.get_int(&[0]).map(|v| v as u8),
114                relative_position_tag: nested_item.get_int(&[1]).map(|v| v as u8),
115                            })
116                        } else {
117                            None
118                        }
119                    } else {
120                        None
121                    }
122                },
123                            })
124                        } else {
125                            None
126                        }
127                    } else {
128                        None
129                    }
130                },
131            });
132        }
133    }
134    Ok(res)
135}
136
137/// Decode SupportedMaps attribute (0x0001)
138pub fn decode_supported_maps(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Map>> {
139    let mut res = Vec::new();
140    if let tlv::TlvItemValue::List(v) = inp {
141        for item in v {
142            res.push(Map {
143                map_id: item.get_int(&[0]).map(|v| v as u32),
144                name: item.get_string_owned(&[1]),
145            });
146        }
147    }
148    Ok(res)
149}
150
151/// Decode SelectedAreas attribute (0x0002)
152pub fn decode_selected_areas(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u32>> {
153    let mut res = Vec::new();
154    if let tlv::TlvItemValue::List(v) = inp {
155        for item in v {
156            if let tlv::TlvItemValue::Int(i) = &item.value {
157                res.push(*i as u32);
158            }
159        }
160    }
161    Ok(res)
162}
163
164/// Decode CurrentArea attribute (0x0003)
165pub fn decode_current_area(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
166    if let tlv::TlvItemValue::Int(v) = inp {
167        Ok(Some(*v as u32))
168    } else {
169        Ok(None)
170    }
171}
172
173/// Decode EstimatedEndTime attribute (0x0004)
174pub fn decode_estimated_end_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
175    if let tlv::TlvItemValue::Int(v) = inp {
176        Ok(Some(*v))
177    } else {
178        Ok(None)
179    }
180}
181
182/// Decode Progress attribute (0x0005)
183pub fn decode_progress(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Progress>> {
184    let mut res = Vec::new();
185    if let tlv::TlvItemValue::List(v) = inp {
186        for item in v {
187            res.push(Progress {
188                area_id: item.get_int(&[0]).map(|v| v as u32),
189                status: item.get_int(&[1]).map(|v| v as u8),
190                total_operational_time: item.get_int(&[2]).map(|v| v as u8),
191                estimated_time: item.get_int(&[3]).map(|v| v as u8),
192            });
193        }
194    }
195    Ok(res)
196}
197
198
199// JSON dispatcher function
200
201/// Decode attribute value and return as JSON string
202/// 
203/// # Parameters
204/// * `cluster_id` - The cluster identifier
205/// * `attribute_id` - The attribute identifier
206/// * `tlv_value` - The TLV value to decode
207/// 
208/// # Returns
209/// JSON string representation of the decoded value or error
210pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
211    // Verify this is the correct cluster
212    if cluster_id != 0x0150 {
213        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0150, got {}\"}}", cluster_id);
214    }
215    
216    match attribute_id {
217        0x0000 => {
218            match decode_supported_areas(tlv_value) {
219                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
220                Err(e) => format!("{{\"error\": \"{}\"}}", e),
221            }
222        }
223        0x0001 => {
224            match decode_supported_maps(tlv_value) {
225                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
226                Err(e) => format!("{{\"error\": \"{}\"}}", e),
227            }
228        }
229        0x0002 => {
230            match decode_selected_areas(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        0x0003 => {
236            match decode_current_area(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        0x0004 => {
242            match decode_estimated_end_time(tlv_value) {
243                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
244                Err(e) => format!("{{\"error\": \"{}\"}}", e),
245            }
246        }
247        0x0005 => {
248            match decode_progress(tlv_value) {
249                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
250                Err(e) => format!("{{\"error\": \"{}\"}}", e),
251            }
252        }
253        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
254    }
255}
256
257/// Get list of all attributes supported by this cluster
258/// 
259/// # Returns
260/// Vector of tuples containing (attribute_id, attribute_name)
261pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
262    vec![
263        (0x0000, "SupportedAreas"),
264        (0x0001, "SupportedMaps"),
265        (0x0002, "SelectedAreas"),
266        (0x0003, "CurrentArea"),
267        (0x0004, "EstimatedEndTime"),
268        (0x0005, "Progress"),
269    ]
270}
271