matc/clusters/codec/
thermostat_user_interface_configuration.rs1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum KeypadLockout {
18 Nolockout = 0,
20 Lockout1 = 1,
22 Lockout2 = 2,
24 Lockout3 = 3,
26 Lockout4 = 4,
28 Lockout5 = 5,
30}
31
32impl KeypadLockout {
33 pub fn from_u8(value: u8) -> Option<Self> {
35 match value {
36 0 => Some(KeypadLockout::Nolockout),
37 1 => Some(KeypadLockout::Lockout1),
38 2 => Some(KeypadLockout::Lockout2),
39 3 => Some(KeypadLockout::Lockout3),
40 4 => Some(KeypadLockout::Lockout4),
41 5 => Some(KeypadLockout::Lockout5),
42 _ => None,
43 }
44 }
45
46 pub fn to_u8(self) -> u8 {
48 self as u8
49 }
50}
51
52impl From<KeypadLockout> for u8 {
53 fn from(val: KeypadLockout) -> Self {
54 val as u8
55 }
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
59#[repr(u8)]
60pub enum ScheduleProgrammingVisibility {
61 Scheduleprogrammingpermitted = 0,
63 Scheduleprogrammingdenied = 1,
65}
66
67impl ScheduleProgrammingVisibility {
68 pub fn from_u8(value: u8) -> Option<Self> {
70 match value {
71 0 => Some(ScheduleProgrammingVisibility::Scheduleprogrammingpermitted),
72 1 => Some(ScheduleProgrammingVisibility::Scheduleprogrammingdenied),
73 _ => None,
74 }
75 }
76
77 pub fn to_u8(self) -> u8 {
79 self as u8
80 }
81}
82
83impl From<ScheduleProgrammingVisibility> for u8 {
84 fn from(val: ScheduleProgrammingVisibility) -> Self {
85 val as u8
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
90#[repr(u8)]
91pub enum TemperatureDisplayMode {
92 Celsius = 0,
94 Fahrenheit = 1,
96}
97
98impl TemperatureDisplayMode {
99 pub fn from_u8(value: u8) -> Option<Self> {
101 match value {
102 0 => Some(TemperatureDisplayMode::Celsius),
103 1 => Some(TemperatureDisplayMode::Fahrenheit),
104 _ => None,
105 }
106 }
107
108 pub fn to_u8(self) -> u8 {
110 self as u8
111 }
112}
113
114impl From<TemperatureDisplayMode> for u8 {
115 fn from(val: TemperatureDisplayMode) -> Self {
116 val as u8
117 }
118}
119
120pub fn decode_temperature_display_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<TemperatureDisplayMode> {
124 if let tlv::TlvItemValue::Int(v) = inp {
125 TemperatureDisplayMode::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
126 } else {
127 Err(anyhow::anyhow!("Expected Integer"))
128 }
129}
130
131pub fn decode_keypad_lockout(inp: &tlv::TlvItemValue) -> anyhow::Result<KeypadLockout> {
133 if let tlv::TlvItemValue::Int(v) = inp {
134 KeypadLockout::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
135 } else {
136 Err(anyhow::anyhow!("Expected Integer"))
137 }
138}
139
140pub fn decode_schedule_programming_visibility(inp: &tlv::TlvItemValue) -> anyhow::Result<ScheduleProgrammingVisibility> {
142 if let tlv::TlvItemValue::Int(v) = inp {
143 ScheduleProgrammingVisibility::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
144 } else {
145 Err(anyhow::anyhow!("Expected Integer"))
146 }
147}
148
149
150pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
162 if cluster_id != 0x0204 {
164 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0204, got {}\"}}", cluster_id);
165 }
166
167 match attribute_id {
168 0x0000 => {
169 match decode_temperature_display_mode(tlv_value) {
170 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
171 Err(e) => format!("{{\"error\": \"{}\"}}", e),
172 }
173 }
174 0x0001 => {
175 match decode_keypad_lockout(tlv_value) {
176 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
177 Err(e) => format!("{{\"error\": \"{}\"}}", e),
178 }
179 }
180 0x0002 => {
181 match decode_schedule_programming_visibility(tlv_value) {
182 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
183 Err(e) => format!("{{\"error\": \"{}\"}}", e),
184 }
185 }
186 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
187 }
188}
189
190pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
195 vec![
196 (0x0000, "TemperatureDisplayMode"),
197 (0x0001, "KeypadLockout"),
198 (0x0002, "ScheduleProgrammingVisibility"),
199 ]
200}
201
202pub async fn read_temperature_display_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TemperatureDisplayMode> {
206 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT_USER_INTERFACE_CONFIGURATION, crate::clusters::defs::CLUSTER_THERMOSTAT_USER_INTERFACE_CONFIGURATION_ATTR_ID_TEMPERATUREDISPLAYMODE).await?;
207 decode_temperature_display_mode(&tlv)
208}
209
210pub async fn read_keypad_lockout(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<KeypadLockout> {
212 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT_USER_INTERFACE_CONFIGURATION, crate::clusters::defs::CLUSTER_THERMOSTAT_USER_INTERFACE_CONFIGURATION_ATTR_ID_KEYPADLOCKOUT).await?;
213 decode_keypad_lockout(&tlv)
214}
215
216pub async fn read_schedule_programming_visibility(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ScheduleProgrammingVisibility> {
218 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_THERMOSTAT_USER_INTERFACE_CONFIGURATION, crate::clusters::defs::CLUSTER_THERMOSTAT_USER_INTERFACE_CONFIGURATION_ATTR_ID_SCHEDULEPROGRAMMINGVISIBILITY).await?;
219 decode_schedule_programming_visibility(&tlv)
220}
221