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
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Enum definitions
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum LevelValue {
18    /// The level is Unknown
19    Unknown = 0,
20    /// The level is considered Low
21    Low = 1,
22    /// The level is considered Medium
23    Medium = 2,
24    /// The level is considered High
25    High = 3,
26    /// The level is considered Critical
27    Critical = 4,
28}
29
30impl LevelValue {
31    /// Convert from u8 value
32    pub fn from_u8(value: u8) -> Option<Self> {
33        match value {
34            0 => Some(LevelValue::Unknown),
35            1 => Some(LevelValue::Low),
36            2 => Some(LevelValue::Medium),
37            3 => Some(LevelValue::High),
38            4 => Some(LevelValue::Critical),
39            _ => None,
40        }
41    }
42
43    /// Convert to u8 value
44    pub fn to_u8(self) -> u8 {
45        self as u8
46    }
47}
48
49impl From<LevelValue> for u8 {
50    fn from(val: LevelValue) -> Self {
51        val as u8
52    }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
56#[repr(u8)]
57pub enum MeasurementMedium {
58    /// The measurement is being made in Air
59    Air = 0,
60    /// The measurement is being made in Water
61    Water = 1,
62    /// The measurement is being made in Soil
63    Soil = 2,
64}
65
66impl MeasurementMedium {
67    /// Convert from u8 value
68    pub fn from_u8(value: u8) -> Option<Self> {
69        match value {
70            0 => Some(MeasurementMedium::Air),
71            1 => Some(MeasurementMedium::Water),
72            2 => Some(MeasurementMedium::Soil),
73            _ => None,
74        }
75    }
76
77    /// Convert to u8 value
78    pub fn to_u8(self) -> u8 {
79        self as u8
80    }
81}
82
83impl From<MeasurementMedium> for u8 {
84    fn from(val: MeasurementMedium) -> Self {
85        val as u8
86    }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
90#[repr(u8)]
91pub enum MeasurementUnit {
92    /// Parts per Million (10)
93    Ppm = 0,
94    /// Parts per Billion (10)
95    Ppb = 1,
96    /// Parts per Trillion (10)
97    Ppt = 2,
98    /// Milligram per m
99    Mgm3 = 3,
100    /// Microgram per m
101    Ugm3 = 4,
102    /// Nanogram per m
103    Ngm3 = 5,
104    /// Particles per m
105    Pm3 = 6,
106    /// Becquerel per m
107    Bqm3 = 7,
108}
109
110impl MeasurementUnit {
111    /// Convert from u8 value
112    pub fn from_u8(value: u8) -> Option<Self> {
113        match value {
114            0 => Some(MeasurementUnit::Ppm),
115            1 => Some(MeasurementUnit::Ppb),
116            2 => Some(MeasurementUnit::Ppt),
117            3 => Some(MeasurementUnit::Mgm3),
118            4 => Some(MeasurementUnit::Ugm3),
119            5 => Some(MeasurementUnit::Ngm3),
120            6 => Some(MeasurementUnit::Pm3),
121            7 => Some(MeasurementUnit::Bqm3),
122            _ => None,
123        }
124    }
125
126    /// Convert to u8 value
127    pub fn to_u8(self) -> u8 {
128        self as u8
129    }
130}
131
132impl From<MeasurementUnit> for u8 {
133    fn from(val: MeasurementUnit) -> Self {
134        val as u8
135    }
136}
137
138// Attribute decoders
139
140/// Decode MeasuredValue attribute (0x0000)
141pub fn decode_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
142    if let tlv::TlvItemValue::Int(v) = inp {
143        Ok(Some(*v as u8))
144    } else {
145        Ok(None)
146    }
147}
148
149/// Decode MinMeasuredValue attribute (0x0001)
150pub fn decode_min_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
151    if let tlv::TlvItemValue::Int(v) = inp {
152        Ok(Some(*v as u8))
153    } else {
154        Ok(None)
155    }
156}
157
158/// Decode MaxMeasuredValue attribute (0x0002)
159pub fn decode_max_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
160    if let tlv::TlvItemValue::Int(v) = inp {
161        Ok(Some(*v as u8))
162    } else {
163        Ok(None)
164    }
165}
166
167/// Decode PeakMeasuredValue attribute (0x0003)
168pub fn decode_peak_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
169    if let tlv::TlvItemValue::Int(v) = inp {
170        Ok(Some(*v as u8))
171    } else {
172        Ok(None)
173    }
174}
175
176/// Decode PeakMeasuredValueWindow attribute (0x0004)
177pub fn decode_peak_measured_value_window(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
178    if let tlv::TlvItemValue::Int(v) = inp {
179        Ok(*v as u32)
180    } else {
181        Err(anyhow::anyhow!("Expected UInt32"))
182    }
183}
184
185/// Decode AverageMeasuredValue attribute (0x0005)
186pub fn decode_average_measured_value(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
187    if let tlv::TlvItemValue::Int(v) = inp {
188        Ok(Some(*v as u8))
189    } else {
190        Ok(None)
191    }
192}
193
194/// Decode AverageMeasuredValueWindow attribute (0x0006)
195pub fn decode_average_measured_value_window(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
196    if let tlv::TlvItemValue::Int(v) = inp {
197        Ok(*v as u32)
198    } else {
199        Err(anyhow::anyhow!("Expected UInt32"))
200    }
201}
202
203/// Decode Uncertainty attribute (0x0007)
204pub fn decode_uncertainty(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
205    if let tlv::TlvItemValue::Int(v) = inp {
206        Ok(*v as u8)
207    } else {
208        Err(anyhow::anyhow!("Expected UInt8"))
209    }
210}
211
212/// Decode MeasurementUnit attribute (0x0008)
213pub fn decode_measurement_unit(inp: &tlv::TlvItemValue) -> anyhow::Result<MeasurementUnit> {
214    if let tlv::TlvItemValue::Int(v) = inp {
215        MeasurementUnit::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
216    } else {
217        Err(anyhow::anyhow!("Expected Integer"))
218    }
219}
220
221/// Decode MeasurementMedium attribute (0x0009)
222pub fn decode_measurement_medium(inp: &tlv::TlvItemValue) -> anyhow::Result<MeasurementMedium> {
223    if let tlv::TlvItemValue::Int(v) = inp {
224        MeasurementMedium::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
225    } else {
226        Err(anyhow::anyhow!("Expected Integer"))
227    }
228}
229
230/// Decode LevelValue attribute (0x000A)
231pub fn decode_level_value(inp: &tlv::TlvItemValue) -> anyhow::Result<LevelValue> {
232    if let tlv::TlvItemValue::Int(v) = inp {
233        LevelValue::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
234    } else {
235        Err(anyhow::anyhow!("Expected Integer"))
236    }
237}
238
239
240// JSON dispatcher function
241
242/// Decode attribute value and return as JSON string
243///
244/// # Parameters
245/// * `cluster_id` - The cluster identifier
246/// * `attribute_id` - The attribute identifier
247/// * `tlv_value` - The TLV value to decode
248///
249/// # Returns
250/// JSON string representation of the decoded value or error
251pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
252    // Verify this is the correct cluster
253    if cluster_id != 0x0000 {
254        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0000, got {}\"}}", cluster_id);
255    }
256
257    match attribute_id {
258        0x0000 => {
259            match decode_measured_value(tlv_value) {
260                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
261                Err(e) => format!("{{\"error\": \"{}\"}}", e),
262            }
263        }
264        0x0001 => {
265            match decode_min_measured_value(tlv_value) {
266                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
267                Err(e) => format!("{{\"error\": \"{}\"}}", e),
268            }
269        }
270        0x0002 => {
271            match decode_max_measured_value(tlv_value) {
272                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
273                Err(e) => format!("{{\"error\": \"{}\"}}", e),
274            }
275        }
276        0x0003 => {
277            match decode_peak_measured_value(tlv_value) {
278                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
279                Err(e) => format!("{{\"error\": \"{}\"}}", e),
280            }
281        }
282        0x0004 => {
283            match decode_peak_measured_value_window(tlv_value) {
284                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
285                Err(e) => format!("{{\"error\": \"{}\"}}", e),
286            }
287        }
288        0x0005 => {
289            match decode_average_measured_value(tlv_value) {
290                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
291                Err(e) => format!("{{\"error\": \"{}\"}}", e),
292            }
293        }
294        0x0006 => {
295            match decode_average_measured_value_window(tlv_value) {
296                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
297                Err(e) => format!("{{\"error\": \"{}\"}}", e),
298            }
299        }
300        0x0007 => {
301            match decode_uncertainty(tlv_value) {
302                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
303                Err(e) => format!("{{\"error\": \"{}\"}}", e),
304            }
305        }
306        0x0008 => {
307            match decode_measurement_unit(tlv_value) {
308                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
309                Err(e) => format!("{{\"error\": \"{}\"}}", e),
310            }
311        }
312        0x0009 => {
313            match decode_measurement_medium(tlv_value) {
314                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
315                Err(e) => format!("{{\"error\": \"{}\"}}", e),
316            }
317        }
318        0x000A => {
319            match decode_level_value(tlv_value) {
320                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
321                Err(e) => format!("{{\"error\": \"{}\"}}", e),
322            }
323        }
324        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
325    }
326}
327
328/// Get list of all attributes supported by this cluster
329///
330/// # Returns
331/// Vector of tuples containing (attribute_id, attribute_name)
332pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
333    vec![
334        (0x0000, "MeasuredValue"),
335        (0x0001, "MinMeasuredValue"),
336        (0x0002, "MaxMeasuredValue"),
337        (0x0003, "PeakMeasuredValue"),
338        (0x0004, "PeakMeasuredValueWindow"),
339        (0x0005, "AverageMeasuredValue"),
340        (0x0006, "AverageMeasuredValueWindow"),
341        (0x0007, "Uncertainty"),
342        (0x0008, "MeasurementUnit"),
343        (0x0009, "MeasurementMedium"),
344        (0x000A, "LevelValue"),
345    ]
346}
347
348// Typed facade (invokes + reads)
349
350/// Read `MeasuredValue` attribute from cluster `Radon Concentration Measurement`.
351pub async fn read_measured_value(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
352    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_MEASUREDVALUE).await?;
353    decode_measured_value(&tlv)
354}
355
356/// Read `MinMeasuredValue` attribute from cluster `Radon Concentration Measurement`.
357pub async fn read_min_measured_value(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
358    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_MINMEASUREDVALUE).await?;
359    decode_min_measured_value(&tlv)
360}
361
362/// Read `MaxMeasuredValue` attribute from cluster `Radon Concentration Measurement`.
363pub async fn read_max_measured_value(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
364    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_MAXMEASUREDVALUE).await?;
365    decode_max_measured_value(&tlv)
366}
367
368/// Read `PeakMeasuredValue` attribute from cluster `Radon Concentration Measurement`.
369pub async fn read_peak_measured_value(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
370    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_PEAKMEASUREDVALUE).await?;
371    decode_peak_measured_value(&tlv)
372}
373
374/// Read `PeakMeasuredValueWindow` attribute from cluster `Radon Concentration Measurement`.
375pub async fn read_peak_measured_value_window(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
376    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_PEAKMEASUREDVALUEWINDOW).await?;
377    decode_peak_measured_value_window(&tlv)
378}
379
380/// Read `AverageMeasuredValue` attribute from cluster `Radon Concentration Measurement`.
381pub async fn read_average_measured_value(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
382    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_AVERAGEMEASUREDVALUE).await?;
383    decode_average_measured_value(&tlv)
384}
385
386/// Read `AverageMeasuredValueWindow` attribute from cluster `Radon Concentration Measurement`.
387pub async fn read_average_measured_value_window(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
388    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_AVERAGEMEASUREDVALUEWINDOW).await?;
389    decode_average_measured_value_window(&tlv)
390}
391
392/// Read `Uncertainty` attribute from cluster `Radon Concentration Measurement`.
393pub async fn read_uncertainty(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
394    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_UNCERTAINTY).await?;
395    decode_uncertainty(&tlv)
396}
397
398/// Read `MeasurementUnit` attribute from cluster `Radon Concentration Measurement`.
399pub async fn read_measurement_unit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<MeasurementUnit> {
400    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_MEASUREMENTUNIT).await?;
401    decode_measurement_unit(&tlv)
402}
403
404/// Read `MeasurementMedium` attribute from cluster `Radon Concentration Measurement`.
405pub async fn read_measurement_medium(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<MeasurementMedium> {
406    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_MEASUREMENTMEDIUM).await?;
407    decode_measurement_medium(&tlv)
408}
409
410/// Read `LevelValue` attribute from cluster `Radon Concentration Measurement`.
411pub async fn read_level_value(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LevelValue> {
412    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_RADON_CONCENTRATION_MEASUREMENT, crate::clusters::defs::CLUSTER_RADON_CONCENTRATION_MEASUREMENT_ATTR_ID_LEVELVALUE).await?;
413    decode_level_value(&tlv)
414}
415