Skip to main content

matter_clusters/gen/
pump_configuration_and_control.rs

1//! PumpConfigurationAndControl cluster (0x0200).
2//! @generated by `cargo xtask codegen` — do not edit.
3
4#![allow(
5    clippy::all,
6    clippy::pedantic,
7    dead_code,
8    unreachable_pub,
9    unused_imports
10)]
11
12use crate::datatypes::SemanticTagStruct;
13use crate::error::ClusterError;
14use crate::types::Nullable;
15use matter_codec::{ContainerKind, Element, Tag, TlvReader, TlvWriter, Value};
16
17/// Cluster ID.
18pub const CLUSTER_ID: u32 = 0x0200;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 5;
21
22/// Command IDs (requests and responses).
23pub mod command_id {}
24
25/// Attribute IDs (cluster-specific).
26pub mod attribute_id {
27    /// `MaxPressure`.
28    pub const MAX_PRESSURE: u32 = 0x0000;
29    /// `MaxSpeed`.
30    pub const MAX_SPEED: u32 = 0x0001;
31    /// `MaxFlow`.
32    pub const MAX_FLOW: u32 = 0x0002;
33    /// `MinConstPressure`.
34    pub const MIN_CONST_PRESSURE: u32 = 0x0003;
35    /// `MaxConstPressure`.
36    pub const MAX_CONST_PRESSURE: u32 = 0x0004;
37    /// `MinCompPressure`.
38    pub const MIN_COMP_PRESSURE: u32 = 0x0005;
39    /// `MaxCompPressure`.
40    pub const MAX_COMP_PRESSURE: u32 = 0x0006;
41    /// `MinConstSpeed`.
42    pub const MIN_CONST_SPEED: u32 = 0x0007;
43    /// `MaxConstSpeed`.
44    pub const MAX_CONST_SPEED: u32 = 0x0008;
45    /// `MinConstFlow`.
46    pub const MIN_CONST_FLOW: u32 = 0x0009;
47    /// `MaxConstFlow`.
48    pub const MAX_CONST_FLOW: u32 = 0x000A;
49    /// `MinConstTemp`.
50    pub const MIN_CONST_TEMP: u32 = 0x000B;
51    /// `MaxConstTemp`.
52    pub const MAX_CONST_TEMP: u32 = 0x000C;
53    /// `PumpStatus`.
54    pub const PUMP_STATUS: u32 = 0x0010;
55    /// `EffectiveOperationMode`.
56    pub const EFFECTIVE_OPERATION_MODE: u32 = 0x0011;
57    /// `EffectiveControlMode`.
58    pub const EFFECTIVE_CONTROL_MODE: u32 = 0x0012;
59    /// `Capacity`.
60    pub const CAPACITY: u32 = 0x0013;
61    /// `Speed`.
62    pub const SPEED: u32 = 0x0014;
63    /// `LifetimeRunningHours`.
64    pub const LIFETIME_RUNNING_HOURS: u32 = 0x0015;
65    /// `Power`.
66    pub const POWER: u32 = 0x0016;
67    /// `LifetimeEnergyConsumed`.
68    pub const LIFETIME_ENERGY_CONSUMED: u32 = 0x0017;
69    /// `OperationMode`.
70    pub const OPERATION_MODE: u32 = 0x0020;
71    /// `ControlMode`.
72    pub const CONTROL_MODE: u32 = 0x0021;
73}
74
75bitflags::bitflags! {
76    /// `PumpConfigurationAndControl` feature bits (FeatureMap).
77    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
78    pub struct Feature: u32 {
79        /// ConstantPressure (PRSCONST).
80        const PRSCONST = 1 << 0;
81        /// CompensatedPressure (PRSCOMP).
82        const PRSCOMP = 1 << 1;
83        /// ConstantFlow (FLW).
84        const FLW = 1 << 2;
85        /// ConstantSpeed (SPD).
86        const SPD = 1 << 3;
87        /// ConstantTemperature (TEMP).
88        const TEMP = 1 << 4;
89        /// Automatic (AUTO).
90        const AUTO = 1 << 5;
91        /// LocalOperation (LOCAL).
92        const LOCAL = 1 << 6;
93    }
94}
95
96/// `ControlModeEnum` (enum8).
97#[derive(Copy, Clone, Debug, PartialEq, Eq)]
98pub enum ControlModeEnum {
99    /// ConstantSpeed = 0.
100    ConstantSpeed,
101    /// ConstantPressure = 1.
102    ConstantPressure,
103    /// ProportionalPressure = 2.
104    ProportionalPressure,
105    /// ConstantFlow = 3.
106    ConstantFlow,
107    /// ConstantTemperature = 5.
108    ConstantTemperature,
109    /// Automatic = 7.
110    Automatic,
111    /// A value not known to this codegen revision.
112    Unknown(u8),
113}
114
115impl ControlModeEnum {
116    /// Decode from its raw discriminant (unknown → `Unknown`).
117    #[must_use]
118    pub fn from_raw(v: u8) -> Self {
119        match v {
120            0 => Self::ConstantSpeed,
121            1 => Self::ConstantPressure,
122            2 => Self::ProportionalPressure,
123            3 => Self::ConstantFlow,
124            5 => Self::ConstantTemperature,
125            7 => Self::Automatic,
126            other => Self::Unknown(other),
127        }
128    }
129    /// The raw discriminant.
130    #[must_use]
131    pub fn to_raw(self) -> u8 {
132        match self {
133            Self::ConstantSpeed => 0,
134            Self::ConstantPressure => 1,
135            Self::ProportionalPressure => 2,
136            Self::ConstantFlow => 3,
137            Self::ConstantTemperature => 5,
138            Self::Automatic => 7,
139            Self::Unknown(v) => v,
140        }
141    }
142}
143
144/// `OperationModeEnum` (enum8).
145#[derive(Copy, Clone, Debug, PartialEq, Eq)]
146pub enum OperationModeEnum {
147    /// Normal = 0.
148    Normal,
149    /// Minimum = 1.
150    Minimum,
151    /// Maximum = 2.
152    Maximum,
153    /// Local = 3.
154    Local,
155    /// A value not known to this codegen revision.
156    Unknown(u8),
157}
158
159impl OperationModeEnum {
160    /// Decode from its raw discriminant (unknown → `Unknown`).
161    #[must_use]
162    pub fn from_raw(v: u8) -> Self {
163        match v {
164            0 => Self::Normal,
165            1 => Self::Minimum,
166            2 => Self::Maximum,
167            3 => Self::Local,
168            other => Self::Unknown(other),
169        }
170    }
171    /// The raw discriminant.
172    #[must_use]
173    pub fn to_raw(self) -> u8 {
174        match self {
175            Self::Normal => 0,
176            Self::Minimum => 1,
177            Self::Maximum => 2,
178            Self::Local => 3,
179            Self::Unknown(v) => v,
180        }
181    }
182}
183
184bitflags::bitflags! {
185    /// `PumpStatusBitmap` (map16).
186    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
187    pub struct PumpStatusBitmap: u16 {
188        /// DeviceFault.
189        const DEVICE_FAULT = 1 << 0;
190        /// SupplyFault.
191        const SUPPLY_FAULT = 1 << 1;
192        /// SpeedLow.
193        const SPEED_LOW = 1 << 2;
194        /// SpeedHigh.
195        const SPEED_HIGH = 1 << 3;
196        /// LocalOverride.
197        const LOCAL_OVERRIDE = 1 << 4;
198        /// Running.
199        const RUNNING = 1 << 5;
200        /// RemotePressure.
201        const REMOTE_PRESSURE = 1 << 6;
202        /// RemoteFlow.
203        const REMOTE_FLOW = 1 << 7;
204        /// RemoteTemperature.
205        const REMOTE_TEMPERATURE = 1 << 8;
206    }
207}
208
209/// Decode the `MaxPressure` attribute value.
210///
211/// # Errors
212/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
213pub fn decode_max_pressure(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
214    let mut r = TlvReader::new(tlv);
215    match r.next()? {
216        Some(Element::Scalar {
217            value: Value::Null, ..
218        }) => Ok(Nullable::Null),
219        Some(Element::Scalar {
220            value: Value::Int(v),
221            ..
222        }) => Ok(Nullable::Value(
223            i16::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxPressure"))?,
224        )),
225        _ => Err(ClusterError::UnexpectedType {
226            context: "MaxPressure",
227        }),
228    }
229}
230
231/// Decode the `MaxSpeed` attribute value.
232///
233/// # Errors
234/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
235pub fn decode_max_speed(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
236    let mut r = TlvReader::new(tlv);
237    match r.next()? {
238        Some(Element::Scalar {
239            value: Value::Null, ..
240        }) => Ok(Nullable::Null),
241        Some(Element::Scalar {
242            value: Value::Uint(v),
243            ..
244        }) => Ok(Nullable::Value(
245            u16::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxSpeed"))?,
246        )),
247        _ => Err(ClusterError::UnexpectedType {
248            context: "MaxSpeed",
249        }),
250    }
251}
252
253/// Decode the `MaxFlow` attribute value.
254///
255/// # Errors
256/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
257pub fn decode_max_flow(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
258    let mut r = TlvReader::new(tlv);
259    match r.next()? {
260        Some(Element::Scalar {
261            value: Value::Null, ..
262        }) => Ok(Nullable::Null),
263        Some(Element::Scalar {
264            value: Value::Uint(v),
265            ..
266        }) => Ok(Nullable::Value(
267            u16::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxFlow"))?,
268        )),
269        _ => Err(ClusterError::UnexpectedType { context: "MaxFlow" }),
270    }
271}
272
273/// Decode the `MinConstPressure` attribute value.
274///
275/// # Errors
276/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
277pub fn decode_min_const_pressure(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
278    let mut r = TlvReader::new(tlv);
279    match r.next()? {
280        Some(Element::Scalar {
281            value: Value::Null, ..
282        }) => Ok(Nullable::Null),
283        Some(Element::Scalar {
284            value: Value::Int(v),
285            ..
286        }) => {
287            Ok(Nullable::Value(i16::try_from(v).map_err(|_| {
288                ClusterError::InvalidLength("MinConstPressure")
289            })?))
290        }
291        _ => Err(ClusterError::UnexpectedType {
292            context: "MinConstPressure",
293        }),
294    }
295}
296
297/// Decode the `MaxConstPressure` attribute value.
298///
299/// # Errors
300/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
301pub fn decode_max_const_pressure(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
302    let mut r = TlvReader::new(tlv);
303    match r.next()? {
304        Some(Element::Scalar {
305            value: Value::Null, ..
306        }) => Ok(Nullable::Null),
307        Some(Element::Scalar {
308            value: Value::Int(v),
309            ..
310        }) => {
311            Ok(Nullable::Value(i16::try_from(v).map_err(|_| {
312                ClusterError::InvalidLength("MaxConstPressure")
313            })?))
314        }
315        _ => Err(ClusterError::UnexpectedType {
316            context: "MaxConstPressure",
317        }),
318    }
319}
320
321/// Decode the `MinCompPressure` attribute value.
322///
323/// # Errors
324/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
325pub fn decode_min_comp_pressure(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
326    let mut r = TlvReader::new(tlv);
327    match r.next()? {
328        Some(Element::Scalar {
329            value: Value::Null, ..
330        }) => Ok(Nullable::Null),
331        Some(Element::Scalar {
332            value: Value::Int(v),
333            ..
334        }) => {
335            Ok(Nullable::Value(i16::try_from(v).map_err(|_| {
336                ClusterError::InvalidLength("MinCompPressure")
337            })?))
338        }
339        _ => Err(ClusterError::UnexpectedType {
340            context: "MinCompPressure",
341        }),
342    }
343}
344
345/// Decode the `MaxCompPressure` attribute value.
346///
347/// # Errors
348/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
349pub fn decode_max_comp_pressure(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
350    let mut r = TlvReader::new(tlv);
351    match r.next()? {
352        Some(Element::Scalar {
353            value: Value::Null, ..
354        }) => Ok(Nullable::Null),
355        Some(Element::Scalar {
356            value: Value::Int(v),
357            ..
358        }) => {
359            Ok(Nullable::Value(i16::try_from(v).map_err(|_| {
360                ClusterError::InvalidLength("MaxCompPressure")
361            })?))
362        }
363        _ => Err(ClusterError::UnexpectedType {
364            context: "MaxCompPressure",
365        }),
366    }
367}
368
369/// Decode the `MinConstSpeed` attribute value.
370///
371/// # Errors
372/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
373pub fn decode_min_const_speed(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
374    let mut r = TlvReader::new(tlv);
375    match r.next()? {
376        Some(Element::Scalar {
377            value: Value::Null, ..
378        }) => Ok(Nullable::Null),
379        Some(Element::Scalar {
380            value: Value::Uint(v),
381            ..
382        }) => {
383            Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
384                ClusterError::InvalidLength("MinConstSpeed")
385            })?))
386        }
387        _ => Err(ClusterError::UnexpectedType {
388            context: "MinConstSpeed",
389        }),
390    }
391}
392
393/// Decode the `MaxConstSpeed` attribute value.
394///
395/// # Errors
396/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
397pub fn decode_max_const_speed(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
398    let mut r = TlvReader::new(tlv);
399    match r.next()? {
400        Some(Element::Scalar {
401            value: Value::Null, ..
402        }) => Ok(Nullable::Null),
403        Some(Element::Scalar {
404            value: Value::Uint(v),
405            ..
406        }) => {
407            Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
408                ClusterError::InvalidLength("MaxConstSpeed")
409            })?))
410        }
411        _ => Err(ClusterError::UnexpectedType {
412            context: "MaxConstSpeed",
413        }),
414    }
415}
416
417/// Decode the `MinConstFlow` attribute value.
418///
419/// # Errors
420/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
421pub fn decode_min_const_flow(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
422    let mut r = TlvReader::new(tlv);
423    match r.next()? {
424        Some(Element::Scalar {
425            value: Value::Null, ..
426        }) => Ok(Nullable::Null),
427        Some(Element::Scalar {
428            value: Value::Uint(v),
429            ..
430        }) => {
431            Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
432                ClusterError::InvalidLength("MinConstFlow")
433            })?))
434        }
435        _ => Err(ClusterError::UnexpectedType {
436            context: "MinConstFlow",
437        }),
438    }
439}
440
441/// Decode the `MaxConstFlow` attribute value.
442///
443/// # Errors
444/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
445pub fn decode_max_const_flow(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
446    let mut r = TlvReader::new(tlv);
447    match r.next()? {
448        Some(Element::Scalar {
449            value: Value::Null, ..
450        }) => Ok(Nullable::Null),
451        Some(Element::Scalar {
452            value: Value::Uint(v),
453            ..
454        }) => {
455            Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
456                ClusterError::InvalidLength("MaxConstFlow")
457            })?))
458        }
459        _ => Err(ClusterError::UnexpectedType {
460            context: "MaxConstFlow",
461        }),
462    }
463}
464
465/// Decode the `MinConstTemp` attribute value.
466///
467/// # Errors
468/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
469pub fn decode_min_const_temp(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
470    let mut r = TlvReader::new(tlv);
471    match r.next()? {
472        Some(Element::Scalar {
473            value: Value::Null, ..
474        }) => Ok(Nullable::Null),
475        Some(Element::Scalar {
476            value: Value::Int(v),
477            ..
478        }) => {
479            Ok(Nullable::Value(i16::try_from(v).map_err(|_| {
480                ClusterError::InvalidLength("MinConstTemp")
481            })?))
482        }
483        _ => Err(ClusterError::UnexpectedType {
484            context: "MinConstTemp",
485        }),
486    }
487}
488
489/// Decode the `MaxConstTemp` attribute value.
490///
491/// # Errors
492/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
493pub fn decode_max_const_temp(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
494    let mut r = TlvReader::new(tlv);
495    match r.next()? {
496        Some(Element::Scalar {
497            value: Value::Null, ..
498        }) => Ok(Nullable::Null),
499        Some(Element::Scalar {
500            value: Value::Int(v),
501            ..
502        }) => {
503            Ok(Nullable::Value(i16::try_from(v).map_err(|_| {
504                ClusterError::InvalidLength("MaxConstTemp")
505            })?))
506        }
507        _ => Err(ClusterError::UnexpectedType {
508            context: "MaxConstTemp",
509        }),
510    }
511}
512
513/// Decode the `PumpStatus` attribute value.
514///
515/// # Errors
516/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
517pub fn decode_pump_status(tlv: &[u8]) -> Result<PumpStatusBitmap, ClusterError> {
518    let mut r = TlvReader::new(tlv);
519    match r.next()? {
520        Some(Element::Scalar {
521            value: Value::Uint(v),
522            ..
523        }) => Ok(PumpStatusBitmap::from_bits_retain(
524            u16::try_from(v).map_err(|_| ClusterError::InvalidLength("PumpStatus"))?,
525        )),
526        _ => Err(ClusterError::UnexpectedType {
527            context: "PumpStatus",
528        }),
529    }
530}
531
532/// Decode the `EffectiveOperationMode` attribute value.
533///
534/// # Errors
535/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
536pub fn decode_effective_operation_mode(tlv: &[u8]) -> Result<OperationModeEnum, ClusterError> {
537    let mut r = TlvReader::new(tlv);
538    match r.next()? {
539        Some(Element::Scalar {
540            value: Value::Uint(v),
541            ..
542        }) => Ok(OperationModeEnum::from_raw(u8::try_from(v).map_err(
543            |_| ClusterError::InvalidLength("EffectiveOperationMode"),
544        )?)),
545        _ => Err(ClusterError::UnexpectedType {
546            context: "EffectiveOperationMode",
547        }),
548    }
549}
550
551/// Decode the `EffectiveControlMode` attribute value.
552///
553/// # Errors
554/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
555pub fn decode_effective_control_mode(tlv: &[u8]) -> Result<ControlModeEnum, ClusterError> {
556    let mut r = TlvReader::new(tlv);
557    match r.next()? {
558        Some(Element::Scalar {
559            value: Value::Uint(v),
560            ..
561        }) => Ok(ControlModeEnum::from_raw(u8::try_from(v).map_err(
562            |_| ClusterError::InvalidLength("EffectiveControlMode"),
563        )?)),
564        _ => Err(ClusterError::UnexpectedType {
565            context: "EffectiveControlMode",
566        }),
567    }
568}
569
570/// Decode the `Capacity` attribute value.
571///
572/// # Errors
573/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
574pub fn decode_capacity(tlv: &[u8]) -> Result<Nullable<i16>, ClusterError> {
575    let mut r = TlvReader::new(tlv);
576    match r.next()? {
577        Some(Element::Scalar {
578            value: Value::Null, ..
579        }) => Ok(Nullable::Null),
580        Some(Element::Scalar {
581            value: Value::Int(v),
582            ..
583        }) => Ok(Nullable::Value(
584            i16::try_from(v).map_err(|_| ClusterError::InvalidLength("Capacity"))?,
585        )),
586        _ => Err(ClusterError::UnexpectedType {
587            context: "Capacity",
588        }),
589    }
590}
591
592/// Decode the `Speed` attribute value.
593///
594/// # Errors
595/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
596pub fn decode_speed(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
597    let mut r = TlvReader::new(tlv);
598    match r.next()? {
599        Some(Element::Scalar {
600            value: Value::Null, ..
601        }) => Ok(Nullable::Null),
602        Some(Element::Scalar {
603            value: Value::Uint(v),
604            ..
605        }) => Ok(Nullable::Value(
606            u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Speed"))?,
607        )),
608        _ => Err(ClusterError::UnexpectedType { context: "Speed" }),
609    }
610}
611
612/// Decode the `LifetimeRunningHours` attribute value.
613///
614/// # Errors
615/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
616pub fn decode_lifetime_running_hours(tlv: &[u8]) -> Result<Nullable<u32>, ClusterError> {
617    let mut r = TlvReader::new(tlv);
618    match r.next()? {
619        Some(Element::Scalar {
620            value: Value::Null, ..
621        }) => Ok(Nullable::Null),
622        Some(Element::Scalar {
623            value: Value::Uint(v),
624            ..
625        }) => Ok(Nullable::Value(u32::try_from(v).map_err(|_| {
626            ClusterError::InvalidLength("LifetimeRunningHours")
627        })?)),
628        _ => Err(ClusterError::UnexpectedType {
629            context: "LifetimeRunningHours",
630        }),
631    }
632}
633
634/// Encode the `LifetimeRunningHours` attribute value as a standalone TLV element.
635#[must_use]
636#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
637pub fn encode_lifetime_running_hours(value: Nullable<u32>) -> Vec<u8> {
638    let mut buf = Vec::new();
639    let mut w = TlvWriter::new(&mut buf);
640    match value {
641        Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
642        Nullable::Value(value) => {
643            w.put_uint(Tag::Anonymous, u64::from(value))
644                .expect("infallible: vec writer");
645        }
646    }
647    buf
648}
649
650/// Decode the `Power` attribute value.
651///
652/// # Errors
653/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
654pub fn decode_power(tlv: &[u8]) -> Result<Nullable<u32>, ClusterError> {
655    let mut r = TlvReader::new(tlv);
656    match r.next()? {
657        Some(Element::Scalar {
658            value: Value::Null, ..
659        }) => Ok(Nullable::Null),
660        Some(Element::Scalar {
661            value: Value::Uint(v),
662            ..
663        }) => Ok(Nullable::Value(
664            u32::try_from(v).map_err(|_| ClusterError::InvalidLength("Power"))?,
665        )),
666        _ => Err(ClusterError::UnexpectedType { context: "Power" }),
667    }
668}
669
670/// Decode the `LifetimeEnergyConsumed` attribute value.
671///
672/// # Errors
673/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
674pub fn decode_lifetime_energy_consumed(tlv: &[u8]) -> Result<Nullable<u32>, ClusterError> {
675    let mut r = TlvReader::new(tlv);
676    match r.next()? {
677        Some(Element::Scalar {
678            value: Value::Null, ..
679        }) => Ok(Nullable::Null),
680        Some(Element::Scalar {
681            value: Value::Uint(v),
682            ..
683        }) => Ok(Nullable::Value(u32::try_from(v).map_err(|_| {
684            ClusterError::InvalidLength("LifetimeEnergyConsumed")
685        })?)),
686        _ => Err(ClusterError::UnexpectedType {
687            context: "LifetimeEnergyConsumed",
688        }),
689    }
690}
691
692/// Encode the `LifetimeEnergyConsumed` attribute value as a standalone TLV element.
693#[must_use]
694#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
695pub fn encode_lifetime_energy_consumed(value: Nullable<u32>) -> Vec<u8> {
696    let mut buf = Vec::new();
697    let mut w = TlvWriter::new(&mut buf);
698    match value {
699        Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
700        Nullable::Value(value) => {
701            w.put_uint(Tag::Anonymous, u64::from(value))
702                .expect("infallible: vec writer");
703        }
704    }
705    buf
706}
707
708/// Decode the `OperationMode` attribute value.
709///
710/// # Errors
711/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
712pub fn decode_operation_mode(tlv: &[u8]) -> Result<OperationModeEnum, ClusterError> {
713    let mut r = TlvReader::new(tlv);
714    match r.next()? {
715        Some(Element::Scalar {
716            value: Value::Uint(v),
717            ..
718        }) => Ok(OperationModeEnum::from_raw(
719            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("OperationMode"))?,
720        )),
721        _ => Err(ClusterError::UnexpectedType {
722            context: "OperationMode",
723        }),
724    }
725}
726
727/// Encode the `OperationMode` attribute value as a standalone TLV element.
728#[must_use]
729#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
730pub fn encode_operation_mode(value: OperationModeEnum) -> Vec<u8> {
731    let mut buf = Vec::new();
732    let mut w = TlvWriter::new(&mut buf);
733    w.put_uint(Tag::Anonymous, u64::from(value.to_raw()))
734        .expect("infallible: vec writer");
735    buf
736}
737
738/// Decode the `ControlMode` attribute value.
739///
740/// # Errors
741/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
742pub fn decode_control_mode(tlv: &[u8]) -> Result<ControlModeEnum, ClusterError> {
743    let mut r = TlvReader::new(tlv);
744    match r.next()? {
745        Some(Element::Scalar {
746            value: Value::Uint(v),
747            ..
748        }) => Ok(ControlModeEnum::from_raw(
749            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ControlMode"))?,
750        )),
751        _ => Err(ClusterError::UnexpectedType {
752            context: "ControlMode",
753        }),
754    }
755}
756
757/// Encode the `ControlMode` attribute value as a standalone TLV element.
758#[must_use]
759#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
760pub fn encode_control_mode(value: ControlModeEnum) -> Vec<u8> {
761    let mut buf = Vec::new();
762    let mut w = TlvWriter::new(&mut buf);
763    w.put_uint(Tag::Anonymous, u64::from(value.to_raw()))
764        .expect("infallible: vec writer");
765    buf
766}