1#![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
17pub const CLUSTER_ID: u32 = 0x0406;
19pub const CLUSTER_REVISION: u16 = 6;
21
22pub mod command_id {}
24
25pub mod attribute_id {
27 pub const OCCUPANCY: u32 = 0x0000;
29 pub const OCCUPANCY_SENSOR_TYPE: u32 = 0x0001;
31 pub const OCCUPANCY_SENSOR_TYPE_BITMAP: u32 = 0x0002;
33 pub const HOLD_TIME: u32 = 0x0003;
35 pub const HOLD_TIME_LIMITS: u32 = 0x0004;
37 pub const PIR_OCCUPIED_TO_UNOCCUPIED_DELAY: u32 = 0x0010;
39 pub const PIR_UNOCCUPIED_TO_OCCUPIED_DELAY: u32 = 0x0011;
41 pub const PIR_UNOCCUPIED_TO_OCCUPIED_THRESHOLD: u32 = 0x0012;
43 pub const ULTRASONIC_OCCUPIED_TO_UNOCCUPIED_DELAY: u32 = 0x0020;
45 pub const ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_DELAY: u32 = 0x0021;
47 pub const ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_THRESHOLD: u32 = 0x0022;
49 pub const PHYSICAL_CONTACT_OCCUPIED_TO_UNOCCUPIED_DELAY: u32 = 0x0030;
51 pub const PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_DELAY: u32 = 0x0031;
53 pub const PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_THRESHOLD: u32 = 0x0032;
55}
56
57bitflags::bitflags! {
58 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
60 pub struct Feature: u32 {
61 const OTHER = 1 << 0;
63 const PIR = 1 << 1;
65 const US = 1 << 2;
67 const PHY = 1 << 3;
69 const AIR = 1 << 4;
71 const RAD = 1 << 5;
73 const RFS = 1 << 6;
75 const VIS = 1 << 7;
77 }
78}
79
80#[derive(Clone, Debug, PartialEq)]
82#[non_exhaustive]
83pub struct HoldTimeLimitsStruct {
84 pub hold_time_min: u16,
86 pub hold_time_max: u16,
88 pub hold_time_default: u16,
90}
91
92bitflags::bitflags! {
93 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
95 pub struct OccupancyBitmap: u8 {
96 const OCCUPIED = 1 << 0;
98 }
99}
100
101bitflags::bitflags! {
102 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
104 pub struct OccupancySensorTypeBitmap: u8 {
105 const PIR = 1 << 0;
107 const ULTRASONIC = 1 << 1;
109 const PHYSICAL_CONTACT = 1 << 2;
111 }
112}
113
114#[derive(Copy, Clone, Debug, PartialEq, Eq)]
116pub enum OccupancySensorTypeEnum {
117 Pir,
119 Ultrasonic,
121 PirAndUltrasonic,
123 PhysicalContact,
125 Unknown(u8),
127}
128
129impl OccupancySensorTypeEnum {
130 #[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 #[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 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(_) => {} }
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 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 #[allow(clippy::expect_used)] 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 #[must_use]
235 #[allow(clippy::expect_used)] 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
247pub 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
266pub 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
285pub 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
307pub 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#[must_use]
326#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
335pub fn decode_hold_time_limits(tlv: &[u8]) -> Result<HoldTimeLimitsStruct, ClusterError> {
340 HoldTimeLimitsStruct::decode(tlv)
341}
342
343pub 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#[must_use]
363#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
372pub 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#[must_use]
392#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
401pub 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#[must_use]
421#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
430pub 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#[must_use]
450#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
459pub 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#[must_use]
479#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
488pub 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#[must_use]
508#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
517pub 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#[must_use]
540#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
549pub 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#[must_use]
572#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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
581pub 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#[must_use]
604#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub 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}