Skip to main content

matter_clusters/gen/
color_control.rs

1//! ColorControl cluster (0x0300).
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 = 0x0300;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 9;
21
22/// Command IDs (requests and responses).
23pub mod command_id {
24    /// `MoveToHue` (request).
25    pub const MOVE_TO_HUE: u32 = 0x00;
26    /// `MoveHue` (request).
27    pub const MOVE_HUE: u32 = 0x01;
28    /// `StepHue` (request).
29    pub const STEP_HUE: u32 = 0x02;
30    /// `MoveToSaturation` (request).
31    pub const MOVE_TO_SATURATION: u32 = 0x03;
32    /// `MoveSaturation` (request).
33    pub const MOVE_SATURATION: u32 = 0x04;
34    /// `StepSaturation` (request).
35    pub const STEP_SATURATION: u32 = 0x05;
36    /// `MoveToHueAndSaturation` (request).
37    pub const MOVE_TO_HUE_AND_SATURATION: u32 = 0x06;
38    /// `MoveToColor` (request).
39    pub const MOVE_TO_COLOR: u32 = 0x07;
40    /// `MoveColor` (request).
41    pub const MOVE_COLOR: u32 = 0x08;
42    /// `StepColor` (request).
43    pub const STEP_COLOR: u32 = 0x09;
44    /// `MoveToColorTemperature` (request).
45    pub const MOVE_TO_COLOR_TEMPERATURE: u32 = 0x0A;
46    /// `EnhancedMoveToHue` (request).
47    pub const ENHANCED_MOVE_TO_HUE: u32 = 0x40;
48    /// `EnhancedMoveHue` (request).
49    pub const ENHANCED_MOVE_HUE: u32 = 0x41;
50    /// `EnhancedStepHue` (request).
51    pub const ENHANCED_STEP_HUE: u32 = 0x42;
52    /// `EnhancedMoveToHueAndSaturation` (request).
53    pub const ENHANCED_MOVE_TO_HUE_AND_SATURATION: u32 = 0x43;
54    /// `ColorLoopSet` (request).
55    pub const COLOR_LOOP_SET: u32 = 0x44;
56    /// `StopMoveStep` (request).
57    pub const STOP_MOVE_STEP: u32 = 0x47;
58    /// `MoveColorTemperature` (request).
59    pub const MOVE_COLOR_TEMPERATURE: u32 = 0x4B;
60    /// `StepColorTemperature` (request).
61    pub const STEP_COLOR_TEMPERATURE: u32 = 0x4C;
62}
63
64/// Attribute IDs (cluster-specific).
65pub mod attribute_id {
66    /// `CurrentHue`.
67    pub const CURRENT_HUE: u32 = 0x0000;
68    /// `CurrentSaturation`.
69    pub const CURRENT_SATURATION: u32 = 0x0001;
70    /// `RemainingTime`.
71    pub const REMAINING_TIME: u32 = 0x0002;
72    /// `CurrentX`.
73    pub const CURRENT_X: u32 = 0x0003;
74    /// `CurrentY`.
75    pub const CURRENT_Y: u32 = 0x0004;
76    /// `DriftCompensation`.
77    pub const DRIFT_COMPENSATION: u32 = 0x0005;
78    /// `CompensationText`.
79    pub const COMPENSATION_TEXT: u32 = 0x0006;
80    /// `ColorTemperatureMireds`.
81    pub const COLOR_TEMPERATURE_MIREDS: u32 = 0x0007;
82    /// `ColorMode`.
83    pub const COLOR_MODE: u32 = 0x0008;
84    /// `Options`.
85    pub const OPTIONS: u32 = 0x000F;
86    /// `NumberOfPrimaries`.
87    pub const NUMBER_OF_PRIMARIES: u32 = 0x0010;
88    /// `Primary1X`.
89    pub const PRIMARY1_X: u32 = 0x0011;
90    /// `Primary1Y`.
91    pub const PRIMARY1_Y: u32 = 0x0012;
92    /// `Primary1Intensity`.
93    pub const PRIMARY1_INTENSITY: u32 = 0x0013;
94    /// `Primary2X`.
95    pub const PRIMARY2_X: u32 = 0x0015;
96    /// `Primary2Y`.
97    pub const PRIMARY2_Y: u32 = 0x0016;
98    /// `Primary2Intensity`.
99    pub const PRIMARY2_INTENSITY: u32 = 0x0017;
100    /// `Primary3X`.
101    pub const PRIMARY3_X: u32 = 0x0019;
102    /// `Primary3Y`.
103    pub const PRIMARY3_Y: u32 = 0x001A;
104    /// `Primary3Intensity`.
105    pub const PRIMARY3_INTENSITY: u32 = 0x001B;
106    /// `Primary4X`.
107    pub const PRIMARY4_X: u32 = 0x0020;
108    /// `Primary4Y`.
109    pub const PRIMARY4_Y: u32 = 0x0021;
110    /// `Primary4Intensity`.
111    pub const PRIMARY4_INTENSITY: u32 = 0x0022;
112    /// `Primary5X`.
113    pub const PRIMARY5_X: u32 = 0x0024;
114    /// `Primary5Y`.
115    pub const PRIMARY5_Y: u32 = 0x0025;
116    /// `Primary5Intensity`.
117    pub const PRIMARY5_INTENSITY: u32 = 0x0026;
118    /// `Primary6X`.
119    pub const PRIMARY6_X: u32 = 0x0028;
120    /// `Primary6Y`.
121    pub const PRIMARY6_Y: u32 = 0x0029;
122    /// `Primary6Intensity`.
123    pub const PRIMARY6_INTENSITY: u32 = 0x002A;
124    /// `WhitePointX`.
125    pub const WHITE_POINT_X: u32 = 0x0030;
126    /// `WhitePointY`.
127    pub const WHITE_POINT_Y: u32 = 0x0031;
128    /// `ColorPointRx`.
129    pub const COLOR_POINT_RX: u32 = 0x0032;
130    /// `ColorPointRy`.
131    pub const COLOR_POINT_RY: u32 = 0x0033;
132    /// `ColorPointRIntensity`.
133    pub const COLOR_POINT_R_INTENSITY: u32 = 0x0034;
134    /// `ColorPointGx`.
135    pub const COLOR_POINT_GX: u32 = 0x0036;
136    /// `ColorPointGy`.
137    pub const COLOR_POINT_GY: u32 = 0x0037;
138    /// `ColorPointGIntensity`.
139    pub const COLOR_POINT_G_INTENSITY: u32 = 0x0038;
140    /// `ColorPointBx`.
141    pub const COLOR_POINT_BX: u32 = 0x003A;
142    /// `ColorPointBy`.
143    pub const COLOR_POINT_BY: u32 = 0x003B;
144    /// `ColorPointBIntensity`.
145    pub const COLOR_POINT_B_INTENSITY: u32 = 0x003C;
146    /// `EnhancedCurrentHue`.
147    pub const ENHANCED_CURRENT_HUE: u32 = 0x4000;
148    /// `EnhancedColorMode`.
149    pub const ENHANCED_COLOR_MODE: u32 = 0x4001;
150    /// `ColorLoopActive`.
151    pub const COLOR_LOOP_ACTIVE: u32 = 0x4002;
152    /// `ColorLoopDirection`.
153    pub const COLOR_LOOP_DIRECTION: u32 = 0x4003;
154    /// `ColorLoopTime`.
155    pub const COLOR_LOOP_TIME: u32 = 0x4004;
156    /// `ColorLoopStartEnhancedHue`.
157    pub const COLOR_LOOP_START_ENHANCED_HUE: u32 = 0x4005;
158    /// `ColorLoopStoredEnhancedHue`.
159    pub const COLOR_LOOP_STORED_ENHANCED_HUE: u32 = 0x4006;
160    /// `ColorCapabilities`.
161    pub const COLOR_CAPABILITIES: u32 = 0x400A;
162    /// `ColorTempPhysicalMinMireds`.
163    pub const COLOR_TEMP_PHYSICAL_MIN_MIREDS: u32 = 0x400B;
164    /// `ColorTempPhysicalMaxMireds`.
165    pub const COLOR_TEMP_PHYSICAL_MAX_MIREDS: u32 = 0x400C;
166    /// `CoupleColorTempToLevelMinMireds`.
167    pub const COUPLE_COLOR_TEMP_TO_LEVEL_MIN_MIREDS: u32 = 0x400D;
168    /// `StartUpColorTemperatureMireds`.
169    pub const START_UP_COLOR_TEMPERATURE_MIREDS: u32 = 0x4010;
170}
171
172bitflags::bitflags! {
173    /// `ColorControl` feature bits (FeatureMap).
174    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
175    pub struct Feature: u32 {
176        /// HueSaturation (HS).
177        const HS = 1 << 0;
178        /// EnhancedHue (EHUE).
179        const EHUE = 1 << 1;
180        /// ColorLoop (CL).
181        const CL = 1 << 2;
182        /// Xy (XY).
183        const XY = 1 << 3;
184        /// ColorTemperature (CT).
185        const CT = 1 << 4;
186    }
187}
188
189bitflags::bitflags! {
190    /// `ColorCapabilitiesBitmap` (map16).
191    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
192    pub struct ColorCapabilitiesBitmap: u16 {
193        /// HueSaturation.
194        const HUE_SATURATION = 1 << 0;
195        /// EnhancedHue.
196        const ENHANCED_HUE = 1 << 1;
197        /// ColorLoop.
198        const COLOR_LOOP = 1 << 2;
199        /// Xy.
200        const XY = 1 << 3;
201        /// ColorTemperature.
202        const COLOR_TEMPERATURE = 1 << 4;
203    }
204}
205
206/// `ColorLoopActionEnum` (enum8).
207#[derive(Copy, Clone, Debug, PartialEq, Eq)]
208pub enum ColorLoopActionEnum {
209    /// Deactivate = 0.
210    Deactivate,
211    /// ActivateFromColorLoopStartEnhancedHue = 1.
212    ActivateFromColorLoopStartEnhancedHue,
213    /// ActivateFromEnhancedCurrentHue = 2.
214    ActivateFromEnhancedCurrentHue,
215    /// A value not known to this codegen revision.
216    Unknown(u8),
217}
218
219impl ColorLoopActionEnum {
220    /// Decode from its raw discriminant (unknown → `Unknown`).
221    #[must_use]
222    pub fn from_raw(v: u8) -> Self {
223        match v {
224            0 => Self::Deactivate,
225            1 => Self::ActivateFromColorLoopStartEnhancedHue,
226            2 => Self::ActivateFromEnhancedCurrentHue,
227            other => Self::Unknown(other),
228        }
229    }
230    /// The raw discriminant.
231    #[must_use]
232    pub fn to_raw(self) -> u8 {
233        match self {
234            Self::Deactivate => 0,
235            Self::ActivateFromColorLoopStartEnhancedHue => 1,
236            Self::ActivateFromEnhancedCurrentHue => 2,
237            Self::Unknown(v) => v,
238        }
239    }
240}
241
242/// `ColorLoopDirectionEnum` (enum8).
243#[derive(Copy, Clone, Debug, PartialEq, Eq)]
244pub enum ColorLoopDirectionEnum {
245    /// Decrement = 0.
246    Decrement,
247    /// Increment = 1.
248    Increment,
249    /// A value not known to this codegen revision.
250    Unknown(u8),
251}
252
253impl ColorLoopDirectionEnum {
254    /// Decode from its raw discriminant (unknown → `Unknown`).
255    #[must_use]
256    pub fn from_raw(v: u8) -> Self {
257        match v {
258            0 => Self::Decrement,
259            1 => Self::Increment,
260            other => Self::Unknown(other),
261        }
262    }
263    /// The raw discriminant.
264    #[must_use]
265    pub fn to_raw(self) -> u8 {
266        match self {
267            Self::Decrement => 0,
268            Self::Increment => 1,
269            Self::Unknown(v) => v,
270        }
271    }
272}
273
274/// `ColorModeEnum` (enum8).
275#[derive(Copy, Clone, Debug, PartialEq, Eq)]
276pub enum ColorModeEnum {
277    /// CurrentHueAndCurrentSaturation = 0.
278    CurrentHueAndCurrentSaturation,
279    /// CurrentXAndCurrentY = 1.
280    CurrentXAndCurrentY,
281    /// ColorTemperatureMireds = 2.
282    ColorTemperatureMireds,
283    /// A value not known to this codegen revision.
284    Unknown(u8),
285}
286
287impl ColorModeEnum {
288    /// Decode from its raw discriminant (unknown → `Unknown`).
289    #[must_use]
290    pub fn from_raw(v: u8) -> Self {
291        match v {
292            0 => Self::CurrentHueAndCurrentSaturation,
293            1 => Self::CurrentXAndCurrentY,
294            2 => Self::ColorTemperatureMireds,
295            other => Self::Unknown(other),
296        }
297    }
298    /// The raw discriminant.
299    #[must_use]
300    pub fn to_raw(self) -> u8 {
301        match self {
302            Self::CurrentHueAndCurrentSaturation => 0,
303            Self::CurrentXAndCurrentY => 1,
304            Self::ColorTemperatureMireds => 2,
305            Self::Unknown(v) => v,
306        }
307    }
308}
309
310/// `DirectionEnum` (enum8).
311#[derive(Copy, Clone, Debug, PartialEq, Eq)]
312pub enum DirectionEnum {
313    /// Shortest = 0.
314    Shortest,
315    /// Longest = 1.
316    Longest,
317    /// Up = 2.
318    Up,
319    /// Down = 3.
320    Down,
321    /// A value not known to this codegen revision.
322    Unknown(u8),
323}
324
325impl DirectionEnum {
326    /// Decode from its raw discriminant (unknown → `Unknown`).
327    #[must_use]
328    pub fn from_raw(v: u8) -> Self {
329        match v {
330            0 => Self::Shortest,
331            1 => Self::Longest,
332            2 => Self::Up,
333            3 => Self::Down,
334            other => Self::Unknown(other),
335        }
336    }
337    /// The raw discriminant.
338    #[must_use]
339    pub fn to_raw(self) -> u8 {
340        match self {
341            Self::Shortest => 0,
342            Self::Longest => 1,
343            Self::Up => 2,
344            Self::Down => 3,
345            Self::Unknown(v) => v,
346        }
347    }
348}
349
350/// `DriftCompensationEnum` (enum8).
351#[derive(Copy, Clone, Debug, PartialEq, Eq)]
352pub enum DriftCompensationEnum {
353    /// None = 0.
354    None,
355    /// OtherOrUnknown = 1.
356    OtherOrUnknown,
357    /// TemperatureMonitoring = 2.
358    TemperatureMonitoring,
359    /// OpticalLuminanceMonitoringAndFeedback = 3.
360    OpticalLuminanceMonitoringAndFeedback,
361    /// OpticalColorMonitoringAndFeedback = 4.
362    OpticalColorMonitoringAndFeedback,
363    /// A value not known to this codegen revision.
364    Unknown(u8),
365}
366
367impl DriftCompensationEnum {
368    /// Decode from its raw discriminant (unknown → `Unknown`).
369    #[must_use]
370    pub fn from_raw(v: u8) -> Self {
371        match v {
372            0 => Self::None,
373            1 => Self::OtherOrUnknown,
374            2 => Self::TemperatureMonitoring,
375            3 => Self::OpticalLuminanceMonitoringAndFeedback,
376            4 => Self::OpticalColorMonitoringAndFeedback,
377            other => Self::Unknown(other),
378        }
379    }
380    /// The raw discriminant.
381    #[must_use]
382    pub fn to_raw(self) -> u8 {
383        match self {
384            Self::None => 0,
385            Self::OtherOrUnknown => 1,
386            Self::TemperatureMonitoring => 2,
387            Self::OpticalLuminanceMonitoringAndFeedback => 3,
388            Self::OpticalColorMonitoringAndFeedback => 4,
389            Self::Unknown(v) => v,
390        }
391    }
392}
393
394/// `EnhancedColorModeEnum` (enum8).
395#[derive(Copy, Clone, Debug, PartialEq, Eq)]
396pub enum EnhancedColorModeEnum {
397    /// CurrentHueAndCurrentSaturation = 0.
398    CurrentHueAndCurrentSaturation,
399    /// CurrentXAndCurrentY = 1.
400    CurrentXAndCurrentY,
401    /// ColorTemperatureMireds = 2.
402    ColorTemperatureMireds,
403    /// EnhancedCurrentHueAndCurrentSaturation = 3.
404    EnhancedCurrentHueAndCurrentSaturation,
405    /// A value not known to this codegen revision.
406    Unknown(u8),
407}
408
409impl EnhancedColorModeEnum {
410    /// Decode from its raw discriminant (unknown → `Unknown`).
411    #[must_use]
412    pub fn from_raw(v: u8) -> Self {
413        match v {
414            0 => Self::CurrentHueAndCurrentSaturation,
415            1 => Self::CurrentXAndCurrentY,
416            2 => Self::ColorTemperatureMireds,
417            3 => Self::EnhancedCurrentHueAndCurrentSaturation,
418            other => Self::Unknown(other),
419        }
420    }
421    /// The raw discriminant.
422    #[must_use]
423    pub fn to_raw(self) -> u8 {
424        match self {
425            Self::CurrentHueAndCurrentSaturation => 0,
426            Self::CurrentXAndCurrentY => 1,
427            Self::ColorTemperatureMireds => 2,
428            Self::EnhancedCurrentHueAndCurrentSaturation => 3,
429            Self::Unknown(v) => v,
430        }
431    }
432}
433
434/// `MoveModeEnum` (enum8).
435#[derive(Copy, Clone, Debug, PartialEq, Eq)]
436pub enum MoveModeEnum {
437    /// Stop = 0.
438    Stop,
439    /// Up = 1.
440    Up,
441    /// Down = 3.
442    Down,
443    /// A value not known to this codegen revision.
444    Unknown(u8),
445}
446
447impl MoveModeEnum {
448    /// Decode from its raw discriminant (unknown → `Unknown`).
449    #[must_use]
450    pub fn from_raw(v: u8) -> Self {
451        match v {
452            0 => Self::Stop,
453            1 => Self::Up,
454            3 => Self::Down,
455            other => Self::Unknown(other),
456        }
457    }
458    /// The raw discriminant.
459    #[must_use]
460    pub fn to_raw(self) -> u8 {
461        match self {
462            Self::Stop => 0,
463            Self::Up => 1,
464            Self::Down => 3,
465            Self::Unknown(v) => v,
466        }
467    }
468}
469
470bitflags::bitflags! {
471    /// `OptionsBitmap` (map8).
472    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
473    pub struct OptionsBitmap: u8 {
474        /// ExecuteIfOff.
475        const EXECUTE_IF_OFF = 1 << 0;
476    }
477}
478
479/// `StepModeEnum` (enum8).
480#[derive(Copy, Clone, Debug, PartialEq, Eq)]
481pub enum StepModeEnum {
482    /// Up = 1.
483    Up,
484    /// Down = 3.
485    Down,
486    /// A value not known to this codegen revision.
487    Unknown(u8),
488}
489
490impl StepModeEnum {
491    /// Decode from its raw discriminant (unknown → `Unknown`).
492    #[must_use]
493    pub fn from_raw(v: u8) -> Self {
494        match v {
495            1 => Self::Up,
496            3 => Self::Down,
497            other => Self::Unknown(other),
498        }
499    }
500    /// The raw discriminant.
501    #[must_use]
502    pub fn to_raw(self) -> u8 {
503        match self {
504            Self::Up => 1,
505            Self::Down => 3,
506            Self::Unknown(v) => v,
507        }
508    }
509}
510
511bitflags::bitflags! {
512    /// `UpdateFlagsBitmap` (map8).
513    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
514    pub struct UpdateFlagsBitmap: u8 {
515        /// UpdateAction.
516        const UPDATE_ACTION = 1 << 0;
517        /// UpdateDirection.
518        const UPDATE_DIRECTION = 1 << 1;
519        /// UpdateTime.
520        const UPDATE_TIME = 1 << 2;
521        /// UpdateStartHue.
522        const UPDATE_START_HUE = 1 << 3;
523    }
524}
525
526/// Decode the `CurrentHue` attribute value.
527///
528/// # Errors
529/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
530pub fn decode_current_hue(tlv: &[u8]) -> Result<u8, ClusterError> {
531    let mut r = TlvReader::new(tlv);
532    match r.next()? {
533        Some(Element::Scalar {
534            value: Value::Uint(v),
535            ..
536        }) => Ok(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("CurrentHue"))?),
537        _ => Err(ClusterError::UnexpectedType {
538            context: "CurrentHue",
539        }),
540    }
541}
542
543/// Decode the `CurrentSaturation` attribute value.
544///
545/// # Errors
546/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
547pub fn decode_current_saturation(tlv: &[u8]) -> Result<u8, ClusterError> {
548    let mut r = TlvReader::new(tlv);
549    match r.next()? {
550        Some(Element::Scalar {
551            value: Value::Uint(v),
552            ..
553        }) => Ok(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("CurrentSaturation"))?),
554        _ => Err(ClusterError::UnexpectedType {
555            context: "CurrentSaturation",
556        }),
557    }
558}
559
560/// Decode the `RemainingTime` attribute value.
561///
562/// # Errors
563/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
564pub fn decode_remaining_time(tlv: &[u8]) -> Result<u16, ClusterError> {
565    let mut r = TlvReader::new(tlv);
566    match r.next()? {
567        Some(Element::Scalar {
568            value: Value::Uint(v),
569            ..
570        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("RemainingTime"))?),
571        _ => Err(ClusterError::UnexpectedType {
572            context: "RemainingTime",
573        }),
574    }
575}
576
577/// Decode the `CurrentX` attribute value.
578///
579/// # Errors
580/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
581pub fn decode_current_x(tlv: &[u8]) -> Result<u16, ClusterError> {
582    let mut r = TlvReader::new(tlv);
583    match r.next()? {
584        Some(Element::Scalar {
585            value: Value::Uint(v),
586            ..
587        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("CurrentX"))?),
588        _ => Err(ClusterError::UnexpectedType {
589            context: "CurrentX",
590        }),
591    }
592}
593
594/// Decode the `CurrentY` attribute value.
595///
596/// # Errors
597/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
598pub fn decode_current_y(tlv: &[u8]) -> Result<u16, ClusterError> {
599    let mut r = TlvReader::new(tlv);
600    match r.next()? {
601        Some(Element::Scalar {
602            value: Value::Uint(v),
603            ..
604        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("CurrentY"))?),
605        _ => Err(ClusterError::UnexpectedType {
606            context: "CurrentY",
607        }),
608    }
609}
610
611/// Decode the `DriftCompensation` attribute value.
612///
613/// # Errors
614/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
615pub fn decode_drift_compensation(tlv: &[u8]) -> Result<DriftCompensationEnum, ClusterError> {
616    let mut r = TlvReader::new(tlv);
617    match r.next()? {
618        Some(Element::Scalar {
619            value: Value::Uint(v),
620            ..
621        }) => Ok(DriftCompensationEnum::from_raw(
622            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("DriftCompensation"))?,
623        )),
624        _ => Err(ClusterError::UnexpectedType {
625            context: "DriftCompensation",
626        }),
627    }
628}
629
630/// Decode the `CompensationText` attribute value.
631///
632/// # Errors
633/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
634pub fn decode_compensation_text(tlv: &[u8]) -> Result<String, ClusterError> {
635    let mut r = TlvReader::new(tlv);
636    match r.next()? {
637        Some(Element::Scalar {
638            value: Value::Utf8(v),
639            ..
640        }) => Ok(v),
641        _ => Err(ClusterError::UnexpectedType {
642            context: "CompensationText",
643        }),
644    }
645}
646
647/// Decode the `ColorTemperatureMireds` attribute value.
648///
649/// # Errors
650/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
651pub fn decode_color_temperature_mireds(tlv: &[u8]) -> Result<u16, ClusterError> {
652    let mut r = TlvReader::new(tlv);
653    match r.next()? {
654        Some(Element::Scalar {
655            value: Value::Uint(v),
656            ..
657        }) => {
658            Ok(u16::try_from(v)
659                .map_err(|_| ClusterError::InvalidLength("ColorTemperatureMireds"))?)
660        }
661        _ => Err(ClusterError::UnexpectedType {
662            context: "ColorTemperatureMireds",
663        }),
664    }
665}
666
667/// Decode the `ColorMode` attribute value.
668///
669/// # Errors
670/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
671pub fn decode_color_mode(tlv: &[u8]) -> Result<ColorModeEnum, ClusterError> {
672    let mut r = TlvReader::new(tlv);
673    match r.next()? {
674        Some(Element::Scalar {
675            value: Value::Uint(v),
676            ..
677        }) => Ok(ColorModeEnum::from_raw(
678            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorMode"))?,
679        )),
680        _ => Err(ClusterError::UnexpectedType {
681            context: "ColorMode",
682        }),
683    }
684}
685
686/// Decode the `Options` attribute value.
687///
688/// # Errors
689/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
690pub fn decode_options(tlv: &[u8]) -> Result<OptionsBitmap, ClusterError> {
691    let mut r = TlvReader::new(tlv);
692    match r.next()? {
693        Some(Element::Scalar {
694            value: Value::Uint(v),
695            ..
696        }) => Ok(OptionsBitmap::from_bits_retain(
697            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Options"))?,
698        )),
699        _ => Err(ClusterError::UnexpectedType { context: "Options" }),
700    }
701}
702
703/// Encode the `Options` attribute value as a standalone TLV element.
704#[must_use]
705#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
706pub fn encode_options(value: OptionsBitmap) -> Vec<u8> {
707    let mut buf = Vec::new();
708    let mut w = TlvWriter::new(&mut buf);
709    w.put_uint(Tag::Anonymous, u64::from(value.bits()))
710        .expect("infallible: vec writer");
711    buf
712}
713
714/// Decode the `NumberOfPrimaries` attribute value.
715///
716/// # Errors
717/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
718pub fn decode_number_of_primaries(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
719    let mut r = TlvReader::new(tlv);
720    match r.next()? {
721        Some(Element::Scalar {
722            value: Value::Null, ..
723        }) => Ok(Nullable::Null),
724        Some(Element::Scalar {
725            value: Value::Uint(v),
726            ..
727        }) => {
728            Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
729                ClusterError::InvalidLength("NumberOfPrimaries")
730            })?))
731        }
732        _ => Err(ClusterError::UnexpectedType {
733            context: "NumberOfPrimaries",
734        }),
735    }
736}
737
738/// Decode the `Primary1X` attribute value.
739///
740/// # Errors
741/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
742pub fn decode_primary1_x(tlv: &[u8]) -> Result<u16, ClusterError> {
743    let mut r = TlvReader::new(tlv);
744    match r.next()? {
745        Some(Element::Scalar {
746            value: Value::Uint(v),
747            ..
748        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary1X"))?),
749        _ => Err(ClusterError::UnexpectedType {
750            context: "Primary1X",
751        }),
752    }
753}
754
755/// Decode the `Primary1Y` attribute value.
756///
757/// # Errors
758/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
759pub fn decode_primary1_y(tlv: &[u8]) -> Result<u16, ClusterError> {
760    let mut r = TlvReader::new(tlv);
761    match r.next()? {
762        Some(Element::Scalar {
763            value: Value::Uint(v),
764            ..
765        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary1Y"))?),
766        _ => Err(ClusterError::UnexpectedType {
767            context: "Primary1Y",
768        }),
769    }
770}
771
772/// Decode the `Primary1Intensity` attribute value.
773///
774/// # Errors
775/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
776pub fn decode_primary1_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
777    let mut r = TlvReader::new(tlv);
778    match r.next()? {
779        Some(Element::Scalar {
780            value: Value::Null, ..
781        }) => Ok(Nullable::Null),
782        Some(Element::Scalar {
783            value: Value::Uint(v),
784            ..
785        }) => {
786            Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
787                ClusterError::InvalidLength("Primary1Intensity")
788            })?))
789        }
790        _ => Err(ClusterError::UnexpectedType {
791            context: "Primary1Intensity",
792        }),
793    }
794}
795
796/// Decode the `Primary2X` attribute value.
797///
798/// # Errors
799/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
800pub fn decode_primary2_x(tlv: &[u8]) -> Result<u16, ClusterError> {
801    let mut r = TlvReader::new(tlv);
802    match r.next()? {
803        Some(Element::Scalar {
804            value: Value::Uint(v),
805            ..
806        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary2X"))?),
807        _ => Err(ClusterError::UnexpectedType {
808            context: "Primary2X",
809        }),
810    }
811}
812
813/// Decode the `Primary2Y` attribute value.
814///
815/// # Errors
816/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
817pub fn decode_primary2_y(tlv: &[u8]) -> Result<u16, ClusterError> {
818    let mut r = TlvReader::new(tlv);
819    match r.next()? {
820        Some(Element::Scalar {
821            value: Value::Uint(v),
822            ..
823        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary2Y"))?),
824        _ => Err(ClusterError::UnexpectedType {
825            context: "Primary2Y",
826        }),
827    }
828}
829
830/// Decode the `Primary2Intensity` attribute value.
831///
832/// # Errors
833/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
834pub fn decode_primary2_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
835    let mut r = TlvReader::new(tlv);
836    match r.next()? {
837        Some(Element::Scalar {
838            value: Value::Null, ..
839        }) => Ok(Nullable::Null),
840        Some(Element::Scalar {
841            value: Value::Uint(v),
842            ..
843        }) => {
844            Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
845                ClusterError::InvalidLength("Primary2Intensity")
846            })?))
847        }
848        _ => Err(ClusterError::UnexpectedType {
849            context: "Primary2Intensity",
850        }),
851    }
852}
853
854/// Decode the `Primary3X` attribute value.
855///
856/// # Errors
857/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
858pub fn decode_primary3_x(tlv: &[u8]) -> Result<u16, ClusterError> {
859    let mut r = TlvReader::new(tlv);
860    match r.next()? {
861        Some(Element::Scalar {
862            value: Value::Uint(v),
863            ..
864        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary3X"))?),
865        _ => Err(ClusterError::UnexpectedType {
866            context: "Primary3X",
867        }),
868    }
869}
870
871/// Decode the `Primary3Y` attribute value.
872///
873/// # Errors
874/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
875pub fn decode_primary3_y(tlv: &[u8]) -> Result<u16, ClusterError> {
876    let mut r = TlvReader::new(tlv);
877    match r.next()? {
878        Some(Element::Scalar {
879            value: Value::Uint(v),
880            ..
881        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary3Y"))?),
882        _ => Err(ClusterError::UnexpectedType {
883            context: "Primary3Y",
884        }),
885    }
886}
887
888/// Decode the `Primary3Intensity` attribute value.
889///
890/// # Errors
891/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
892pub fn decode_primary3_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
893    let mut r = TlvReader::new(tlv);
894    match r.next()? {
895        Some(Element::Scalar {
896            value: Value::Null, ..
897        }) => Ok(Nullable::Null),
898        Some(Element::Scalar {
899            value: Value::Uint(v),
900            ..
901        }) => {
902            Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
903                ClusterError::InvalidLength("Primary3Intensity")
904            })?))
905        }
906        _ => Err(ClusterError::UnexpectedType {
907            context: "Primary3Intensity",
908        }),
909    }
910}
911
912/// Decode the `Primary4X` attribute value.
913///
914/// # Errors
915/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
916pub fn decode_primary4_x(tlv: &[u8]) -> Result<u16, ClusterError> {
917    let mut r = TlvReader::new(tlv);
918    match r.next()? {
919        Some(Element::Scalar {
920            value: Value::Uint(v),
921            ..
922        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary4X"))?),
923        _ => Err(ClusterError::UnexpectedType {
924            context: "Primary4X",
925        }),
926    }
927}
928
929/// Decode the `Primary4Y` attribute value.
930///
931/// # Errors
932/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
933pub fn decode_primary4_y(tlv: &[u8]) -> Result<u16, ClusterError> {
934    let mut r = TlvReader::new(tlv);
935    match r.next()? {
936        Some(Element::Scalar {
937            value: Value::Uint(v),
938            ..
939        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary4Y"))?),
940        _ => Err(ClusterError::UnexpectedType {
941            context: "Primary4Y",
942        }),
943    }
944}
945
946/// Decode the `Primary4Intensity` attribute value.
947///
948/// # Errors
949/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
950pub fn decode_primary4_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
951    let mut r = TlvReader::new(tlv);
952    match r.next()? {
953        Some(Element::Scalar {
954            value: Value::Null, ..
955        }) => Ok(Nullable::Null),
956        Some(Element::Scalar {
957            value: Value::Uint(v),
958            ..
959        }) => {
960            Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
961                ClusterError::InvalidLength("Primary4Intensity")
962            })?))
963        }
964        _ => Err(ClusterError::UnexpectedType {
965            context: "Primary4Intensity",
966        }),
967    }
968}
969
970/// Decode the `Primary5X` attribute value.
971///
972/// # Errors
973/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
974pub fn decode_primary5_x(tlv: &[u8]) -> Result<u16, ClusterError> {
975    let mut r = TlvReader::new(tlv);
976    match r.next()? {
977        Some(Element::Scalar {
978            value: Value::Uint(v),
979            ..
980        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary5X"))?),
981        _ => Err(ClusterError::UnexpectedType {
982            context: "Primary5X",
983        }),
984    }
985}
986
987/// Decode the `Primary5Y` attribute value.
988///
989/// # Errors
990/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
991pub fn decode_primary5_y(tlv: &[u8]) -> Result<u16, ClusterError> {
992    let mut r = TlvReader::new(tlv);
993    match r.next()? {
994        Some(Element::Scalar {
995            value: Value::Uint(v),
996            ..
997        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary5Y"))?),
998        _ => Err(ClusterError::UnexpectedType {
999            context: "Primary5Y",
1000        }),
1001    }
1002}
1003
1004/// Decode the `Primary5Intensity` attribute value.
1005///
1006/// # Errors
1007/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1008pub fn decode_primary5_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
1009    let mut r = TlvReader::new(tlv);
1010    match r.next()? {
1011        Some(Element::Scalar {
1012            value: Value::Null, ..
1013        }) => Ok(Nullable::Null),
1014        Some(Element::Scalar {
1015            value: Value::Uint(v),
1016            ..
1017        }) => {
1018            Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
1019                ClusterError::InvalidLength("Primary5Intensity")
1020            })?))
1021        }
1022        _ => Err(ClusterError::UnexpectedType {
1023            context: "Primary5Intensity",
1024        }),
1025    }
1026}
1027
1028/// Decode the `Primary6X` attribute value.
1029///
1030/// # Errors
1031/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1032pub fn decode_primary6_x(tlv: &[u8]) -> Result<u16, ClusterError> {
1033    let mut r = TlvReader::new(tlv);
1034    match r.next()? {
1035        Some(Element::Scalar {
1036            value: Value::Uint(v),
1037            ..
1038        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary6X"))?),
1039        _ => Err(ClusterError::UnexpectedType {
1040            context: "Primary6X",
1041        }),
1042    }
1043}
1044
1045/// Decode the `Primary6Y` attribute value.
1046///
1047/// # Errors
1048/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1049pub fn decode_primary6_y(tlv: &[u8]) -> Result<u16, ClusterError> {
1050    let mut r = TlvReader::new(tlv);
1051    match r.next()? {
1052        Some(Element::Scalar {
1053            value: Value::Uint(v),
1054            ..
1055        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Primary6Y"))?),
1056        _ => Err(ClusterError::UnexpectedType {
1057            context: "Primary6Y",
1058        }),
1059    }
1060}
1061
1062/// Decode the `Primary6Intensity` attribute value.
1063///
1064/// # Errors
1065/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1066pub fn decode_primary6_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
1067    let mut r = TlvReader::new(tlv);
1068    match r.next()? {
1069        Some(Element::Scalar {
1070            value: Value::Null, ..
1071        }) => Ok(Nullable::Null),
1072        Some(Element::Scalar {
1073            value: Value::Uint(v),
1074            ..
1075        }) => {
1076            Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
1077                ClusterError::InvalidLength("Primary6Intensity")
1078            })?))
1079        }
1080        _ => Err(ClusterError::UnexpectedType {
1081            context: "Primary6Intensity",
1082        }),
1083    }
1084}
1085
1086/// Decode the `WhitePointX` attribute value.
1087///
1088/// # Errors
1089/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1090pub fn decode_white_point_x(tlv: &[u8]) -> Result<u16, ClusterError> {
1091    let mut r = TlvReader::new(tlv);
1092    match r.next()? {
1093        Some(Element::Scalar {
1094            value: Value::Uint(v),
1095            ..
1096        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("WhitePointX"))?),
1097        _ => Err(ClusterError::UnexpectedType {
1098            context: "WhitePointX",
1099        }),
1100    }
1101}
1102
1103/// Decode the `WhitePointY` attribute value.
1104///
1105/// # Errors
1106/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1107pub fn decode_white_point_y(tlv: &[u8]) -> Result<u16, ClusterError> {
1108    let mut r = TlvReader::new(tlv);
1109    match r.next()? {
1110        Some(Element::Scalar {
1111            value: Value::Uint(v),
1112            ..
1113        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("WhitePointY"))?),
1114        _ => Err(ClusterError::UnexpectedType {
1115            context: "WhitePointY",
1116        }),
1117    }
1118}
1119
1120/// Decode the `ColorPointRx` attribute value.
1121///
1122/// # Errors
1123/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1124pub fn decode_color_point_rx(tlv: &[u8]) -> Result<u16, ClusterError> {
1125    let mut r = TlvReader::new(tlv);
1126    match r.next()? {
1127        Some(Element::Scalar {
1128            value: Value::Uint(v),
1129            ..
1130        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorPointRx"))?),
1131        _ => Err(ClusterError::UnexpectedType {
1132            context: "ColorPointRx",
1133        }),
1134    }
1135}
1136
1137/// Decode the `ColorPointRy` attribute value.
1138///
1139/// # Errors
1140/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1141pub fn decode_color_point_ry(tlv: &[u8]) -> Result<u16, ClusterError> {
1142    let mut r = TlvReader::new(tlv);
1143    match r.next()? {
1144        Some(Element::Scalar {
1145            value: Value::Uint(v),
1146            ..
1147        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorPointRy"))?),
1148        _ => Err(ClusterError::UnexpectedType {
1149            context: "ColorPointRy",
1150        }),
1151    }
1152}
1153
1154/// Decode the `ColorPointRIntensity` attribute value.
1155///
1156/// # Errors
1157/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1158pub fn decode_color_point_r_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
1159    let mut r = TlvReader::new(tlv);
1160    match r.next()? {
1161        Some(Element::Scalar {
1162            value: Value::Null, ..
1163        }) => Ok(Nullable::Null),
1164        Some(Element::Scalar {
1165            value: Value::Uint(v),
1166            ..
1167        }) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
1168            ClusterError::InvalidLength("ColorPointRIntensity")
1169        })?)),
1170        _ => Err(ClusterError::UnexpectedType {
1171            context: "ColorPointRIntensity",
1172        }),
1173    }
1174}
1175
1176/// Decode the `ColorPointGx` attribute value.
1177///
1178/// # Errors
1179/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1180pub fn decode_color_point_gx(tlv: &[u8]) -> Result<u16, ClusterError> {
1181    let mut r = TlvReader::new(tlv);
1182    match r.next()? {
1183        Some(Element::Scalar {
1184            value: Value::Uint(v),
1185            ..
1186        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorPointGx"))?),
1187        _ => Err(ClusterError::UnexpectedType {
1188            context: "ColorPointGx",
1189        }),
1190    }
1191}
1192
1193/// Decode the `ColorPointGy` attribute value.
1194///
1195/// # Errors
1196/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1197pub fn decode_color_point_gy(tlv: &[u8]) -> Result<u16, ClusterError> {
1198    let mut r = TlvReader::new(tlv);
1199    match r.next()? {
1200        Some(Element::Scalar {
1201            value: Value::Uint(v),
1202            ..
1203        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorPointGy"))?),
1204        _ => Err(ClusterError::UnexpectedType {
1205            context: "ColorPointGy",
1206        }),
1207    }
1208}
1209
1210/// Decode the `ColorPointGIntensity` attribute value.
1211///
1212/// # Errors
1213/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1214pub fn decode_color_point_g_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
1215    let mut r = TlvReader::new(tlv);
1216    match r.next()? {
1217        Some(Element::Scalar {
1218            value: Value::Null, ..
1219        }) => Ok(Nullable::Null),
1220        Some(Element::Scalar {
1221            value: Value::Uint(v),
1222            ..
1223        }) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
1224            ClusterError::InvalidLength("ColorPointGIntensity")
1225        })?)),
1226        _ => Err(ClusterError::UnexpectedType {
1227            context: "ColorPointGIntensity",
1228        }),
1229    }
1230}
1231
1232/// Decode the `ColorPointBx` attribute value.
1233///
1234/// # Errors
1235/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1236pub fn decode_color_point_bx(tlv: &[u8]) -> Result<u16, ClusterError> {
1237    let mut r = TlvReader::new(tlv);
1238    match r.next()? {
1239        Some(Element::Scalar {
1240            value: Value::Uint(v),
1241            ..
1242        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorPointBx"))?),
1243        _ => Err(ClusterError::UnexpectedType {
1244            context: "ColorPointBx",
1245        }),
1246    }
1247}
1248
1249/// Decode the `ColorPointBy` attribute value.
1250///
1251/// # Errors
1252/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1253pub fn decode_color_point_by(tlv: &[u8]) -> Result<u16, ClusterError> {
1254    let mut r = TlvReader::new(tlv);
1255    match r.next()? {
1256        Some(Element::Scalar {
1257            value: Value::Uint(v),
1258            ..
1259        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorPointBy"))?),
1260        _ => Err(ClusterError::UnexpectedType {
1261            context: "ColorPointBy",
1262        }),
1263    }
1264}
1265
1266/// Decode the `ColorPointBIntensity` attribute value.
1267///
1268/// # Errors
1269/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1270pub fn decode_color_point_b_intensity(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
1271    let mut r = TlvReader::new(tlv);
1272    match r.next()? {
1273        Some(Element::Scalar {
1274            value: Value::Null, ..
1275        }) => Ok(Nullable::Null),
1276        Some(Element::Scalar {
1277            value: Value::Uint(v),
1278            ..
1279        }) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
1280            ClusterError::InvalidLength("ColorPointBIntensity")
1281        })?)),
1282        _ => Err(ClusterError::UnexpectedType {
1283            context: "ColorPointBIntensity",
1284        }),
1285    }
1286}
1287
1288/// Decode the `EnhancedCurrentHue` attribute value.
1289///
1290/// # Errors
1291/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1292pub fn decode_enhanced_current_hue(tlv: &[u8]) -> Result<u16, ClusterError> {
1293    let mut r = TlvReader::new(tlv);
1294    match r.next()? {
1295        Some(Element::Scalar {
1296            value: Value::Uint(v),
1297            ..
1298        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("EnhancedCurrentHue"))?),
1299        _ => Err(ClusterError::UnexpectedType {
1300            context: "EnhancedCurrentHue",
1301        }),
1302    }
1303}
1304
1305/// Decode the `EnhancedColorMode` attribute value.
1306///
1307/// # Errors
1308/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1309pub fn decode_enhanced_color_mode(tlv: &[u8]) -> Result<EnhancedColorModeEnum, ClusterError> {
1310    let mut r = TlvReader::new(tlv);
1311    match r.next()? {
1312        Some(Element::Scalar {
1313            value: Value::Uint(v),
1314            ..
1315        }) => Ok(EnhancedColorModeEnum::from_raw(
1316            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("EnhancedColorMode"))?,
1317        )),
1318        _ => Err(ClusterError::UnexpectedType {
1319            context: "EnhancedColorMode",
1320        }),
1321    }
1322}
1323
1324/// Decode the `ColorLoopActive` attribute value.
1325///
1326/// # Errors
1327/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1328pub fn decode_color_loop_active(tlv: &[u8]) -> Result<u8, ClusterError> {
1329    let mut r = TlvReader::new(tlv);
1330    match r.next()? {
1331        Some(Element::Scalar {
1332            value: Value::Uint(v),
1333            ..
1334        }) => Ok(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorLoopActive"))?),
1335        _ => Err(ClusterError::UnexpectedType {
1336            context: "ColorLoopActive",
1337        }),
1338    }
1339}
1340
1341/// Decode the `ColorLoopDirection` attribute value.
1342///
1343/// # Errors
1344/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1345pub fn decode_color_loop_direction(tlv: &[u8]) -> Result<ColorLoopDirectionEnum, ClusterError> {
1346    let mut r = TlvReader::new(tlv);
1347    match r.next()? {
1348        Some(Element::Scalar {
1349            value: Value::Uint(v),
1350            ..
1351        }) => Ok(ColorLoopDirectionEnum::from_raw(u8::try_from(v).map_err(
1352            |_| ClusterError::InvalidLength("ColorLoopDirection"),
1353        )?)),
1354        _ => Err(ClusterError::UnexpectedType {
1355            context: "ColorLoopDirection",
1356        }),
1357    }
1358}
1359
1360/// Decode the `ColorLoopTime` attribute value.
1361///
1362/// # Errors
1363/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1364pub fn decode_color_loop_time(tlv: &[u8]) -> Result<u16, ClusterError> {
1365    let mut r = TlvReader::new(tlv);
1366    match r.next()? {
1367        Some(Element::Scalar {
1368            value: Value::Uint(v),
1369            ..
1370        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorLoopTime"))?),
1371        _ => Err(ClusterError::UnexpectedType {
1372            context: "ColorLoopTime",
1373        }),
1374    }
1375}
1376
1377/// Decode the `ColorLoopStartEnhancedHue` attribute value.
1378///
1379/// # Errors
1380/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1381pub fn decode_color_loop_start_enhanced_hue(tlv: &[u8]) -> Result<u16, ClusterError> {
1382    let mut r = TlvReader::new(tlv);
1383    match r.next()? {
1384        Some(Element::Scalar {
1385            value: Value::Uint(v),
1386            ..
1387        }) => Ok(u16::try_from(v)
1388            .map_err(|_| ClusterError::InvalidLength("ColorLoopStartEnhancedHue"))?),
1389        _ => Err(ClusterError::UnexpectedType {
1390            context: "ColorLoopStartEnhancedHue",
1391        }),
1392    }
1393}
1394
1395/// Decode the `ColorLoopStoredEnhancedHue` attribute value.
1396///
1397/// # Errors
1398/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1399pub fn decode_color_loop_stored_enhanced_hue(tlv: &[u8]) -> Result<u16, ClusterError> {
1400    let mut r = TlvReader::new(tlv);
1401    match r.next()? {
1402        Some(Element::Scalar {
1403            value: Value::Uint(v),
1404            ..
1405        }) => Ok(u16::try_from(v)
1406            .map_err(|_| ClusterError::InvalidLength("ColorLoopStoredEnhancedHue"))?),
1407        _ => Err(ClusterError::UnexpectedType {
1408            context: "ColorLoopStoredEnhancedHue",
1409        }),
1410    }
1411}
1412
1413/// Decode the `ColorCapabilities` attribute value.
1414///
1415/// # Errors
1416/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1417pub fn decode_color_capabilities(tlv: &[u8]) -> Result<ColorCapabilitiesBitmap, ClusterError> {
1418    let mut r = TlvReader::new(tlv);
1419    match r.next()? {
1420        Some(Element::Scalar {
1421            value: Value::Uint(v),
1422            ..
1423        }) => Ok(ColorCapabilitiesBitmap::from_bits_retain(
1424            u16::try_from(v).map_err(|_| ClusterError::InvalidLength("ColorCapabilities"))?,
1425        )),
1426        _ => Err(ClusterError::UnexpectedType {
1427            context: "ColorCapabilities",
1428        }),
1429    }
1430}
1431
1432/// Decode the `ColorTempPhysicalMinMireds` attribute value.
1433///
1434/// # Errors
1435/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1436pub fn decode_color_temp_physical_min_mireds(tlv: &[u8]) -> Result<u16, ClusterError> {
1437    let mut r = TlvReader::new(tlv);
1438    match r.next()? {
1439        Some(Element::Scalar {
1440            value: Value::Uint(v),
1441            ..
1442        }) => Ok(u16::try_from(v)
1443            .map_err(|_| ClusterError::InvalidLength("ColorTempPhysicalMinMireds"))?),
1444        _ => Err(ClusterError::UnexpectedType {
1445            context: "ColorTempPhysicalMinMireds",
1446        }),
1447    }
1448}
1449
1450/// Decode the `ColorTempPhysicalMaxMireds` attribute value.
1451///
1452/// # Errors
1453/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1454pub fn decode_color_temp_physical_max_mireds(tlv: &[u8]) -> Result<u16, ClusterError> {
1455    let mut r = TlvReader::new(tlv);
1456    match r.next()? {
1457        Some(Element::Scalar {
1458            value: Value::Uint(v),
1459            ..
1460        }) => Ok(u16::try_from(v)
1461            .map_err(|_| ClusterError::InvalidLength("ColorTempPhysicalMaxMireds"))?),
1462        _ => Err(ClusterError::UnexpectedType {
1463            context: "ColorTempPhysicalMaxMireds",
1464        }),
1465    }
1466}
1467
1468/// Decode the `CoupleColorTempToLevelMinMireds` attribute value.
1469///
1470/// # Errors
1471/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1472pub fn decode_couple_color_temp_to_level_min_mireds(tlv: &[u8]) -> Result<u16, ClusterError> {
1473    let mut r = TlvReader::new(tlv);
1474    match r.next()? {
1475        Some(Element::Scalar {
1476            value: Value::Uint(v),
1477            ..
1478        }) => Ok(u16::try_from(v)
1479            .map_err(|_| ClusterError::InvalidLength("CoupleColorTempToLevelMinMireds"))?),
1480        _ => Err(ClusterError::UnexpectedType {
1481            context: "CoupleColorTempToLevelMinMireds",
1482        }),
1483    }
1484}
1485
1486/// Decode the `StartUpColorTemperatureMireds` attribute value.
1487///
1488/// # Errors
1489/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1490pub fn decode_start_up_color_temperature_mireds(tlv: &[u8]) -> Result<Nullable<u16>, ClusterError> {
1491    let mut r = TlvReader::new(tlv);
1492    match r.next()? {
1493        Some(Element::Scalar {
1494            value: Value::Null, ..
1495        }) => Ok(Nullable::Null),
1496        Some(Element::Scalar {
1497            value: Value::Uint(v),
1498            ..
1499        }) => Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
1500            ClusterError::InvalidLength("StartUpColorTemperatureMireds")
1501        })?)),
1502        _ => Err(ClusterError::UnexpectedType {
1503            context: "StartUpColorTemperatureMireds",
1504        }),
1505    }
1506}
1507
1508/// Encode the `StartUpColorTemperatureMireds` attribute value as a standalone TLV element.
1509#[must_use]
1510#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1511pub fn encode_start_up_color_temperature_mireds(value: Nullable<u16>) -> Vec<u8> {
1512    let mut buf = Vec::new();
1513    let mut w = TlvWriter::new(&mut buf);
1514    match value {
1515        Nullable::Null => w.put_null(Tag::Anonymous).expect("infallible: vec writer"),
1516        Nullable::Value(value) => {
1517            w.put_uint(Tag::Anonymous, u64::from(value))
1518                .expect("infallible: vec writer");
1519        }
1520    }
1521    buf
1522}
1523
1524/// Encode the `MoveToHue` command request payload.
1525#[must_use]
1526#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1527pub fn encode_move_to_hue(
1528    hue: u8,
1529    direction: DirectionEnum,
1530    transition_time: u16,
1531    options_mask: OptionsBitmap,
1532    options_override: OptionsBitmap,
1533) -> Vec<u8> {
1534    let mut buf = Vec::new();
1535    let mut w = TlvWriter::new(&mut buf);
1536    w.start_structure(Tag::Anonymous)
1537        .expect("infallible: vec writer");
1538    w.put_uint(Tag::Context(0), u64::from(hue))
1539        .expect("infallible: vec writer");
1540    w.put_uint(Tag::Context(1), u64::from(direction.to_raw()))
1541        .expect("infallible: vec writer");
1542    w.put_uint(Tag::Context(2), u64::from(transition_time))
1543        .expect("infallible: vec writer");
1544    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1545        .expect("infallible: vec writer");
1546    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1547        .expect("infallible: vec writer");
1548    w.end_container().expect("infallible: vec writer");
1549    buf
1550}
1551
1552/// Encode the `MoveHue` command request payload.
1553#[must_use]
1554#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1555pub fn encode_move_hue(
1556    move_mode: MoveModeEnum,
1557    rate: u8,
1558    options_mask: OptionsBitmap,
1559    options_override: OptionsBitmap,
1560) -> Vec<u8> {
1561    let mut buf = Vec::new();
1562    let mut w = TlvWriter::new(&mut buf);
1563    w.start_structure(Tag::Anonymous)
1564        .expect("infallible: vec writer");
1565    w.put_uint(Tag::Context(0), u64::from(move_mode.to_raw()))
1566        .expect("infallible: vec writer");
1567    w.put_uint(Tag::Context(1), u64::from(rate))
1568        .expect("infallible: vec writer");
1569    w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
1570        .expect("infallible: vec writer");
1571    w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
1572        .expect("infallible: vec writer");
1573    w.end_container().expect("infallible: vec writer");
1574    buf
1575}
1576
1577/// Encode the `StepHue` command request payload.
1578#[must_use]
1579#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1580pub fn encode_step_hue(
1581    step_mode: StepModeEnum,
1582    step_size: u8,
1583    transition_time: u8,
1584    options_mask: OptionsBitmap,
1585    options_override: OptionsBitmap,
1586) -> Vec<u8> {
1587    let mut buf = Vec::new();
1588    let mut w = TlvWriter::new(&mut buf);
1589    w.start_structure(Tag::Anonymous)
1590        .expect("infallible: vec writer");
1591    w.put_uint(Tag::Context(0), u64::from(step_mode.to_raw()))
1592        .expect("infallible: vec writer");
1593    w.put_uint(Tag::Context(1), u64::from(step_size))
1594        .expect("infallible: vec writer");
1595    w.put_uint(Tag::Context(2), u64::from(transition_time))
1596        .expect("infallible: vec writer");
1597    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1598        .expect("infallible: vec writer");
1599    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1600        .expect("infallible: vec writer");
1601    w.end_container().expect("infallible: vec writer");
1602    buf
1603}
1604
1605/// Encode the `MoveToSaturation` command request payload.
1606#[must_use]
1607#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1608pub fn encode_move_to_saturation(
1609    saturation: u8,
1610    transition_time: u16,
1611    options_mask: OptionsBitmap,
1612    options_override: OptionsBitmap,
1613) -> Vec<u8> {
1614    let mut buf = Vec::new();
1615    let mut w = TlvWriter::new(&mut buf);
1616    w.start_structure(Tag::Anonymous)
1617        .expect("infallible: vec writer");
1618    w.put_uint(Tag::Context(0), u64::from(saturation))
1619        .expect("infallible: vec writer");
1620    w.put_uint(Tag::Context(1), u64::from(transition_time))
1621        .expect("infallible: vec writer");
1622    w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
1623        .expect("infallible: vec writer");
1624    w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
1625        .expect("infallible: vec writer");
1626    w.end_container().expect("infallible: vec writer");
1627    buf
1628}
1629
1630/// Encode the `MoveSaturation` command request payload.
1631#[must_use]
1632#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1633pub fn encode_move_saturation(
1634    move_mode: MoveModeEnum,
1635    rate: u8,
1636    options_mask: OptionsBitmap,
1637    options_override: OptionsBitmap,
1638) -> Vec<u8> {
1639    let mut buf = Vec::new();
1640    let mut w = TlvWriter::new(&mut buf);
1641    w.start_structure(Tag::Anonymous)
1642        .expect("infallible: vec writer");
1643    w.put_uint(Tag::Context(0), u64::from(move_mode.to_raw()))
1644        .expect("infallible: vec writer");
1645    w.put_uint(Tag::Context(1), u64::from(rate))
1646        .expect("infallible: vec writer");
1647    w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
1648        .expect("infallible: vec writer");
1649    w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
1650        .expect("infallible: vec writer");
1651    w.end_container().expect("infallible: vec writer");
1652    buf
1653}
1654
1655/// Encode the `StepSaturation` command request payload.
1656#[must_use]
1657#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1658pub fn encode_step_saturation(
1659    step_mode: StepModeEnum,
1660    step_size: u8,
1661    transition_time: u8,
1662    options_mask: OptionsBitmap,
1663    options_override: OptionsBitmap,
1664) -> Vec<u8> {
1665    let mut buf = Vec::new();
1666    let mut w = TlvWriter::new(&mut buf);
1667    w.start_structure(Tag::Anonymous)
1668        .expect("infallible: vec writer");
1669    w.put_uint(Tag::Context(0), u64::from(step_mode.to_raw()))
1670        .expect("infallible: vec writer");
1671    w.put_uint(Tag::Context(1), u64::from(step_size))
1672        .expect("infallible: vec writer");
1673    w.put_uint(Tag::Context(2), u64::from(transition_time))
1674        .expect("infallible: vec writer");
1675    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1676        .expect("infallible: vec writer");
1677    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1678        .expect("infallible: vec writer");
1679    w.end_container().expect("infallible: vec writer");
1680    buf
1681}
1682
1683/// Encode the `MoveToHueAndSaturation` command request payload.
1684#[must_use]
1685#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1686pub fn encode_move_to_hue_and_saturation(
1687    hue: u8,
1688    saturation: u8,
1689    transition_time: u16,
1690    options_mask: OptionsBitmap,
1691    options_override: OptionsBitmap,
1692) -> Vec<u8> {
1693    let mut buf = Vec::new();
1694    let mut w = TlvWriter::new(&mut buf);
1695    w.start_structure(Tag::Anonymous)
1696        .expect("infallible: vec writer");
1697    w.put_uint(Tag::Context(0), u64::from(hue))
1698        .expect("infallible: vec writer");
1699    w.put_uint(Tag::Context(1), u64::from(saturation))
1700        .expect("infallible: vec writer");
1701    w.put_uint(Tag::Context(2), u64::from(transition_time))
1702        .expect("infallible: vec writer");
1703    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1704        .expect("infallible: vec writer");
1705    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1706        .expect("infallible: vec writer");
1707    w.end_container().expect("infallible: vec writer");
1708    buf
1709}
1710
1711/// Encode the `MoveToColor` command request payload.
1712#[must_use]
1713#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1714pub fn encode_move_to_color(
1715    color_x: u16,
1716    color_y: u16,
1717    transition_time: u16,
1718    options_mask: OptionsBitmap,
1719    options_override: OptionsBitmap,
1720) -> Vec<u8> {
1721    let mut buf = Vec::new();
1722    let mut w = TlvWriter::new(&mut buf);
1723    w.start_structure(Tag::Anonymous)
1724        .expect("infallible: vec writer");
1725    w.put_uint(Tag::Context(0), u64::from(color_x))
1726        .expect("infallible: vec writer");
1727    w.put_uint(Tag::Context(1), u64::from(color_y))
1728        .expect("infallible: vec writer");
1729    w.put_uint(Tag::Context(2), u64::from(transition_time))
1730        .expect("infallible: vec writer");
1731    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1732        .expect("infallible: vec writer");
1733    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1734        .expect("infallible: vec writer");
1735    w.end_container().expect("infallible: vec writer");
1736    buf
1737}
1738
1739/// Encode the `MoveColor` command request payload.
1740#[must_use]
1741#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1742pub fn encode_move_color(
1743    rate_x: i16,
1744    rate_y: i16,
1745    options_mask: OptionsBitmap,
1746    options_override: OptionsBitmap,
1747) -> Vec<u8> {
1748    let mut buf = Vec::new();
1749    let mut w = TlvWriter::new(&mut buf);
1750    w.start_structure(Tag::Anonymous)
1751        .expect("infallible: vec writer");
1752    w.put_int(Tag::Context(0), i64::from(rate_x))
1753        .expect("infallible: vec writer");
1754    w.put_int(Tag::Context(1), i64::from(rate_y))
1755        .expect("infallible: vec writer");
1756    w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
1757        .expect("infallible: vec writer");
1758    w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
1759        .expect("infallible: vec writer");
1760    w.end_container().expect("infallible: vec writer");
1761    buf
1762}
1763
1764/// Encode the `StepColor` command request payload.
1765#[must_use]
1766#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1767pub fn encode_step_color(
1768    step_x: i16,
1769    step_y: i16,
1770    transition_time: u16,
1771    options_mask: OptionsBitmap,
1772    options_override: OptionsBitmap,
1773) -> Vec<u8> {
1774    let mut buf = Vec::new();
1775    let mut w = TlvWriter::new(&mut buf);
1776    w.start_structure(Tag::Anonymous)
1777        .expect("infallible: vec writer");
1778    w.put_int(Tag::Context(0), i64::from(step_x))
1779        .expect("infallible: vec writer");
1780    w.put_int(Tag::Context(1), i64::from(step_y))
1781        .expect("infallible: vec writer");
1782    w.put_uint(Tag::Context(2), u64::from(transition_time))
1783        .expect("infallible: vec writer");
1784    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1785        .expect("infallible: vec writer");
1786    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1787        .expect("infallible: vec writer");
1788    w.end_container().expect("infallible: vec writer");
1789    buf
1790}
1791
1792/// Encode the `MoveToColorTemperature` command request payload.
1793#[must_use]
1794#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1795pub fn encode_move_to_color_temperature(
1796    color_temperature_mireds: u16,
1797    transition_time: u16,
1798    options_mask: OptionsBitmap,
1799    options_override: OptionsBitmap,
1800) -> Vec<u8> {
1801    let mut buf = Vec::new();
1802    let mut w = TlvWriter::new(&mut buf);
1803    w.start_structure(Tag::Anonymous)
1804        .expect("infallible: vec writer");
1805    w.put_uint(Tag::Context(0), u64::from(color_temperature_mireds))
1806        .expect("infallible: vec writer");
1807    w.put_uint(Tag::Context(1), u64::from(transition_time))
1808        .expect("infallible: vec writer");
1809    w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
1810        .expect("infallible: vec writer");
1811    w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
1812        .expect("infallible: vec writer");
1813    w.end_container().expect("infallible: vec writer");
1814    buf
1815}
1816
1817/// Encode the `EnhancedMoveToHue` command request payload.
1818#[must_use]
1819#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1820pub fn encode_enhanced_move_to_hue(
1821    enhanced_hue: u16,
1822    direction: DirectionEnum,
1823    transition_time: u16,
1824    options_mask: OptionsBitmap,
1825    options_override: OptionsBitmap,
1826) -> Vec<u8> {
1827    let mut buf = Vec::new();
1828    let mut w = TlvWriter::new(&mut buf);
1829    w.start_structure(Tag::Anonymous)
1830        .expect("infallible: vec writer");
1831    w.put_uint(Tag::Context(0), u64::from(enhanced_hue))
1832        .expect("infallible: vec writer");
1833    w.put_uint(Tag::Context(1), u64::from(direction.to_raw()))
1834        .expect("infallible: vec writer");
1835    w.put_uint(Tag::Context(2), u64::from(transition_time))
1836        .expect("infallible: vec writer");
1837    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1838        .expect("infallible: vec writer");
1839    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1840        .expect("infallible: vec writer");
1841    w.end_container().expect("infallible: vec writer");
1842    buf
1843}
1844
1845/// Encode the `EnhancedMoveHue` command request payload.
1846#[must_use]
1847#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1848pub fn encode_enhanced_move_hue(
1849    move_mode: MoveModeEnum,
1850    rate: u16,
1851    options_mask: OptionsBitmap,
1852    options_override: OptionsBitmap,
1853) -> Vec<u8> {
1854    let mut buf = Vec::new();
1855    let mut w = TlvWriter::new(&mut buf);
1856    w.start_structure(Tag::Anonymous)
1857        .expect("infallible: vec writer");
1858    w.put_uint(Tag::Context(0), u64::from(move_mode.to_raw()))
1859        .expect("infallible: vec writer");
1860    w.put_uint(Tag::Context(1), u64::from(rate))
1861        .expect("infallible: vec writer");
1862    w.put_uint(Tag::Context(2), u64::from(options_mask.bits()))
1863        .expect("infallible: vec writer");
1864    w.put_uint(Tag::Context(3), u64::from(options_override.bits()))
1865        .expect("infallible: vec writer");
1866    w.end_container().expect("infallible: vec writer");
1867    buf
1868}
1869
1870/// Encode the `EnhancedStepHue` command request payload.
1871#[must_use]
1872#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1873pub fn encode_enhanced_step_hue(
1874    step_mode: StepModeEnum,
1875    step_size: u16,
1876    transition_time: u16,
1877    options_mask: OptionsBitmap,
1878    options_override: OptionsBitmap,
1879) -> Vec<u8> {
1880    let mut buf = Vec::new();
1881    let mut w = TlvWriter::new(&mut buf);
1882    w.start_structure(Tag::Anonymous)
1883        .expect("infallible: vec writer");
1884    w.put_uint(Tag::Context(0), u64::from(step_mode.to_raw()))
1885        .expect("infallible: vec writer");
1886    w.put_uint(Tag::Context(1), u64::from(step_size))
1887        .expect("infallible: vec writer");
1888    w.put_uint(Tag::Context(2), u64::from(transition_time))
1889        .expect("infallible: vec writer");
1890    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1891        .expect("infallible: vec writer");
1892    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1893        .expect("infallible: vec writer");
1894    w.end_container().expect("infallible: vec writer");
1895    buf
1896}
1897
1898/// Encode the `EnhancedMoveToHueAndSaturation` command request payload.
1899#[must_use]
1900#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1901pub fn encode_enhanced_move_to_hue_and_saturation(
1902    enhanced_hue: u16,
1903    saturation: u8,
1904    transition_time: u16,
1905    options_mask: OptionsBitmap,
1906    options_override: OptionsBitmap,
1907) -> Vec<u8> {
1908    let mut buf = Vec::new();
1909    let mut w = TlvWriter::new(&mut buf);
1910    w.start_structure(Tag::Anonymous)
1911        .expect("infallible: vec writer");
1912    w.put_uint(Tag::Context(0), u64::from(enhanced_hue))
1913        .expect("infallible: vec writer");
1914    w.put_uint(Tag::Context(1), u64::from(saturation))
1915        .expect("infallible: vec writer");
1916    w.put_uint(Tag::Context(2), u64::from(transition_time))
1917        .expect("infallible: vec writer");
1918    w.put_uint(Tag::Context(3), u64::from(options_mask.bits()))
1919        .expect("infallible: vec writer");
1920    w.put_uint(Tag::Context(4), u64::from(options_override.bits()))
1921        .expect("infallible: vec writer");
1922    w.end_container().expect("infallible: vec writer");
1923    buf
1924}
1925
1926/// Encode the `ColorLoopSet` command request payload.
1927#[must_use]
1928#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1929pub fn encode_color_loop_set(
1930    update_flags: UpdateFlagsBitmap,
1931    action: ColorLoopActionEnum,
1932    direction: ColorLoopDirectionEnum,
1933    time: u16,
1934    start_hue: u16,
1935    options_mask: OptionsBitmap,
1936    options_override: OptionsBitmap,
1937) -> Vec<u8> {
1938    let mut buf = Vec::new();
1939    let mut w = TlvWriter::new(&mut buf);
1940    w.start_structure(Tag::Anonymous)
1941        .expect("infallible: vec writer");
1942    w.put_uint(Tag::Context(0), u64::from(update_flags.bits()))
1943        .expect("infallible: vec writer");
1944    w.put_uint(Tag::Context(1), u64::from(action.to_raw()))
1945        .expect("infallible: vec writer");
1946    w.put_uint(Tag::Context(2), u64::from(direction.to_raw()))
1947        .expect("infallible: vec writer");
1948    w.put_uint(Tag::Context(3), u64::from(time))
1949        .expect("infallible: vec writer");
1950    w.put_uint(Tag::Context(4), u64::from(start_hue))
1951        .expect("infallible: vec writer");
1952    w.put_uint(Tag::Context(5), u64::from(options_mask.bits()))
1953        .expect("infallible: vec writer");
1954    w.put_uint(Tag::Context(6), u64::from(options_override.bits()))
1955        .expect("infallible: vec writer");
1956    w.end_container().expect("infallible: vec writer");
1957    buf
1958}
1959
1960/// Encode the `StopMoveStep` command request payload.
1961#[must_use]
1962#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1963pub fn encode_stop_move_step(
1964    options_mask: OptionsBitmap,
1965    options_override: OptionsBitmap,
1966) -> Vec<u8> {
1967    let mut buf = Vec::new();
1968    let mut w = TlvWriter::new(&mut buf);
1969    w.start_structure(Tag::Anonymous)
1970        .expect("infallible: vec writer");
1971    w.put_uint(Tag::Context(0), u64::from(options_mask.bits()))
1972        .expect("infallible: vec writer");
1973    w.put_uint(Tag::Context(1), u64::from(options_override.bits()))
1974        .expect("infallible: vec writer");
1975    w.end_container().expect("infallible: vec writer");
1976    buf
1977}
1978
1979/// Encode the `MoveColorTemperature` command request payload.
1980#[must_use]
1981#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1982pub fn encode_move_color_temperature(
1983    move_mode: MoveModeEnum,
1984    rate: u16,
1985    color_temperature_minimum_mireds: u16,
1986    color_temperature_maximum_mireds: u16,
1987    options_mask: OptionsBitmap,
1988    options_override: OptionsBitmap,
1989) -> Vec<u8> {
1990    let mut buf = Vec::new();
1991    let mut w = TlvWriter::new(&mut buf);
1992    w.start_structure(Tag::Anonymous)
1993        .expect("infallible: vec writer");
1994    w.put_uint(Tag::Context(0), u64::from(move_mode.to_raw()))
1995        .expect("infallible: vec writer");
1996    w.put_uint(Tag::Context(1), u64::from(rate))
1997        .expect("infallible: vec writer");
1998    w.put_uint(Tag::Context(2), u64::from(color_temperature_minimum_mireds))
1999        .expect("infallible: vec writer");
2000    w.put_uint(Tag::Context(3), u64::from(color_temperature_maximum_mireds))
2001        .expect("infallible: vec writer");
2002    w.put_uint(Tag::Context(4), u64::from(options_mask.bits()))
2003        .expect("infallible: vec writer");
2004    w.put_uint(Tag::Context(5), u64::from(options_override.bits()))
2005        .expect("infallible: vec writer");
2006    w.end_container().expect("infallible: vec writer");
2007    buf
2008}
2009
2010/// Encode the `StepColorTemperature` command request payload.
2011#[must_use]
2012#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
2013pub fn encode_step_color_temperature(
2014    step_mode: StepModeEnum,
2015    step_size: u16,
2016    transition_time: u16,
2017    color_temperature_minimum_mireds: u16,
2018    color_temperature_maximum_mireds: u16,
2019    options_mask: OptionsBitmap,
2020    options_override: OptionsBitmap,
2021) -> Vec<u8> {
2022    let mut buf = Vec::new();
2023    let mut w = TlvWriter::new(&mut buf);
2024    w.start_structure(Tag::Anonymous)
2025        .expect("infallible: vec writer");
2026    w.put_uint(Tag::Context(0), u64::from(step_mode.to_raw()))
2027        .expect("infallible: vec writer");
2028    w.put_uint(Tag::Context(1), u64::from(step_size))
2029        .expect("infallible: vec writer");
2030    w.put_uint(Tag::Context(2), u64::from(transition_time))
2031        .expect("infallible: vec writer");
2032    w.put_uint(Tag::Context(3), u64::from(color_temperature_minimum_mireds))
2033        .expect("infallible: vec writer");
2034    w.put_uint(Tag::Context(4), u64::from(color_temperature_maximum_mireds))
2035        .expect("infallible: vec writer");
2036    w.put_uint(Tag::Context(5), u64::from(options_mask.bits()))
2037        .expect("infallible: vec writer");
2038    w.put_uint(Tag::Context(6), u64::from(options_override.bits()))
2039        .expect("infallible: vec writer");
2040    w.end_container().expect("infallible: vec writer");
2041    buf
2042}