1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum ACCapacityFormat {
21 Btuh = 0,
23}
24
25impl ACCapacityFormat {
26 pub fn from_u8(value: u8) -> Option<Self> {
28 match value {
29 0 => Some(ACCapacityFormat::Btuh),
30 _ => None,
31 }
32 }
33
34 pub fn to_u8(self) -> u8 {
36 self as u8
37 }
38}
39
40impl From<ACCapacityFormat> for u8 {
41 fn from(val: ACCapacityFormat) -> Self {
42 val as u8
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
47#[repr(u8)]
48pub enum ACCompressorType {
49 Unknown = 0,
51 T1 = 1,
53 T2 = 2,
55 T3 = 3,
57}
58
59impl ACCompressorType {
60 pub fn from_u8(value: u8) -> Option<Self> {
62 match value {
63 0 => Some(ACCompressorType::Unknown),
64 1 => Some(ACCompressorType::T1),
65 2 => Some(ACCompressorType::T2),
66 3 => Some(ACCompressorType::T3),
67 _ => None,
68 }
69 }
70
71 pub fn to_u8(self) -> u8 {
73 self as u8
74 }
75}
76
77impl From<ACCompressorType> for u8 {
78 fn from(val: ACCompressorType) -> Self {
79 val as u8
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
84#[repr(u8)]
85pub enum ACLouverPosition {
86 Closed = 1,
88 Open = 2,
90 Quarter = 3,
92 Half = 4,
94 Threequarters = 5,
96}
97
98impl ACLouverPosition {
99 pub fn from_u8(value: u8) -> Option<Self> {
101 match value {
102 1 => Some(ACLouverPosition::Closed),
103 2 => Some(ACLouverPosition::Open),
104 3 => Some(ACLouverPosition::Quarter),
105 4 => Some(ACLouverPosition::Half),
106 5 => Some(ACLouverPosition::Threequarters),
107 _ => None,
108 }
109 }
110
111 pub fn to_u8(self) -> u8 {
113 self as u8
114 }
115}
116
117impl From<ACLouverPosition> for u8 {
118 fn from(val: ACLouverPosition) -> Self {
119 val as u8
120 }
121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
124#[repr(u8)]
125pub enum ACRefrigerantType {
126 Unknown = 0,
128 R22 = 1,
130 R410a = 2,
132 R407c = 3,
134}
135
136impl ACRefrigerantType {
137 pub fn from_u8(value: u8) -> Option<Self> {
139 match value {
140 0 => Some(ACRefrigerantType::Unknown),
141 1 => Some(ACRefrigerantType::R22),
142 2 => Some(ACRefrigerantType::R410a),
143 3 => Some(ACRefrigerantType::R407c),
144 _ => None,
145 }
146 }
147
148 pub fn to_u8(self) -> u8 {
150 self as u8
151 }
152}
153
154impl From<ACRefrigerantType> for u8 {
155 fn from(val: ACRefrigerantType) -> Self {
156 val as u8
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
161#[repr(u8)]
162pub enum ACType {
163 Unknown = 0,
165 Coolingfixed = 1,
167 Heatpumpfixed = 2,
169 Coolinginverter = 3,
171 Heatpumpinverter = 4,
173}
174
175impl ACType {
176 pub fn from_u8(value: u8) -> Option<Self> {
178 match value {
179 0 => Some(ACType::Unknown),
180 1 => Some(ACType::Coolingfixed),
181 2 => Some(ACType::Heatpumpfixed),
182 3 => Some(ACType::Coolinginverter),
183 4 => Some(ACType::Heatpumpinverter),
184 _ => None,
185 }
186 }
187
188 pub fn to_u8(self) -> u8 {
190 self as u8
191 }
192}
193
194impl From<ACType> for u8 {
195 fn from(val: ACType) -> Self {
196 val as u8
197 }
198}
199
200#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
201#[repr(u8)]
202pub enum ControlSequenceOfOperation {
203 Coolingonly = 0,
205 Coolingwithreheat = 1,
207 Heatingonly = 2,
209 Heatingwithreheat = 3,
211 Coolingandheating = 4,
213 Coolingandheatingwithreheat = 5,
215}
216
217impl ControlSequenceOfOperation {
218 pub fn from_u8(value: u8) -> Option<Self> {
220 match value {
221 0 => Some(ControlSequenceOfOperation::Coolingonly),
222 1 => Some(ControlSequenceOfOperation::Coolingwithreheat),
223 2 => Some(ControlSequenceOfOperation::Heatingonly),
224 3 => Some(ControlSequenceOfOperation::Heatingwithreheat),
225 4 => Some(ControlSequenceOfOperation::Coolingandheating),
226 5 => Some(ControlSequenceOfOperation::Coolingandheatingwithreheat),
227 _ => None,
228 }
229 }
230
231 pub fn to_u8(self) -> u8 {
233 self as u8
234 }
235}
236
237impl From<ControlSequenceOfOperation> for u8 {
238 fn from(val: ControlSequenceOfOperation) -> Self {
239 val as u8
240 }
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
244#[repr(u8)]
245pub enum PresetScenario {
246 Occupied = 1,
248 Unoccupied = 2,
250 Sleep = 3,
252 Wake = 4,
254 Vacation = 5,
256 Goingtosleep = 6,
258 Userdefined = 254,
260}
261
262impl PresetScenario {
263 pub fn from_u8(value: u8) -> Option<Self> {
265 match value {
266 1 => Some(PresetScenario::Occupied),
267 2 => Some(PresetScenario::Unoccupied),
268 3 => Some(PresetScenario::Sleep),
269 4 => Some(PresetScenario::Wake),
270 5 => Some(PresetScenario::Vacation),
271 6 => Some(PresetScenario::Goingtosleep),
272 254 => Some(PresetScenario::Userdefined),
273 _ => None,
274 }
275 }
276
277 pub fn to_u8(self) -> u8 {
279 self as u8
280 }
281}
282
283impl From<PresetScenario> for u8 {
284 fn from(val: PresetScenario) -> Self {
285 val as u8
286 }
287}
288
289#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
290#[repr(u8)]
291pub enum SetpointChangeSource {
292 Manual = 0,
294 Schedule = 1,
296 External = 2,
298}
299
300impl SetpointChangeSource {
301 pub fn from_u8(value: u8) -> Option<Self> {
303 match value {
304 0 => Some(SetpointChangeSource::Manual),
305 1 => Some(SetpointChangeSource::Schedule),
306 2 => Some(SetpointChangeSource::External),
307 _ => None,
308 }
309 }
310
311 pub fn to_u8(self) -> u8 {
313 self as u8
314 }
315}
316
317impl From<SetpointChangeSource> for u8 {
318 fn from(val: SetpointChangeSource) -> Self {
319 val as u8
320 }
321}
322
323#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
324#[repr(u8)]
325pub enum SetpointRaiseLowerMode {
326 Heat = 0,
328 Cool = 1,
330 Both = 2,
332}
333
334impl SetpointRaiseLowerMode {
335 pub fn from_u8(value: u8) -> Option<Self> {
337 match value {
338 0 => Some(SetpointRaiseLowerMode::Heat),
339 1 => Some(SetpointRaiseLowerMode::Cool),
340 2 => Some(SetpointRaiseLowerMode::Both),
341 _ => None,
342 }
343 }
344
345 pub fn to_u8(self) -> u8 {
347 self as u8
348 }
349}
350
351impl From<SetpointRaiseLowerMode> for u8 {
352 fn from(val: SetpointRaiseLowerMode) -> Self {
353 val as u8
354 }
355}
356
357#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
358#[repr(u8)]
359pub enum StartOfWeek {
360 Sunday = 0,
361 Monday = 1,
362 Tuesday = 2,
363 Wednesday = 3,
364 Thursday = 4,
365 Friday = 5,
366 Saturday = 6,
367}
368
369impl StartOfWeek {
370 pub fn from_u8(value: u8) -> Option<Self> {
372 match value {
373 0 => Some(StartOfWeek::Sunday),
374 1 => Some(StartOfWeek::Monday),
375 2 => Some(StartOfWeek::Tuesday),
376 3 => Some(StartOfWeek::Wednesday),
377 4 => Some(StartOfWeek::Thursday),
378 5 => Some(StartOfWeek::Friday),
379 6 => Some(StartOfWeek::Saturday),
380 _ => None,
381 }
382 }
383
384 pub fn to_u8(self) -> u8 {
386 self as u8
387 }
388}
389
390impl From<StartOfWeek> for u8 {
391 fn from(val: StartOfWeek) -> Self {
392 val as u8
393 }
394}
395
396#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
397#[repr(u8)]
398pub enum SystemMode {
399 Off = 0,
401 Auto = 1,
403 Cool = 3,
405 Heat = 4,
407 Emergencyheat = 5,
409 Precooling = 6,
411 Fanonly = 7,
412 Dry = 8,
413 Sleep = 9,
414}
415
416impl SystemMode {
417 pub fn from_u8(value: u8) -> Option<Self> {
419 match value {
420 0 => Some(SystemMode::Off),
421 1 => Some(SystemMode::Auto),
422 3 => Some(SystemMode::Cool),
423 4 => Some(SystemMode::Heat),
424 5 => Some(SystemMode::Emergencyheat),
425 6 => Some(SystemMode::Precooling),
426 7 => Some(SystemMode::Fanonly),
427 8 => Some(SystemMode::Dry),
428 9 => Some(SystemMode::Sleep),
429 _ => None,
430 }
431 }
432
433 pub fn to_u8(self) -> u8 {
435 self as u8
436 }
437}
438
439impl From<SystemMode> for u8 {
440 fn from(val: SystemMode) -> Self {
441 val as u8
442 }
443}
444
445#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
446#[repr(u8)]
447pub enum TemperatureSetpointHold {
448 Setpointholdoff = 0,
450 Setpointholdon = 1,
452}
453
454impl TemperatureSetpointHold {
455 pub fn from_u8(value: u8) -> Option<Self> {
457 match value {
458 0 => Some(TemperatureSetpointHold::Setpointholdoff),
459 1 => Some(TemperatureSetpointHold::Setpointholdon),
460 _ => None,
461 }
462 }
463
464 pub fn to_u8(self) -> u8 {
466 self as u8
467 }
468}
469
470impl From<TemperatureSetpointHold> for u8 {
471 fn from(val: TemperatureSetpointHold) -> Self {
472 val as u8
473 }
474}
475
476#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
477#[repr(u8)]
478pub enum ThermostatRunningMode {
479 Off = 0,
481 Cool = 3,
483 Heat = 4,
485}
486
487impl ThermostatRunningMode {
488 pub fn from_u8(value: u8) -> Option<Self> {
490 match value {
491 0 => Some(ThermostatRunningMode::Off),
492 3 => Some(ThermostatRunningMode::Cool),
493 4 => Some(ThermostatRunningMode::Heat),
494 _ => None,
495 }
496 }
497
498 pub fn to_u8(self) -> u8 {
500 self as u8
501 }
502}
503
504impl From<ThermostatRunningMode> for u8 {
505 fn from(val: ThermostatRunningMode) -> Self {
506 val as u8
507 }
508}
509
510pub type ACErrorCode = u8;
514
515pub mod acerrorcode {
517 pub const COMPRESSOR_FAIL: u8 = 0x01;
519 pub const ROOM_SENSOR_FAIL: u8 = 0x02;
521 pub const OUTDOOR_SENSOR_FAIL: u8 = 0x04;
523 pub const COIL_SENSOR_FAIL: u8 = 0x08;
525 pub const FAN_FAIL: u8 = 0x10;
527}
528
529pub type Occupancy = u8;
531
532pub mod occupancy {
534 pub const OCCUPIED: u8 = 0x01;
536}
537
538pub type PresetTypeFeatures = u8;
540
541pub mod presettypefeatures {
543 pub const AUTOMATIC: u8 = 0x01;
545 pub const SUPPORTS_NAMES: u8 = 0x02;
547}
548
549pub type ProgrammingOperationMode = u8;
551
552pub mod programmingoperationmode {
554 pub const SCHEDULE_ACTIVE: u8 = 0x01;
556 pub const AUTO_RECOVERY: u8 = 0x02;
558 pub const ECONOMY: u8 = 0x04;
560}
561
562pub type RelayState = u8;
564
565pub mod relaystate {
567 pub const HEAT: u8 = 0x01;
569 pub const COOL: u8 = 0x02;
571 pub const FAN: u8 = 0x04;
573 pub const HEAT_STAGE2: u8 = 0x08;
575 pub const COOL_STAGE2: u8 = 0x10;
577 pub const FAN_STAGE2: u8 = 0x20;
579 pub const FAN_STAGE3: u8 = 0x40;
581}
582
583pub type RemoteSensing = u8;
585
586pub mod remotesensing {
588 pub const LOCAL_TEMPERATURE: u8 = 0x01;
590 pub const OUTDOOR_TEMPERATURE: u8 = 0x02;
592 pub const OCCUPANCY: u8 = 0x04;
594}
595
596pub type ScheduleDayOfWeek = u8;
598
599pub mod scheduledayofweek {
601 pub const SUNDAY: u8 = 0x01;
603 pub const MONDAY: u8 = 0x02;
605 pub const TUESDAY: u8 = 0x04;
607 pub const WEDNESDAY: u8 = 0x08;
609 pub const THURSDAY: u8 = 0x10;
611 pub const FRIDAY: u8 = 0x20;
613 pub const SATURDAY: u8 = 0x40;
615 pub const AWAY: u8 = 0x80;
617}
618
619pub type ScheduleMode = u8;
621
622pub mod schedulemode {
624 pub const HEAT_SETPOINT_PRESENT: u8 = 0x01;
626 pub const COOL_SETPOINT_PRESENT: u8 = 0x02;
628}
629
630pub type ScheduleTypeFeatures = u8;
632
633pub mod scheduletypefeatures {
635 pub const SUPPORTS_PRESETS: u8 = 0x01;
637 pub const SUPPORTS_SETPOINTS: u8 = 0x02;
639 pub const SUPPORTS_NAMES: u8 = 0x04;
641 pub const SUPPORTS_OFF: u8 = 0x08;
643}
644
645#[derive(Debug, serde::Serialize)]
648pub struct Preset {
649 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
650 pub preset_handle: Option<Vec<u8>>,
651 pub preset_scenario: Option<PresetScenario>,
652 pub name: Option<String>,
653 pub cooling_setpoint: Option<i16>,
654 pub heating_setpoint: Option<i16>,
655 pub built_in: Option<bool>,
656}
657
658#[derive(Debug, serde::Serialize)]
659pub struct PresetType {
660 pub preset_scenario: Option<PresetScenario>,
661 pub number_of_presets: Option<u8>,
662 pub preset_type_features: Option<PresetTypeFeatures>,
663}
664
665#[derive(Debug, serde::Serialize)]
666pub struct Schedule {
667 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
668 pub schedule_handle: Option<Vec<u8>>,
669 pub system_mode: Option<SystemMode>,
670 pub name: Option<String>,
671 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
672 pub preset_handle: Option<Vec<u8>>,
673 pub transitions: Option<Vec<ScheduleTransition>>,
674 pub built_in: Option<bool>,
675}
676
677#[derive(Debug, serde::Serialize)]
678pub struct ScheduleTransition {
679 pub day_of_week: Option<ScheduleDayOfWeek>,
680 pub transition_time: Option<u16>,
681 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
682 pub preset_handle: Option<Vec<u8>>,
683 pub system_mode: Option<SystemMode>,
684 pub cooling_setpoint: Option<i16>,
685 pub heating_setpoint: Option<i16>,
686}
687
688#[derive(Debug, serde::Serialize)]
689pub struct ScheduleType {
690 pub system_mode: Option<SystemMode>,
691 pub number_of_schedules: Option<u8>,
692 pub schedule_type_features: Option<ScheduleTypeFeatures>,
693}
694
695#[derive(Debug, serde::Serialize)]
696pub struct WeeklyScheduleTransition {
697 pub transition_time: Option<u16>,
698 pub heat_setpoint: Option<i16>,
699 pub cool_setpoint: Option<i16>,
700}
701
702pub fn encode_setpoint_raise_lower(mode: SetpointRaiseLowerMode, amount: i8) -> anyhow::Result<Vec<u8>> {
706 let tlv = tlv::TlvItemEnc {
707 tag: 0,
708 value: tlv::TlvItemValueEnc::StructInvisible(vec![
709 (0, tlv::TlvItemValueEnc::UInt8(mode.to_u8())).into(),
710 (1, tlv::TlvItemValueEnc::Int8(amount)).into(),
711 ]),
712 };
713 Ok(tlv.encode()?)
714}
715
716pub fn encode_set_active_schedule_request(schedule_handle: Vec<u8>) -> anyhow::Result<Vec<u8>> {
718 let tlv = tlv::TlvItemEnc {
719 tag: 0,
720 value: tlv::TlvItemValueEnc::StructInvisible(vec![
721 (0, tlv::TlvItemValueEnc::OctetString(schedule_handle)).into(),
722 ]),
723 };
724 Ok(tlv.encode()?)
725}
726
727pub fn encode_set_active_preset_request(preset_handle: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
729 let tlv = tlv::TlvItemEnc {
730 tag: 0,
731 value: tlv::TlvItemValueEnc::StructInvisible(vec![
732 (0, tlv::TlvItemValueEnc::OctetString(preset_handle.unwrap_or(vec![]))).into(),
733 ]),
734 };
735 Ok(tlv.encode()?)
736}
737
738pub fn decode_local_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
742 if let tlv::TlvItemValue::Int(v) = inp {
743 Ok(Some(*v as i16))
744 } else {
745 Ok(None)
746 }
747}
748
749pub fn decode_outdoor_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
751 if let tlv::TlvItemValue::Int(v) = inp {
752 Ok(Some(*v as i16))
753 } else {
754 Ok(None)
755 }
756}
757
758pub fn decode_occupancy(inp: &tlv::TlvItemValue) -> anyhow::Result<Occupancy> {
760 if let tlv::TlvItemValue::Int(v) = inp {
761 Ok(*v as u8)
762 } else {
763 Err(anyhow::anyhow!("Expected Integer"))
764 }
765}
766
767pub fn decode_abs_min_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
769 if let tlv::TlvItemValue::Int(v) = inp {
770 Ok(*v as i16)
771 } else {
772 Err(anyhow::anyhow!("Expected Int16"))
773 }
774}
775
776pub fn decode_abs_max_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
778 if let tlv::TlvItemValue::Int(v) = inp {
779 Ok(*v as i16)
780 } else {
781 Err(anyhow::anyhow!("Expected Int16"))
782 }
783}
784
785pub fn decode_abs_min_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
787 if let tlv::TlvItemValue::Int(v) = inp {
788 Ok(*v as i16)
789 } else {
790 Err(anyhow::anyhow!("Expected Int16"))
791 }
792}
793
794pub fn decode_abs_max_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
796 if let tlv::TlvItemValue::Int(v) = inp {
797 Ok(*v as i16)
798 } else {
799 Err(anyhow::anyhow!("Expected Int16"))
800 }
801}
802
803pub fn decode_pi_cooling_demand(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
805 if let tlv::TlvItemValue::Int(v) = inp {
806 Ok(*v as u8)
807 } else {
808 Err(anyhow::anyhow!("Expected UInt8"))
809 }
810}
811
812pub fn decode_pi_heating_demand(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
814 if let tlv::TlvItemValue::Int(v) = inp {
815 Ok(*v as u8)
816 } else {
817 Err(anyhow::anyhow!("Expected UInt8"))
818 }
819}
820
821pub fn decode_hvac_system_type_configuration(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
823 if let tlv::TlvItemValue::Int(v) = inp {
824 Ok(*v as u8)
825 } else {
826 Err(anyhow::anyhow!("Expected UInt8"))
827 }
828}
829
830pub fn decode_local_temperature_calibration(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
832 if let tlv::TlvItemValue::Int(v) = inp {
833 Ok(*v as u8)
834 } else {
835 Err(anyhow::anyhow!("Expected UInt8"))
836 }
837}
838
839pub fn decode_occupied_cooling_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
841 if let tlv::TlvItemValue::Int(v) = inp {
842 Ok(*v as i16)
843 } else {
844 Err(anyhow::anyhow!("Expected Int16"))
845 }
846}
847
848pub fn decode_occupied_heating_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
850 if let tlv::TlvItemValue::Int(v) = inp {
851 Ok(*v as i16)
852 } else {
853 Err(anyhow::anyhow!("Expected Int16"))
854 }
855}
856
857pub fn decode_unoccupied_cooling_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
859 if let tlv::TlvItemValue::Int(v) = inp {
860 Ok(*v as i16)
861 } else {
862 Err(anyhow::anyhow!("Expected Int16"))
863 }
864}
865
866pub fn decode_unoccupied_heating_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
868 if let tlv::TlvItemValue::Int(v) = inp {
869 Ok(*v as i16)
870 } else {
871 Err(anyhow::anyhow!("Expected Int16"))
872 }
873}
874
875pub fn decode_min_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
877 if let tlv::TlvItemValue::Int(v) = inp {
878 Ok(*v as i16)
879 } else {
880 Err(anyhow::anyhow!("Expected Int16"))
881 }
882}
883
884pub fn decode_max_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
886 if let tlv::TlvItemValue::Int(v) = inp {
887 Ok(*v as i16)
888 } else {
889 Err(anyhow::anyhow!("Expected Int16"))
890 }
891}
892
893pub fn decode_min_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
895 if let tlv::TlvItemValue::Int(v) = inp {
896 Ok(*v as i16)
897 } else {
898 Err(anyhow::anyhow!("Expected Int16"))
899 }
900}
901
902pub fn decode_max_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
904 if let tlv::TlvItemValue::Int(v) = inp {
905 Ok(*v as i16)
906 } else {
907 Err(anyhow::anyhow!("Expected Int16"))
908 }
909}
910
911pub fn decode_min_setpoint_dead_band(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
913 if let tlv::TlvItemValue::Int(v) = inp {
914 Ok(*v as u8)
915 } else {
916 Err(anyhow::anyhow!("Expected UInt8"))
917 }
918}
919
920pub fn decode_remote_sensing(inp: &tlv::TlvItemValue) -> anyhow::Result<RemoteSensing> {
922 if let tlv::TlvItemValue::Int(v) = inp {
923 Ok(*v as u8)
924 } else {
925 Err(anyhow::anyhow!("Expected Integer"))
926 }
927}
928
929pub fn decode_control_sequence_of_operation(inp: &tlv::TlvItemValue) -> anyhow::Result<ControlSequenceOfOperation> {
931 if let tlv::TlvItemValue::Int(v) = inp {
932 ControlSequenceOfOperation::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
933 } else {
934 Err(anyhow::anyhow!("Expected Integer"))
935 }
936}
937
938pub fn decode_system_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<SystemMode> {
940 if let tlv::TlvItemValue::Int(v) = inp {
941 SystemMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
942 } else {
943 Err(anyhow::anyhow!("Expected Integer"))
944 }
945}
946
947pub fn decode_thermostat_running_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<ThermostatRunningMode> {
949 if let tlv::TlvItemValue::Int(v) = inp {
950 ThermostatRunningMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
951 } else {
952 Err(anyhow::anyhow!("Expected Integer"))
953 }
954}
955
956pub fn decode_temperature_setpoint_hold(inp: &tlv::TlvItemValue) -> anyhow::Result<TemperatureSetpointHold> {
958 if let tlv::TlvItemValue::Int(v) = inp {
959 TemperatureSetpointHold::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
960 } else {
961 Err(anyhow::anyhow!("Expected Integer"))
962 }
963}
964
965pub fn decode_temperature_setpoint_hold_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
967 if let tlv::TlvItemValue::Int(v) = inp {
968 Ok(Some(*v as u16))
969 } else {
970 Ok(None)
971 }
972}
973
974pub fn decode_thermostat_programming_operation_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<ProgrammingOperationMode> {
976 if let tlv::TlvItemValue::Int(v) = inp {
977 Ok(*v as u8)
978 } else {
979 Err(anyhow::anyhow!("Expected Integer"))
980 }
981}
982
983pub fn decode_thermostat_running_state(inp: &tlv::TlvItemValue) -> anyhow::Result<RelayState> {
985 if let tlv::TlvItemValue::Int(v) = inp {
986 Ok(*v as u8)
987 } else {
988 Err(anyhow::anyhow!("Expected Integer"))
989 }
990}
991
992pub fn decode_setpoint_change_source(inp: &tlv::TlvItemValue) -> anyhow::Result<SetpointChangeSource> {
994 if let tlv::TlvItemValue::Int(v) = inp {
995 SetpointChangeSource::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
996 } else {
997 Err(anyhow::anyhow!("Expected Integer"))
998 }
999}
1000
1001pub fn decode_setpoint_change_amount(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
1003 if let tlv::TlvItemValue::Int(v) = inp {
1004 Ok(Some(*v as u8))
1005 } else {
1006 Ok(None)
1007 }
1008}
1009
1010pub fn decode_setpoint_change_source_timestamp(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
1012 if let tlv::TlvItemValue::Int(v) = inp {
1013 Ok(*v)
1014 } else {
1015 Err(anyhow::anyhow!("Expected UInt64"))
1016 }
1017}
1018
1019pub fn decode_occupied_setback(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1021 if let tlv::TlvItemValue::Int(v) = inp {
1022 Ok(*v as u8)
1023 } else {
1024 Err(anyhow::anyhow!("Expected UInt8"))
1025 }
1026}
1027
1028pub fn decode_occupied_setback_min(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1030 if let tlv::TlvItemValue::Int(v) = inp {
1031 Ok(*v as u8)
1032 } else {
1033 Err(anyhow::anyhow!("Expected UInt8"))
1034 }
1035}
1036
1037pub fn decode_occupied_setback_max(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1039 if let tlv::TlvItemValue::Int(v) = inp {
1040 Ok(*v as u8)
1041 } else {
1042 Err(anyhow::anyhow!("Expected UInt8"))
1043 }
1044}
1045
1046pub fn decode_unoccupied_setback(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1048 if let tlv::TlvItemValue::Int(v) = inp {
1049 Ok(*v as u8)
1050 } else {
1051 Err(anyhow::anyhow!("Expected UInt8"))
1052 }
1053}
1054
1055pub fn decode_unoccupied_setback_min(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1057 if let tlv::TlvItemValue::Int(v) = inp {
1058 Ok(*v as u8)
1059 } else {
1060 Err(anyhow::anyhow!("Expected UInt8"))
1061 }
1062}
1063
1064pub fn decode_unoccupied_setback_max(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1066 if let tlv::TlvItemValue::Int(v) = inp {
1067 Ok(*v as u8)
1068 } else {
1069 Err(anyhow::anyhow!("Expected UInt8"))
1070 }
1071}
1072
1073pub fn decode_emergency_heat_delta(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1075 if let tlv::TlvItemValue::Int(v) = inp {
1076 Ok(*v as u8)
1077 } else {
1078 Err(anyhow::anyhow!("Expected UInt8"))
1079 }
1080}
1081
1082pub fn decode_ac_type(inp: &tlv::TlvItemValue) -> anyhow::Result<ACType> {
1084 if let tlv::TlvItemValue::Int(v) = inp {
1085 ACType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1086 } else {
1087 Err(anyhow::anyhow!("Expected Integer"))
1088 }
1089}
1090
1091pub fn decode_ac_capacity(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1093 if let tlv::TlvItemValue::Int(v) = inp {
1094 Ok(*v as u16)
1095 } else {
1096 Err(anyhow::anyhow!("Expected UInt16"))
1097 }
1098}
1099
1100pub fn decode_ac_refrigerant_type(inp: &tlv::TlvItemValue) -> anyhow::Result<ACRefrigerantType> {
1102 if let tlv::TlvItemValue::Int(v) = inp {
1103 ACRefrigerantType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1104 } else {
1105 Err(anyhow::anyhow!("Expected Integer"))
1106 }
1107}
1108
1109pub fn decode_ac_compressor_type(inp: &tlv::TlvItemValue) -> anyhow::Result<ACCompressorType> {
1111 if let tlv::TlvItemValue::Int(v) = inp {
1112 ACCompressorType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1113 } else {
1114 Err(anyhow::anyhow!("Expected Integer"))
1115 }
1116}
1117
1118pub fn decode_ac_error_code(inp: &tlv::TlvItemValue) -> anyhow::Result<ACErrorCode> {
1120 if let tlv::TlvItemValue::Int(v) = inp {
1121 Ok(*v as u8)
1122 } else {
1123 Err(anyhow::anyhow!("Expected Integer"))
1124 }
1125}
1126
1127pub fn decode_aclouver_position(inp: &tlv::TlvItemValue) -> anyhow::Result<ACLouverPosition> {
1129 if let tlv::TlvItemValue::Int(v) = inp {
1130 ACLouverPosition::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1131 } else {
1132 Err(anyhow::anyhow!("Expected Integer"))
1133 }
1134}
1135
1136pub fn decode_ac_coil_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i16>> {
1138 if let tlv::TlvItemValue::Int(v) = inp {
1139 Ok(Some(*v as i16))
1140 } else {
1141 Ok(None)
1142 }
1143}
1144
1145pub fn decode_ac_capacity_format(inp: &tlv::TlvItemValue) -> anyhow::Result<ACCapacityFormat> {
1147 if let tlv::TlvItemValue::Int(v) = inp {
1148 ACCapacityFormat::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
1149 } else {
1150 Err(anyhow::anyhow!("Expected Integer"))
1151 }
1152}
1153
1154pub fn decode_preset_types(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<PresetType>> {
1156 let mut res = Vec::new();
1157 if let tlv::TlvItemValue::List(v) = inp {
1158 for item in v {
1159 res.push(PresetType {
1160 preset_scenario: item.get_int(&[0]).and_then(|v| PresetScenario::from_u8(v as u8)),
1161 number_of_presets: item.get_int(&[1]).map(|v| v as u8),
1162 preset_type_features: item.get_int(&[2]).map(|v| v as u8),
1163 });
1164 }
1165 }
1166 Ok(res)
1167}
1168
1169pub fn decode_schedule_types(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ScheduleType>> {
1171 let mut res = Vec::new();
1172 if let tlv::TlvItemValue::List(v) = inp {
1173 for item in v {
1174 res.push(ScheduleType {
1175 system_mode: item.get_int(&[0]).and_then(|v| SystemMode::from_u8(v as u8)),
1176 number_of_schedules: item.get_int(&[1]).map(|v| v as u8),
1177 schedule_type_features: item.get_int(&[2]).map(|v| v as u8),
1178 });
1179 }
1180 }
1181 Ok(res)
1182}
1183
1184pub fn decode_number_of_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1186 if let tlv::TlvItemValue::Int(v) = inp {
1187 Ok(*v as u8)
1188 } else {
1189 Err(anyhow::anyhow!("Expected UInt8"))
1190 }
1191}
1192
1193pub fn decode_number_of_schedules(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1195 if let tlv::TlvItemValue::Int(v) = inp {
1196 Ok(*v as u8)
1197 } else {
1198 Err(anyhow::anyhow!("Expected UInt8"))
1199 }
1200}
1201
1202pub fn decode_number_of_schedule_transitions(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1204 if let tlv::TlvItemValue::Int(v) = inp {
1205 Ok(*v as u8)
1206 } else {
1207 Err(anyhow::anyhow!("Expected UInt8"))
1208 }
1209}
1210
1211pub fn decode_number_of_schedule_transition_per_day(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
1213 if let tlv::TlvItemValue::Int(v) = inp {
1214 Ok(Some(*v as u8))
1215 } else {
1216 Ok(None)
1217 }
1218}
1219
1220pub fn decode_active_preset_handle(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
1222 if let tlv::TlvItemValue::OctetString(v) = inp {
1223 Ok(Some(v.clone()))
1224 } else {
1225 Ok(None)
1226 }
1227}
1228
1229pub fn decode_active_schedule_handle(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
1231 if let tlv::TlvItemValue::OctetString(v) = inp {
1232 Ok(Some(v.clone()))
1233 } else {
1234 Ok(None)
1235 }
1236}
1237
1238pub fn decode_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Preset>> {
1240 let mut res = Vec::new();
1241 if let tlv::TlvItemValue::List(v) = inp {
1242 for item in v {
1243 res.push(Preset {
1244 preset_handle: item.get_octet_string_owned(&[0]),
1245 preset_scenario: item.get_int(&[1]).and_then(|v| PresetScenario::from_u8(v as u8)),
1246 name: item.get_string_owned(&[2]),
1247 cooling_setpoint: item.get_int(&[3]).map(|v| v as i16),
1248 heating_setpoint: item.get_int(&[4]).map(|v| v as i16),
1249 built_in: item.get_bool(&[5]),
1250 });
1251 }
1252 }
1253 Ok(res)
1254}
1255
1256pub fn decode_schedules(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Schedule>> {
1258 let mut res = Vec::new();
1259 if let tlv::TlvItemValue::List(v) = inp {
1260 for item in v {
1261 res.push(Schedule {
1262 schedule_handle: item.get_octet_string_owned(&[0]),
1263 system_mode: item.get_int(&[1]).and_then(|v| SystemMode::from_u8(v as u8)),
1264 name: item.get_string_owned(&[2]),
1265 preset_handle: item.get_octet_string_owned(&[3]),
1266 transitions: {
1267 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[4]) {
1268 let mut items = Vec::new();
1269 for list_item in l {
1270 items.push(ScheduleTransition {
1271 day_of_week: list_item.get_int(&[0]).map(|v| v as u8),
1272 transition_time: list_item.get_int(&[1]).map(|v| v as u16),
1273 preset_handle: list_item.get_octet_string_owned(&[2]),
1274 system_mode: list_item.get_int(&[3]).and_then(|v| SystemMode::from_u8(v as u8)),
1275 cooling_setpoint: list_item.get_int(&[4]).map(|v| v as i16),
1276 heating_setpoint: list_item.get_int(&[5]).map(|v| v as i16),
1277 });
1278 }
1279 Some(items)
1280 } else {
1281 None
1282 }
1283 },
1284 built_in: item.get_bool(&[5]),
1285 });
1286 }
1287 }
1288 Ok(res)
1289}
1290
1291pub fn decode_setpoint_hold_expiry_timestamp(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
1293 if let tlv::TlvItemValue::Int(v) = inp {
1294 Ok(Some(*v))
1295 } else {
1296 Ok(None)
1297 }
1298}
1299
1300
1301pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
1313 if cluster_id != 0x0201 {
1315 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0201, got {}\"}}", cluster_id);
1316 }
1317
1318 match attribute_id {
1319 0x0000 => {
1320 match decode_local_temperature(tlv_value) {
1321 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1322 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1323 }
1324 }
1325 0x0001 => {
1326 match decode_outdoor_temperature(tlv_value) {
1327 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1328 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1329 }
1330 }
1331 0x0002 => {
1332 match decode_occupancy(tlv_value) {
1333 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1334 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1335 }
1336 }
1337 0x0003 => {
1338 match decode_abs_min_heat_setpoint_limit(tlv_value) {
1339 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1340 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1341 }
1342 }
1343 0x0004 => {
1344 match decode_abs_max_heat_setpoint_limit(tlv_value) {
1345 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1346 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1347 }
1348 }
1349 0x0005 => {
1350 match decode_abs_min_cool_setpoint_limit(tlv_value) {
1351 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1352 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1353 }
1354 }
1355 0x0006 => {
1356 match decode_abs_max_cool_setpoint_limit(tlv_value) {
1357 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1358 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1359 }
1360 }
1361 0x0007 => {
1362 match decode_pi_cooling_demand(tlv_value) {
1363 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1364 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1365 }
1366 }
1367 0x0008 => {
1368 match decode_pi_heating_demand(tlv_value) {
1369 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1370 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1371 }
1372 }
1373 0x0009 => {
1374 match decode_hvac_system_type_configuration(tlv_value) {
1375 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1376 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1377 }
1378 }
1379 0x0010 => {
1380 match decode_local_temperature_calibration(tlv_value) {
1381 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1382 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1383 }
1384 }
1385 0x0011 => {
1386 match decode_occupied_cooling_setpoint(tlv_value) {
1387 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1388 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1389 }
1390 }
1391 0x0012 => {
1392 match decode_occupied_heating_setpoint(tlv_value) {
1393 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1394 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1395 }
1396 }
1397 0x0013 => {
1398 match decode_unoccupied_cooling_setpoint(tlv_value) {
1399 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1400 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1401 }
1402 }
1403 0x0014 => {
1404 match decode_unoccupied_heating_setpoint(tlv_value) {
1405 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1406 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1407 }
1408 }
1409 0x0015 => {
1410 match decode_min_heat_setpoint_limit(tlv_value) {
1411 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1412 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1413 }
1414 }
1415 0x0016 => {
1416 match decode_max_heat_setpoint_limit(tlv_value) {
1417 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1418 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1419 }
1420 }
1421 0x0017 => {
1422 match decode_min_cool_setpoint_limit(tlv_value) {
1423 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1424 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1425 }
1426 }
1427 0x0018 => {
1428 match decode_max_cool_setpoint_limit(tlv_value) {
1429 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1430 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1431 }
1432 }
1433 0x0019 => {
1434 match decode_min_setpoint_dead_band(tlv_value) {
1435 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1436 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1437 }
1438 }
1439 0x001A => {
1440 match decode_remote_sensing(tlv_value) {
1441 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1442 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1443 }
1444 }
1445 0x001B => {
1446 match decode_control_sequence_of_operation(tlv_value) {
1447 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1448 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1449 }
1450 }
1451 0x001C => {
1452 match decode_system_mode(tlv_value) {
1453 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1454 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1455 }
1456 }
1457 0x001E => {
1458 match decode_thermostat_running_mode(tlv_value) {
1459 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1460 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1461 }
1462 }
1463 0x0023 => {
1464 match decode_temperature_setpoint_hold(tlv_value) {
1465 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1466 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1467 }
1468 }
1469 0x0024 => {
1470 match decode_temperature_setpoint_hold_duration(tlv_value) {
1471 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1472 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1473 }
1474 }
1475 0x0025 => {
1476 match decode_thermostat_programming_operation_mode(tlv_value) {
1477 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1478 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1479 }
1480 }
1481 0x0029 => {
1482 match decode_thermostat_running_state(tlv_value) {
1483 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1484 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1485 }
1486 }
1487 0x0030 => {
1488 match decode_setpoint_change_source(tlv_value) {
1489 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1490 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1491 }
1492 }
1493 0x0031 => {
1494 match decode_setpoint_change_amount(tlv_value) {
1495 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1496 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1497 }
1498 }
1499 0x0032 => {
1500 match decode_setpoint_change_source_timestamp(tlv_value) {
1501 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1502 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1503 }
1504 }
1505 0x0034 => {
1506 match decode_occupied_setback(tlv_value) {
1507 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1508 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1509 }
1510 }
1511 0x0035 => {
1512 match decode_occupied_setback_min(tlv_value) {
1513 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1514 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1515 }
1516 }
1517 0x0036 => {
1518 match decode_occupied_setback_max(tlv_value) {
1519 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1520 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1521 }
1522 }
1523 0x0037 => {
1524 match decode_unoccupied_setback(tlv_value) {
1525 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1526 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1527 }
1528 }
1529 0x0038 => {
1530 match decode_unoccupied_setback_min(tlv_value) {
1531 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1532 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1533 }
1534 }
1535 0x0039 => {
1536 match decode_unoccupied_setback_max(tlv_value) {
1537 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1538 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1539 }
1540 }
1541 0x003A => {
1542 match decode_emergency_heat_delta(tlv_value) {
1543 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1544 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1545 }
1546 }
1547 0x0040 => {
1548 match decode_ac_type(tlv_value) {
1549 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1550 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1551 }
1552 }
1553 0x0041 => {
1554 match decode_ac_capacity(tlv_value) {
1555 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1556 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1557 }
1558 }
1559 0x0042 => {
1560 match decode_ac_refrigerant_type(tlv_value) {
1561 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1562 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1563 }
1564 }
1565 0x0043 => {
1566 match decode_ac_compressor_type(tlv_value) {
1567 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1568 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1569 }
1570 }
1571 0x0044 => {
1572 match decode_ac_error_code(tlv_value) {
1573 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1574 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1575 }
1576 }
1577 0x0045 => {
1578 match decode_aclouver_position(tlv_value) {
1579 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1580 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1581 }
1582 }
1583 0x0046 => {
1584 match decode_ac_coil_temperature(tlv_value) {
1585 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1586 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1587 }
1588 }
1589 0x0047 => {
1590 match decode_ac_capacity_format(tlv_value) {
1591 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1592 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1593 }
1594 }
1595 0x0048 => {
1596 match decode_preset_types(tlv_value) {
1597 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1598 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1599 }
1600 }
1601 0x0049 => {
1602 match decode_schedule_types(tlv_value) {
1603 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1604 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1605 }
1606 }
1607 0x004A => {
1608 match decode_number_of_presets(tlv_value) {
1609 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1610 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1611 }
1612 }
1613 0x004B => {
1614 match decode_number_of_schedules(tlv_value) {
1615 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1616 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1617 }
1618 }
1619 0x004C => {
1620 match decode_number_of_schedule_transitions(tlv_value) {
1621 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1622 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1623 }
1624 }
1625 0x004D => {
1626 match decode_number_of_schedule_transition_per_day(tlv_value) {
1627 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1628 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1629 }
1630 }
1631 0x004E => {
1632 match decode_active_preset_handle(tlv_value) {
1633 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1634 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1635 }
1636 }
1637 0x004F => {
1638 match decode_active_schedule_handle(tlv_value) {
1639 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1640 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1641 }
1642 }
1643 0x0050 => {
1644 match decode_presets(tlv_value) {
1645 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1646 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1647 }
1648 }
1649 0x0051 => {
1650 match decode_schedules(tlv_value) {
1651 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1652 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1653 }
1654 }
1655 0x0052 => {
1656 match decode_setpoint_hold_expiry_timestamp(tlv_value) {
1657 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1658 Err(e) => format!("{{\"error\": \"{}\"}}", e),
1659 }
1660 }
1661 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
1662 }
1663}
1664
1665pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
1670 vec![
1671 (0x0000, "LocalTemperature"),
1672 (0x0001, "OutdoorTemperature"),
1673 (0x0002, "Occupancy"),
1674 (0x0003, "AbsMinHeatSetpointLimit"),
1675 (0x0004, "AbsMaxHeatSetpointLimit"),
1676 (0x0005, "AbsMinCoolSetpointLimit"),
1677 (0x0006, "AbsMaxCoolSetpointLimit"),
1678 (0x0007, "PICoolingDemand"),
1679 (0x0008, "PIHeatingDemand"),
1680 (0x0009, "HVACSystemTypeConfiguration"),
1681 (0x0010, "LocalTemperatureCalibration"),
1682 (0x0011, "OccupiedCoolingSetpoint"),
1683 (0x0012, "OccupiedHeatingSetpoint"),
1684 (0x0013, "UnoccupiedCoolingSetpoint"),
1685 (0x0014, "UnoccupiedHeatingSetpoint"),
1686 (0x0015, "MinHeatSetpointLimit"),
1687 (0x0016, "MaxHeatSetpointLimit"),
1688 (0x0017, "MinCoolSetpointLimit"),
1689 (0x0018, "MaxCoolSetpointLimit"),
1690 (0x0019, "MinSetpointDeadBand"),
1691 (0x001A, "RemoteSensing"),
1692 (0x001B, "ControlSequenceOfOperation"),
1693 (0x001C, "SystemMode"),
1694 (0x001E, "ThermostatRunningMode"),
1695 (0x0023, "TemperatureSetpointHold"),
1696 (0x0024, "TemperatureSetpointHoldDuration"),
1697 (0x0025, "ThermostatProgrammingOperationMode"),
1698 (0x0029, "ThermostatRunningState"),
1699 (0x0030, "SetpointChangeSource"),
1700 (0x0031, "SetpointChangeAmount"),
1701 (0x0032, "SetpointChangeSourceTimestamp"),
1702 (0x0034, "OccupiedSetback"),
1703 (0x0035, "OccupiedSetbackMin"),
1704 (0x0036, "OccupiedSetbackMax"),
1705 (0x0037, "UnoccupiedSetback"),
1706 (0x0038, "UnoccupiedSetbackMin"),
1707 (0x0039, "UnoccupiedSetbackMax"),
1708 (0x003A, "EmergencyHeatDelta"),
1709 (0x0040, "ACType"),
1710 (0x0041, "ACCapacity"),
1711 (0x0042, "ACRefrigerantType"),
1712 (0x0043, "ACCompressorType"),
1713 (0x0044, "ACErrorCode"),
1714 (0x0045, "ACLouverPosition"),
1715 (0x0046, "ACCoilTemperature"),
1716 (0x0047, "ACCapacityFormat"),
1717 (0x0048, "PresetTypes"),
1718 (0x0049, "ScheduleTypes"),
1719 (0x004A, "NumberOfPresets"),
1720 (0x004B, "NumberOfSchedules"),
1721 (0x004C, "NumberOfScheduleTransitions"),
1722 (0x004D, "NumberOfScheduleTransitionPerDay"),
1723 (0x004E, "ActivePresetHandle"),
1724 (0x004F, "ActiveScheduleHandle"),
1725 (0x0050, "Presets"),
1726 (0x0051, "Schedules"),
1727 (0x0052, "SetpointHoldExpiryTimestamp"),
1728 ]
1729}
1730
1731pub fn get_command_list() -> Vec<(u32, &'static str)> {
1734 vec![
1735 (0x00, "SetpointRaiseLower"),
1736 (0x05, "SetActiveScheduleRequest"),
1737 (0x06, "SetActivePresetRequest"),
1738 ]
1739}
1740
1741pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
1742 match cmd_id {
1743 0x00 => Some("SetpointRaiseLower"),
1744 0x05 => Some("SetActiveScheduleRequest"),
1745 0x06 => Some("SetActivePresetRequest"),
1746 _ => None,
1747 }
1748}
1749
1750pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
1751 match cmd_id {
1752 0x00 => Some(vec![
1753 crate::clusters::codec::CommandField { tag: 0, name: "mode", kind: crate::clusters::codec::FieldKind::Enum { name: "SetpointRaiseLowerMode", variants: &[(0, "Heat"), (1, "Cool"), (2, "Both")] }, optional: false, nullable: false },
1754 crate::clusters::codec::CommandField { tag: 1, name: "amount", kind: crate::clusters::codec::FieldKind::I8, optional: false, nullable: false },
1755 ]),
1756 0x05 => Some(vec![
1757 crate::clusters::codec::CommandField { tag: 0, name: "schedule_handle", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
1758 ]),
1759 0x06 => Some(vec![
1760 crate::clusters::codec::CommandField { tag: 0, name: "preset_handle", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: true },
1761 ]),
1762 _ => None,
1763 }
1764}
1765
1766pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
1767 match cmd_id {
1768 0x00 => {
1769 let mode = {
1770 let n = crate::clusters::codec::json_util::get_u64(args, "mode")?;
1771 SetpointRaiseLowerMode::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid SetpointRaiseLowerMode: {}", n))?
1772 };
1773 let amount = crate::clusters::codec::json_util::get_i8(args, "amount")?;
1774 encode_setpoint_raise_lower(mode, amount)
1775 }
1776 0x05 => {
1777 let schedule_handle = crate::clusters::codec::json_util::get_octstr(args, "schedule_handle")?;
1778 encode_set_active_schedule_request(schedule_handle)
1779 }
1780 0x06 => {
1781 let preset_handle = crate::clusters::codec::json_util::get_opt_octstr(args, "preset_handle")?;
1782 encode_set_active_preset_request(preset_handle)
1783 }
1784 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
1785 }
1786}
1787
1788pub async fn setpoint_raise_lower(conn: &crate::controller::Connection, endpoint: u16, mode: SetpointRaiseLowerMode, amount: i8) -> anyhow::Result<()> {
1792 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_CMD_ID_SETPOINTRAISELOWER, &encode_setpoint_raise_lower(mode, amount)?).await?;
1793 Ok(())
1794}
1795
1796pub async fn set_active_schedule_request(conn: &crate::controller::Connection, endpoint: u16, schedule_handle: Vec<u8>) -> anyhow::Result<()> {
1798 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_CMD_ID_SETACTIVESCHEDULEREQUEST, &encode_set_active_schedule_request(schedule_handle)?).await?;
1799 Ok(())
1800}
1801
1802pub async fn set_active_preset_request(conn: &crate::controller::Connection, endpoint: u16, preset_handle: Option<Vec<u8>>) -> anyhow::Result<()> {
1804 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_CMD_ID_SETACTIVEPRESETREQUEST, &encode_set_active_preset_request(preset_handle)?).await?;
1805 Ok(())
1806}
1807
1808pub async fn read_local_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i16>> {
1810 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_LOCALTEMPERATURE).await?;
1811 decode_local_temperature(&tlv)
1812}
1813
1814pub async fn read_outdoor_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i16>> {
1816 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OUTDOORTEMPERATURE).await?;
1817 decode_outdoor_temperature(&tlv)
1818}
1819
1820pub async fn read_occupancy(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Occupancy> {
1822 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPANCY).await?;
1823 decode_occupancy(&tlv)
1824}
1825
1826pub async fn read_abs_min_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1828 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMINHEATSETPOINTLIMIT).await?;
1829 decode_abs_min_heat_setpoint_limit(&tlv)
1830}
1831
1832pub async fn read_abs_max_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1834 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMAXHEATSETPOINTLIMIT).await?;
1835 decode_abs_max_heat_setpoint_limit(&tlv)
1836}
1837
1838pub async fn read_abs_min_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1840 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMINCOOLSETPOINTLIMIT).await?;
1841 decode_abs_min_cool_setpoint_limit(&tlv)
1842}
1843
1844pub async fn read_abs_max_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1846 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ABSMAXCOOLSETPOINTLIMIT).await?;
1847 decode_abs_max_cool_setpoint_limit(&tlv)
1848}
1849
1850pub async fn read_pi_cooling_demand(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1852 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PICOOLINGDEMAND).await?;
1853 decode_pi_cooling_demand(&tlv)
1854}
1855
1856pub async fn read_pi_heating_demand(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1858 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PIHEATINGDEMAND).await?;
1859 decode_pi_heating_demand(&tlv)
1860}
1861
1862pub async fn read_hvac_system_type_configuration(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1864 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_HVACSYSTEMTYPECONFIGURATION).await?;
1865 decode_hvac_system_type_configuration(&tlv)
1866}
1867
1868pub async fn read_local_temperature_calibration(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1870 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_LOCALTEMPERATURECALIBRATION).await?;
1871 decode_local_temperature_calibration(&tlv)
1872}
1873
1874pub async fn read_occupied_cooling_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1876 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDCOOLINGSETPOINT).await?;
1877 decode_occupied_cooling_setpoint(&tlv)
1878}
1879
1880pub async fn read_occupied_heating_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1882 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDHEATINGSETPOINT).await?;
1883 decode_occupied_heating_setpoint(&tlv)
1884}
1885
1886pub async fn read_unoccupied_cooling_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1888 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDCOOLINGSETPOINT).await?;
1889 decode_unoccupied_cooling_setpoint(&tlv)
1890}
1891
1892pub async fn read_unoccupied_heating_setpoint(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1894 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDHEATINGSETPOINT).await?;
1895 decode_unoccupied_heating_setpoint(&tlv)
1896}
1897
1898pub async fn read_min_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1900 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MINHEATSETPOINTLIMIT).await?;
1901 decode_min_heat_setpoint_limit(&tlv)
1902}
1903
1904pub async fn read_max_heat_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1906 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MAXHEATSETPOINTLIMIT).await?;
1907 decode_max_heat_setpoint_limit(&tlv)
1908}
1909
1910pub async fn read_min_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1912 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MINCOOLSETPOINTLIMIT).await?;
1913 decode_min_cool_setpoint_limit(&tlv)
1914}
1915
1916pub async fn read_max_cool_setpoint_limit(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
1918 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MAXCOOLSETPOINTLIMIT).await?;
1919 decode_max_cool_setpoint_limit(&tlv)
1920}
1921
1922pub async fn read_min_setpoint_dead_band(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1924 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_MINSETPOINTDEADBAND).await?;
1925 decode_min_setpoint_dead_band(&tlv)
1926}
1927
1928pub async fn read_remote_sensing(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<RemoteSensing> {
1930 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_REMOTESENSING).await?;
1931 decode_remote_sensing(&tlv)
1932}
1933
1934pub async fn read_control_sequence_of_operation(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ControlSequenceOfOperation> {
1936 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_CONTROLSEQUENCEOFOPERATION).await?;
1937 decode_control_sequence_of_operation(&tlv)
1938}
1939
1940pub async fn read_system_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<SystemMode> {
1942 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SYSTEMMODE).await?;
1943 decode_system_mode(&tlv)
1944}
1945
1946pub async fn read_thermostat_running_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ThermostatRunningMode> {
1948 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_THERMOSTATRUNNINGMODE).await?;
1949 decode_thermostat_running_mode(&tlv)
1950}
1951
1952pub async fn read_temperature_setpoint_hold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TemperatureSetpointHold> {
1954 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_TEMPERATURESETPOINTHOLD).await?;
1955 decode_temperature_setpoint_hold(&tlv)
1956}
1957
1958pub async fn read_temperature_setpoint_hold_duration(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u16>> {
1960 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_TEMPERATURESETPOINTHOLDDURATION).await?;
1961 decode_temperature_setpoint_hold_duration(&tlv)
1962}
1963
1964pub async fn read_thermostat_programming_operation_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ProgrammingOperationMode> {
1966 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_THERMOSTATPROGRAMMINGOPERATIONMODE).await?;
1967 decode_thermostat_programming_operation_mode(&tlv)
1968}
1969
1970pub async fn read_thermostat_running_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<RelayState> {
1972 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_THERMOSTATRUNNINGSTATE).await?;
1973 decode_thermostat_running_state(&tlv)
1974}
1975
1976pub async fn read_setpoint_change_source(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<SetpointChangeSource> {
1978 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTCHANGESOURCE).await?;
1979 decode_setpoint_change_source(&tlv)
1980}
1981
1982pub async fn read_setpoint_change_amount(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
1984 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTCHANGEAMOUNT).await?;
1985 decode_setpoint_change_amount(&tlv)
1986}
1987
1988pub async fn read_setpoint_change_source_timestamp(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u64> {
1990 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTCHANGESOURCETIMESTAMP).await?;
1991 decode_setpoint_change_source_timestamp(&tlv)
1992}
1993
1994pub async fn read_occupied_setback(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1996 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDSETBACK).await?;
1997 decode_occupied_setback(&tlv)
1998}
1999
2000pub async fn read_occupied_setback_min(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2002 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDSETBACKMIN).await?;
2003 decode_occupied_setback_min(&tlv)
2004}
2005
2006pub async fn read_occupied_setback_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2008 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_OCCUPIEDSETBACKMAX).await?;
2009 decode_occupied_setback_max(&tlv)
2010}
2011
2012pub async fn read_unoccupied_setback(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2014 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDSETBACK).await?;
2015 decode_unoccupied_setback(&tlv)
2016}
2017
2018pub async fn read_unoccupied_setback_min(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2020 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDSETBACKMIN).await?;
2021 decode_unoccupied_setback_min(&tlv)
2022}
2023
2024pub async fn read_unoccupied_setback_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2026 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_UNOCCUPIEDSETBACKMAX).await?;
2027 decode_unoccupied_setback_max(&tlv)
2028}
2029
2030pub async fn read_emergency_heat_delta(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2032 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_EMERGENCYHEATDELTA).await?;
2033 decode_emergency_heat_delta(&tlv)
2034}
2035
2036pub async fn read_ac_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACType> {
2038 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACTYPE).await?;
2039 decode_ac_type(&tlv)
2040}
2041
2042pub async fn read_ac_capacity(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
2044 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCAPACITY).await?;
2045 decode_ac_capacity(&tlv)
2046}
2047
2048pub async fn read_ac_refrigerant_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACRefrigerantType> {
2050 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACREFRIGERANTTYPE).await?;
2051 decode_ac_refrigerant_type(&tlv)
2052}
2053
2054pub async fn read_ac_compressor_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACCompressorType> {
2056 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCOMPRESSORTYPE).await?;
2057 decode_ac_compressor_type(&tlv)
2058}
2059
2060pub async fn read_ac_error_code(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACErrorCode> {
2062 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACERRORCODE).await?;
2063 decode_ac_error_code(&tlv)
2064}
2065
2066pub async fn read_aclouver_position(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACLouverPosition> {
2068 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACLOUVERPOSITION).await?;
2069 decode_aclouver_position(&tlv)
2070}
2071
2072pub async fn read_ac_coil_temperature(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i16>> {
2074 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCOILTEMPERATURE).await?;
2075 decode_ac_coil_temperature(&tlv)
2076}
2077
2078pub async fn read_ac_capacity_format(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ACCapacityFormat> {
2080 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACCAPACITYFORMAT).await?;
2081 decode_ac_capacity_format(&tlv)
2082}
2083
2084pub async fn read_preset_types(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<PresetType>> {
2086 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PRESETTYPES).await?;
2087 decode_preset_types(&tlv)
2088}
2089
2090pub async fn read_schedule_types(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<ScheduleType>> {
2092 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SCHEDULETYPES).await?;
2093 decode_schedule_types(&tlv)
2094}
2095
2096pub async fn read_number_of_presets(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2098 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFPRESETS).await?;
2099 decode_number_of_presets(&tlv)
2100}
2101
2102pub async fn read_number_of_schedules(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2104 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFSCHEDULES).await?;
2105 decode_number_of_schedules(&tlv)
2106}
2107
2108pub async fn read_number_of_schedule_transitions(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
2110 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFSCHEDULETRANSITIONS).await?;
2111 decode_number_of_schedule_transitions(&tlv)
2112}
2113
2114pub async fn read_number_of_schedule_transition_per_day(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u8>> {
2116 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_NUMBEROFSCHEDULETRANSITIONPERDAY).await?;
2117 decode_number_of_schedule_transition_per_day(&tlv)
2118}
2119
2120pub async fn read_active_preset_handle(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
2122 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACTIVEPRESETHANDLE).await?;
2123 decode_active_preset_handle(&tlv)
2124}
2125
2126pub async fn read_active_schedule_handle(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
2128 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_ACTIVESCHEDULEHANDLE).await?;
2129 decode_active_schedule_handle(&tlv)
2130}
2131
2132pub async fn read_presets(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Preset>> {
2134 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_PRESETS).await?;
2135 decode_presets(&tlv)
2136}
2137
2138pub async fn read_schedules(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<Schedule>> {
2140 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SCHEDULES).await?;
2141 decode_schedules(&tlv)
2142}
2143
2144pub async fn read_setpoint_hold_expiry_timestamp(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u64>> {
2146 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT, crate::clusters::defs::CLUSTER_THERMOSTAT_ATTR_ID_SETPOINTHOLDEXPIRYTIMESTAMP).await?;
2147 decode_setpoint_hold_expiry_timestamp(&tlv)
2148}
2149