matc/clusters/codec/
thermostat.rs

1//! Matter TLV encoders and decoders for Thermostat Cluster
2//! Cluster ID: 0x0201
3//!
4//! This file is automatically generated from Thermostat.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Import serialization helpers for octet strings
14use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16// Enum definitions
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum ACCapacityFormat {
21    /// British Thermal Unit per Hour
22    Btuh = 0,
23}
24
25impl ACCapacityFormat {
26    /// Convert from u8 value
27    pub fn from_u8(value: u8) -> Option<Self> {
28        match value {
29            0 => Some(ACCapacityFormat::Btuh),
30            _ => None,
31        }
32    }
33
34    /// Convert to u8 value
35    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 compressor type
50    Unknown = 0,
51    /// Max working ambient 43 °C
52    T1 = 1,
53    /// Max working ambient 35 °C
54    T2 = 2,
55    /// Max working ambient 52 °C
56    T3 = 3,
57}
58
59impl ACCompressorType {
60    /// Convert from u8 value
61    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    /// Convert to u8 value
72    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    /// Fully Closed
87    Closed = 1,
88    /// Fully Open
89    Open = 2,
90    /// Quarter Open
91    Quarter = 3,
92    /// Half Open
93    Half = 4,
94    /// Three Quarters Open
95    Threequarters = 5,
96}
97
98impl ACLouverPosition {
99    /// Convert from u8 value
100    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    /// Convert to u8 value
112    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 Refrigerant Type
127    Unknown = 0,
128    /// R22 Refrigerant
129    R22 = 1,
130    /// R410a Refrigerant
131    R410a = 2,
132    /// R407c Refrigerant
133    R407c = 3,
134}
135
136impl ACRefrigerantType {
137    /// Convert from u8 value
138    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    /// Convert to u8 value
149    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 AC Type
164    Unknown = 0,
165    /// Cooling and Fixed Speed
166    Coolingfixed = 1,
167    /// Heat Pump and Fixed Speed
168    Heatpumpfixed = 2,
169    /// Cooling and Inverter
170    Coolinginverter = 3,
171    /// Heat Pump and Inverter
172    Heatpumpinverter = 4,
173}
174
175impl ACType {
176    /// Convert from u8 value
177    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    /// Convert to u8 value
189    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    /// Heat and Emergency are not possible
204    Coolingonly = 0,
205    /// Heat and Emergency are not possible
206    Coolingwithreheat = 1,
207    /// Cool and precooling (see Terms) are not possible
208    Heatingonly = 2,
209    /// Cool and precooling are not possible
210    Heatingwithreheat = 3,
211    /// All modes are possible
212    Coolingandheating = 4,
213    /// All modes are possible
214    Coolingandheatingwithreheat = 5,
215}
216
217impl ControlSequenceOfOperation {
218    /// Convert from u8 value
219    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    /// Convert to u8 value
232    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    /// The thermostat-controlled area is occupied
247    Occupied = 1,
248    /// The thermostat-controlled area is unoccupied
249    Unoccupied = 2,
250    /// Users are likely to be sleeping
251    Sleep = 3,
252    /// Users are likely to be waking up
253    Wake = 4,
254    /// Users are on vacation
255    Vacation = 5,
256    /// Users are likely to be going to sleep
257    Goingtosleep = 6,
258    /// Custom presets
259    Userdefined = 254,
260}
261
262impl PresetScenario {
263    /// Convert from u8 value
264    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    /// Convert to u8 value
278    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, user-initiated setpoint change via the thermostat
293    Manual = 0,
294    /// Schedule/internal programming-initiated setpoint change
295    Schedule = 1,
296    /// Externally-initiated setpoint change (e.g., DRLC cluster command, attribute write)
297    External = 2,
298}
299
300impl SetpointChangeSource {
301    /// Convert from u8 value
302    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    /// Convert to u8 value
312    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    /// Adjust Heat Setpoint
327    Heat = 0,
328    /// Adjust Cool Setpoint
329    Cool = 1,
330    /// Adjust Heat Setpoint and Cool Setpoint
331    Both = 2,
332}
333
334impl SetpointRaiseLowerMode {
335    /// Convert from u8 value
336    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    /// Convert to u8 value
346    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    /// Convert from u8 value
371    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    /// Convert to u8 value
385    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    /// The Thermostat does not generate demand for Cooling or Heating
400    Off = 0,
401    /// Demand is generated for either Cooling or Heating, as required
402    Auto = 1,
403    /// Demand is only generated for Cooling
404    Cool = 3,
405    /// Demand is only generated for Heating
406    Heat = 4,
407    /// 2nd stage heating is in use to achieve desired temperature
408    Emergencyheat = 5,
409    /// (see Terms)
410    Precooling = 6,
411    Fanonly = 7,
412    Dry = 8,
413    Sleep = 9,
414}
415
416impl SystemMode {
417    /// Convert from u8 value
418    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    /// Convert to u8 value
434    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    /// Follow scheduling program
449    Setpointholdoff = 0,
450    /// Maintain current setpoint, regardless of schedule transitions
451    Setpointholdon = 1,
452}
453
454impl TemperatureSetpointHold {
455    /// Convert from u8 value
456    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    /// Convert to u8 value
465    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    /// The Thermostat does not generate demand for Cooling or Heating
480    Off = 0,
481    /// Demand is only generated for Cooling
482    Cool = 3,
483    /// Demand is only generated for Heating
484    Heat = 4,
485}
486
487impl ThermostatRunningMode {
488    /// Convert from u8 value
489    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    /// Convert to u8 value
499    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
510// Bitmap definitions
511
512/// ACErrorCode bitmap type
513pub type ACErrorCode = u8;
514
515/// Constants for ACErrorCode
516pub mod acerrorcode {
517    /// Compressor Failure or Refrigerant Leakage
518    pub const COMPRESSOR_FAIL: u8 = 0x01;
519    /// Room Temperature Sensor Failure
520    pub const ROOM_SENSOR_FAIL: u8 = 0x02;
521    /// Outdoor Temperature Sensor Failure
522    pub const OUTDOOR_SENSOR_FAIL: u8 = 0x04;
523    /// Indoor Coil Temperature Sensor Failure
524    pub const COIL_SENSOR_FAIL: u8 = 0x08;
525    /// Fan Failure
526    pub const FAN_FAIL: u8 = 0x10;
527}
528
529/// Occupancy bitmap type
530pub type Occupancy = u8;
531
532/// Constants for Occupancy
533pub mod occupancy {
534    /// Indicates the occupancy state
535    pub const OCCUPIED: u8 = 0x01;
536}
537
538/// PresetTypeFeatures bitmap type
539pub type PresetTypeFeatures = u8;
540
541/// Constants for PresetTypeFeatures
542pub mod presettypefeatures {
543    /// Preset may be automatically activated by the thermostat
544    pub const AUTOMATIC: u8 = 0x01;
545    /// Preset supports user-provided names
546    pub const SUPPORTS_NAMES: u8 = 0x02;
547}
548
549/// ProgrammingOperationMode bitmap type
550pub type ProgrammingOperationMode = u8;
551
552/// Constants for ProgrammingOperationMode
553pub mod programmingoperationmode {
554    /// Schedule programming mode. This enables any programmed weekly schedule configurations.
555    pub const SCHEDULE_ACTIVE: u8 = 0x01;
556    /// Auto/recovery mode
557    pub const AUTO_RECOVERY: u8 = 0x02;
558    /// Economy/EnergyStar mode
559    pub const ECONOMY: u8 = 0x04;
560}
561
562/// RelayState bitmap type
563pub type RelayState = u8;
564
565/// Constants for RelayState
566pub mod relaystate {
567    /// Heat Stage On
568    pub const HEAT: u8 = 0x01;
569    /// Cool Stage On
570    pub const COOL: u8 = 0x02;
571    /// Fan Stage On
572    pub const FAN: u8 = 0x04;
573    /// Heat 2nd Stage On
574    pub const HEAT_STAGE2: u8 = 0x08;
575    /// Cool 2nd Stage On
576    pub const COOL_STAGE2: u8 = 0x10;
577    /// Fan 2nd Stage On
578    pub const FAN_STAGE2: u8 = 0x20;
579    /// Fan 3rd Stage On
580    pub const FAN_STAGE3: u8 = 0x40;
581}
582
583/// RemoteSensing bitmap type
584pub type RemoteSensing = u8;
585
586/// Constants for RemoteSensing
587pub mod remotesensing {
588    /// Calculated Local Temperature is derived from a remote node
589    pub const LOCAL_TEMPERATURE: u8 = 0x01;
590    /// OutdoorTemperature is derived from a remote node
591    pub const OUTDOOR_TEMPERATURE: u8 = 0x02;
592    /// Occupancy is derived from a remote node
593    pub const OCCUPANCY: u8 = 0x04;
594}
595
596/// ScheduleDayOfWeek bitmap type
597pub type ScheduleDayOfWeek = u8;
598
599/// Constants for ScheduleDayOfWeek
600pub mod scheduledayofweek {
601    /// Sunday
602    pub const SUNDAY: u8 = 0x01;
603    /// Monday
604    pub const MONDAY: u8 = 0x02;
605    /// Tuesday
606    pub const TUESDAY: u8 = 0x04;
607    /// Wednesday
608    pub const WEDNESDAY: u8 = 0x08;
609    /// Thursday
610    pub const THURSDAY: u8 = 0x10;
611    /// Friday
612    pub const FRIDAY: u8 = 0x20;
613    /// Saturday
614    pub const SATURDAY: u8 = 0x40;
615    /// Away or Vacation
616    pub const AWAY: u8 = 0x80;
617}
618
619/// ScheduleMode bitmap type
620pub type ScheduleMode = u8;
621
622/// Constants for ScheduleMode
623pub mod schedulemode {
624    /// Adjust Heat Setpoint
625    pub const HEAT_SETPOINT_PRESENT: u8 = 0x01;
626    /// Adjust Cool Setpoint
627    pub const COOL_SETPOINT_PRESENT: u8 = 0x02;
628}
629
630/// ScheduleTypeFeatures bitmap type
631pub type ScheduleTypeFeatures = u8;
632
633/// Constants for ScheduleTypeFeatures
634pub mod scheduletypefeatures {
635    /// Supports presets
636    pub const SUPPORTS_PRESETS: u8 = 0x01;
637    /// Supports setpoints
638    pub const SUPPORTS_SETPOINTS: u8 = 0x02;
639    /// Supports user-provided names
640    pub const SUPPORTS_NAMES: u8 = 0x04;
641    /// Supports transitioning to SystemModeOff
642    pub const SUPPORTS_OFF: u8 = 0x08;
643}
644
645// Struct definitions
646
647#[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
702// Command encoders
703
704/// Encode SetpointRaiseLower command (0x00)
705pub 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
716/// Encode SetActiveScheduleRequest command (0x05)
717pub 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
727/// Encode SetActivePresetRequest command (0x06)
728pub 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
738// Attribute decoders
739
740/// Decode LocalTemperature attribute (0x0000)
741pub 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
749/// Decode OutdoorTemperature attribute (0x0001)
750pub 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
758/// Decode Occupancy attribute (0x0002)
759pub 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
767/// Decode AbsMinHeatSetpointLimit attribute (0x0003)
768pub 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
776/// Decode AbsMaxHeatSetpointLimit attribute (0x0004)
777pub 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
785/// Decode AbsMinCoolSetpointLimit attribute (0x0005)
786pub 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
794/// Decode AbsMaxCoolSetpointLimit attribute (0x0006)
795pub 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
803/// Decode PICoolingDemand attribute (0x0007)
804pub 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
812/// Decode PIHeatingDemand attribute (0x0008)
813pub 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
821/// Decode HVACSystemTypeConfiguration attribute (0x0009)
822pub 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
830/// Decode LocalTemperatureCalibration attribute (0x0010)
831pub 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
839/// Decode OccupiedCoolingSetpoint attribute (0x0011)
840pub 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
848/// Decode OccupiedHeatingSetpoint attribute (0x0012)
849pub 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
857/// Decode UnoccupiedCoolingSetpoint attribute (0x0013)
858pub 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
866/// Decode UnoccupiedHeatingSetpoint attribute (0x0014)
867pub 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
875/// Decode MinHeatSetpointLimit attribute (0x0015)
876pub 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
884/// Decode MaxHeatSetpointLimit attribute (0x0016)
885pub 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
893/// Decode MinCoolSetpointLimit attribute (0x0017)
894pub 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
902/// Decode MaxCoolSetpointLimit attribute (0x0018)
903pub 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
911/// Decode MinSetpointDeadBand attribute (0x0019)
912pub 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
920/// Decode RemoteSensing attribute (0x001A)
921pub 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
929/// Decode ControlSequenceOfOperation attribute (0x001B)
930pub 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
938/// Decode SystemMode attribute (0x001C)
939pub 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
947/// Decode ThermostatRunningMode attribute (0x001E)
948pub 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
956/// Decode TemperatureSetpointHold attribute (0x0023)
957pub 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
965/// Decode TemperatureSetpointHoldDuration attribute (0x0024)
966pub 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
974/// Decode ThermostatProgrammingOperationMode attribute (0x0025)
975pub 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
983/// Decode ThermostatRunningState attribute (0x0029)
984pub 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
992/// Decode SetpointChangeSource attribute (0x0030)
993pub 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
1001/// Decode SetpointChangeAmount attribute (0x0031)
1002pub 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
1010/// Decode SetpointChangeSourceTimestamp attribute (0x0032)
1011pub 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
1019/// Decode OccupiedSetback attribute (0x0034)
1020pub 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
1028/// Decode OccupiedSetbackMin attribute (0x0035)
1029pub 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
1037/// Decode OccupiedSetbackMax attribute (0x0036)
1038pub 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
1046/// Decode UnoccupiedSetback attribute (0x0037)
1047pub 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
1055/// Decode UnoccupiedSetbackMin attribute (0x0038)
1056pub 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
1064/// Decode UnoccupiedSetbackMax attribute (0x0039)
1065pub 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
1073/// Decode EmergencyHeatDelta attribute (0x003A)
1074pub 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
1082/// Decode ACType attribute (0x0040)
1083pub 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
1091/// Decode ACCapacity attribute (0x0041)
1092pub 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
1100/// Decode ACRefrigerantType attribute (0x0042)
1101pub 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
1109/// Decode ACCompressorType attribute (0x0043)
1110pub 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
1118/// Decode ACErrorCode attribute (0x0044)
1119pub 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
1127/// Decode ACLouverPosition attribute (0x0045)
1128pub 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
1136/// Decode ACCoilTemperature attribute (0x0046)
1137pub 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
1145/// Decode ACCapacityFormat attribute (0x0047)
1146pub 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
1154/// Decode PresetTypes attribute (0x0048)
1155pub 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
1169/// Decode ScheduleTypes attribute (0x0049)
1170pub 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
1184/// Decode NumberOfPresets attribute (0x004A)
1185pub 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
1193/// Decode NumberOfSchedules attribute (0x004B)
1194pub 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
1202/// Decode NumberOfScheduleTransitions attribute (0x004C)
1203pub 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
1211/// Decode NumberOfScheduleTransitionPerDay attribute (0x004D)
1212pub 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
1220/// Decode ActivePresetHandle attribute (0x004E)
1221pub 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
1229/// Decode ActiveScheduleHandle attribute (0x004F)
1230pub 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
1238/// Decode Presets attribute (0x0050)
1239pub 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
1256/// Decode Schedules attribute (0x0051)
1257pub 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
1291/// Decode SetpointHoldExpiryTimestamp attribute (0x0052)
1292pub 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
1301// JSON dispatcher function
1302
1303/// Decode attribute value and return as JSON string
1304///
1305/// # Parameters
1306/// * `cluster_id` - The cluster identifier
1307/// * `attribute_id` - The attribute identifier
1308/// * `tlv_value` - The TLV value to decode
1309///
1310/// # Returns
1311/// JSON string representation of the decoded value or error
1312pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
1313    // Verify this is the correct cluster
1314    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
1665/// Get list of all attributes supported by this cluster
1666///
1667/// # Returns
1668/// Vector of tuples containing (attribute_id, attribute_name)
1669pub 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
1731// Command listing
1732
1733pub 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
1788// Typed facade (invokes + reads)
1789
1790/// Invoke `SetpointRaiseLower` command on cluster `Thermostat`.
1791pub 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
1796/// Invoke `SetActiveScheduleRequest` command on cluster `Thermostat`.
1797pub 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
1802/// Invoke `SetActivePresetRequest` command on cluster `Thermostat`.
1803pub 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
1808/// Read `LocalTemperature` attribute from cluster `Thermostat`.
1809pub 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
1814/// Read `OutdoorTemperature` attribute from cluster `Thermostat`.
1815pub 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
1820/// Read `Occupancy` attribute from cluster `Thermostat`.
1821pub 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
1826/// Read `AbsMinHeatSetpointLimit` attribute from cluster `Thermostat`.
1827pub 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
1832/// Read `AbsMaxHeatSetpointLimit` attribute from cluster `Thermostat`.
1833pub 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
1838/// Read `AbsMinCoolSetpointLimit` attribute from cluster `Thermostat`.
1839pub 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
1844/// Read `AbsMaxCoolSetpointLimit` attribute from cluster `Thermostat`.
1845pub 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
1850/// Read `PICoolingDemand` attribute from cluster `Thermostat`.
1851pub 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
1856/// Read `PIHeatingDemand` attribute from cluster `Thermostat`.
1857pub 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
1862/// Read `HVACSystemTypeConfiguration` attribute from cluster `Thermostat`.
1863pub 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
1868/// Read `LocalTemperatureCalibration` attribute from cluster `Thermostat`.
1869pub 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
1874/// Read `OccupiedCoolingSetpoint` attribute from cluster `Thermostat`.
1875pub 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
1880/// Read `OccupiedHeatingSetpoint` attribute from cluster `Thermostat`.
1881pub 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
1886/// Read `UnoccupiedCoolingSetpoint` attribute from cluster `Thermostat`.
1887pub 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
1892/// Read `UnoccupiedHeatingSetpoint` attribute from cluster `Thermostat`.
1893pub 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
1898/// Read `MinHeatSetpointLimit` attribute from cluster `Thermostat`.
1899pub 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
1904/// Read `MaxHeatSetpointLimit` attribute from cluster `Thermostat`.
1905pub 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
1910/// Read `MinCoolSetpointLimit` attribute from cluster `Thermostat`.
1911pub 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
1916/// Read `MaxCoolSetpointLimit` attribute from cluster `Thermostat`.
1917pub 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
1922/// Read `MinSetpointDeadBand` attribute from cluster `Thermostat`.
1923pub 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
1928/// Read `RemoteSensing` attribute from cluster `Thermostat`.
1929pub 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
1934/// Read `ControlSequenceOfOperation` attribute from cluster `Thermostat`.
1935pub 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
1940/// Read `SystemMode` attribute from cluster `Thermostat`.
1941pub 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
1946/// Read `ThermostatRunningMode` attribute from cluster `Thermostat`.
1947pub 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
1952/// Read `TemperatureSetpointHold` attribute from cluster `Thermostat`.
1953pub 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
1958/// Read `TemperatureSetpointHoldDuration` attribute from cluster `Thermostat`.
1959pub 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
1964/// Read `ThermostatProgrammingOperationMode` attribute from cluster `Thermostat`.
1965pub 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
1970/// Read `ThermostatRunningState` attribute from cluster `Thermostat`.
1971pub 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
1976/// Read `SetpointChangeSource` attribute from cluster `Thermostat`.
1977pub 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
1982/// Read `SetpointChangeAmount` attribute from cluster `Thermostat`.
1983pub 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
1988/// Read `SetpointChangeSourceTimestamp` attribute from cluster `Thermostat`.
1989pub 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
1994/// Read `OccupiedSetback` attribute from cluster `Thermostat`.
1995pub 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
2000/// Read `OccupiedSetbackMin` attribute from cluster `Thermostat`.
2001pub 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
2006/// Read `OccupiedSetbackMax` attribute from cluster `Thermostat`.
2007pub 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
2012/// Read `UnoccupiedSetback` attribute from cluster `Thermostat`.
2013pub 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
2018/// Read `UnoccupiedSetbackMin` attribute from cluster `Thermostat`.
2019pub 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
2024/// Read `UnoccupiedSetbackMax` attribute from cluster `Thermostat`.
2025pub 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
2030/// Read `EmergencyHeatDelta` attribute from cluster `Thermostat`.
2031pub 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
2036/// Read `ACType` attribute from cluster `Thermostat`.
2037pub 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
2042/// Read `ACCapacity` attribute from cluster `Thermostat`.
2043pub 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
2048/// Read `ACRefrigerantType` attribute from cluster `Thermostat`.
2049pub 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
2054/// Read `ACCompressorType` attribute from cluster `Thermostat`.
2055pub 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
2060/// Read `ACErrorCode` attribute from cluster `Thermostat`.
2061pub 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
2066/// Read `ACLouverPosition` attribute from cluster `Thermostat`.
2067pub 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
2072/// Read `ACCoilTemperature` attribute from cluster `Thermostat`.
2073pub 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
2078/// Read `ACCapacityFormat` attribute from cluster `Thermostat`.
2079pub 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
2084/// Read `PresetTypes` attribute from cluster `Thermostat`.
2085pub 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
2090/// Read `ScheduleTypes` attribute from cluster `Thermostat`.
2091pub 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
2096/// Read `NumberOfPresets` attribute from cluster `Thermostat`.
2097pub 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
2102/// Read `NumberOfSchedules` attribute from cluster `Thermostat`.
2103pub 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
2108/// Read `NumberOfScheduleTransitions` attribute from cluster `Thermostat`.
2109pub 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
2114/// Read `NumberOfScheduleTransitionPerDay` attribute from cluster `Thermostat`.
2115pub 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
2120/// Read `ActivePresetHandle` attribute from cluster `Thermostat`.
2121pub 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
2126/// Read `ActiveScheduleHandle` attribute from cluster `Thermostat`.
2127pub 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
2132/// Read `Presets` attribute from cluster `Thermostat`.
2133pub 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
2138/// Read `Schedules` attribute from cluster `Thermostat`.
2139pub 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
2144/// Read `SetpointHoldExpiryTimestamp` attribute from cluster `Thermostat`.
2145pub 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