matc/clusters/codec/
electrical_power_measurement.rs

1//! Matter TLV encoders and decoders for Electrical Power Measurement Cluster
2//! Cluster ID: 0x0090
3//!
4//! This file is automatically generated from ElectricalPowerMeasurement.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 MeasurementType {
18    Unspecified = 0,
19    /// Voltage in millivolts (mV)
20    Voltage = 1,
21    /// Active current in milliamps (mA)
22    Activecurrent = 2,
23    /// Reactive current in milliamps (mA)
24    Reactivecurrent = 3,
25    /// Apparent current in milliamps (mA)
26    Apparentcurrent = 4,
27    /// Active power in milliwatts (mW)
28    Activepower = 5,
29    /// Reactive power in millivolt-amps reactive (mVAR)
30    Reactivepower = 6,
31    /// Apparent power in millivolt-amps (mVA)
32    Apparentpower = 7,
33    /// Root mean squared voltage in millivolts (mV)
34    Rmsvoltage = 8,
35    /// Root mean squared current in milliamps (mA)
36    Rmscurrent = 9,
37    /// Root mean squared power in milliwatts (mW)
38    Rmspower = 10,
39    /// AC frequency in millihertz (mHz)
40    Frequency = 11,
41    /// Power Factor ratio in +/- 1/100ths of a percent.
42    Powerfactor = 12,
43    /// AC neutral current in milliamps (mA)
44    Neutralcurrent = 13,
45    /// Electrical energy in milliwatt-hours (mWh)
46    Electricalenergy = 14,
47    /// Reactive power in millivolt-amp-hours reactive (mVARh)
48    Reactiveenergy = 15,
49    /// Apparent power in millivolt-amp-hours (mVAh)
50    Apparentenergy = 16,
51}
52
53impl MeasurementType {
54    /// Convert from u8 value
55    pub fn from_u8(value: u8) -> Option<Self> {
56        match value {
57            0 => Some(MeasurementType::Unspecified),
58            1 => Some(MeasurementType::Voltage),
59            2 => Some(MeasurementType::Activecurrent),
60            3 => Some(MeasurementType::Reactivecurrent),
61            4 => Some(MeasurementType::Apparentcurrent),
62            5 => Some(MeasurementType::Activepower),
63            6 => Some(MeasurementType::Reactivepower),
64            7 => Some(MeasurementType::Apparentpower),
65            8 => Some(MeasurementType::Rmsvoltage),
66            9 => Some(MeasurementType::Rmscurrent),
67            10 => Some(MeasurementType::Rmspower),
68            11 => Some(MeasurementType::Frequency),
69            12 => Some(MeasurementType::Powerfactor),
70            13 => Some(MeasurementType::Neutralcurrent),
71            14 => Some(MeasurementType::Electricalenergy),
72            15 => Some(MeasurementType::Reactiveenergy),
73            16 => Some(MeasurementType::Apparentenergy),
74            _ => None,
75        }
76    }
77
78    /// Convert to u8 value
79    pub fn to_u8(self) -> u8 {
80        self as u8
81    }
82}
83
84impl From<MeasurementType> for u8 {
85    fn from(val: MeasurementType) -> Self {
86        val as u8
87    }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
91#[repr(u8)]
92pub enum PowerMode {
93    Unknown = 0,
94    /// Direct current
95    Dc = 1,
96    /// Alternating current, either single-phase or polyphase
97    Ac = 2,
98}
99
100impl PowerMode {
101    /// Convert from u8 value
102    pub fn from_u8(value: u8) -> Option<Self> {
103        match value {
104            0 => Some(PowerMode::Unknown),
105            1 => Some(PowerMode::Dc),
106            2 => Some(PowerMode::Ac),
107            _ => None,
108        }
109    }
110
111    /// Convert to u8 value
112    pub fn to_u8(self) -> u8 {
113        self as u8
114    }
115}
116
117impl From<PowerMode> for u8 {
118    fn from(val: PowerMode) -> Self {
119        val as u8
120    }
121}
122
123// Struct definitions
124
125#[derive(Debug, serde::Serialize)]
126pub struct HarmonicMeasurement {
127    pub order: Option<u8>,
128    pub measurement: Option<i64>,
129}
130
131#[derive(Debug, serde::Serialize)]
132pub struct MeasurementAccuracyRange {
133    pub range_min: Option<i64>,
134    pub range_max: Option<i64>,
135    pub percent_max: Option<u8>,
136    pub percent_min: Option<u8>,
137    pub percent_typical: Option<u8>,
138    pub fixed_max: Option<u64>,
139    pub fixed_min: Option<u64>,
140    pub fixed_typical: Option<u64>,
141}
142
143#[derive(Debug, serde::Serialize)]
144pub struct MeasurementAccuracy {
145    pub measurement_type: Option<MeasurementType>,
146    pub measured: Option<bool>,
147    pub min_measured_value: Option<i64>,
148    pub max_measured_value: Option<i64>,
149    pub accuracy_ranges: Option<Vec<MeasurementAccuracyRange>>,
150}
151
152#[derive(Debug, serde::Serialize)]
153pub struct MeasurementRange {
154    pub measurement_type: Option<MeasurementType>,
155    pub min: Option<i64>,
156    pub max: Option<i64>,
157    pub start_timestamp: Option<u64>,
158    pub end_timestamp: Option<u64>,
159    pub min_timestamp: Option<u64>,
160    pub max_timestamp: Option<u64>,
161    pub start_systime: Option<u8>,
162    pub end_systime: Option<u8>,
163    pub min_systime: Option<u8>,
164    pub max_systime: Option<u8>,
165}
166
167// Attribute decoders
168
169/// Decode PowerMode attribute (0x0000)
170pub fn decode_power_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<PowerMode> {
171    if let tlv::TlvItemValue::Int(v) = inp {
172        PowerMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
173    } else {
174        Err(anyhow::anyhow!("Expected Integer"))
175    }
176}
177
178/// Decode NumberOfMeasurementTypes attribute (0x0001)
179pub fn decode_number_of_measurement_types(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
180    if let tlv::TlvItemValue::Int(v) = inp {
181        Ok(*v as u8)
182    } else {
183        Err(anyhow::anyhow!("Expected UInt8"))
184    }
185}
186
187/// Decode Accuracy attribute (0x0002)
188pub fn decode_accuracy(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<MeasurementAccuracy>> {
189    let mut res = Vec::new();
190    if let tlv::TlvItemValue::List(v) = inp {
191        for item in v {
192            res.push(MeasurementAccuracy {
193                measurement_type: item.get_int(&[0]).and_then(|v| MeasurementType::from_u8(v as u8)),
194                measured: item.get_bool(&[1]),
195                min_measured_value: item.get_int(&[2]).map(|v| v as i64),
196                max_measured_value: item.get_int(&[3]).map(|v| v as i64),
197                accuracy_ranges: {
198                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[4]) {
199                        let mut items = Vec::new();
200                        for list_item in l {
201                            items.push(MeasurementAccuracyRange {
202                range_min: list_item.get_int(&[0]).map(|v| v as i64),
203                range_max: list_item.get_int(&[1]).map(|v| v as i64),
204                percent_max: list_item.get_int(&[2]).map(|v| v as u8),
205                percent_min: list_item.get_int(&[3]).map(|v| v as u8),
206                percent_typical: list_item.get_int(&[4]).map(|v| v as u8),
207                fixed_max: list_item.get_int(&[5]),
208                fixed_min: list_item.get_int(&[6]),
209                fixed_typical: list_item.get_int(&[7]),
210                            });
211                        }
212                        Some(items)
213                    } else {
214                        None
215                    }
216                },
217            });
218        }
219    }
220    Ok(res)
221}
222
223/// Decode Ranges attribute (0x0003)
224pub fn decode_ranges(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<MeasurementRange>> {
225    let mut res = Vec::new();
226    if let tlv::TlvItemValue::List(v) = inp {
227        for item in v {
228            res.push(MeasurementRange {
229                measurement_type: item.get_int(&[0]).and_then(|v| MeasurementType::from_u8(v as u8)),
230                min: item.get_int(&[1]).map(|v| v as i64),
231                max: item.get_int(&[2]).map(|v| v as i64),
232                start_timestamp: item.get_int(&[3]),
233                end_timestamp: item.get_int(&[4]),
234                min_timestamp: item.get_int(&[5]),
235                max_timestamp: item.get_int(&[6]),
236                start_systime: item.get_int(&[7]).map(|v| v as u8),
237                end_systime: item.get_int(&[8]).map(|v| v as u8),
238                min_systime: item.get_int(&[9]).map(|v| v as u8),
239                max_systime: item.get_int(&[10]).map(|v| v as u8),
240            });
241        }
242    }
243    Ok(res)
244}
245
246/// Decode Voltage attribute (0x0004)
247pub fn decode_voltage(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
248    if let tlv::TlvItemValue::Int(v) = inp {
249        Ok(Some(*v as u8))
250    } else {
251        Ok(None)
252    }
253}
254
255/// Decode ActiveCurrent attribute (0x0005)
256pub fn decode_active_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
257    if let tlv::TlvItemValue::Int(v) = inp {
258        Ok(Some(*v as u8))
259    } else {
260        Ok(None)
261    }
262}
263
264/// Decode ReactiveCurrent attribute (0x0006)
265pub fn decode_reactive_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
266    if let tlv::TlvItemValue::Int(v) = inp {
267        Ok(Some(*v as u8))
268    } else {
269        Ok(None)
270    }
271}
272
273/// Decode ApparentCurrent attribute (0x0007)
274pub fn decode_apparent_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
275    if let tlv::TlvItemValue::Int(v) = inp {
276        Ok(Some(*v as u8))
277    } else {
278        Ok(None)
279    }
280}
281
282/// Decode ActivePower attribute (0x0008)
283pub fn decode_active_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
284    if let tlv::TlvItemValue::Int(v) = inp {
285        Ok(Some(*v as u32))
286    } else {
287        Ok(None)
288    }
289}
290
291/// Decode ReactivePower attribute (0x0009)
292pub fn decode_reactive_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
293    if let tlv::TlvItemValue::Int(v) = inp {
294        Ok(Some(*v as u8))
295    } else {
296        Ok(None)
297    }
298}
299
300/// Decode ApparentPower attribute (0x000A)
301pub fn decode_apparent_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
302    if let tlv::TlvItemValue::Int(v) = inp {
303        Ok(Some(*v as u8))
304    } else {
305        Ok(None)
306    }
307}
308
309/// Decode RMSVoltage attribute (0x000B)
310pub fn decode_rms_voltage(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
311    if let tlv::TlvItemValue::Int(v) = inp {
312        Ok(Some(*v as u8))
313    } else {
314        Ok(None)
315    }
316}
317
318/// Decode RMSCurrent attribute (0x000C)
319pub fn decode_rms_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
320    if let tlv::TlvItemValue::Int(v) = inp {
321        Ok(Some(*v as u8))
322    } else {
323        Ok(None)
324    }
325}
326
327/// Decode RMSPower attribute (0x000D)
328pub fn decode_rms_power(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
329    if let tlv::TlvItemValue::Int(v) = inp {
330        Ok(Some(*v as u32))
331    } else {
332        Ok(None)
333    }
334}
335
336/// Decode Frequency attribute (0x000E)
337pub fn decode_frequency(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i64>> {
338    if let tlv::TlvItemValue::Int(v) = inp {
339        Ok(Some(*v as i64))
340    } else {
341        Ok(None)
342    }
343}
344
345/// Decode HarmonicCurrents attribute (0x000F)
346pub fn decode_harmonic_currents(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<HarmonicMeasurement>> {
347    let mut res = Vec::new();
348    if let tlv::TlvItemValue::List(v) = inp {
349        for item in v {
350            res.push(HarmonicMeasurement {
351                order: item.get_int(&[0]).map(|v| v as u8),
352                measurement: item.get_int(&[1]).map(|v| v as i64),
353            });
354        }
355    }
356    Ok(res)
357}
358
359/// Decode HarmonicPhases attribute (0x0010)
360pub fn decode_harmonic_phases(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<HarmonicMeasurement>> {
361    let mut res = Vec::new();
362    if let tlv::TlvItemValue::List(v) = inp {
363        for item in v {
364            res.push(HarmonicMeasurement {
365                order: item.get_int(&[0]).map(|v| v as u8),
366                measurement: item.get_int(&[1]).map(|v| v as i64),
367            });
368        }
369    }
370    Ok(res)
371}
372
373/// Decode PowerFactor attribute (0x0011)
374pub fn decode_power_factor(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i64>> {
375    if let tlv::TlvItemValue::Int(v) = inp {
376        Ok(Some(*v as i64))
377    } else {
378        Ok(None)
379    }
380}
381
382/// Decode NeutralCurrent attribute (0x0012)
383pub fn decode_neutral_current(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
384    if let tlv::TlvItemValue::Int(v) = inp {
385        Ok(Some(*v as u8))
386    } else {
387        Ok(None)
388    }
389}
390
391
392// JSON dispatcher function
393
394/// Decode attribute value and return as JSON string
395///
396/// # Parameters
397/// * `cluster_id` - The cluster identifier
398/// * `attribute_id` - The attribute identifier
399/// * `tlv_value` - The TLV value to decode
400///
401/// # Returns
402/// JSON string representation of the decoded value or error
403pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
404    // Verify this is the correct cluster
405    if cluster_id != 0x0090 {
406        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0090, got {}\"}}", cluster_id);
407    }
408
409    match attribute_id {
410        0x0000 => {
411            match decode_power_mode(tlv_value) {
412                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
413                Err(e) => format!("{{\"error\": \"{}\"}}", e),
414            }
415        }
416        0x0001 => {
417            match decode_number_of_measurement_types(tlv_value) {
418                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
419                Err(e) => format!("{{\"error\": \"{}\"}}", e),
420            }
421        }
422        0x0002 => {
423            match decode_accuracy(tlv_value) {
424                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
425                Err(e) => format!("{{\"error\": \"{}\"}}", e),
426            }
427        }
428        0x0003 => {
429            match decode_ranges(tlv_value) {
430                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
431                Err(e) => format!("{{\"error\": \"{}\"}}", e),
432            }
433        }
434        0x0004 => {
435            match decode_voltage(tlv_value) {
436                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
437                Err(e) => format!("{{\"error\": \"{}\"}}", e),
438            }
439        }
440        0x0005 => {
441            match decode_active_current(tlv_value) {
442                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
443                Err(e) => format!("{{\"error\": \"{}\"}}", e),
444            }
445        }
446        0x0006 => {
447            match decode_reactive_current(tlv_value) {
448                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
449                Err(e) => format!("{{\"error\": \"{}\"}}", e),
450            }
451        }
452        0x0007 => {
453            match decode_apparent_current(tlv_value) {
454                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
455                Err(e) => format!("{{\"error\": \"{}\"}}", e),
456            }
457        }
458        0x0008 => {
459            match decode_active_power(tlv_value) {
460                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
461                Err(e) => format!("{{\"error\": \"{}\"}}", e),
462            }
463        }
464        0x0009 => {
465            match decode_reactive_power(tlv_value) {
466                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
467                Err(e) => format!("{{\"error\": \"{}\"}}", e),
468            }
469        }
470        0x000A => {
471            match decode_apparent_power(tlv_value) {
472                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
473                Err(e) => format!("{{\"error\": \"{}\"}}", e),
474            }
475        }
476        0x000B => {
477            match decode_rms_voltage(tlv_value) {
478                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
479                Err(e) => format!("{{\"error\": \"{}\"}}", e),
480            }
481        }
482        0x000C => {
483            match decode_rms_current(tlv_value) {
484                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
485                Err(e) => format!("{{\"error\": \"{}\"}}", e),
486            }
487        }
488        0x000D => {
489            match decode_rms_power(tlv_value) {
490                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
491                Err(e) => format!("{{\"error\": \"{}\"}}", e),
492            }
493        }
494        0x000E => {
495            match decode_frequency(tlv_value) {
496                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
497                Err(e) => format!("{{\"error\": \"{}\"}}", e),
498            }
499        }
500        0x000F => {
501            match decode_harmonic_currents(tlv_value) {
502                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
503                Err(e) => format!("{{\"error\": \"{}\"}}", e),
504            }
505        }
506        0x0010 => {
507            match decode_harmonic_phases(tlv_value) {
508                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
509                Err(e) => format!("{{\"error\": \"{}\"}}", e),
510            }
511        }
512        0x0011 => {
513            match decode_power_factor(tlv_value) {
514                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
515                Err(e) => format!("{{\"error\": \"{}\"}}", e),
516            }
517        }
518        0x0012 => {
519            match decode_neutral_current(tlv_value) {
520                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
521                Err(e) => format!("{{\"error\": \"{}\"}}", e),
522            }
523        }
524        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
525    }
526}
527
528/// Get list of all attributes supported by this cluster
529///
530/// # Returns
531/// Vector of tuples containing (attribute_id, attribute_name)
532pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
533    vec![
534        (0x0000, "PowerMode"),
535        (0x0001, "NumberOfMeasurementTypes"),
536        (0x0002, "Accuracy"),
537        (0x0003, "Ranges"),
538        (0x0004, "Voltage"),
539        (0x0005, "ActiveCurrent"),
540        (0x0006, "ReactiveCurrent"),
541        (0x0007, "ApparentCurrent"),
542        (0x0008, "ActivePower"),
543        (0x0009, "ReactivePower"),
544        (0x000A, "ApparentPower"),
545        (0x000B, "RMSVoltage"),
546        (0x000C, "RMSCurrent"),
547        (0x000D, "RMSPower"),
548        (0x000E, "Frequency"),
549        (0x000F, "HarmonicCurrents"),
550        (0x0010, "HarmonicPhases"),
551        (0x0011, "PowerFactor"),
552        (0x0012, "NeutralCurrent"),
553    ]
554}
555
556// Typed facade (invokes + reads)
557
558/// Read `PowerMode` attribute from cluster `Electrical Power Measurement`.
559pub async fn read_power_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<PowerMode> {
560    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_POWERMODE).await?;
561    decode_power_mode(&tlv)
562}
563
564/// Read `NumberOfMeasurementTypes` attribute from cluster `Electrical Power Measurement`.
565pub async fn read_number_of_measurement_types(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
566    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_NUMBEROFMEASUREMENTTYPES).await?;
567    decode_number_of_measurement_types(&tlv)
568}
569
570/// Read `Accuracy` attribute from cluster `Electrical Power Measurement`.
571pub async fn read_accuracy(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<MeasurementAccuracy>> {
572    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_ACCURACY).await?;
573    decode_accuracy(&tlv)
574}
575
576/// Read `Ranges` attribute from cluster `Electrical Power Measurement`.
577pub async fn read_ranges(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<MeasurementRange>> {
578    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_RANGES).await?;
579    decode_ranges(&tlv)
580}
581
582/// Read `Voltage` attribute from cluster `Electrical Power Measurement`.
583pub async fn read_voltage(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
584    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_VOLTAGE).await?;
585    decode_voltage(&tlv)
586}
587
588/// Read `ActiveCurrent` attribute from cluster `Electrical Power Measurement`.
589pub async fn read_active_current(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
590    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_ACTIVECURRENT).await?;
591    decode_active_current(&tlv)
592}
593
594/// Read `ReactiveCurrent` attribute from cluster `Electrical Power Measurement`.
595pub async fn read_reactive_current(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
596    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_REACTIVECURRENT).await?;
597    decode_reactive_current(&tlv)
598}
599
600/// Read `ApparentCurrent` attribute from cluster `Electrical Power Measurement`.
601pub async fn read_apparent_current(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
602    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_APPARENTCURRENT).await?;
603    decode_apparent_current(&tlv)
604}
605
606/// Read `ActivePower` attribute from cluster `Electrical Power Measurement`.
607pub async fn read_active_power(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
608    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_ACTIVEPOWER).await?;
609    decode_active_power(&tlv)
610}
611
612/// Read `ReactivePower` attribute from cluster `Electrical Power Measurement`.
613pub async fn read_reactive_power(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
614    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_REACTIVEPOWER).await?;
615    decode_reactive_power(&tlv)
616}
617
618/// Read `ApparentPower` attribute from cluster `Electrical Power Measurement`.
619pub async fn read_apparent_power(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
620    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_APPARENTPOWER).await?;
621    decode_apparent_power(&tlv)
622}
623
624/// Read `RMSVoltage` attribute from cluster `Electrical Power Measurement`.
625pub async fn read_rms_voltage(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
626    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_RMSVOLTAGE).await?;
627    decode_rms_voltage(&tlv)
628}
629
630/// Read `RMSCurrent` attribute from cluster `Electrical Power Measurement`.
631pub async fn read_rms_current(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
632    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_RMSCURRENT).await?;
633    decode_rms_current(&tlv)
634}
635
636/// Read `RMSPower` attribute from cluster `Electrical Power Measurement`.
637pub async fn read_rms_power(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
638    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_RMSPOWER).await?;
639    decode_rms_power(&tlv)
640}
641
642/// Read `Frequency` attribute from cluster `Electrical Power Measurement`.
643pub async fn read_frequency(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i64>> {
644    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_FREQUENCY).await?;
645    decode_frequency(&tlv)
646}
647
648/// Read `HarmonicCurrents` attribute from cluster `Electrical Power Measurement`.
649pub async fn read_harmonic_currents(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<HarmonicMeasurement>> {
650    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_HARMONICCURRENTS).await?;
651    decode_harmonic_currents(&tlv)
652}
653
654/// Read `HarmonicPhases` attribute from cluster `Electrical Power Measurement`.
655pub async fn read_harmonic_phases(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<HarmonicMeasurement>> {
656    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_HARMONICPHASES).await?;
657    decode_harmonic_phases(&tlv)
658}
659
660/// Read `PowerFactor` attribute from cluster `Electrical Power Measurement`.
661pub async fn read_power_factor(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i64>> {
662    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_POWERFACTOR).await?;
663    decode_power_factor(&tlv)
664}
665
666/// Read `NeutralCurrent` attribute from cluster `Electrical Power Measurement`.
667pub async fn read_neutral_current(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
668    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_ELECTRICAL_POWER_MEASUREMENT, crate::clusters::defs::CLUSTER_ELECTRICAL_POWER_MEASUREMENT_ATTR_ID_NEUTRALCURRENT).await?;
669    decode_neutral_current(&tlv)
670}
671
672#[derive(Debug, serde::Serialize)]
673pub struct MeasurementPeriodRangesEvent {
674    pub ranges: Option<Vec<MeasurementRange>>,
675}
676
677// Event decoders
678
679/// Decode MeasurementPeriodRanges event (0x00, priority: info)
680pub fn decode_measurement_period_ranges_event(inp: &tlv::TlvItemValue) -> anyhow::Result<MeasurementPeriodRangesEvent> {
681    if let tlv::TlvItemValue::List(_fields) = inp {
682        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
683        Ok(MeasurementPeriodRangesEvent {
684                                ranges: {
685                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
686                        let mut items = Vec::new();
687                        for list_item in l {
688                            items.push(MeasurementRange {
689                measurement_type: list_item.get_int(&[0]).and_then(|v| MeasurementType::from_u8(v as u8)),
690                min: list_item.get_int(&[1]).map(|v| v as i64),
691                max: list_item.get_int(&[2]).map(|v| v as i64),
692                start_timestamp: list_item.get_int(&[3]),
693                end_timestamp: list_item.get_int(&[4]),
694                min_timestamp: list_item.get_int(&[5]),
695                max_timestamp: list_item.get_int(&[6]),
696                start_systime: list_item.get_int(&[7]).map(|v| v as u8),
697                end_systime: list_item.get_int(&[8]).map(|v| v as u8),
698                min_systime: list_item.get_int(&[9]).map(|v| v as u8),
699                max_systime: list_item.get_int(&[10]).map(|v| v as u8),
700                            });
701                        }
702                        Some(items)
703                    } else {
704                        None
705                    }
706                },
707        })
708    } else {
709        Err(anyhow::anyhow!("Expected struct fields"))
710    }
711}
712