matc/clusters/codec/
resource_monitoring.rs1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum ChangeIndication {
16 Ok = 0,
18 Warning = 1,
20 Critical = 2,
22}
23
24impl ChangeIndication {
25 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 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 Up = 0,
52 Down = 1,
54}
55
56impl DegradationDirection {
57 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 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 Upc = 0,
83 Gtin8 = 1,
85 Ean = 2,
87 Gtin14 = 3,
89 Oem = 4,
91}
92
93impl ProductIdentifierType {
94 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 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#[derive(Debug, serde::Serialize)]
121pub struct ReplacementProduct {
122 pub product_identifier_type: Option<ProductIdentifierType>,
123 pub product_identifier_value: Option<String>,
124}
125
126pub 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
139pub 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
148pub 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
157pub 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
166pub 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
175pub 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
190pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
202 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
248pub 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