matc/clusters/codec/
resource_monitoring.rs

1//! Matter TLV encoders and decoders for Resource Monitoring Clusters
2//! Cluster ID: 0x0000
3//!
4//! This file is automatically generated from ResourceMonitoring.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 ChangeIndication {
16    /// Resource is in good condition, no intervention required
17    Ok = 0,
18    /// Resource will be exhausted soon, intervention will shortly be required
19    Warning = 1,
20    /// Resource is exhausted, immediate intervention is required
21    Critical = 2,
22}
23
24impl ChangeIndication {
25    /// Convert from u8 value
26    pub fn from_u8(value: u8) -> Option<Self> {
27        match value {
28            0 => Some(ChangeIndication::Ok),
29            1 => Some(ChangeIndication::Warning),
30            2 => Some(ChangeIndication::Critical),
31            _ => None,
32        }
33    }
34
35    /// Convert to u8 value
36    pub fn to_u8(self) -> u8 {
37        self as u8
38    }
39}
40
41impl From<ChangeIndication> for u8 {
42    fn from(val: ChangeIndication) -> Self {
43        val as u8
44    }
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
48#[repr(u8)]
49pub enum DegradationDirection {
50    /// The degradation of the resource is indicated by an upwards moving/increasing value
51    Up = 0,
52    /// The degradation of the resource is indicated by a downwards moving/decreasing value
53    Down = 1,
54}
55
56impl DegradationDirection {
57    /// Convert from u8 value
58    pub fn from_u8(value: u8) -> Option<Self> {
59        match value {
60            0 => Some(DegradationDirection::Up),
61            1 => Some(DegradationDirection::Down),
62            _ => None,
63        }
64    }
65
66    /// Convert to u8 value
67    pub fn to_u8(self) -> u8 {
68        self as u8
69    }
70}
71
72impl From<DegradationDirection> for u8 {
73    fn from(val: DegradationDirection) -> Self {
74        val as u8
75    }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
79#[repr(u8)]
80pub enum ProductIdentifierType {
81    /// 12-digit Universal Product Code
82    Upc = 0,
83    /// 8-digit Global Trade Item Number
84    Gtin8 = 1,
85    /// 13-digit European Article Number
86    Ean = 2,
87    /// 14-digit Global Trade Item Number
88    Gtin14 = 3,
89    /// Original Equipment Manufacturer part number
90    Oem = 4,
91}
92
93impl ProductIdentifierType {
94    /// Convert from u8 value
95    pub fn from_u8(value: u8) -> Option<Self> {
96        match value {
97            0 => Some(ProductIdentifierType::Upc),
98            1 => Some(ProductIdentifierType::Gtin8),
99            2 => Some(ProductIdentifierType::Ean),
100            3 => Some(ProductIdentifierType::Gtin14),
101            4 => Some(ProductIdentifierType::Oem),
102            _ => None,
103        }
104    }
105
106    /// Convert to u8 value
107    pub fn to_u8(self) -> u8 {
108        self as u8
109    }
110}
111
112impl From<ProductIdentifierType> for u8 {
113    fn from(val: ProductIdentifierType) -> Self {
114        val as u8
115    }
116}
117
118// Struct definitions
119
120#[derive(Debug, serde::Serialize)]
121pub struct ReplacementProduct {
122    pub product_identifier_type: Option<ProductIdentifierType>,
123    pub product_identifier_value: Option<String>,
124}
125
126// Command encoders
127
128// Attribute decoders
129
130/// Decode Condition attribute (0x0000)
131pub fn decode_condition(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
132    if let tlv::TlvItemValue::Int(v) = inp {
133        Ok(*v as u8)
134    } else {
135        Err(anyhow::anyhow!("Expected UInt8"))
136    }
137}
138
139/// Decode DegradationDirection attribute (0x0001)
140pub fn decode_degradation_direction(inp: &tlv::TlvItemValue) -> anyhow::Result<DegradationDirection> {
141    if let tlv::TlvItemValue::Int(v) = inp {
142        DegradationDirection::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
143    } else {
144        Err(anyhow::anyhow!("Expected Integer"))
145    }
146}
147
148/// Decode ChangeIndication attribute (0x0002)
149pub fn decode_change_indication(inp: &tlv::TlvItemValue) -> anyhow::Result<ChangeIndication> {
150    if let tlv::TlvItemValue::Int(v) = inp {
151        ChangeIndication::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
152    } else {
153        Err(anyhow::anyhow!("Expected Integer"))
154    }
155}
156
157/// Decode InPlaceIndicator attribute (0x0003)
158pub fn decode_in_place_indicator(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
159    if let tlv::TlvItemValue::Bool(v) = inp {
160        Ok(*v)
161    } else {
162        Err(anyhow::anyhow!("Expected Bool"))
163    }
164}
165
166/// Decode LastChangedTime attribute (0x0004)
167pub fn decode_last_changed_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
168    if let tlv::TlvItemValue::Int(v) = inp {
169        Ok(Some(*v))
170    } else {
171        Ok(None)
172    }
173}
174
175/// Decode ReplacementProductList attribute (0x0005)
176pub fn decode_replacement_product_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ReplacementProduct>> {
177    let mut res = Vec::new();
178    if let tlv::TlvItemValue::List(v) = inp {
179        for item in v {
180            res.push(ReplacementProduct {
181                product_identifier_type: item.get_int(&[0]).and_then(|v| ProductIdentifierType::from_u8(v as u8)),
182                product_identifier_value: item.get_string_owned(&[1]),
183            });
184        }
185    }
186    Ok(res)
187}
188
189
190// JSON dispatcher function
191
192/// Decode attribute value and return as JSON string
193///
194/// # Parameters
195/// * `cluster_id` - The cluster identifier
196/// * `attribute_id` - The attribute identifier
197/// * `tlv_value` - The TLV value to decode
198///
199/// # Returns
200/// JSON string representation of the decoded value or error
201pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
202    // Verify this is the correct cluster
203    if cluster_id != 0x0000 {
204        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0000, got {}\"}}", cluster_id);
205    }
206
207    match attribute_id {
208        0x0000 => {
209            match decode_condition(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        0x0001 => {
215            match decode_degradation_direction(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        0x0002 => {
221            match decode_change_indication(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        0x0003 => {
227            match decode_in_place_indicator(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        0x0004 => {
233            match decode_last_changed_time(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        0x0005 => {
239            match decode_replacement_product_list(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        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
245    }
246}
247
248/// Get list of all attributes supported by this cluster
249///
250/// # Returns
251/// Vector of tuples containing (attribute_id, attribute_name)
252pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
253    vec![
254        (0x0000, "Condition"),
255        (0x0001, "DegradationDirection"),
256        (0x0002, "ChangeIndication"),
257        (0x0003, "InPlaceIndicator"),
258        (0x0004, "LastChangedTime"),
259        (0x0005, "ReplacementProductList"),
260    ]
261}
262