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 = 0x0102;
19pub const CLUSTER_REVISION: u16 = 8;
21
22pub mod command_id {
24 pub const UP_OR_OPEN: u32 = 0x00;
26 pub const DOWN_OR_CLOSE: u32 = 0x01;
28 pub const STOP_MOTION: u32 = 0x02;
30 pub const GO_TO_LIFT_PERCENTAGE: u32 = 0x05;
32 pub const GO_TO_TILT_PERCENTAGE: u32 = 0x08;
34}
35
36pub mod attribute_id {
38 pub const TYPE: u32 = 0x0000;
40 pub const NUMBER_OF_ACTUATIONS_LIFT: u32 = 0x0005;
42 pub const NUMBER_OF_ACTUATIONS_TILT: u32 = 0x0006;
44 pub const CONFIG_STATUS: u32 = 0x0007;
46 pub const CURRENT_POSITION_LIFT_PERCENTAGE: u32 = 0x0008;
48 pub const CURRENT_POSITION_TILT_PERCENTAGE: u32 = 0x0009;
50 pub const OPERATIONAL_STATUS: u32 = 0x000A;
52 pub const TARGET_POSITION_LIFT_PERCENT100THS: u32 = 0x000B;
54 pub const TARGET_POSITION_TILT_PERCENT100THS: u32 = 0x000C;
56 pub const END_PRODUCT_TYPE: u32 = 0x000D;
58 pub const CURRENT_POSITION_LIFT_PERCENT100THS: u32 = 0x000E;
60 pub const CURRENT_POSITION_TILT_PERCENT100THS: u32 = 0x000F;
62 pub const MODE: u32 = 0x0017;
64 pub const SAFETY_STATUS: u32 = 0x001A;
66}
67
68bitflags::bitflags! {
69 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
71 pub struct Feature: u32 {
72 const LF = 1 << 0;
74 const TL = 1 << 1;
76 const PA_LF = 1 << 2;
78 const PA_TL = 1 << 4;
80 }
81}
82
83bitflags::bitflags! {
84 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
86 pub struct ConfigStatusBitmap: u8 {
87 const OPERATIONAL = 1 << 0;
89 const ONLINE_RESERVED = 1 << 1;
91 const LIFT_MOVEMENT_REVERSED = 1 << 2;
93 const LIFT_POSITION_AWARE = 1 << 3;
95 const TILT_POSITION_AWARE = 1 << 4;
97 const LIFT_ENCODER_CONTROLLED = 1 << 5;
99 const TILT_ENCODER_CONTROLLED = 1 << 6;
101 }
102}
103
104#[derive(Copy, Clone, Debug, PartialEq, Eq)]
106pub enum EndProductTypeEnum {
107 RollerShade,
109 RomanShade,
111 BalloonShade,
113 WovenWood,
115 PleatedShade,
117 CellularShade,
119 LayeredShade,
121 LayeredShade2D,
123 SheerShade,
125 TiltOnlyInteriorBlind,
127 InteriorBlind,
129 VerticalBlindStripCurtain,
131 InteriorVenetianBlind,
133 ExteriorVenetianBlind,
135 LateralLeftCurtain,
137 LateralRightCurtain,
139 CentralCurtain,
141 RollerShutter,
143 ExteriorVerticalScreen,
145 AwningTerracePatio,
147 AwningVerticalScreen,
149 TiltOnlyPergola,
151 SwingingShutter,
153 SlidingShutter,
155 Unknown,
157 Unrecognized(u8),
159}
160
161impl EndProductTypeEnum {
162 #[must_use]
164 pub fn from_raw(v: u8) -> Self {
165 match v {
166 0 => Self::RollerShade,
167 1 => Self::RomanShade,
168 2 => Self::BalloonShade,
169 3 => Self::WovenWood,
170 4 => Self::PleatedShade,
171 5 => Self::CellularShade,
172 6 => Self::LayeredShade,
173 7 => Self::LayeredShade2D,
174 8 => Self::SheerShade,
175 9 => Self::TiltOnlyInteriorBlind,
176 10 => Self::InteriorBlind,
177 11 => Self::VerticalBlindStripCurtain,
178 12 => Self::InteriorVenetianBlind,
179 13 => Self::ExteriorVenetianBlind,
180 14 => Self::LateralLeftCurtain,
181 15 => Self::LateralRightCurtain,
182 16 => Self::CentralCurtain,
183 17 => Self::RollerShutter,
184 18 => Self::ExteriorVerticalScreen,
185 19 => Self::AwningTerracePatio,
186 20 => Self::AwningVerticalScreen,
187 21 => Self::TiltOnlyPergola,
188 22 => Self::SwingingShutter,
189 23 => Self::SlidingShutter,
190 255 => Self::Unknown,
191 other => Self::Unrecognized(other),
192 }
193 }
194 #[must_use]
196 pub fn to_raw(self) -> u8 {
197 match self {
198 Self::RollerShade => 0,
199 Self::RomanShade => 1,
200 Self::BalloonShade => 2,
201 Self::WovenWood => 3,
202 Self::PleatedShade => 4,
203 Self::CellularShade => 5,
204 Self::LayeredShade => 6,
205 Self::LayeredShade2D => 7,
206 Self::SheerShade => 8,
207 Self::TiltOnlyInteriorBlind => 9,
208 Self::InteriorBlind => 10,
209 Self::VerticalBlindStripCurtain => 11,
210 Self::InteriorVenetianBlind => 12,
211 Self::ExteriorVenetianBlind => 13,
212 Self::LateralLeftCurtain => 14,
213 Self::LateralRightCurtain => 15,
214 Self::CentralCurtain => 16,
215 Self::RollerShutter => 17,
216 Self::ExteriorVerticalScreen => 18,
217 Self::AwningTerracePatio => 19,
218 Self::AwningVerticalScreen => 20,
219 Self::TiltOnlyPergola => 21,
220 Self::SwingingShutter => 22,
221 Self::SlidingShutter => 23,
222 Self::Unknown => 255,
223 Self::Unrecognized(v) => v,
224 }
225 }
226}
227
228bitflags::bitflags! {
229 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
231 pub struct ModeBitmap: u8 {
232 const MOTOR_DIRECTION_REVERSED = 1 << 0;
234 const CALIBRATION_MODE = 1 << 1;
236 const MAINTENANCE_MODE = 1 << 2;
238 const LED_FEEDBACK = 1 << 3;
240 }
241}
242
243#[derive(Copy, Clone, Debug, PartialEq, Eq)]
245pub enum MovementStatus {
246 Stopped,
248 Opening,
250 Closing,
252 Unknown(u8),
254}
255
256impl MovementStatus {
257 #[must_use]
259 pub fn from_raw(v: u8) -> Self {
260 match v {
261 0 => Self::Stopped,
262 1 => Self::Opening,
263 2 => Self::Closing,
264 other => Self::Unknown(other),
265 }
266 }
267 #[must_use]
269 pub fn to_raw(self) -> u8 {
270 match self {
271 Self::Stopped => 0,
272 Self::Opening => 1,
273 Self::Closing => 2,
274 Self::Unknown(v) => v,
275 }
276 }
277}
278
279bitflags::bitflags! {
280 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
282 pub struct OperationalStatusBitmap: u8 {
283 }
284}
285
286bitflags::bitflags! {
287 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
289 pub struct SafetyStatusBitmap: u16 {
290 const REMOTE_LOCKOUT = 1 << 0;
292 const TAMPER_DETECTION = 1 << 1;
294 const FAILED_COMMUNICATION = 1 << 2;
296 const POSITION_FAILURE = 1 << 3;
298 const THERMAL_PROTECTION = 1 << 4;
300 const OBSTACLE_DETECTED = 1 << 5;
302 const POWER = 1 << 6;
304 const STOP_INPUT = 1 << 7;
306 const MOTOR_JAMMED = 1 << 8;
308 const HARDWARE_FAILURE = 1 << 9;
310 const MANUAL_OPERATION = 1 << 10;
312 const PROTECTION = 1 << 11;
314 }
315}
316
317#[derive(Copy, Clone, Debug, PartialEq, Eq)]
319pub enum TypeEnum {
320 Rollershade,
322 Rollershade2Motor,
324 RollershadeExterior,
326 RollershadeExterior2Motor,
328 Drapery,
330 Awning,
332 Shutter,
334 TiltBlindTiltOnly,
336 TiltBlindLift,
338 ProjectorScreen,
340 Unknown,
342 Unrecognized(u8),
344}
345
346impl TypeEnum {
347 #[must_use]
349 pub fn from_raw(v: u8) -> Self {
350 match v {
351 0 => Self::Rollershade,
352 1 => Self::Rollershade2Motor,
353 2 => Self::RollershadeExterior,
354 3 => Self::RollershadeExterior2Motor,
355 4 => Self::Drapery,
356 5 => Self::Awning,
357 6 => Self::Shutter,
358 7 => Self::TiltBlindTiltOnly,
359 8 => Self::TiltBlindLift,
360 9 => Self::ProjectorScreen,
361 255 => Self::Unknown,
362 other => Self::Unrecognized(other),
363 }
364 }
365 #[must_use]
367 pub fn to_raw(self) -> u8 {
368 match self {
369 Self::Rollershade => 0,
370 Self::Rollershade2Motor => 1,
371 Self::RollershadeExterior => 2,
372 Self::RollershadeExterior2Motor => 3,
373 Self::Drapery => 4,
374 Self::Awning => 5,
375 Self::Shutter => 6,
376 Self::TiltBlindTiltOnly => 7,
377 Self::TiltBlindLift => 8,
378 Self::ProjectorScreen => 9,
379 Self::Unknown => 255,
380 Self::Unrecognized(v) => v,
381 }
382 }
383}
384
385pub fn decode_type(tlv: &[u8]) -> Result<TypeEnum, ClusterError> {
390 let mut r = TlvReader::new(tlv);
391 match r.next()? {
392 Some(Element::Scalar {
393 value: Value::Uint(v),
394 ..
395 }) => Ok(TypeEnum::from_raw(
396 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Type"))?,
397 )),
398 _ => Err(ClusterError::UnexpectedType { context: "Type" }),
399 }
400}
401
402pub fn decode_number_of_actuations_lift(tlv: &[u8]) -> Result<u16, ClusterError> {
407 let mut r = TlvReader::new(tlv);
408 match r.next()? {
409 Some(Element::Scalar {
410 value: Value::Uint(v),
411 ..
412 }) => {
413 Ok(u16::try_from(v)
414 .map_err(|_| ClusterError::InvalidLength("NumberOfActuationsLift"))?)
415 }
416 _ => Err(ClusterError::UnexpectedType {
417 context: "NumberOfActuationsLift",
418 }),
419 }
420}
421
422pub fn decode_number_of_actuations_tilt(tlv: &[u8]) -> Result<u16, ClusterError> {
427 let mut r = TlvReader::new(tlv);
428 match r.next()? {
429 Some(Element::Scalar {
430 value: Value::Uint(v),
431 ..
432 }) => {
433 Ok(u16::try_from(v)
434 .map_err(|_| ClusterError::InvalidLength("NumberOfActuationsTilt"))?)
435 }
436 _ => Err(ClusterError::UnexpectedType {
437 context: "NumberOfActuationsTilt",
438 }),
439 }
440}
441
442pub fn decode_config_status(tlv: &[u8]) -> Result<ConfigStatusBitmap, ClusterError> {
447 let mut r = TlvReader::new(tlv);
448 match r.next()? {
449 Some(Element::Scalar {
450 value: Value::Uint(v),
451 ..
452 }) => Ok(ConfigStatusBitmap::from_bits_retain(
453 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("ConfigStatus"))?,
454 )),
455 _ => Err(ClusterError::UnexpectedType {
456 context: "ConfigStatus",
457 }),
458 }
459}
460
461pub fn decode_current_position_lift_percentage(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
466 let mut r = TlvReader::new(tlv);
467 match r.next()? {
468 Some(Element::Scalar {
469 value: Value::Null, ..
470 }) => Ok(Nullable::Null),
471 Some(Element::Scalar {
472 value: Value::Uint(v),
473 ..
474 }) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
475 ClusterError::InvalidLength("CurrentPositionLiftPercentage")
476 })?)),
477 _ => Err(ClusterError::UnexpectedType {
478 context: "CurrentPositionLiftPercentage",
479 }),
480 }
481}
482
483pub fn decode_current_position_tilt_percentage(tlv: &[u8]) -> Result<Nullable<u8>, ClusterError> {
488 let mut r = TlvReader::new(tlv);
489 match r.next()? {
490 Some(Element::Scalar {
491 value: Value::Null, ..
492 }) => Ok(Nullable::Null),
493 Some(Element::Scalar {
494 value: Value::Uint(v),
495 ..
496 }) => Ok(Nullable::Value(u8::try_from(v).map_err(|_| {
497 ClusterError::InvalidLength("CurrentPositionTiltPercentage")
498 })?)),
499 _ => Err(ClusterError::UnexpectedType {
500 context: "CurrentPositionTiltPercentage",
501 }),
502 }
503}
504
505pub fn decode_operational_status(tlv: &[u8]) -> Result<OperationalStatusBitmap, ClusterError> {
510 let mut r = TlvReader::new(tlv);
511 match r.next()? {
512 Some(Element::Scalar {
513 value: Value::Uint(v),
514 ..
515 }) => Ok(OperationalStatusBitmap::from_bits_retain(
516 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("OperationalStatus"))?,
517 )),
518 _ => Err(ClusterError::UnexpectedType {
519 context: "OperationalStatus",
520 }),
521 }
522}
523
524pub fn decode_target_position_lift_percent100ths(
529 tlv: &[u8],
530) -> Result<Nullable<u16>, ClusterError> {
531 let mut r = TlvReader::new(tlv);
532 match r.next()? {
533 Some(Element::Scalar {
534 value: Value::Null, ..
535 }) => Ok(Nullable::Null),
536 Some(Element::Scalar {
537 value: Value::Uint(v),
538 ..
539 }) => Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
540 ClusterError::InvalidLength("TargetPositionLiftPercent100ths")
541 })?)),
542 _ => Err(ClusterError::UnexpectedType {
543 context: "TargetPositionLiftPercent100ths",
544 }),
545 }
546}
547
548pub fn decode_target_position_tilt_percent100ths(
553 tlv: &[u8],
554) -> Result<Nullable<u16>, ClusterError> {
555 let mut r = TlvReader::new(tlv);
556 match r.next()? {
557 Some(Element::Scalar {
558 value: Value::Null, ..
559 }) => Ok(Nullable::Null),
560 Some(Element::Scalar {
561 value: Value::Uint(v),
562 ..
563 }) => Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
564 ClusterError::InvalidLength("TargetPositionTiltPercent100ths")
565 })?)),
566 _ => Err(ClusterError::UnexpectedType {
567 context: "TargetPositionTiltPercent100ths",
568 }),
569 }
570}
571
572pub fn decode_end_product_type(tlv: &[u8]) -> Result<EndProductTypeEnum, ClusterError> {
577 let mut r = TlvReader::new(tlv);
578 match r.next()? {
579 Some(Element::Scalar {
580 value: Value::Uint(v),
581 ..
582 }) => Ok(EndProductTypeEnum::from_raw(
583 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("EndProductType"))?,
584 )),
585 _ => Err(ClusterError::UnexpectedType {
586 context: "EndProductType",
587 }),
588 }
589}
590
591pub fn decode_current_position_lift_percent100ths(
596 tlv: &[u8],
597) -> Result<Nullable<u16>, ClusterError> {
598 let mut r = TlvReader::new(tlv);
599 match r.next()? {
600 Some(Element::Scalar {
601 value: Value::Null, ..
602 }) => Ok(Nullable::Null),
603 Some(Element::Scalar {
604 value: Value::Uint(v),
605 ..
606 }) => Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
607 ClusterError::InvalidLength("CurrentPositionLiftPercent100ths")
608 })?)),
609 _ => Err(ClusterError::UnexpectedType {
610 context: "CurrentPositionLiftPercent100ths",
611 }),
612 }
613}
614
615pub fn decode_current_position_tilt_percent100ths(
620 tlv: &[u8],
621) -> Result<Nullable<u16>, ClusterError> {
622 let mut r = TlvReader::new(tlv);
623 match r.next()? {
624 Some(Element::Scalar {
625 value: Value::Null, ..
626 }) => Ok(Nullable::Null),
627 Some(Element::Scalar {
628 value: Value::Uint(v),
629 ..
630 }) => Ok(Nullable::Value(u16::try_from(v).map_err(|_| {
631 ClusterError::InvalidLength("CurrentPositionTiltPercent100ths")
632 })?)),
633 _ => Err(ClusterError::UnexpectedType {
634 context: "CurrentPositionTiltPercent100ths",
635 }),
636 }
637}
638
639pub fn decode_mode(tlv: &[u8]) -> Result<ModeBitmap, ClusterError> {
644 let mut r = TlvReader::new(tlv);
645 match r.next()? {
646 Some(Element::Scalar {
647 value: Value::Uint(v),
648 ..
649 }) => Ok(ModeBitmap::from_bits_retain(
650 u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Mode"))?,
651 )),
652 _ => Err(ClusterError::UnexpectedType { context: "Mode" }),
653 }
654}
655
656#[must_use]
658#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_mode(value: ModeBitmap) -> Vec<u8> {
660 let mut buf = Vec::new();
661 let mut w = TlvWriter::new(&mut buf);
662 w.put_uint(Tag::Anonymous, u64::from(value.bits()))
663 .expect("infallible: vec writer");
664 buf
665}
666
667pub fn decode_safety_status(tlv: &[u8]) -> Result<SafetyStatusBitmap, ClusterError> {
672 let mut r = TlvReader::new(tlv);
673 match r.next()? {
674 Some(Element::Scalar {
675 value: Value::Uint(v),
676 ..
677 }) => Ok(SafetyStatusBitmap::from_bits_retain(
678 u16::try_from(v).map_err(|_| ClusterError::InvalidLength("SafetyStatus"))?,
679 )),
680 _ => Err(ClusterError::UnexpectedType {
681 context: "SafetyStatus",
682 }),
683 }
684}
685
686#[must_use]
688#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_up_or_open() -> Vec<u8> {
690 let mut buf = Vec::new();
691 let mut w = TlvWriter::new(&mut buf);
692 w.start_structure(Tag::Anonymous)
693 .expect("infallible: vec writer");
694 w.end_container().expect("infallible: vec writer");
695 buf
696}
697
698#[must_use]
700#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_down_or_close() -> Vec<u8> {
702 let mut buf = Vec::new();
703 let mut w = TlvWriter::new(&mut buf);
704 w.start_structure(Tag::Anonymous)
705 .expect("infallible: vec writer");
706 w.end_container().expect("infallible: vec writer");
707 buf
708}
709
710#[must_use]
712#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_stop_motion() -> Vec<u8> {
714 let mut buf = Vec::new();
715 let mut w = TlvWriter::new(&mut buf);
716 w.start_structure(Tag::Anonymous)
717 .expect("infallible: vec writer");
718 w.end_container().expect("infallible: vec writer");
719 buf
720}
721
722#[must_use]
724#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_go_to_lift_percentage(lift_percent100ths_value: u16) -> Vec<u8> {
726 let mut buf = Vec::new();
727 let mut w = TlvWriter::new(&mut buf);
728 w.start_structure(Tag::Anonymous)
729 .expect("infallible: vec writer");
730 w.put_uint(Tag::Context(0), u64::from(lift_percent100ths_value))
731 .expect("infallible: vec writer");
732 w.end_container().expect("infallible: vec writer");
733 buf
734}
735
736#[must_use]
738#[allow(clippy::expect_used, clippy::missing_panics_doc)] pub fn encode_go_to_tilt_percentage(tilt_percent100ths_value: u16) -> Vec<u8> {
740 let mut buf = Vec::new();
741 let mut w = TlvWriter::new(&mut buf);
742 w.start_structure(Tag::Anonymous)
743 .expect("infallible: vec writer");
744 w.put_uint(Tag::Context(0), u64::from(tilt_percent100ths_value))
745 .expect("infallible: vec writer");
746 w.end_container().expect("infallible: vec writer");
747 buf
748}