1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum ClosureUnit {
18 Millimeter = 0,
20 Degree = 1,
22}
23
24impl ClosureUnit {
25 pub fn from_u8(value: u8) -> Option<Self> {
27 match value {
28 0 => Some(ClosureUnit::Millimeter),
29 1 => Some(ClosureUnit::Degree),
30 _ => None,
31 }
32 }
33
34 pub fn to_u8(self) -> u8 {
36 self as u8
37 }
38}
39
40impl From<ClosureUnit> for u8 {
41 fn from(val: ClosureUnit) -> Self {
42 val as u8
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
47#[repr(u8)]
48pub enum ModulationType {
49 Slatsorientation = 0,
51 Slatsopenwork = 1,
53 Stripesalignment = 2,
55 Opacity = 3,
57 Ventilation = 4,
59}
60
61impl ModulationType {
62 pub fn from_u8(value: u8) -> Option<Self> {
64 match value {
65 0 => Some(ModulationType::Slatsorientation),
66 1 => Some(ModulationType::Slatsopenwork),
67 2 => Some(ModulationType::Stripesalignment),
68 3 => Some(ModulationType::Opacity),
69 4 => Some(ModulationType::Ventilation),
70 _ => None,
71 }
72 }
73
74 pub fn to_u8(self) -> u8 {
76 self as u8
77 }
78}
79
80impl From<ModulationType> for u8 {
81 fn from(val: ModulationType) -> Self {
82 val as u8
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
87#[repr(u8)]
88pub enum Overflow {
89 Nooverflow = 0,
91 Inside = 1,
93 Outside = 2,
95 Topinside = 3,
97 Topoutside = 4,
99 Bottominside = 5,
101 Bottomoutside = 6,
103 Leftinside = 7,
105 Leftoutside = 8,
107 Rightinside = 9,
109 Rightoutside = 10,
111}
112
113impl Overflow {
114 pub fn from_u8(value: u8) -> Option<Self> {
116 match value {
117 0 => Some(Overflow::Nooverflow),
118 1 => Some(Overflow::Inside),
119 2 => Some(Overflow::Outside),
120 3 => Some(Overflow::Topinside),
121 4 => Some(Overflow::Topoutside),
122 5 => Some(Overflow::Bottominside),
123 6 => Some(Overflow::Bottomoutside),
124 7 => Some(Overflow::Leftinside),
125 8 => Some(Overflow::Leftoutside),
126 9 => Some(Overflow::Rightinside),
127 10 => Some(Overflow::Rightoutside),
128 _ => None,
129 }
130 }
131
132 pub fn to_u8(self) -> u8 {
134 self as u8
135 }
136}
137
138impl From<Overflow> for u8 {
139 fn from(val: Overflow) -> Self {
140 val as u8
141 }
142}
143
144#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
145#[repr(u8)]
146pub enum RotationAxis {
147 Left = 0,
149 Centeredvertical = 1,
151 Leftandright = 2,
153 Right = 3,
155 Top = 4,
157 Centeredhorizontal = 5,
159 Topandbottom = 6,
161 Bottom = 7,
163 Leftbarrier = 8,
165 Leftandrightbarriers = 9,
167 Rightbarrier = 10,
169}
170
171impl RotationAxis {
172 pub fn from_u8(value: u8) -> Option<Self> {
174 match value {
175 0 => Some(RotationAxis::Left),
176 1 => Some(RotationAxis::Centeredvertical),
177 2 => Some(RotationAxis::Leftandright),
178 3 => Some(RotationAxis::Right),
179 4 => Some(RotationAxis::Top),
180 5 => Some(RotationAxis::Centeredhorizontal),
181 6 => Some(RotationAxis::Topandbottom),
182 7 => Some(RotationAxis::Bottom),
183 8 => Some(RotationAxis::Leftbarrier),
184 9 => Some(RotationAxis::Leftandrightbarriers),
185 10 => Some(RotationAxis::Rightbarrier),
186 _ => None,
187 }
188 }
189
190 pub fn to_u8(self) -> u8 {
192 self as u8
193 }
194}
195
196impl From<RotationAxis> for u8 {
197 fn from(val: RotationAxis) -> Self {
198 val as u8
199 }
200}
201
202#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
203#[repr(u8)]
204pub enum StepDirection {
205 Decrease = 0,
207 Increase = 1,
209}
210
211impl StepDirection {
212 pub fn from_u8(value: u8) -> Option<Self> {
214 match value {
215 0 => Some(StepDirection::Decrease),
216 1 => Some(StepDirection::Increase),
217 _ => None,
218 }
219 }
220
221 pub fn to_u8(self) -> u8 {
223 self as u8
224 }
225}
226
227impl From<StepDirection> for u8 {
228 fn from(val: StepDirection) -> Self {
229 val as u8
230 }
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
234#[repr(u8)]
235pub enum TranslationDirection {
236 Downward = 0,
238 Upward = 1,
240 Verticalmask = 2,
242 Verticalsymmetry = 3,
244 Leftward = 4,
246 Rightward = 5,
248 Horizontalmask = 6,
250 Horizontalsymmetry = 7,
252 Forward = 8,
254 Backward = 9,
256 Depthmask = 10,
258 Depthsymmetry = 11,
260}
261
262impl TranslationDirection {
263 pub fn from_u8(value: u8) -> Option<Self> {
265 match value {
266 0 => Some(TranslationDirection::Downward),
267 1 => Some(TranslationDirection::Upward),
268 2 => Some(TranslationDirection::Verticalmask),
269 3 => Some(TranslationDirection::Verticalsymmetry),
270 4 => Some(TranslationDirection::Leftward),
271 5 => Some(TranslationDirection::Rightward),
272 6 => Some(TranslationDirection::Horizontalmask),
273 7 => Some(TranslationDirection::Horizontalsymmetry),
274 8 => Some(TranslationDirection::Forward),
275 9 => Some(TranslationDirection::Backward),
276 10 => Some(TranslationDirection::Depthmask),
277 11 => Some(TranslationDirection::Depthsymmetry),
278 _ => None,
279 }
280 }
281
282 pub fn to_u8(self) -> u8 {
284 self as u8
285 }
286}
287
288impl From<TranslationDirection> for u8 {
289 fn from(val: TranslationDirection) -> Self {
290 val as u8
291 }
292}
293
294pub type LatchControlModes = u8;
298
299pub mod latchcontrolmodes {
301 pub const REMOTE_LATCHING: u8 = 0x01;
303 pub const REMOTE_UNLATCHING: u8 = 0x02;
305}
306
307#[derive(Debug, serde::Serialize)]
310pub struct DimensionState {
311 pub position: Option<u8>,
312 pub latch: Option<bool>,
313 pub speed: Option<u8>,
314}
315
316#[derive(Debug, serde::Serialize)]
317pub struct RangePercent {
318 pub min: Option<u8>,
319 pub max: Option<u8>,
320}
321
322#[derive(Debug, serde::Serialize)]
323pub struct UnitRange {
324 pub min: Option<i16>,
325 pub max: Option<i16>,
326}
327
328pub fn encode_set_target(position: u8, latch: bool, speed: u8) -> anyhow::Result<Vec<u8>> {
332 let tlv = tlv::TlvItemEnc {
333 tag: 0,
334 value: tlv::TlvItemValueEnc::StructInvisible(vec![
335 (0, tlv::TlvItemValueEnc::UInt8(position)).into(),
336 (1, tlv::TlvItemValueEnc::Bool(latch)).into(),
337 (2, tlv::TlvItemValueEnc::UInt8(speed)).into(),
338 ]),
339 };
340 Ok(tlv.encode()?)
341}
342
343pub fn encode_step(direction: StepDirection, number_of_steps: u16, speed: u8) -> anyhow::Result<Vec<u8>> {
345 let tlv = tlv::TlvItemEnc {
346 tag: 0,
347 value: tlv::TlvItemValueEnc::StructInvisible(vec![
348 (0, tlv::TlvItemValueEnc::UInt8(direction.to_u8())).into(),
349 (1, tlv::TlvItemValueEnc::UInt16(number_of_steps)).into(),
350 (2, tlv::TlvItemValueEnc::UInt8(speed)).into(),
351 ]),
352 };
353 Ok(tlv.encode()?)
354}
355
356pub fn decode_current_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<DimensionState>> {
360 if let tlv::TlvItemValue::List(_fields) = inp {
361 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
363 Ok(Some(DimensionState {
364 position: item.get_int(&[0]).map(|v| v as u8),
365 latch: item.get_bool(&[1]),
366 speed: item.get_int(&[2]).map(|v| v as u8),
367 }))
368 } else {
372 Ok(None)
373 }
375}
376
377pub fn decode_target_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<DimensionState>> {
379 if let tlv::TlvItemValue::List(_fields) = inp {
380 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
382 Ok(Some(DimensionState {
383 position: item.get_int(&[0]).map(|v| v as u8),
384 latch: item.get_bool(&[1]),
385 speed: item.get_int(&[2]).map(|v| v as u8),
386 }))
387 } else {
391 Ok(None)
392 }
394}
395
396pub fn decode_resolution(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
398 if let tlv::TlvItemValue::Int(v) = inp {
399 Ok(*v as u8)
400 } else {
401 Err(anyhow::anyhow!("Expected UInt8"))
402 }
403}
404
405pub fn decode_step_value(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
407 if let tlv::TlvItemValue::Int(v) = inp {
408 Ok(*v as u8)
409 } else {
410 Err(anyhow::anyhow!("Expected UInt8"))
411 }
412}
413
414pub fn decode_unit(inp: &tlv::TlvItemValue) -> anyhow::Result<ClosureUnit> {
416 if let tlv::TlvItemValue::Int(v) = inp {
417 ClosureUnit::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
418 } else {
419 Err(anyhow::anyhow!("Expected Integer"))
420 }
421}
422
423pub fn decode_unit_range(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<UnitRange>> {
425 if let tlv::TlvItemValue::List(_fields) = inp {
426 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
428 Ok(Some(UnitRange {
429 min: item.get_int(&[0]).map(|v| v as i16),
430 max: item.get_int(&[1]).map(|v| v as i16),
431 }))
432 } else {
436 Ok(None)
437 }
439}
440
441pub fn decode_limit_range(inp: &tlv::TlvItemValue) -> anyhow::Result<RangePercent> {
443 if let tlv::TlvItemValue::List(_fields) = inp {
444 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
446 Ok(RangePercent {
447 min: item.get_int(&[0]).map(|v| v as u8),
448 max: item.get_int(&[1]).map(|v| v as u8),
449 })
450 } else {
451 Err(anyhow::anyhow!("Expected struct fields"))
452 }
453}
454
455pub fn decode_translation_direction(inp: &tlv::TlvItemValue) -> anyhow::Result<TranslationDirection> {
457 if let tlv::TlvItemValue::Int(v) = inp {
458 TranslationDirection::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
459 } else {
460 Err(anyhow::anyhow!("Expected Integer"))
461 }
462}
463
464pub fn decode_rotation_axis(inp: &tlv::TlvItemValue) -> anyhow::Result<RotationAxis> {
466 if let tlv::TlvItemValue::Int(v) = inp {
467 RotationAxis::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
468 } else {
469 Err(anyhow::anyhow!("Expected Integer"))
470 }
471}
472
473pub fn decode_overflow(inp: &tlv::TlvItemValue) -> anyhow::Result<Overflow> {
475 if let tlv::TlvItemValue::Int(v) = inp {
476 Overflow::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
477 } else {
478 Err(anyhow::anyhow!("Expected Integer"))
479 }
480}
481
482pub fn decode_modulation_type(inp: &tlv::TlvItemValue) -> anyhow::Result<ModulationType> {
484 if let tlv::TlvItemValue::Int(v) = inp {
485 ModulationType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
486 } else {
487 Err(anyhow::anyhow!("Expected Integer"))
488 }
489}
490
491pub fn decode_latch_control_modes(inp: &tlv::TlvItemValue) -> anyhow::Result<LatchControlModes> {
493 if let tlv::TlvItemValue::Int(v) = inp {
494 Ok(*v as u8)
495 } else {
496 Err(anyhow::anyhow!("Expected Integer"))
497 }
498}
499
500
501pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
513 if cluster_id != 0x0105 {
515 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0105, got {}\"}}", cluster_id);
516 }
517
518 match attribute_id {
519 0x0000 => {
520 match decode_current_state(tlv_value) {
521 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
522 Err(e) => format!("{{\"error\": \"{}\"}}", e),
523 }
524 }
525 0x0001 => {
526 match decode_target_state(tlv_value) {
527 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
528 Err(e) => format!("{{\"error\": \"{}\"}}", e),
529 }
530 }
531 0x0002 => {
532 match decode_resolution(tlv_value) {
533 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
534 Err(e) => format!("{{\"error\": \"{}\"}}", e),
535 }
536 }
537 0x0003 => {
538 match decode_step_value(tlv_value) {
539 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
540 Err(e) => format!("{{\"error\": \"{}\"}}", e),
541 }
542 }
543 0x0004 => {
544 match decode_unit(tlv_value) {
545 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
546 Err(e) => format!("{{\"error\": \"{}\"}}", e),
547 }
548 }
549 0x0005 => {
550 match decode_unit_range(tlv_value) {
551 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
552 Err(e) => format!("{{\"error\": \"{}\"}}", e),
553 }
554 }
555 0x0006 => {
556 match decode_limit_range(tlv_value) {
557 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
558 Err(e) => format!("{{\"error\": \"{}\"}}", e),
559 }
560 }
561 0x0007 => {
562 match decode_translation_direction(tlv_value) {
563 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
564 Err(e) => format!("{{\"error\": \"{}\"}}", e),
565 }
566 }
567 0x0008 => {
568 match decode_rotation_axis(tlv_value) {
569 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
570 Err(e) => format!("{{\"error\": \"{}\"}}", e),
571 }
572 }
573 0x0009 => {
574 match decode_overflow(tlv_value) {
575 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
576 Err(e) => format!("{{\"error\": \"{}\"}}", e),
577 }
578 }
579 0x000A => {
580 match decode_modulation_type(tlv_value) {
581 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
582 Err(e) => format!("{{\"error\": \"{}\"}}", e),
583 }
584 }
585 0x000B => {
586 match decode_latch_control_modes(tlv_value) {
587 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
588 Err(e) => format!("{{\"error\": \"{}\"}}", e),
589 }
590 }
591 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
592 }
593}
594
595pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
600 vec![
601 (0x0000, "CurrentState"),
602 (0x0001, "TargetState"),
603 (0x0002, "Resolution"),
604 (0x0003, "StepValue"),
605 (0x0004, "Unit"),
606 (0x0005, "UnitRange"),
607 (0x0006, "LimitRange"),
608 (0x0007, "TranslationDirection"),
609 (0x0008, "RotationAxis"),
610 (0x0009, "Overflow"),
611 (0x000A, "ModulationType"),
612 (0x000B, "LatchControlModes"),
613 ]
614}
615
616pub fn get_command_list() -> Vec<(u32, &'static str)> {
619 vec![
620 (0x00, "SetTarget"),
621 (0x01, "Step"),
622 ]
623}
624
625pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
626 match cmd_id {
627 0x00 => Some("SetTarget"),
628 0x01 => Some("Step"),
629 _ => None,
630 }
631}
632
633pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
634 match cmd_id {
635 0x00 => Some(vec![
636 crate::clusters::codec::CommandField { tag: 0, name: "position", kind: crate::clusters::codec::FieldKind::U32, optional: true, nullable: false },
637 crate::clusters::codec::CommandField { tag: 1, name: "latch", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
638 crate::clusters::codec::CommandField { tag: 2, name: "speed", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
639 ]),
640 0x01 => Some(vec![
641 crate::clusters::codec::CommandField { tag: 0, name: "direction", kind: crate::clusters::codec::FieldKind::Enum { name: "StepDirection", variants: &[(0, "Decrease"), (1, "Increase")] }, optional: false, nullable: false },
642 crate::clusters::codec::CommandField { tag: 1, name: "number_of_steps", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
643 crate::clusters::codec::CommandField { tag: 2, name: "speed", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
644 ]),
645 _ => None,
646 }
647}
648
649pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
650 match cmd_id {
651 0x00 => {
652 let position = crate::clusters::codec::json_util::get_u8(args, "position")?;
653 let latch = crate::clusters::codec::json_util::get_bool(args, "latch")?;
654 let speed = crate::clusters::codec::json_util::get_u8(args, "speed")?;
655 encode_set_target(position, latch, speed)
656 }
657 0x01 => {
658 let direction = {
659 let n = crate::clusters::codec::json_util::get_u64(args, "direction")?;
660 StepDirection::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid StepDirection: {}", n))?
661 };
662 let number_of_steps = crate::clusters::codec::json_util::get_u16(args, "number_of_steps")?;
663 let speed = crate::clusters::codec::json_util::get_u8(args, "speed")?;
664 encode_step(direction, number_of_steps, speed)
665 }
666 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
667 }
668}
669
670pub async fn set_target(conn: &crate::controller::Connection, endpoint: u16, position: u8, latch: bool, speed: u8) -> anyhow::Result<()> {
674 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_CMD_ID_SETTARGET, &encode_set_target(position, latch, speed)?).await?;
675 Ok(())
676}
677
678pub async fn step(conn: &crate::controller::Connection, endpoint: u16, direction: StepDirection, number_of_steps: u16, speed: u8) -> anyhow::Result<()> {
680 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_CMD_ID_STEP, &encode_step(direction, number_of_steps, speed)?).await?;
681 Ok(())
682}
683
684pub async fn read_current_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<DimensionState>> {
686 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_CURRENTSTATE).await?;
687 decode_current_state(&tlv)
688}
689
690pub async fn read_target_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<DimensionState>> {
692 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_TARGETSTATE).await?;
693 decode_target_state(&tlv)
694}
695
696pub async fn read_resolution(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
698 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_RESOLUTION).await?;
699 decode_resolution(&tlv)
700}
701
702pub async fn read_step_value(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
704 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_STEPVALUE).await?;
705 decode_step_value(&tlv)
706}
707
708pub async fn read_unit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ClosureUnit> {
710 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_UNIT).await?;
711 decode_unit(&tlv)
712}
713
714pub async fn read_unit_range(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<UnitRange>> {
716 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_UNITRANGE).await?;
717 decode_unit_range(&tlv)
718}
719
720pub async fn read_limit_range(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<RangePercent> {
722 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_LIMITRANGE).await?;
723 decode_limit_range(&tlv)
724}
725
726pub async fn read_translation_direction(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TranslationDirection> {
728 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_TRANSLATIONDIRECTION).await?;
729 decode_translation_direction(&tlv)
730}
731
732pub async fn read_rotation_axis(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<RotationAxis> {
734 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_ROTATIONAXIS).await?;
735 decode_rotation_axis(&tlv)
736}
737
738pub async fn read_overflow(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Overflow> {
740 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_OVERFLOW).await?;
741 decode_overflow(&tlv)
742}
743
744pub async fn read_modulation_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ModulationType> {
746 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_MODULATIONTYPE).await?;
747 decode_modulation_type(&tlv)
748}
749
750pub async fn read_latch_control_modes(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<LatchControlModes> {
752 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CLOSURE_DIMENSION, crate::clusters::defs::CLUSTER_CLOSURE_DIMENSION_ATTR_ID_LATCHCONTROLMODES).await?;
753 decode_latch_control_modes(&tlv)
754}
755