matc/clusters/codec/
thermostat.rs

1//! Generated Matter TLV encoders and decoders for Thermostat Cluster
2//! Cluster ID: 0x0201
3//! 
4//! This file is automatically generated from Thermostat.xml
5
6use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11// Struct definitions
12
13#[derive(Debug, serde::Serialize)]
14pub struct Preset {
15    pub preset_handle: Option<Vec<u8>>,
16    pub preset_scenario: Option<u8>,
17    pub name: Option<String>,
18    pub cooling_setpoint: Option<u8>,
19    pub heating_setpoint: Option<u8>,
20    pub built_in: Option<bool>,
21}
22
23#[derive(Debug, serde::Serialize)]
24pub struct PresetType {
25    pub preset_scenario: Option<u8>,
26    pub number_of_presets: Option<u8>,
27    pub preset_type_features: Option<u8>,
28}
29
30#[derive(Debug, serde::Serialize)]
31pub struct Schedule {
32    pub schedule_handle: Option<Vec<u8>>,
33    pub system_mode: Option<u8>,
34    pub name: Option<String>,
35    pub preset_handle: Option<Vec<u8>>,
36    pub transitions: Option<Vec<ScheduleTransition>>,
37    pub built_in: Option<bool>,
38}
39
40#[derive(Debug, serde::Serialize)]
41pub struct ScheduleTransition {
42    pub day_of_week: Option<u8>,
43    pub transition_time: Option<u16>,
44    pub preset_handle: Option<Vec<u8>>,
45    pub system_mode: Option<u8>,
46    pub cooling_setpoint: Option<u8>,
47    pub heating_setpoint: Option<u8>,
48}
49
50#[derive(Debug, serde::Serialize)]
51pub struct ScheduleType {
52    pub system_mode: Option<u8>,
53    pub number_of_schedules: Option<u8>,
54    pub schedule_type_features: Option<u8>,
55}
56
57#[derive(Debug, serde::Serialize)]
58pub struct WeeklyScheduleTransition {
59    pub transition_time: Option<u16>,
60    pub heat_setpoint: Option<u8>,
61    pub cool_setpoint: Option<u8>,
62}
63
64// Command encoders
65
66/// Encode SetpointRaiseLower command (0x00)
67pub fn encode_setpoint_raise_lower(mode: u8, amount: i8) -> anyhow::Result<Vec<u8>> {
68    let tlv = tlv::TlvItemEnc {
69        tag: 0,
70        value: tlv::TlvItemValueEnc::StructInvisible(vec![
71        (0, tlv::TlvItemValueEnc::UInt8(mode)).into(),
72        (1, tlv::TlvItemValueEnc::Int8(amount)).into(),
73        ]),
74    };
75    Ok(tlv.encode()?)
76}
77
78/// Encode SetWeeklySchedule command (0x01)
79pub fn encode_set_weekly_schedule(number_of_transitions_for_sequence: u8, day_of_week_for_sequence: u8, mode_for_sequence: u8, transitions: Vec<u8>) -> anyhow::Result<Vec<u8>> {
80    let tlv = tlv::TlvItemEnc {
81        tag: 0,
82        value: tlv::TlvItemValueEnc::StructInvisible(vec![
83        (0, tlv::TlvItemValueEnc::UInt8(number_of_transitions_for_sequence)).into(),
84        (1, tlv::TlvItemValueEnc::UInt8(day_of_week_for_sequence)).into(),
85        (2, tlv::TlvItemValueEnc::UInt8(mode_for_sequence)).into(),
86        (3, tlv::TlvItemValueEnc::StructAnon(transitions.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
87        ]),
88    };
89    Ok(tlv.encode()?)
90}
91
92/// Encode GetWeeklySchedule command (0x02)
93pub fn encode_get_weekly_schedule(days_to_return: u8, mode_to_return: u8) -> anyhow::Result<Vec<u8>> {
94    let tlv = tlv::TlvItemEnc {
95        tag: 0,
96        value: tlv::TlvItemValueEnc::StructInvisible(vec![
97        (0, tlv::TlvItemValueEnc::UInt8(days_to_return)).into(),
98        (1, tlv::TlvItemValueEnc::UInt8(mode_to_return)).into(),
99        ]),
100    };
101    Ok(tlv.encode()?)
102}
103
104/// Encode SetActiveScheduleRequest command (0x05)
105pub fn encode_set_active_schedule_request(schedule_handle: Vec<u8>) -> anyhow::Result<Vec<u8>> {
106    let tlv = tlv::TlvItemEnc {
107        tag: 0,
108        value: tlv::TlvItemValueEnc::StructInvisible(vec![
109        (0, tlv::TlvItemValueEnc::OctetString(schedule_handle)).into(),
110        ]),
111    };
112    Ok(tlv.encode()?)
113}
114
115/// Encode SetActivePresetRequest command (0x06)
116pub fn encode_set_active_preset_request(preset_handle: Option<Vec<u8>>) -> anyhow::Result<Vec<u8>> {
117    let tlv = tlv::TlvItemEnc {
118        tag: 0,
119        value: tlv::TlvItemValueEnc::StructInvisible(vec![
120        (0, tlv::TlvItemValueEnc::OctetString(preset_handle.unwrap_or(vec![]))).into(),
121        ]),
122    };
123    Ok(tlv.encode()?)
124}
125
126// Attribute decoders
127
128/// Decode LocalTemperature attribute (0x0000)
129pub fn decode_local_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
130    if let tlv::TlvItemValue::Int(v) = inp {
131        Ok(Some(*v as u8))
132    } else {
133        Ok(None)
134    }
135}
136
137/// Decode OutdoorTemperature attribute (0x0001)
138pub fn decode_outdoor_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
139    if let tlv::TlvItemValue::Int(v) = inp {
140        Ok(Some(*v as u8))
141    } else {
142        Ok(None)
143    }
144}
145
146/// Decode Occupancy attribute (0x0002)
147pub fn decode_occupancy(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
148    if let tlv::TlvItemValue::Int(v) = inp {
149        Ok(*v as u8)
150    } else {
151        Err(anyhow::anyhow!("Expected Integer"))
152    }
153}
154
155/// Decode AbsMinHeatSetpointLimit attribute (0x0003)
156pub fn decode_abs_min_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
157    if let tlv::TlvItemValue::Int(v) = inp {
158        Ok(*v as u8)
159    } else {
160        Err(anyhow::anyhow!("Expected Integer"))
161    }
162}
163
164/// Decode AbsMaxHeatSetpointLimit attribute (0x0004)
165pub fn decode_abs_max_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
166    if let tlv::TlvItemValue::Int(v) = inp {
167        Ok(*v as u8)
168    } else {
169        Err(anyhow::anyhow!("Expected Integer"))
170    }
171}
172
173/// Decode AbsMinCoolSetpointLimit attribute (0x0005)
174pub fn decode_abs_min_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
175    if let tlv::TlvItemValue::Int(v) = inp {
176        Ok(*v as u8)
177    } else {
178        Err(anyhow::anyhow!("Expected Integer"))
179    }
180}
181
182/// Decode AbsMaxCoolSetpointLimit attribute (0x0006)
183pub fn decode_abs_max_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
184    if let tlv::TlvItemValue::Int(v) = inp {
185        Ok(*v as u8)
186    } else {
187        Err(anyhow::anyhow!("Expected Integer"))
188    }
189}
190
191/// Decode PICoolingDemand attribute (0x0007)
192pub fn decode_pi_cooling_demand(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
193    if let tlv::TlvItemValue::Int(v) = inp {
194        Ok(*v as u8)
195    } else {
196        Err(anyhow::anyhow!("Expected Integer"))
197    }
198}
199
200/// Decode PIHeatingDemand attribute (0x0008)
201pub fn decode_pi_heating_demand(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
202    if let tlv::TlvItemValue::Int(v) = inp {
203        Ok(*v as u8)
204    } else {
205        Err(anyhow::anyhow!("Expected Integer"))
206    }
207}
208
209/// Decode HVACSystemTypeConfiguration attribute (0x0009)
210pub fn decode_hvac_system_type_configuration(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
211    if let tlv::TlvItemValue::Int(v) = inp {
212        Ok(*v as u8)
213    } else {
214        Err(anyhow::anyhow!("Expected Integer"))
215    }
216}
217
218/// Decode LocalTemperatureCalibration attribute (0x0010)
219pub fn decode_local_temperature_calibration(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
220    if let tlv::TlvItemValue::Int(v) = inp {
221        Ok(*v as u8)
222    } else {
223        Err(anyhow::anyhow!("Expected Integer"))
224    }
225}
226
227/// Decode OccupiedCoolingSetpoint attribute (0x0011)
228pub fn decode_occupied_cooling_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
229    if let tlv::TlvItemValue::Int(v) = inp {
230        Ok(*v as u8)
231    } else {
232        Err(anyhow::anyhow!("Expected Integer"))
233    }
234}
235
236/// Decode OccupiedHeatingSetpoint attribute (0x0012)
237pub fn decode_occupied_heating_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
238    if let tlv::TlvItemValue::Int(v) = inp {
239        Ok(*v as u8)
240    } else {
241        Err(anyhow::anyhow!("Expected Integer"))
242    }
243}
244
245/// Decode UnoccupiedCoolingSetpoint attribute (0x0013)
246pub fn decode_unoccupied_cooling_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
247    if let tlv::TlvItemValue::Int(v) = inp {
248        Ok(*v as u8)
249    } else {
250        Err(anyhow::anyhow!("Expected Integer"))
251    }
252}
253
254/// Decode UnoccupiedHeatingSetpoint attribute (0x0014)
255pub fn decode_unoccupied_heating_setpoint(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
256    if let tlv::TlvItemValue::Int(v) = inp {
257        Ok(*v as u8)
258    } else {
259        Err(anyhow::anyhow!("Expected Integer"))
260    }
261}
262
263/// Decode MinHeatSetpointLimit attribute (0x0015)
264pub fn decode_min_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
265    if let tlv::TlvItemValue::Int(v) = inp {
266        Ok(*v as u8)
267    } else {
268        Err(anyhow::anyhow!("Expected Integer"))
269    }
270}
271
272/// Decode MaxHeatSetpointLimit attribute (0x0016)
273pub fn decode_max_heat_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
274    if let tlv::TlvItemValue::Int(v) = inp {
275        Ok(*v as u8)
276    } else {
277        Err(anyhow::anyhow!("Expected Integer"))
278    }
279}
280
281/// Decode MinCoolSetpointLimit attribute (0x0017)
282pub fn decode_min_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
283    if let tlv::TlvItemValue::Int(v) = inp {
284        Ok(*v as u8)
285    } else {
286        Err(anyhow::anyhow!("Expected Integer"))
287    }
288}
289
290/// Decode MaxCoolSetpointLimit attribute (0x0018)
291pub fn decode_max_cool_setpoint_limit(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
292    if let tlv::TlvItemValue::Int(v) = inp {
293        Ok(*v as u8)
294    } else {
295        Err(anyhow::anyhow!("Expected Integer"))
296    }
297}
298
299/// Decode MinSetpointDeadBand attribute (0x0019)
300pub fn decode_min_setpoint_dead_band(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
301    if let tlv::TlvItemValue::Int(v) = inp {
302        Ok(*v as u8)
303    } else {
304        Err(anyhow::anyhow!("Expected Integer"))
305    }
306}
307
308/// Decode RemoteSensing attribute (0x001A)
309pub fn decode_remote_sensing(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
310    if let tlv::TlvItemValue::Int(v) = inp {
311        Ok(*v as u8)
312    } else {
313        Err(anyhow::anyhow!("Expected Integer"))
314    }
315}
316
317/// Decode ControlSequenceOfOperation attribute (0x001B)
318pub fn decode_control_sequence_of_operation(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
319    if let tlv::TlvItemValue::Int(v) = inp {
320        Ok(*v as u8)
321    } else {
322        Err(anyhow::anyhow!("Expected Integer"))
323    }
324}
325
326/// Decode SystemMode attribute (0x001C)
327pub fn decode_system_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
328    if let tlv::TlvItemValue::Int(v) = inp {
329        Ok(*v as u8)
330    } else {
331        Err(anyhow::anyhow!("Expected Integer"))
332    }
333}
334
335/// Decode ThermostatRunningMode attribute (0x001E)
336pub fn decode_thermostat_running_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
337    if let tlv::TlvItemValue::Int(v) = inp {
338        Ok(*v as u8)
339    } else {
340        Err(anyhow::anyhow!("Expected Integer"))
341    }
342}
343
344/// Decode StartOfWeek attribute (0x0020)
345pub fn decode_start_of_week(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
346    if let tlv::TlvItemValue::Int(v) = inp {
347        Ok(*v as u8)
348    } else {
349        Err(anyhow::anyhow!("Expected Integer"))
350    }
351}
352
353/// Decode NumberOfWeeklyTransitions attribute (0x0021)
354pub fn decode_number_of_weekly_transitions(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
355    if let tlv::TlvItemValue::Int(v) = inp {
356        Ok(*v as u8)
357    } else {
358        Err(anyhow::anyhow!("Expected Integer"))
359    }
360}
361
362/// Decode NumberOfDailyTransitions attribute (0x0022)
363pub fn decode_number_of_daily_transitions(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
364    if let tlv::TlvItemValue::Int(v) = inp {
365        Ok(*v as u8)
366    } else {
367        Err(anyhow::anyhow!("Expected Integer"))
368    }
369}
370
371/// Decode TemperatureSetpointHold attribute (0x0023)
372pub fn decode_temperature_setpoint_hold(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
373    if let tlv::TlvItemValue::Int(v) = inp {
374        Ok(*v as u8)
375    } else {
376        Err(anyhow::anyhow!("Expected Integer"))
377    }
378}
379
380/// Decode TemperatureSetpointHoldDuration attribute (0x0024)
381pub fn decode_temperature_setpoint_hold_duration(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
382    if let tlv::TlvItemValue::Int(v) = inp {
383        Ok(Some(*v as u16))
384    } else {
385        Ok(None)
386    }
387}
388
389/// Decode ThermostatProgrammingOperationMode attribute (0x0025)
390pub fn decode_thermostat_programming_operation_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
391    if let tlv::TlvItemValue::Int(v) = inp {
392        Ok(*v as u8)
393    } else {
394        Err(anyhow::anyhow!("Expected Integer"))
395    }
396}
397
398/// Decode ThermostatRunningState attribute (0x0029)
399pub fn decode_thermostat_running_state(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
400    if let tlv::TlvItemValue::Int(v) = inp {
401        Ok(*v as u8)
402    } else {
403        Err(anyhow::anyhow!("Expected Integer"))
404    }
405}
406
407/// Decode SetpointChangeSource attribute (0x0030)
408pub fn decode_setpoint_change_source(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
409    if let tlv::TlvItemValue::Int(v) = inp {
410        Ok(*v as u8)
411    } else {
412        Err(anyhow::anyhow!("Expected Integer"))
413    }
414}
415
416/// Decode SetpointChangeAmount attribute (0x0031)
417pub fn decode_setpoint_change_amount(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
418    if let tlv::TlvItemValue::Int(v) = inp {
419        Ok(Some(*v as u8))
420    } else {
421        Ok(None)
422    }
423}
424
425/// Decode SetpointChangeSourceTimestamp attribute (0x0032)
426pub fn decode_setpoint_change_source_timestamp(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
427    if let tlv::TlvItemValue::Int(v) = inp {
428        Ok(*v)
429    } else {
430        Err(anyhow::anyhow!("Expected Integer"))
431    }
432}
433
434/// Decode OccupiedSetback attribute (0x0034)
435pub fn decode_occupied_setback(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
436    if let tlv::TlvItemValue::Int(v) = inp {
437        Ok(Some(*v as u8))
438    } else {
439        Ok(None)
440    }
441}
442
443/// Decode OccupiedSetbackMin attribute (0x0035)
444pub fn decode_occupied_setback_min(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
445    if let tlv::TlvItemValue::Int(v) = inp {
446        Ok(Some(*v as u8))
447    } else {
448        Ok(None)
449    }
450}
451
452/// Decode OccupiedSetbackMax attribute (0x0036)
453pub fn decode_occupied_setback_max(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
454    if let tlv::TlvItemValue::Int(v) = inp {
455        Ok(Some(*v as u8))
456    } else {
457        Ok(None)
458    }
459}
460
461/// Decode UnoccupiedSetback attribute (0x0037)
462pub fn decode_unoccupied_setback(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
463    if let tlv::TlvItemValue::Int(v) = inp {
464        Ok(Some(*v as u8))
465    } else {
466        Ok(None)
467    }
468}
469
470/// Decode UnoccupiedSetbackMin attribute (0x0038)
471pub fn decode_unoccupied_setback_min(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
472    if let tlv::TlvItemValue::Int(v) = inp {
473        Ok(Some(*v as u8))
474    } else {
475        Ok(None)
476    }
477}
478
479/// Decode UnoccupiedSetbackMax attribute (0x0039)
480pub fn decode_unoccupied_setback_max(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
481    if let tlv::TlvItemValue::Int(v) = inp {
482        Ok(Some(*v as u8))
483    } else {
484        Ok(None)
485    }
486}
487
488/// Decode EmergencyHeatDelta attribute (0x003A)
489pub fn decode_emergency_heat_delta(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
490    if let tlv::TlvItemValue::Int(v) = inp {
491        Ok(*v as u8)
492    } else {
493        Err(anyhow::anyhow!("Expected Integer"))
494    }
495}
496
497/// Decode ACType attribute (0x0040)
498pub fn decode_ac_type(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
499    if let tlv::TlvItemValue::Int(v) = inp {
500        Ok(*v as u8)
501    } else {
502        Err(anyhow::anyhow!("Expected Integer"))
503    }
504}
505
506/// Decode ACCapacity attribute (0x0041)
507pub fn decode_ac_capacity(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
508    if let tlv::TlvItemValue::Int(v) = inp {
509        Ok(*v as u16)
510    } else {
511        Err(anyhow::anyhow!("Expected Integer"))
512    }
513}
514
515/// Decode ACRefrigerantType attribute (0x0042)
516pub fn decode_ac_refrigerant_type(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
517    if let tlv::TlvItemValue::Int(v) = inp {
518        Ok(*v as u8)
519    } else {
520        Err(anyhow::anyhow!("Expected Integer"))
521    }
522}
523
524/// Decode ACCompressorType attribute (0x0043)
525pub fn decode_ac_compressor_type(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
526    if let tlv::TlvItemValue::Int(v) = inp {
527        Ok(*v as u8)
528    } else {
529        Err(anyhow::anyhow!("Expected Integer"))
530    }
531}
532
533/// Decode ACErrorCode attribute (0x0044)
534pub fn decode_ac_error_code(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
535    if let tlv::TlvItemValue::Int(v) = inp {
536        Ok(*v as u8)
537    } else {
538        Err(anyhow::anyhow!("Expected Integer"))
539    }
540}
541
542/// Decode ACLouverPosition attribute (0x0045)
543pub fn decode_aclouver_position(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
544    if let tlv::TlvItemValue::Int(v) = inp {
545        Ok(*v as u8)
546    } else {
547        Err(anyhow::anyhow!("Expected Integer"))
548    }
549}
550
551/// Decode ACCoilTemperature attribute (0x0046)
552pub fn decode_ac_coil_temperature(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
553    if let tlv::TlvItemValue::Int(v) = inp {
554        Ok(Some(*v as u8))
555    } else {
556        Ok(None)
557    }
558}
559
560/// Decode ACCapacityFormat attribute (0x0047)
561pub fn decode_ac_capacity_format(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
562    if let tlv::TlvItemValue::Int(v) = inp {
563        Ok(*v as u8)
564    } else {
565        Err(anyhow::anyhow!("Expected Integer"))
566    }
567}
568
569/// Decode PresetTypes attribute (0x0048)
570pub fn decode_preset_types(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<PresetType>> {
571    let mut res = Vec::new();
572    if let tlv::TlvItemValue::List(v) = inp {
573        for item in v {
574            res.push(PresetType {
575                preset_scenario: item.get_int(&[0]).map(|v| v as u8),
576                number_of_presets: item.get_int(&[1]).map(|v| v as u8),
577                preset_type_features: item.get_int(&[2]).map(|v| v as u8),
578            });
579        }
580    }
581    Ok(res)
582}
583
584/// Decode ScheduleTypes attribute (0x0049)
585pub fn decode_schedule_types(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ScheduleType>> {
586    let mut res = Vec::new();
587    if let tlv::TlvItemValue::List(v) = inp {
588        for item in v {
589            res.push(ScheduleType {
590                system_mode: item.get_int(&[0]).map(|v| v as u8),
591                number_of_schedules: item.get_int(&[1]).map(|v| v as u8),
592                schedule_type_features: item.get_int(&[2]).map(|v| v as u8),
593            });
594        }
595    }
596    Ok(res)
597}
598
599/// Decode NumberOfPresets attribute (0x004A)
600pub fn decode_number_of_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
601    if let tlv::TlvItemValue::Int(v) = inp {
602        Ok(*v as u8)
603    } else {
604        Err(anyhow::anyhow!("Expected Integer"))
605    }
606}
607
608/// Decode NumberOfSchedules attribute (0x004B)
609pub fn decode_number_of_schedules(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
610    if let tlv::TlvItemValue::Int(v) = inp {
611        Ok(*v as u8)
612    } else {
613        Err(anyhow::anyhow!("Expected Integer"))
614    }
615}
616
617/// Decode NumberOfScheduleTransitions attribute (0x004C)
618pub fn decode_number_of_schedule_transitions(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
619    if let tlv::TlvItemValue::Int(v) = inp {
620        Ok(*v as u8)
621    } else {
622        Err(anyhow::anyhow!("Expected Integer"))
623    }
624}
625
626/// Decode NumberOfScheduleTransitionPerDay attribute (0x004D)
627pub fn decode_number_of_schedule_transition_per_day(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
628    if let tlv::TlvItemValue::Int(v) = inp {
629        Ok(Some(*v as u8))
630    } else {
631        Ok(None)
632    }
633}
634
635/// Decode ActivePresetHandle attribute (0x004E)
636pub fn decode_active_preset_handle(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
637    if let tlv::TlvItemValue::OctetString(v) = inp {
638        Ok(Some(v.clone()))
639    } else {
640        Ok(None)
641    }
642}
643
644/// Decode ActiveScheduleHandle attribute (0x004F)
645pub fn decode_active_schedule_handle(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
646    if let tlv::TlvItemValue::OctetString(v) = inp {
647        Ok(Some(v.clone()))
648    } else {
649        Ok(None)
650    }
651}
652
653/// Decode Presets attribute (0x0050)
654pub fn decode_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Preset>> {
655    let mut res = Vec::new();
656    if let tlv::TlvItemValue::List(v) = inp {
657        for item in v {
658            res.push(Preset {
659                preset_handle: item.get_octet_string_owned(&[0]),
660                preset_scenario: item.get_int(&[1]).map(|v| v as u8),
661                name: item.get_string_owned(&[2]),
662                cooling_setpoint: item.get_int(&[3]).map(|v| v as u8),
663                heating_setpoint: item.get_int(&[4]).map(|v| v as u8),
664                built_in: item.get_bool(&[5]),
665            });
666        }
667    }
668    Ok(res)
669}
670
671/// Decode Schedules attribute (0x0051)
672pub fn decode_schedules(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<Schedule>> {
673    let mut res = Vec::new();
674    if let tlv::TlvItemValue::List(v) = inp {
675        for item in v {
676            res.push(Schedule {
677                schedule_handle: item.get_octet_string_owned(&[0]),
678                system_mode: item.get_int(&[1]).map(|v| v as u8),
679                name: item.get_string_owned(&[2]),
680                preset_handle: item.get_octet_string_owned(&[3]),
681                transitions: {
682                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[4]) {
683                        let mut items = Vec::new();
684                        for list_item in l {
685                            items.push(ScheduleTransition {
686                day_of_week: list_item.get_int(&[0]).map(|v| v as u8),
687                transition_time: list_item.get_int(&[1]).map(|v| v as u16),
688                preset_handle: list_item.get_octet_string_owned(&[2]),
689                system_mode: list_item.get_int(&[3]).map(|v| v as u8),
690                cooling_setpoint: list_item.get_int(&[4]).map(|v| v as u8),
691                heating_setpoint: list_item.get_int(&[5]).map(|v| v as u8),
692                            });
693                        }
694                        Some(items)
695                    } else {
696                        None
697                    }
698                },
699                built_in: item.get_bool(&[5]),
700            });
701        }
702    }
703    Ok(res)
704}
705
706/// Decode SetpointHoldExpiryTimestamp attribute (0x0052)
707pub fn decode_setpoint_hold_expiry_timestamp(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
708    if let tlv::TlvItemValue::Int(v) = inp {
709        Ok(Some(*v))
710    } else {
711        Ok(None)
712    }
713}
714
715
716// JSON dispatcher function
717
718/// Decode attribute value and return as JSON string
719/// 
720/// # Parameters
721/// * `cluster_id` - The cluster identifier
722/// * `attribute_id` - The attribute identifier
723/// * `tlv_value` - The TLV value to decode
724/// 
725/// # Returns
726/// JSON string representation of the decoded value or error
727pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
728    // Verify this is the correct cluster
729    if cluster_id != 0x0201 {
730        return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0201, got {}\"}}", cluster_id);
731    }
732    
733    match attribute_id {
734        0x0000 => {
735            match decode_local_temperature(tlv_value) {
736                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
737                Err(e) => format!("{{\"error\": \"{}\"}}", e),
738            }
739        }
740        0x0001 => {
741            match decode_outdoor_temperature(tlv_value) {
742                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
743                Err(e) => format!("{{\"error\": \"{}\"}}", e),
744            }
745        }
746        0x0002 => {
747            match decode_occupancy(tlv_value) {
748                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
749                Err(e) => format!("{{\"error\": \"{}\"}}", e),
750            }
751        }
752        0x0003 => {
753            match decode_abs_min_heat_setpoint_limit(tlv_value) {
754                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
755                Err(e) => format!("{{\"error\": \"{}\"}}", e),
756            }
757        }
758        0x0004 => {
759            match decode_abs_max_heat_setpoint_limit(tlv_value) {
760                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
761                Err(e) => format!("{{\"error\": \"{}\"}}", e),
762            }
763        }
764        0x0005 => {
765            match decode_abs_min_cool_setpoint_limit(tlv_value) {
766                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
767                Err(e) => format!("{{\"error\": \"{}\"}}", e),
768            }
769        }
770        0x0006 => {
771            match decode_abs_max_cool_setpoint_limit(tlv_value) {
772                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
773                Err(e) => format!("{{\"error\": \"{}\"}}", e),
774            }
775        }
776        0x0007 => {
777            match decode_pi_cooling_demand(tlv_value) {
778                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
779                Err(e) => format!("{{\"error\": \"{}\"}}", e),
780            }
781        }
782        0x0008 => {
783            match decode_pi_heating_demand(tlv_value) {
784                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
785                Err(e) => format!("{{\"error\": \"{}\"}}", e),
786            }
787        }
788        0x0009 => {
789            match decode_hvac_system_type_configuration(tlv_value) {
790                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
791                Err(e) => format!("{{\"error\": \"{}\"}}", e),
792            }
793        }
794        0x0010 => {
795            match decode_local_temperature_calibration(tlv_value) {
796                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
797                Err(e) => format!("{{\"error\": \"{}\"}}", e),
798            }
799        }
800        0x0011 => {
801            match decode_occupied_cooling_setpoint(tlv_value) {
802                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
803                Err(e) => format!("{{\"error\": \"{}\"}}", e),
804            }
805        }
806        0x0012 => {
807            match decode_occupied_heating_setpoint(tlv_value) {
808                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
809                Err(e) => format!("{{\"error\": \"{}\"}}", e),
810            }
811        }
812        0x0013 => {
813            match decode_unoccupied_cooling_setpoint(tlv_value) {
814                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
815                Err(e) => format!("{{\"error\": \"{}\"}}", e),
816            }
817        }
818        0x0014 => {
819            match decode_unoccupied_heating_setpoint(tlv_value) {
820                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
821                Err(e) => format!("{{\"error\": \"{}\"}}", e),
822            }
823        }
824        0x0015 => {
825            match decode_min_heat_setpoint_limit(tlv_value) {
826                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
827                Err(e) => format!("{{\"error\": \"{}\"}}", e),
828            }
829        }
830        0x0016 => {
831            match decode_max_heat_setpoint_limit(tlv_value) {
832                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
833                Err(e) => format!("{{\"error\": \"{}\"}}", e),
834            }
835        }
836        0x0017 => {
837            match decode_min_cool_setpoint_limit(tlv_value) {
838                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
839                Err(e) => format!("{{\"error\": \"{}\"}}", e),
840            }
841        }
842        0x0018 => {
843            match decode_max_cool_setpoint_limit(tlv_value) {
844                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
845                Err(e) => format!("{{\"error\": \"{}\"}}", e),
846            }
847        }
848        0x0019 => {
849            match decode_min_setpoint_dead_band(tlv_value) {
850                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
851                Err(e) => format!("{{\"error\": \"{}\"}}", e),
852            }
853        }
854        0x001A => {
855            match decode_remote_sensing(tlv_value) {
856                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
857                Err(e) => format!("{{\"error\": \"{}\"}}", e),
858            }
859        }
860        0x001B => {
861            match decode_control_sequence_of_operation(tlv_value) {
862                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
863                Err(e) => format!("{{\"error\": \"{}\"}}", e),
864            }
865        }
866        0x001C => {
867            match decode_system_mode(tlv_value) {
868                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
869                Err(e) => format!("{{\"error\": \"{}\"}}", e),
870            }
871        }
872        0x001E => {
873            match decode_thermostat_running_mode(tlv_value) {
874                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
875                Err(e) => format!("{{\"error\": \"{}\"}}", e),
876            }
877        }
878        0x0020 => {
879            match decode_start_of_week(tlv_value) {
880                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
881                Err(e) => format!("{{\"error\": \"{}\"}}", e),
882            }
883        }
884        0x0021 => {
885            match decode_number_of_weekly_transitions(tlv_value) {
886                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
887                Err(e) => format!("{{\"error\": \"{}\"}}", e),
888            }
889        }
890        0x0022 => {
891            match decode_number_of_daily_transitions(tlv_value) {
892                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
893                Err(e) => format!("{{\"error\": \"{}\"}}", e),
894            }
895        }
896        0x0023 => {
897            match decode_temperature_setpoint_hold(tlv_value) {
898                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
899                Err(e) => format!("{{\"error\": \"{}\"}}", e),
900            }
901        }
902        0x0024 => {
903            match decode_temperature_setpoint_hold_duration(tlv_value) {
904                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
905                Err(e) => format!("{{\"error\": \"{}\"}}", e),
906            }
907        }
908        0x0025 => {
909            match decode_thermostat_programming_operation_mode(tlv_value) {
910                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
911                Err(e) => format!("{{\"error\": \"{}\"}}", e),
912            }
913        }
914        0x0029 => {
915            match decode_thermostat_running_state(tlv_value) {
916                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
917                Err(e) => format!("{{\"error\": \"{}\"}}", e),
918            }
919        }
920        0x0030 => {
921            match decode_setpoint_change_source(tlv_value) {
922                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
923                Err(e) => format!("{{\"error\": \"{}\"}}", e),
924            }
925        }
926        0x0031 => {
927            match decode_setpoint_change_amount(tlv_value) {
928                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
929                Err(e) => format!("{{\"error\": \"{}\"}}", e),
930            }
931        }
932        0x0032 => {
933            match decode_setpoint_change_source_timestamp(tlv_value) {
934                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
935                Err(e) => format!("{{\"error\": \"{}\"}}", e),
936            }
937        }
938        0x0034 => {
939            match decode_occupied_setback(tlv_value) {
940                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
941                Err(e) => format!("{{\"error\": \"{}\"}}", e),
942            }
943        }
944        0x0035 => {
945            match decode_occupied_setback_min(tlv_value) {
946                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
947                Err(e) => format!("{{\"error\": \"{}\"}}", e),
948            }
949        }
950        0x0036 => {
951            match decode_occupied_setback_max(tlv_value) {
952                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
953                Err(e) => format!("{{\"error\": \"{}\"}}", e),
954            }
955        }
956        0x0037 => {
957            match decode_unoccupied_setback(tlv_value) {
958                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
959                Err(e) => format!("{{\"error\": \"{}\"}}", e),
960            }
961        }
962        0x0038 => {
963            match decode_unoccupied_setback_min(tlv_value) {
964                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
965                Err(e) => format!("{{\"error\": \"{}\"}}", e),
966            }
967        }
968        0x0039 => {
969            match decode_unoccupied_setback_max(tlv_value) {
970                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
971                Err(e) => format!("{{\"error\": \"{}\"}}", e),
972            }
973        }
974        0x003A => {
975            match decode_emergency_heat_delta(tlv_value) {
976                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
977                Err(e) => format!("{{\"error\": \"{}\"}}", e),
978            }
979        }
980        0x0040 => {
981            match decode_ac_type(tlv_value) {
982                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
983                Err(e) => format!("{{\"error\": \"{}\"}}", e),
984            }
985        }
986        0x0041 => {
987            match decode_ac_capacity(tlv_value) {
988                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
989                Err(e) => format!("{{\"error\": \"{}\"}}", e),
990            }
991        }
992        0x0042 => {
993            match decode_ac_refrigerant_type(tlv_value) {
994                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
995                Err(e) => format!("{{\"error\": \"{}\"}}", e),
996            }
997        }
998        0x0043 => {
999            match decode_ac_compressor_type(tlv_value) {
1000                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1001                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1002            }
1003        }
1004        0x0044 => {
1005            match decode_ac_error_code(tlv_value) {
1006                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1007                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1008            }
1009        }
1010        0x0045 => {
1011            match decode_aclouver_position(tlv_value) {
1012                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1013                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1014            }
1015        }
1016        0x0046 => {
1017            match decode_ac_coil_temperature(tlv_value) {
1018                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1019                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1020            }
1021        }
1022        0x0047 => {
1023            match decode_ac_capacity_format(tlv_value) {
1024                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1025                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1026            }
1027        }
1028        0x0048 => {
1029            match decode_preset_types(tlv_value) {
1030                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1031                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1032            }
1033        }
1034        0x0049 => {
1035            match decode_schedule_types(tlv_value) {
1036                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1037                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1038            }
1039        }
1040        0x004A => {
1041            match decode_number_of_presets(tlv_value) {
1042                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1043                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1044            }
1045        }
1046        0x004B => {
1047            match decode_number_of_schedules(tlv_value) {
1048                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1049                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1050            }
1051        }
1052        0x004C => {
1053            match decode_number_of_schedule_transitions(tlv_value) {
1054                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1055                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1056            }
1057        }
1058        0x004D => {
1059            match decode_number_of_schedule_transition_per_day(tlv_value) {
1060                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1061                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1062            }
1063        }
1064        0x004E => {
1065            match decode_active_preset_handle(tlv_value) {
1066                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1067                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1068            }
1069        }
1070        0x004F => {
1071            match decode_active_schedule_handle(tlv_value) {
1072                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1073                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1074            }
1075        }
1076        0x0050 => {
1077            match decode_presets(tlv_value) {
1078                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1079                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1080            }
1081        }
1082        0x0051 => {
1083            match decode_schedules(tlv_value) {
1084                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1085                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1086            }
1087        }
1088        0x0052 => {
1089            match decode_setpoint_hold_expiry_timestamp(tlv_value) {
1090                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1091                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1092            }
1093        }
1094        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
1095    }
1096}
1097
1098/// Get list of all attributes supported by this cluster
1099/// 
1100/// # Returns
1101/// Vector of tuples containing (attribute_id, attribute_name)
1102pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
1103    vec![
1104        (0x0000, "LocalTemperature"),
1105        (0x0001, "OutdoorTemperature"),
1106        (0x0002, "Occupancy"),
1107        (0x0003, "AbsMinHeatSetpointLimit"),
1108        (0x0004, "AbsMaxHeatSetpointLimit"),
1109        (0x0005, "AbsMinCoolSetpointLimit"),
1110        (0x0006, "AbsMaxCoolSetpointLimit"),
1111        (0x0007, "PICoolingDemand"),
1112        (0x0008, "PIHeatingDemand"),
1113        (0x0009, "HVACSystemTypeConfiguration"),
1114        (0x0010, "LocalTemperatureCalibration"),
1115        (0x0011, "OccupiedCoolingSetpoint"),
1116        (0x0012, "OccupiedHeatingSetpoint"),
1117        (0x0013, "UnoccupiedCoolingSetpoint"),
1118        (0x0014, "UnoccupiedHeatingSetpoint"),
1119        (0x0015, "MinHeatSetpointLimit"),
1120        (0x0016, "MaxHeatSetpointLimit"),
1121        (0x0017, "MinCoolSetpointLimit"),
1122        (0x0018, "MaxCoolSetpointLimit"),
1123        (0x0019, "MinSetpointDeadBand"),
1124        (0x001A, "RemoteSensing"),
1125        (0x001B, "ControlSequenceOfOperation"),
1126        (0x001C, "SystemMode"),
1127        (0x001E, "ThermostatRunningMode"),
1128        (0x0020, "StartOfWeek"),
1129        (0x0021, "NumberOfWeeklyTransitions"),
1130        (0x0022, "NumberOfDailyTransitions"),
1131        (0x0023, "TemperatureSetpointHold"),
1132        (0x0024, "TemperatureSetpointHoldDuration"),
1133        (0x0025, "ThermostatProgrammingOperationMode"),
1134        (0x0029, "ThermostatRunningState"),
1135        (0x0030, "SetpointChangeSource"),
1136        (0x0031, "SetpointChangeAmount"),
1137        (0x0032, "SetpointChangeSourceTimestamp"),
1138        (0x0034, "OccupiedSetback"),
1139        (0x0035, "OccupiedSetbackMin"),
1140        (0x0036, "OccupiedSetbackMax"),
1141        (0x0037, "UnoccupiedSetback"),
1142        (0x0038, "UnoccupiedSetbackMin"),
1143        (0x0039, "UnoccupiedSetbackMax"),
1144        (0x003A, "EmergencyHeatDelta"),
1145        (0x0040, "ACType"),
1146        (0x0041, "ACCapacity"),
1147        (0x0042, "ACRefrigerantType"),
1148        (0x0043, "ACCompressorType"),
1149        (0x0044, "ACErrorCode"),
1150        (0x0045, "ACLouverPosition"),
1151        (0x0046, "ACCoilTemperature"),
1152        (0x0047, "ACCapacityFormat"),
1153        (0x0048, "PresetTypes"),
1154        (0x0049, "ScheduleTypes"),
1155        (0x004A, "NumberOfPresets"),
1156        (0x004B, "NumberOfSchedules"),
1157        (0x004C, "NumberOfScheduleTransitions"),
1158        (0x004D, "NumberOfScheduleTransitionPerDay"),
1159        (0x004E, "ActivePresetHandle"),
1160        (0x004F, "ActiveScheduleHandle"),
1161        (0x0050, "Presets"),
1162        (0x0051, "Schedules"),
1163        (0x0052, "SetpointHoldExpiryTimestamp"),
1164    ]
1165}
1166