matc/clusters/codec/
electrical_energy_measurement.rs1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, serde::Serialize)]
14pub struct CumulativeEnergyReset {
15 pub imported_reset_timestamp: Option<u64>,
16 pub exported_reset_timestamp: Option<u64>,
17 pub imported_reset_systime: Option<u8>,
18 pub exported_reset_systime: Option<u8>,
19}
20
21#[derive(Debug, serde::Serialize)]
22pub struct EnergyMeasurement {
23 pub energy: Option<u8>,
24 pub start_timestamp: Option<u64>,
25 pub end_timestamp: Option<u64>,
26 pub start_systime: Option<u8>,
27 pub end_systime: Option<u8>,
28}
29
30pub fn decode_accuracy(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
34 if let tlv::TlvItemValue::Int(v) = inp {
35 Ok(*v as u8)
36 } else {
37 Err(anyhow::anyhow!("Expected Integer"))
38 }
39}
40
41pub fn decode_cumulative_energy_imported(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<EnergyMeasurement>> {
43 if let tlv::TlvItemValue::List(_fields) = inp {
44 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
46 Ok(Some(EnergyMeasurement {
47 energy: item.get_int(&[0]).map(|v| v as u8),
48 start_timestamp: item.get_int(&[1]),
49 end_timestamp: item.get_int(&[2]),
50 start_systime: item.get_int(&[3]).map(|v| v as u8),
51 end_systime: item.get_int(&[4]).map(|v| v as u8),
52 }))
53 } else {
57 Ok(None)
58 }
60}
61
62pub fn decode_cumulative_energy_exported(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<EnergyMeasurement>> {
64 if let tlv::TlvItemValue::List(_fields) = inp {
65 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
67 Ok(Some(EnergyMeasurement {
68 energy: item.get_int(&[0]).map(|v| v as u8),
69 start_timestamp: item.get_int(&[1]),
70 end_timestamp: item.get_int(&[2]),
71 start_systime: item.get_int(&[3]).map(|v| v as u8),
72 end_systime: item.get_int(&[4]).map(|v| v as u8),
73 }))
74 } else {
78 Ok(None)
79 }
81}
82
83pub fn decode_periodic_energy_imported(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<EnergyMeasurement>> {
85 if let tlv::TlvItemValue::List(_fields) = inp {
86 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
88 Ok(Some(EnergyMeasurement {
89 energy: item.get_int(&[0]).map(|v| v as u8),
90 start_timestamp: item.get_int(&[1]),
91 end_timestamp: item.get_int(&[2]),
92 start_systime: item.get_int(&[3]).map(|v| v as u8),
93 end_systime: item.get_int(&[4]).map(|v| v as u8),
94 }))
95 } else {
99 Ok(None)
100 }
102}
103
104pub fn decode_periodic_energy_exported(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<EnergyMeasurement>> {
106 if let tlv::TlvItemValue::List(_fields) = inp {
107 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
109 Ok(Some(EnergyMeasurement {
110 energy: item.get_int(&[0]).map(|v| v as u8),
111 start_timestamp: item.get_int(&[1]),
112 end_timestamp: item.get_int(&[2]),
113 start_systime: item.get_int(&[3]).map(|v| v as u8),
114 end_systime: item.get_int(&[4]).map(|v| v as u8),
115 }))
116 } else {
120 Ok(None)
121 }
123}
124
125pub fn decode_cumulative_energy_reset(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<CumulativeEnergyReset>> {
127 if let tlv::TlvItemValue::List(_fields) = inp {
128 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
130 Ok(Some(CumulativeEnergyReset {
131 imported_reset_timestamp: item.get_int(&[0]),
132 exported_reset_timestamp: item.get_int(&[1]),
133 imported_reset_systime: item.get_int(&[2]).map(|v| v as u8),
134 exported_reset_systime: item.get_int(&[3]).map(|v| v as u8),
135 }))
136 } else {
140 Ok(None)
141 }
143}
144
145
146pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
158 if cluster_id != 0x0091 {
160 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0091, got {}\"}}", cluster_id);
161 }
162
163 match attribute_id {
164 0x0000 => {
165 match decode_accuracy(tlv_value) {
166 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
167 Err(e) => format!("{{\"error\": \"{}\"}}", e),
168 }
169 }
170 0x0001 => {
171 match decode_cumulative_energy_imported(tlv_value) {
172 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
173 Err(e) => format!("{{\"error\": \"{}\"}}", e),
174 }
175 }
176 0x0002 => {
177 match decode_cumulative_energy_exported(tlv_value) {
178 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
179 Err(e) => format!("{{\"error\": \"{}\"}}", e),
180 }
181 }
182 0x0003 => {
183 match decode_periodic_energy_imported(tlv_value) {
184 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
185 Err(e) => format!("{{\"error\": \"{}\"}}", e),
186 }
187 }
188 0x0004 => {
189 match decode_periodic_energy_exported(tlv_value) {
190 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
191 Err(e) => format!("{{\"error\": \"{}\"}}", e),
192 }
193 }
194 0x0005 => {
195 match decode_cumulative_energy_reset(tlv_value) {
196 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
197 Err(e) => format!("{{\"error\": \"{}\"}}", e),
198 }
199 }
200 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
201 }
202}
203
204pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
209 vec![
210 (0x0000, "Accuracy"),
211 (0x0001, "CumulativeEnergyImported"),
212 (0x0002, "CumulativeEnergyExported"),
213 (0x0003, "PeriodicEnergyImported"),
214 (0x0004, "PeriodicEnergyExported"),
215 (0x0005, "CumulativeEnergyReset"),
216 ]
217}
218