1use 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 MeasurementType {
16 Unspecified = 0,
17 Voltage = 1,
19 Activecurrent = 2,
21 Reactivecurrent = 3,
23 Apparentcurrent = 4,
25 Activepower = 5,
27 Reactivepower = 6,
29 Apparentpower = 7,
31 Rmsvoltage = 8,
33 Rmscurrent = 9,
35 Rmspower = 10,
37 Frequency = 11,
39 Powerfactor = 12,
41 Neutralcurrent = 13,
43 Electricalenergy = 14,
45 Reactiveenergy = 15,
47 Apparentenergy = 16,
49}
50
51impl MeasurementType {
52 pub fn from_u8(value: u8) -> Option<Self> {
54 match value {
55 0 => Some(MeasurementType::Unspecified),
56 1 => Some(MeasurementType::Voltage),
57 2 => Some(MeasurementType::Activecurrent),
58 3 => Some(MeasurementType::Reactivecurrent),
59 4 => Some(MeasurementType::Apparentcurrent),
60 5 => Some(MeasurementType::Activepower),
61 6 => Some(MeasurementType::Reactivepower),
62 7 => Some(MeasurementType::Apparentpower),
63 8 => Some(MeasurementType::Rmsvoltage),
64 9 => Some(MeasurementType::Rmscurrent),
65 10 => Some(MeasurementType::Rmspower),
66 11 => Some(MeasurementType::Frequency),
67 12 => Some(MeasurementType::Powerfactor),
68 13 => Some(MeasurementType::Neutralcurrent),
69 14 => Some(MeasurementType::Electricalenergy),
70 15 => Some(MeasurementType::Reactiveenergy),
71 16 => Some(MeasurementType::Apparentenergy),
72 _ => None,
73 }
74 }
75
76 pub fn to_u8(self) -> u8 {
78 self as u8
79 }
80}
81
82impl From<MeasurementType> for u8 {
83 fn from(val: MeasurementType) -> Self {
84 val as u8
85 }
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
89#[repr(u8)]
90pub enum PowerMode {
91 Unknown = 0,
92 Dc = 1,
94 Ac = 2,
96}
97
98impl PowerMode {
99 pub fn from_u8(value: u8) -> Option<Self> {
101 match value {
102 0 => Some(PowerMode::Unknown),
103 1 => Some(PowerMode::Dc),
104 2 => Some(PowerMode::Ac),
105 _ => None,
106 }
107 }
108
109 pub fn to_u8(self) -> u8 {
111 self as u8
112 }
113}
114
115impl From<PowerMode> for u8 {
116 fn from(val: PowerMode) -> Self {
117 val as u8
118 }
119}
120
121#[derive(Debug, serde::Serialize)]
124pub struct HarmonicMeasurement {
125 pub order: Option<u8>,
126 pub measurement: Option<i64>,
127}
128
129#[derive(Debug, serde::Serialize)]
130pub struct MeasurementAccuracyRange {
131 pub range_min: Option<i64>,
132 pub range_max: Option<i64>,
133 pub percent_max: Option<u8>,
134 pub percent_min: Option<u8>,
135 pub percent_typical: Option<u8>,
136 pub fixed_max: Option<u64>,
137 pub fixed_min: Option<u64>,
138 pub fixed_typical: Option<u64>,
139}
140
141#[derive(Debug, serde::Serialize)]
142pub struct MeasurementAccuracy {
143 pub measurement_type: Option<MeasurementType>,
144 pub measured: Option<bool>,
145 pub min_measured_value: Option<i64>,
146 pub max_measured_value: Option<i64>,
147 pub accuracy_ranges: Option<Vec<MeasurementAccuracyRange>>,
148}
149
150#[derive(Debug, serde::Serialize)]
151pub struct MeasurementRange {
152 pub measurement_type: Option<MeasurementType>,
153 pub min: Option<i64>,
154 pub max: Option<i64>,
155 pub start_timestamp: Option<u64>,
156 pub end_timestamp: Option<u64>,
157 pub min_timestamp: Option<u64>,
158 pub max_timestamp: Option<u64>,
159 pub start_systime: Option<u8>,
160 pub end_systime: Option<u8>,
161 pub min_systime: Option<u8>,
162 pub max_systime: Option<u8>,
163}
164
165pub fn decode_power_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<PowerMode> {
169 if let tlv::TlvItemValue::Int(v) = inp {
170 PowerMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
171 } else {
172 Err(anyhow::anyhow!("Expected Integer"))
173 }
174}
175
176pub fn decode_number_of_measurement_types(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
178 if let tlv::TlvItemValue::Int(v) = inp {
179 Ok(*v as u8)
180 } else {
181 Err(anyhow::anyhow!("Expected UInt8"))
182 }
183}
184
185pub fn decode_accuracy(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<MeasurementAccuracy>> {
187 let mut res = Vec::new();
188 if let tlv::TlvItemValue::List(v) = inp {
189 for item in v {
190 res.push(MeasurementAccuracy {
191 measurement_type: item.get_int(&[0]).and_then(|v| MeasurementType::from_u8(v as u8)),
192 measured: item.get_bool(&[1]),
193 min_measured_value: item.get_int(&[2]).map(|v| v as i64),
194 max_measured_value: item.get_int(&[3]).map(|v| v as i64),
195 accuracy_ranges: {
196 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[4]) {
197 let mut items = Vec::new();
198 for list_item in l {
199 items.push(MeasurementAccuracyRange {
200 range_min: list_item.get_int(&[0]).map(|v| v as i64),
201 range_max: list_item.get_int(&[1]).map(|v| v as i64),
202 percent_max: list_item.get_int(&[2]).map(|v| v as u8),
203 percent_min: list_item.get_int(&[3]).map(|v| v as u8),
204 percent_typical: list_item.get_int(&[4]).map(|v| v as u8),
205 fixed_max: list_item.get_int(&[5]),
206 fixed_min: list_item.get_int(&[6]),
207 fixed_typical: list_item.get_int(&[7]),
208 });
209 }
210 Some(items)
211 } else {
212 None
213 }
214 },
215 });
216 }
217 }
218 Ok(res)
219}
220
221pub fn decode_ranges(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<MeasurementRange>> {
223 let mut res = Vec::new();
224 if let tlv::TlvItemValue::List(v) = inp {
225 for item in v {
226 res.push(MeasurementRange {
227 measurement_type: item.get_int(&[0]).and_then(|v| MeasurementType::from_u8(v as u8)),
228 min: item.get_int(&[1]).map(|v| v as i64),
229 max: item.get_int(&[2]).map(|v| v as i64),
230 start_timestamp: item.get_int(&[3]),
231 end_timestamp: item.get_int(&[4]),
232 min_timestamp: item.get_int(&[5]),
233 max_timestamp: item.get_int(&[6]),
234 start_systime: item.get_int(&[7]).map(|v| v as u8),
235 end_systime: item.get_int(&[8]).map(|v| v as u8),
236 min_systime: item.get_int(&[9]).map(|v| v as u8),
237 max_systime: item.get_int(&[10]).map(|v| v as u8),
238 });
239 }
240 }
241 Ok(res)
242}
243
244pub fn decode_voltage(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
246 if let tlv::TlvItemValue::Int(v) = inp {
247 Ok(Some(*v as u8))
248 } else {
249 Ok(None)
250 }
251}
252
253pub fn decode_active_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
255 if let tlv::TlvItemValue::Int(v) = inp {
256 Ok(Some(*v as u8))
257 } else {
258 Ok(None)
259 }
260}
261
262pub fn decode_reactive_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
264 if let tlv::TlvItemValue::Int(v) = inp {
265 Ok(Some(*v as u8))
266 } else {
267 Ok(None)
268 }
269}
270
271pub fn decode_apparent_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
273 if let tlv::TlvItemValue::Int(v) = inp {
274 Ok(Some(*v as u8))
275 } else {
276 Ok(None)
277 }
278}
279
280pub fn decode_active_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
282 if let tlv::TlvItemValue::Int(v) = inp {
283 Ok(Some(*v as u32))
284 } else {
285 Ok(None)
286 }
287}
288
289pub fn decode_reactive_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
291 if let tlv::TlvItemValue::Int(v) = inp {
292 Ok(Some(*v as u8))
293 } else {
294 Ok(None)
295 }
296}
297
298pub fn decode_apparent_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
300 if let tlv::TlvItemValue::Int(v) = inp {
301 Ok(Some(*v as u8))
302 } else {
303 Ok(None)
304 }
305}
306
307pub fn decode_rms_voltage(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
309 if let tlv::TlvItemValue::Int(v) = inp {
310 Ok(Some(*v as u8))
311 } else {
312 Ok(None)
313 }
314}
315
316pub fn decode_rms_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
318 if let tlv::TlvItemValue::Int(v) = inp {
319 Ok(Some(*v as u8))
320 } else {
321 Ok(None)
322 }
323}
324
325pub fn decode_rms_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
327 if let tlv::TlvItemValue::Int(v) = inp {
328 Ok(Some(*v as u32))
329 } else {
330 Ok(None)
331 }
332}
333
334pub fn decode_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i64>> {
336 if let tlv::TlvItemValue::Int(v) = inp {
337 Ok(Some(*v as i64))
338 } else {
339 Ok(None)
340 }
341}
342
343pub fn decode_harmonic_currents(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<HarmonicMeasurement>> {
345 let mut res = Vec::new();
346 if let tlv::TlvItemValue::List(v) = inp {
347 for item in v {
348 res.push(HarmonicMeasurement {
349 order: item.get_int(&[0]).map(|v| v as u8),
350 measurement: item.get_int(&[1]).map(|v| v as i64),
351 });
352 }
353 }
354 Ok(res)
355}
356
357pub fn decode_harmonic_phases(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<HarmonicMeasurement>> {
359 let mut res = Vec::new();
360 if let tlv::TlvItemValue::List(v) = inp {
361 for item in v {
362 res.push(HarmonicMeasurement {
363 order: item.get_int(&[0]).map(|v| v as u8),
364 measurement: item.get_int(&[1]).map(|v| v as i64),
365 });
366 }
367 }
368 Ok(res)
369}
370
371pub fn decode_power_factor(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i64>> {
373 if let tlv::TlvItemValue::Int(v) = inp {
374 Ok(Some(*v as i64))
375 } else {
376 Ok(None)
377 }
378}
379
380pub fn decode_neutral_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
382 if let tlv::TlvItemValue::Int(v) = inp {
383 Ok(Some(*v as u8))
384 } else {
385 Ok(None)
386 }
387}
388
389
390pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
402 if cluster_id != 0x0090 {
404 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0090, got {}\"}}", cluster_id);
405 }
406
407 match attribute_id {
408 0x0000 => {
409 match decode_power_mode(tlv_value) {
410 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
411 Err(e) => format!("{{\"error\": \"{}\"}}", e),
412 }
413 }
414 0x0001 => {
415 match decode_number_of_measurement_types(tlv_value) {
416 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
417 Err(e) => format!("{{\"error\": \"{}\"}}", e),
418 }
419 }
420 0x0002 => {
421 match decode_accuracy(tlv_value) {
422 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
423 Err(e) => format!("{{\"error\": \"{}\"}}", e),
424 }
425 }
426 0x0003 => {
427 match decode_ranges(tlv_value) {
428 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
429 Err(e) => format!("{{\"error\": \"{}\"}}", e),
430 }
431 }
432 0x0004 => {
433 match decode_voltage(tlv_value) {
434 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
435 Err(e) => format!("{{\"error\": \"{}\"}}", e),
436 }
437 }
438 0x0005 => {
439 match decode_active_current(tlv_value) {
440 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
441 Err(e) => format!("{{\"error\": \"{}\"}}", e),
442 }
443 }
444 0x0006 => {
445 match decode_reactive_current(tlv_value) {
446 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
447 Err(e) => format!("{{\"error\": \"{}\"}}", e),
448 }
449 }
450 0x0007 => {
451 match decode_apparent_current(tlv_value) {
452 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
453 Err(e) => format!("{{\"error\": \"{}\"}}", e),
454 }
455 }
456 0x0008 => {
457 match decode_active_power(tlv_value) {
458 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
459 Err(e) => format!("{{\"error\": \"{}\"}}", e),
460 }
461 }
462 0x0009 => {
463 match decode_reactive_power(tlv_value) {
464 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
465 Err(e) => format!("{{\"error\": \"{}\"}}", e),
466 }
467 }
468 0x000A => {
469 match decode_apparent_power(tlv_value) {
470 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
471 Err(e) => format!("{{\"error\": \"{}\"}}", e),
472 }
473 }
474 0x000B => {
475 match decode_rms_voltage(tlv_value) {
476 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
477 Err(e) => format!("{{\"error\": \"{}\"}}", e),
478 }
479 }
480 0x000C => {
481 match decode_rms_current(tlv_value) {
482 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
483 Err(e) => format!("{{\"error\": \"{}\"}}", e),
484 }
485 }
486 0x000D => {
487 match decode_rms_power(tlv_value) {
488 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
489 Err(e) => format!("{{\"error\": \"{}\"}}", e),
490 }
491 }
492 0x000E => {
493 match decode_frequency(tlv_value) {
494 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
495 Err(e) => format!("{{\"error\": \"{}\"}}", e),
496 }
497 }
498 0x000F => {
499 match decode_harmonic_currents(tlv_value) {
500 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
501 Err(e) => format!("{{\"error\": \"{}\"}}", e),
502 }
503 }
504 0x0010 => {
505 match decode_harmonic_phases(tlv_value) {
506 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
507 Err(e) => format!("{{\"error\": \"{}\"}}", e),
508 }
509 }
510 0x0011 => {
511 match decode_power_factor(tlv_value) {
512 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
513 Err(e) => format!("{{\"error\": \"{}\"}}", e),
514 }
515 }
516 0x0012 => {
517 match decode_neutral_current(tlv_value) {
518 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
519 Err(e) => format!("{{\"error\": \"{}\"}}", e),
520 }
521 }
522 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
523 }
524}
525
526pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
531 vec![
532 (0x0000, "PowerMode"),
533 (0x0001, "NumberOfMeasurementTypes"),
534 (0x0002, "Accuracy"),
535 (0x0003, "Ranges"),
536 (0x0004, "Voltage"),
537 (0x0005, "ActiveCurrent"),
538 (0x0006, "ReactiveCurrent"),
539 (0x0007, "ApparentCurrent"),
540 (0x0008, "ActivePower"),
541 (0x0009, "ReactivePower"),
542 (0x000A, "ApparentPower"),
543 (0x000B, "RMSVoltage"),
544 (0x000C, "RMSCurrent"),
545 (0x000D, "RMSPower"),
546 (0x000E, "Frequency"),
547 (0x000F, "HarmonicCurrents"),
548 (0x0010, "HarmonicPhases"),
549 (0x0011, "PowerFactor"),
550 (0x0012, "NeutralCurrent"),
551 ]
552}
553
554#[derive(Debug, serde::Serialize)]
555pub struct MeasurementPeriodRangesEvent {
556 pub ranges: Option<Vec<MeasurementRange>>,
557}
558
559pub fn decode_measurement_period_ranges_event(inp: &tlv::TlvItemValue) -> anyhow::Result<MeasurementPeriodRangesEvent> {
563 if let tlv::TlvItemValue::List(_fields) = inp {
564 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
565 Ok(MeasurementPeriodRangesEvent {
566 ranges: {
567 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
568 let mut items = Vec::new();
569 for list_item in l {
570 items.push(MeasurementRange {
571 measurement_type: list_item.get_int(&[0]).and_then(|v| MeasurementType::from_u8(v as u8)),
572 min: list_item.get_int(&[1]).map(|v| v as i64),
573 max: list_item.get_int(&[2]).map(|v| v as i64),
574 start_timestamp: list_item.get_int(&[3]),
575 end_timestamp: list_item.get_int(&[4]),
576 min_timestamp: list_item.get_int(&[5]),
577 max_timestamp: list_item.get_int(&[6]),
578 start_systime: list_item.get_int(&[7]).map(|v| v as u8),
579 end_systime: list_item.get_int(&[8]).map(|v| v as u8),
580 min_systime: list_item.get_int(&[9]).map(|v| v as u8),
581 max_systime: list_item.get_int(&[10]).map(|v| v as u8),
582 });
583 }
584 Some(items)
585 } else {
586 None
587 }
588 },
589 })
590 } else {
591 Err(anyhow::anyhow!("Expected struct fields"))
592 }
593}
594