Skip to main content

matter_clusters/gen/
occupancy_sensing.rs

1//! OccupancySensing cluster (0x0406).
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 = 0x0406;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 6;
21
22/// Command IDs (requests and responses).
23pub mod command_id {}
24
25/// Attribute IDs (cluster-specific).
26pub mod attribute_id {
27    /// `Occupancy`.
28    pub const OCCUPANCY: u32 = 0x0000;
29    /// `OccupancySensorType`.
30    pub const OCCUPANCY_SENSOR_TYPE: u32 = 0x0001;
31    /// `OccupancySensorTypeBitmap`.
32    pub const OCCUPANCY_SENSOR_TYPE_BITMAP: u32 = 0x0002;
33    /// `HoldTime`.
34    pub const HOLD_TIME: u32 = 0x0003;
35    /// `HoldTimeLimits`.
36    pub const HOLD_TIME_LIMITS: u32 = 0x0004;
37    /// `PirOccupiedToUnoccupiedDelay`.
38    pub const PIR_OCCUPIED_TO_UNOCCUPIED_DELAY: u32 = 0x0010;
39    /// `PirUnoccupiedToOccupiedDelay`.
40    pub const PIR_UNOCCUPIED_TO_OCCUPIED_DELAY: u32 = 0x0011;
41    /// `PirUnoccupiedToOccupiedThreshold`.
42    pub const PIR_UNOCCUPIED_TO_OCCUPIED_THRESHOLD: u32 = 0x0012;
43    /// `UltrasonicOccupiedToUnoccupiedDelay`.
44    pub const ULTRASONIC_OCCUPIED_TO_UNOCCUPIED_DELAY: u32 = 0x0020;
45    /// `UltrasonicUnoccupiedToOccupiedDelay`.
46    pub const ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_DELAY: u32 = 0x0021;
47    /// `UltrasonicUnoccupiedToOccupiedThreshold`.
48    pub const ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_THRESHOLD: u32 = 0x0022;
49    /// `PhysicalContactOccupiedToUnoccupiedDelay`.
50    pub const PHYSICAL_CONTACT_OCCUPIED_TO_UNOCCUPIED_DELAY: u32 = 0x0030;
51    /// `PhysicalContactUnoccupiedToOccupiedDelay`.
52    pub const PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_DELAY: u32 = 0x0031;
53    /// `PhysicalContactUnoccupiedToOccupiedThreshold`.
54    pub const PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_THRESHOLD: u32 = 0x0032;
55}
56
57bitflags::bitflags! {
58    /// `OccupancySensing` feature bits (FeatureMap).
59    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
60    pub struct Feature: u32 {
61        /// Other (OTHER).
62        const OTHER = 1 << 0;
63        /// PassiveInfrared (PIR).
64        const PIR = 1 << 1;
65        /// Ultrasonic (US).
66        const US = 1 << 2;
67        /// PhysicalContact (PHY).
68        const PHY = 1 << 3;
69        /// ActiveInfrared (AIR).
70        const AIR = 1 << 4;
71        /// Radar (RAD).
72        const RAD = 1 << 5;
73        /// RfSensing (RFS).
74        const RFS = 1 << 6;
75        /// Vision (VIS).
76        const VIS = 1 << 7;
77    }
78}
79
80/// `HoldTimeLimitsStruct` struct.
81#[derive(Clone, Debug, PartialEq)]
82#[non_exhaustive]
83pub struct HoldTimeLimitsStruct {
84    /// Field HoldTimeMin (tag 0).
85    pub hold_time_min: u16,
86    /// Field HoldTimeMax (tag 1).
87    pub hold_time_max: u16,
88    /// Field HoldTimeDefault (tag 2).
89    pub hold_time_default: u16,
90}
91
92bitflags::bitflags! {
93    /// `OccupancyBitmap` (map8).
94    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
95    pub struct OccupancyBitmap: u8 {
96        /// Occupied.
97        const OCCUPIED = 1 << 0;
98    }
99}
100
101bitflags::bitflags! {
102    /// `OccupancySensorTypeBitmap` (map8).
103    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
104    pub struct OccupancySensorTypeBitmap: u8 {
105        /// Pir.
106        const PIR = 1 << 0;
107        /// Ultrasonic.
108        const ULTRASONIC = 1 << 1;
109        /// PhysicalContact.
110        const PHYSICAL_CONTACT = 1 << 2;
111    }
112}
113
114/// `OccupancySensorTypeEnum` (enum8).
115#[derive(Copy, Clone, Debug, PartialEq, Eq)]
116pub enum OccupancySensorTypeEnum {
117    /// Pir = 0.
118    Pir,
119    /// Ultrasonic = 1.
120    Ultrasonic,
121    /// PirAndUltrasonic = 2.
122    PirAndUltrasonic,
123    /// PhysicalContact = 3.
124    PhysicalContact,
125    /// A value not known to this codegen revision.
126    Unknown(u8),
127}
128
129impl OccupancySensorTypeEnum {
130    /// Decode from its raw discriminant (unknown → `Unknown`).
131    #[must_use]
132    pub fn from_raw(v: u8) -> Self {
133        match v {
134            0 => Self::Pir,
135            1 => Self::Ultrasonic,
136            2 => Self::PirAndUltrasonic,
137            3 => Self::PhysicalContact,
138            other => Self::Unknown(other),
139        }
140    }
141    /// The raw discriminant.
142    #[must_use]
143    pub fn to_raw(self) -> u8 {
144        match self {
145            Self::Pir => 0,
146            Self::Ultrasonic => 1,
147            Self::PirAndUltrasonic => 2,
148            Self::PhysicalContact => 3,
149            Self::Unknown(v) => v,
150        }
151    }
152}
153
154impl HoldTimeLimitsStruct {
155    /// Decode the fields of an already-opened anonymous structure
156    /// (reader positioned after the struct start; consumes to its end).
157    ///
158    /// # Errors
159    /// Returns [`ClusterError`] on a malformed structure or missing required field.
160    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
161        let mut f_hold_time_min: Option<u16> = None;
162        let mut f_hold_time_max: Option<u16> = None;
163        let mut f_hold_time_default: Option<u16> = None;
164        loop {
165            match r.next()? {
166                Some(Element::ContainerEnd) => break,
167                Some(Element::Scalar {
168                    tag: Tag::Context(0),
169                    value: Value::Uint(v),
170                }) => {
171                    f_hold_time_min = Some(
172                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("HoldTimeMin"))?,
173                    )
174                }
175                Some(Element::Scalar {
176                    tag: Tag::Context(1),
177                    value: Value::Uint(v),
178                }) => {
179                    f_hold_time_max = Some(
180                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("HoldTimeMax"))?,
181                    )
182                }
183                Some(Element::Scalar {
184                    tag: Tag::Context(2),
185                    value: Value::Uint(v),
186                }) => {
187                    f_hold_time_default = Some(
188                        u16::try_from(v)
189                            .map_err(|_| ClusterError::InvalidLength("HoldTimeDefault"))?,
190                    )
191                }
192                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
193                Some(Element::ContainerStart { .. }) => r.skip_container()?,
194                Some(_) => {} // unknown/future scalar — skip
195            }
196        }
197        Ok(Self {
198            hold_time_min: f_hold_time_min.ok_or(ClusterError::MissingField("HoldTimeMin"))?,
199            hold_time_max: f_hold_time_max.ok_or(ClusterError::MissingField("HoldTimeMax"))?,
200            hold_time_default: f_hold_time_default
201                .ok_or(ClusterError::MissingField("HoldTimeDefault"))?,
202        })
203    }
204    /// Decode from a standalone anonymous TLV structure.
205    ///
206    /// # Errors
207    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
208    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
209        let mut r = TlvReader::new(tlv);
210        match r.next()? {
211            Some(Element::ContainerStart {
212                kind: ContainerKind::Structure,
213                ..
214            }) => {}
215            _ => {
216                return Err(ClusterError::UnexpectedType {
217                    context: "HoldTimeLimitsStruct",
218                })
219            }
220        }
221        Self::decode_from(&mut r)
222    }
223    /// Write this struct's fields into an already-open container.
224    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
225    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
226        w.put_uint(Tag::Context(0), u64::from(self.hold_time_min))
227            .expect("infallible: vec writer");
228        w.put_uint(Tag::Context(1), u64::from(self.hold_time_max))
229            .expect("infallible: vec writer");
230        w.put_uint(Tag::Context(2), u64::from(self.hold_time_default))
231            .expect("infallible: vec writer");
232    }
233    /// Encode as a standalone anonymous TLV structure.
234    #[must_use]
235    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
236    pub fn encode(&self) -> Vec<u8> {
237        let mut buf = Vec::new();
238        let mut w = TlvWriter::new(&mut buf);
239        w.start_structure(Tag::Anonymous)
240            .expect("infallible: vec writer");
241        self.write_fields(&mut w);
242        w.end_container().expect("infallible: vec writer");
243        buf
244    }
245}
246
247/// Decode the `Occupancy` attribute value.
248///
249/// # Errors
250/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
251pub fn decode_occupancy(tlv: &[u8]) -> Result<OccupancyBitmap, ClusterError> {
252    let mut r = TlvReader::new(tlv);
253    match r.next()? {
254        Some(Element::Scalar {
255            value: Value::Uint(v),
256            ..
257        }) => Ok(OccupancyBitmap::from_bits_retain(
258            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Occupancy"))?,
259        )),
260        _ => Err(ClusterError::UnexpectedType {
261            context: "Occupancy",
262        }),
263    }
264}
265
266/// Decode the `OccupancySensorType` attribute value.
267///
268/// # Errors
269/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
270pub fn decode_occupancy_sensor_type(tlv: &[u8]) -> Result<OccupancySensorTypeEnum, ClusterError> {
271    let mut r = TlvReader::new(tlv);
272    match r.next()? {
273        Some(Element::Scalar {
274            value: Value::Uint(v),
275            ..
276        }) => Ok(OccupancySensorTypeEnum::from_raw(u8::try_from(v).map_err(
277            |_| ClusterError::InvalidLength("OccupancySensorType"),
278        )?)),
279        _ => Err(ClusterError::UnexpectedType {
280            context: "OccupancySensorType",
281        }),
282    }
283}
284
285/// Decode the `OccupancySensorTypeBitmap` attribute value.
286///
287/// # Errors
288/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
289pub fn decode_occupancy_sensor_type_bitmap(
290    tlv: &[u8],
291) -> Result<OccupancySensorTypeBitmap, ClusterError> {
292    let mut r = TlvReader::new(tlv);
293    match r.next()? {
294        Some(Element::Scalar {
295            value: Value::Uint(v),
296            ..
297        }) => Ok(OccupancySensorTypeBitmap::from_bits_retain(
298            u8::try_from(v)
299                .map_err(|_| ClusterError::InvalidLength("OccupancySensorTypeBitmap"))?,
300        )),
301        _ => Err(ClusterError::UnexpectedType {
302            context: "OccupancySensorTypeBitmap",
303        }),
304    }
305}
306
307/// Decode the `HoldTime` attribute value.
308///
309/// # Errors
310/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
311pub fn decode_hold_time(tlv: &[u8]) -> Result<u16, ClusterError> {
312    let mut r = TlvReader::new(tlv);
313    match r.next()? {
314        Some(Element::Scalar {
315            value: Value::Uint(v),
316            ..
317        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("HoldTime"))?),
318        _ => Err(ClusterError::UnexpectedType {
319            context: "HoldTime",
320        }),
321    }
322}
323
324/// Encode the `HoldTime` attribute value as a standalone TLV element.
325#[must_use]
326#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
327pub fn encode_hold_time(value: u16) -> Vec<u8> {
328    let mut buf = Vec::new();
329    let mut w = TlvWriter::new(&mut buf);
330    w.put_uint(Tag::Anonymous, u64::from(value))
331        .expect("infallible: vec writer");
332    buf
333}
334
335/// Decode the `HoldTimeLimits` attribute value.
336///
337/// # Errors
338/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
339pub fn decode_hold_time_limits(tlv: &[u8]) -> Result<HoldTimeLimitsStruct, ClusterError> {
340    HoldTimeLimitsStruct::decode(tlv)
341}
342
343/// Decode the `PirOccupiedToUnoccupiedDelay` attribute value.
344///
345/// # Errors
346/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
347pub fn decode_pir_occupied_to_unoccupied_delay(tlv: &[u8]) -> Result<u16, ClusterError> {
348    let mut r = TlvReader::new(tlv);
349    match r.next()? {
350        Some(Element::Scalar {
351            value: Value::Uint(v),
352            ..
353        }) => Ok(u16::try_from(v)
354            .map_err(|_| ClusterError::InvalidLength("PirOccupiedToUnoccupiedDelay"))?),
355        _ => Err(ClusterError::UnexpectedType {
356            context: "PirOccupiedToUnoccupiedDelay",
357        }),
358    }
359}
360
361/// Encode the `PirOccupiedToUnoccupiedDelay` attribute value as a standalone TLV element.
362#[must_use]
363#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
364pub fn encode_pir_occupied_to_unoccupied_delay(value: u16) -> Vec<u8> {
365    let mut buf = Vec::new();
366    let mut w = TlvWriter::new(&mut buf);
367    w.put_uint(Tag::Anonymous, u64::from(value))
368        .expect("infallible: vec writer");
369    buf
370}
371
372/// Decode the `PirUnoccupiedToOccupiedDelay` attribute value.
373///
374/// # Errors
375/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
376pub fn decode_pir_unoccupied_to_occupied_delay(tlv: &[u8]) -> Result<u16, ClusterError> {
377    let mut r = TlvReader::new(tlv);
378    match r.next()? {
379        Some(Element::Scalar {
380            value: Value::Uint(v),
381            ..
382        }) => Ok(u16::try_from(v)
383            .map_err(|_| ClusterError::InvalidLength("PirUnoccupiedToOccupiedDelay"))?),
384        _ => Err(ClusterError::UnexpectedType {
385            context: "PirUnoccupiedToOccupiedDelay",
386        }),
387    }
388}
389
390/// Encode the `PirUnoccupiedToOccupiedDelay` attribute value as a standalone TLV element.
391#[must_use]
392#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
393pub fn encode_pir_unoccupied_to_occupied_delay(value: u16) -> Vec<u8> {
394    let mut buf = Vec::new();
395    let mut w = TlvWriter::new(&mut buf);
396    w.put_uint(Tag::Anonymous, u64::from(value))
397        .expect("infallible: vec writer");
398    buf
399}
400
401/// Decode the `PirUnoccupiedToOccupiedThreshold` attribute value.
402///
403/// # Errors
404/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
405pub fn decode_pir_unoccupied_to_occupied_threshold(tlv: &[u8]) -> Result<u8, ClusterError> {
406    let mut r = TlvReader::new(tlv);
407    match r.next()? {
408        Some(Element::Scalar {
409            value: Value::Uint(v),
410            ..
411        }) => Ok(u8::try_from(v)
412            .map_err(|_| ClusterError::InvalidLength("PirUnoccupiedToOccupiedThreshold"))?),
413        _ => Err(ClusterError::UnexpectedType {
414            context: "PirUnoccupiedToOccupiedThreshold",
415        }),
416    }
417}
418
419/// Encode the `PirUnoccupiedToOccupiedThreshold` attribute value as a standalone TLV element.
420#[must_use]
421#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
422pub fn encode_pir_unoccupied_to_occupied_threshold(value: u8) -> Vec<u8> {
423    let mut buf = Vec::new();
424    let mut w = TlvWriter::new(&mut buf);
425    w.put_uint(Tag::Anonymous, u64::from(value))
426        .expect("infallible: vec writer");
427    buf
428}
429
430/// Decode the `UltrasonicOccupiedToUnoccupiedDelay` attribute value.
431///
432/// # Errors
433/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
434pub fn decode_ultrasonic_occupied_to_unoccupied_delay(tlv: &[u8]) -> Result<u16, ClusterError> {
435    let mut r = TlvReader::new(tlv);
436    match r.next()? {
437        Some(Element::Scalar {
438            value: Value::Uint(v),
439            ..
440        }) => Ok(u16::try_from(v)
441            .map_err(|_| ClusterError::InvalidLength("UltrasonicOccupiedToUnoccupiedDelay"))?),
442        _ => Err(ClusterError::UnexpectedType {
443            context: "UltrasonicOccupiedToUnoccupiedDelay",
444        }),
445    }
446}
447
448/// Encode the `UltrasonicOccupiedToUnoccupiedDelay` attribute value as a standalone TLV element.
449#[must_use]
450#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
451pub fn encode_ultrasonic_occupied_to_unoccupied_delay(value: u16) -> Vec<u8> {
452    let mut buf = Vec::new();
453    let mut w = TlvWriter::new(&mut buf);
454    w.put_uint(Tag::Anonymous, u64::from(value))
455        .expect("infallible: vec writer");
456    buf
457}
458
459/// Decode the `UltrasonicUnoccupiedToOccupiedDelay` attribute value.
460///
461/// # Errors
462/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
463pub fn decode_ultrasonic_unoccupied_to_occupied_delay(tlv: &[u8]) -> Result<u16, ClusterError> {
464    let mut r = TlvReader::new(tlv);
465    match r.next()? {
466        Some(Element::Scalar {
467            value: Value::Uint(v),
468            ..
469        }) => Ok(u16::try_from(v)
470            .map_err(|_| ClusterError::InvalidLength("UltrasonicUnoccupiedToOccupiedDelay"))?),
471        _ => Err(ClusterError::UnexpectedType {
472            context: "UltrasonicUnoccupiedToOccupiedDelay",
473        }),
474    }
475}
476
477/// Encode the `UltrasonicUnoccupiedToOccupiedDelay` attribute value as a standalone TLV element.
478#[must_use]
479#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
480pub fn encode_ultrasonic_unoccupied_to_occupied_delay(value: u16) -> Vec<u8> {
481    let mut buf = Vec::new();
482    let mut w = TlvWriter::new(&mut buf);
483    w.put_uint(Tag::Anonymous, u64::from(value))
484        .expect("infallible: vec writer");
485    buf
486}
487
488/// Decode the `UltrasonicUnoccupiedToOccupiedThreshold` attribute value.
489///
490/// # Errors
491/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
492pub fn decode_ultrasonic_unoccupied_to_occupied_threshold(tlv: &[u8]) -> Result<u8, ClusterError> {
493    let mut r = TlvReader::new(tlv);
494    match r.next()? {
495        Some(Element::Scalar {
496            value: Value::Uint(v),
497            ..
498        }) => Ok(u8::try_from(v)
499            .map_err(|_| ClusterError::InvalidLength("UltrasonicUnoccupiedToOccupiedThreshold"))?),
500        _ => Err(ClusterError::UnexpectedType {
501            context: "UltrasonicUnoccupiedToOccupiedThreshold",
502        }),
503    }
504}
505
506/// Encode the `UltrasonicUnoccupiedToOccupiedThreshold` attribute value as a standalone TLV element.
507#[must_use]
508#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
509pub fn encode_ultrasonic_unoccupied_to_occupied_threshold(value: u8) -> Vec<u8> {
510    let mut buf = Vec::new();
511    let mut w = TlvWriter::new(&mut buf);
512    w.put_uint(Tag::Anonymous, u64::from(value))
513        .expect("infallible: vec writer");
514    buf
515}
516
517/// Decode the `PhysicalContactOccupiedToUnoccupiedDelay` attribute value.
518///
519/// # Errors
520/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
521pub fn decode_physical_contact_occupied_to_unoccupied_delay(
522    tlv: &[u8],
523) -> Result<u16, ClusterError> {
524    let mut r = TlvReader::new(tlv);
525    match r.next()? {
526        Some(Element::Scalar {
527            value: Value::Uint(v),
528            ..
529        }) => Ok(u16::try_from(v).map_err(|_| {
530            ClusterError::InvalidLength("PhysicalContactOccupiedToUnoccupiedDelay")
531        })?),
532        _ => Err(ClusterError::UnexpectedType {
533            context: "PhysicalContactOccupiedToUnoccupiedDelay",
534        }),
535    }
536}
537
538/// Encode the `PhysicalContactOccupiedToUnoccupiedDelay` attribute value as a standalone TLV element.
539#[must_use]
540#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
541pub fn encode_physical_contact_occupied_to_unoccupied_delay(value: u16) -> Vec<u8> {
542    let mut buf = Vec::new();
543    let mut w = TlvWriter::new(&mut buf);
544    w.put_uint(Tag::Anonymous, u64::from(value))
545        .expect("infallible: vec writer");
546    buf
547}
548
549/// Decode the `PhysicalContactUnoccupiedToOccupiedDelay` attribute value.
550///
551/// # Errors
552/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
553pub fn decode_physical_contact_unoccupied_to_occupied_delay(
554    tlv: &[u8],
555) -> Result<u16, ClusterError> {
556    let mut r = TlvReader::new(tlv);
557    match r.next()? {
558        Some(Element::Scalar {
559            value: Value::Uint(v),
560            ..
561        }) => Ok(u16::try_from(v).map_err(|_| {
562            ClusterError::InvalidLength("PhysicalContactUnoccupiedToOccupiedDelay")
563        })?),
564        _ => Err(ClusterError::UnexpectedType {
565            context: "PhysicalContactUnoccupiedToOccupiedDelay",
566        }),
567    }
568}
569
570/// Encode the `PhysicalContactUnoccupiedToOccupiedDelay` attribute value as a standalone TLV element.
571#[must_use]
572#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
573pub fn encode_physical_contact_unoccupied_to_occupied_delay(value: u16) -> Vec<u8> {
574    let mut buf = Vec::new();
575    let mut w = TlvWriter::new(&mut buf);
576    w.put_uint(Tag::Anonymous, u64::from(value))
577        .expect("infallible: vec writer");
578    buf
579}
580
581/// Decode the `PhysicalContactUnoccupiedToOccupiedThreshold` attribute value.
582///
583/// # Errors
584/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
585pub fn decode_physical_contact_unoccupied_to_occupied_threshold(
586    tlv: &[u8],
587) -> Result<u8, ClusterError> {
588    let mut r = TlvReader::new(tlv);
589    match r.next()? {
590        Some(Element::Scalar {
591            value: Value::Uint(v),
592            ..
593        }) => Ok(u8::try_from(v).map_err(|_| {
594            ClusterError::InvalidLength("PhysicalContactUnoccupiedToOccupiedThreshold")
595        })?),
596        _ => Err(ClusterError::UnexpectedType {
597            context: "PhysicalContactUnoccupiedToOccupiedThreshold",
598        }),
599    }
600}
601
602/// Encode the `PhysicalContactUnoccupiedToOccupiedThreshold` attribute value as a standalone TLV element.
603#[must_use]
604#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
605pub fn encode_physical_contact_unoccupied_to_occupied_threshold(value: u8) -> Vec<u8> {
606    let mut buf = Vec::new();
607    let mut w = TlvWriter::new(&mut buf);
608    w.put_uint(Tag::Anonymous, u64::from(value))
609        .expect("infallible: vec writer");
610    buf
611}