matc/clusters/codec/
concentration_measurement.rs

1//! Matter TLV encoders and decoders for Concentration Measurement Clusters
2//! Cluster ID: 0x0000
3//!
4//! This file is automatically generated from ConcentrationMeasurement.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Enum definitions
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum LevelValue {
16    /// The level is Unknown
17    Unknown = 0,
18    /// The level is considered Low
19    Low = 1,
20    /// The level is considered Medium
21    Medium = 2,
22    /// The level is considered High
23    High = 3,
24    /// The level is considered Critical
25    Critical = 4,
26}
27
28impl LevelValue {
29    /// Convert from u8 value
30    pub fn from_u8(value: u8) -> Option<Self> {
31        match value {
32            0 => Some(LevelValue::Unknown),
33            1 => Some(LevelValue::Low),
34            2 => Some(LevelValue::Medium),
35            3 => Some(LevelValue::High),
36            4 => Some(LevelValue::Critical),
37            _ => None,
38        }
39    }
40
41    /// Convert to u8 value
42    pub fn to_u8(self) -> u8 {
43        self as u8
44    }
45}
46
47impl From<LevelValue> for u8 {
48    fn from(val: LevelValue) -> Self {
49        val as u8
50    }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
54#[repr(u8)]
55pub enum MeasurementMedium {
56    /// The measurement is being made in Air
57    Air = 0,
58    /// The measurement is being made in Water
59    Water = 1,
60    /// The measurement is being made in Soil
61    Soil = 2,
62}
63
64impl MeasurementMedium {
65    /// Convert from u8 value
66    pub fn from_u8(value: u8) -> Option<Self> {
67        match value {
68            0 => Some(MeasurementMedium::Air),
69            1 => Some(MeasurementMedium::Water),
70            2 => Some(MeasurementMedium::Soil),
71            _ => None,
72        }
73    }
74
75    /// Convert to u8 value
76    pub fn to_u8(self) -> u8 {
77        self as u8
78    }
79}
80
81impl From<MeasurementMedium> for u8 {
82    fn from(val: MeasurementMedium) -> Self {
83        val as u8
84    }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
88#[repr(u8)]
89pub enum MeasurementUnit {
90    /// Parts per Million (10)
91    Ppm = 0,
92    /// Parts per Billion (10)
93    Ppb = 1,
94    /// Parts per Trillion (10)
95    Ppt = 2,
96    /// Milligram per m
97    Mgm3 = 3,
98    /// Microgram per m
99    Ugm3 = 4,
100    /// Nanogram per m
101    Ngm3 = 5,
102    /// Particles per m
103    Pm3 = 6,
104    /// Becquerel per m
105    Bqm3 = 7,
106}
107
108impl MeasurementUnit {
109    /// Convert from u8 value
110    pub fn from_u8(value: u8) -> Option<Self> {
111        match value {
112            0 => Some(MeasurementUnit::Ppm),
113            1 => Some(MeasurementUnit::Ppb),
114            2 => Some(MeasurementUnit::Ppt),
115            3 => Some(MeasurementUnit::Mgm3),
116            4 => Some(MeasurementUnit::Ugm3),
117            5 => Some(MeasurementUnit::Ngm3),
118            6 => Some(MeasurementUnit::Pm3),
119            7 => Some(MeasurementUnit::Bqm3),
120            _ => None,
121        }
122    }
123
124    /// Convert to u8 value
125    pub fn to_u8(self) -> u8 {
126        self as u8
127    }
128}
129
130impl From<MeasurementUnit> for u8 {
131    fn from(val: MeasurementUnit) -> Self {
132        val as u8
133    }
134}
135
136// Attribute decoders
137
138/// Decode MeasuredValue attribute (0x0000)
139pub fn decode_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
140    if let tlv::TlvItemValue::Int(v) = inp {
141        Ok(Some(*v as u8))
142    } else {
143        Ok(None)
144    }
145}
146
147/// Decode MinMeasuredValue attribute (0x0001)
148pub fn decode_min_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
149    if let tlv::TlvItemValue::Int(v) = inp {
150        Ok(Some(*v as u8))
151    } else {
152        Ok(None)
153    }
154}
155
156/// Decode MaxMeasuredValue attribute (0x0002)
157pub fn decode_max_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
158    if let tlv::TlvItemValue::Int(v) = inp {
159        Ok(Some(*v as u8))
160    } else {
161        Ok(None)
162    }
163}
164
165/// Decode PeakMeasuredValue attribute (0x0003)
166pub fn decode_peak_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
167    if let tlv::TlvItemValue::Int(v) = inp {
168        Ok(Some(*v as u8))
169    } else {
170        Ok(None)
171    }
172}
173
174/// Decode PeakMeasuredValueWindow attribute (0x0004)
175pub fn decode_peak_measured_value_window(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
176    if let tlv::TlvItemValue::Int(v) = inp {
177        Ok(*v as u32)
178    } else {
179        Err(anyhow::anyhow!("Expected UInt32"))
180    }
181}
182
183/// Decode AverageMeasuredValue attribute (0x0005)
184pub fn decode_average_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
185    if let tlv::TlvItemValue::Int(v) = inp {
186        Ok(Some(*v as u8))
187    } else {
188        Ok(None)
189    }
190}
191
192/// Decode AverageMeasuredValueWindow attribute (0x0006)
193pub fn decode_average_measured_value_window(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
194    if let tlv::TlvItemValue::Int(v) = inp {
195        Ok(*v as u32)
196    } else {
197        Err(anyhow::anyhow!("Expected UInt32"))
198    }
199}
200
201/// Decode Uncertainty attribute (0x0007)
202pub fn decode_uncertainty(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
203    if let tlv::TlvItemValue::Int(v) = inp {
204        Ok(*v as u8)
205    } else {
206        Err(anyhow::anyhow!("Expected UInt8"))
207    }
208}
209
210/// Decode MeasurementUnit attribute (0x0008)
211pub fn decode_measurement_unit(inp: &tlv::TlvItemValue) -> anyhow::Result<MeasurementUnit> {
212    if let tlv::TlvItemValue::Int(v) = inp {
213        MeasurementUnit::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
214    } else {
215        Err(anyhow::anyhow!("Expected Integer"))
216    }
217}
218
219/// Decode MeasurementMedium attribute (0x0009)
220pub fn decode_measurement_medium(inp: &tlv::TlvItemValue) -> anyhow::Result<MeasurementMedium> {
221    if let tlv::TlvItemValue::Int(v) = inp {
222        MeasurementMedium::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
223    } else {
224        Err(anyhow::anyhow!("Expected Integer"))
225    }
226}
227
228/// Decode LevelValue attribute (0x000A)
229pub fn decode_level_value(inp: &tlv::TlvItemValue) -> anyhow::Result<LevelValue> {
230    if let tlv::TlvItemValue::Int(v) = inp {
231        LevelValue::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
232    } else {
233        Err(anyhow::anyhow!("Expected Integer"))
234    }
235}
236
237
238// JSON dispatcher function
239
240/// Decode attribute value and return as JSON string
241///
242/// # Parameters
243/// * `cluster_id` - The cluster identifier
244/// * `attribute_id` - The attribute identifier
245/// * `tlv_value` - The TLV value to decode
246///
247/// # Returns
248/// JSON string representation of the decoded value or error
249pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
250    // Verify this is the correct cluster
251    if cluster_id != 0x0000 {
252        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0000, got {}\"}}", cluster_id);
253    }
254
255    match attribute_id {
256        0x0000 => {
257            match decode_measured_value(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        0x0001 => {
263            match decode_min_measured_value(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        0x0002 => {
269            match decode_max_measured_value(tlv_value) {
270                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
271                Err(e) => format!("{{\"error\": \"{}\"}}", e),
272            }
273        }
274        0x0003 => {
275            match decode_peak_measured_value(tlv_value) {
276                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
277                Err(e) => format!("{{\"error\": \"{}\"}}", e),
278            }
279        }
280        0x0004 => {
281            match decode_peak_measured_value_window(tlv_value) {
282                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
283                Err(e) => format!("{{\"error\": \"{}\"}}", e),
284            }
285        }
286        0x0005 => {
287            match decode_average_measured_value(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        0x0006 => {
293            match decode_average_measured_value_window(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        0x0007 => {
299            match decode_uncertainty(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        0x0008 => {
305            match decode_measurement_unit(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        0x0009 => {
311            match decode_measurement_medium(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        0x000A => {
317            match decode_level_value(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        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
323    }
324}
325
326/// Get list of all attributes supported by this cluster
327///
328/// # Returns
329/// Vector of tuples containing (attribute_id, attribute_name)
330pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
331    vec![
332        (0x0000, "MeasuredValue"),
333        (0x0001, "MinMeasuredValue"),
334        (0x0002, "MaxMeasuredValue"),
335        (0x0003, "PeakMeasuredValue"),
336        (0x0004, "PeakMeasuredValueWindow"),
337        (0x0005, "AverageMeasuredValue"),
338        (0x0006, "AverageMeasuredValueWindow"),
339        (0x0007, "Uncertainty"),
340        (0x0008, "MeasurementUnit"),
341        (0x0009, "MeasurementMedium"),
342        (0x000A, "LevelValue"),
343    ]
344}
345