1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13pub type Alarm = u8;
17
18pub mod alarm {
20 pub const CRITICAL_OVER_TEMPERATURE_ALARM: u8 = 0x01;
22 pub const MAJOR_OVER_TEMPERATURE_ALARM: u8 = 0x02;
24 pub const MINOR_OVER_TEMPERATURE_ALARM: u8 = 0x04;
26 pub const MINOR_UNDER_TEMPERATURE_ALARM: u8 = 0x08;
28 pub const MAJOR_UNDER_TEMPERATURE_ALARM: u8 = 0x10;
30 pub const CRITICAL_UNDER_TEMPERATURE_ALARM: u8 = 0x20;
32}
33
34pub fn encode_set_temperature_alarm_thresholds(critical_over_temperature_threshold: Option<i16>, major_over_temperature_threshold: Option<i16>, minor_over_temperature_threshold: Option<i16>, minor_under_temperature_threshold: Option<i16>, major_under_temperature_threshold: Option<i16>, critical_under_temperature_threshold: Option<i16>) -> anyhow::Result<Vec<u8>> {
38 let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
39 if let Some(x) = critical_over_temperature_threshold { tlv_fields.push((0, tlv::TlvItemValueEnc::Int16(x)).into()); }
40 if let Some(x) = major_over_temperature_threshold { tlv_fields.push((1, tlv::TlvItemValueEnc::Int16(x)).into()); }
41 if let Some(x) = minor_over_temperature_threshold { tlv_fields.push((2, tlv::TlvItemValueEnc::Int16(x)).into()); }
42 if let Some(x) = minor_under_temperature_threshold { tlv_fields.push((3, tlv::TlvItemValueEnc::Int16(x)).into()); }
43 if let Some(x) = major_under_temperature_threshold { tlv_fields.push((4, tlv::TlvItemValueEnc::Int16(x)).into()); }
44 if let Some(x) = critical_under_temperature_threshold { tlv_fields.push((5, tlv::TlvItemValueEnc::Int16(x)).into()); }
45 let tlv = tlv::TlvItemEnc {
46 tag: 0,
47 value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
48 };
49 Ok(tlv.encode()?)
50}
51
52pub fn decode_critical_over_temperature_threshold(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
56 if let tlv::TlvItemValue::Int(v) = inp {
57 Ok(*v as i16)
58 } else {
59 Err(anyhow::anyhow!("Expected Int16"))
60 }
61}
62
63pub fn decode_major_over_temperature_threshold(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
65 if let tlv::TlvItemValue::Int(v) = inp {
66 Ok(*v as i16)
67 } else {
68 Err(anyhow::anyhow!("Expected Int16"))
69 }
70}
71
72pub fn decode_minor_over_temperature_threshold(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
74 if let tlv::TlvItemValue::Int(v) = inp {
75 Ok(*v as i16)
76 } else {
77 Err(anyhow::anyhow!("Expected Int16"))
78 }
79}
80
81pub fn decode_minor_under_temperature_threshold(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
83 if let tlv::TlvItemValue::Int(v) = inp {
84 Ok(*v as i16)
85 } else {
86 Err(anyhow::anyhow!("Expected Int16"))
87 }
88}
89
90pub fn decode_major_under_temperature_threshold(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
92 if let tlv::TlvItemValue::Int(v) = inp {
93 Ok(*v as i16)
94 } else {
95 Err(anyhow::anyhow!("Expected Int16"))
96 }
97}
98
99pub fn decode_critical_under_temperature_threshold(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
101 if let tlv::TlvItemValue::Int(v) = inp {
102 Ok(*v as i16)
103 } else {
104 Err(anyhow::anyhow!("Expected Int16"))
105 }
106}
107
108
109pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
121 if cluster_id != 0x0064 {
123 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0064, got {}\"}}", cluster_id);
124 }
125
126 match attribute_id {
127 0x0080 => {
128 match decode_critical_over_temperature_threshold(tlv_value) {
129 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
130 Err(e) => format!("{{\"error\": \"{}\"}}", e),
131 }
132 }
133 0x0081 => {
134 match decode_major_over_temperature_threshold(tlv_value) {
135 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
136 Err(e) => format!("{{\"error\": \"{}\"}}", e),
137 }
138 }
139 0x0082 => {
140 match decode_minor_over_temperature_threshold(tlv_value) {
141 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
142 Err(e) => format!("{{\"error\": \"{}\"}}", e),
143 }
144 }
145 0x0083 => {
146 match decode_minor_under_temperature_threshold(tlv_value) {
147 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
148 Err(e) => format!("{{\"error\": \"{}\"}}", e),
149 }
150 }
151 0x0084 => {
152 match decode_major_under_temperature_threshold(tlv_value) {
153 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
154 Err(e) => format!("{{\"error\": \"{}\"}}", e),
155 }
156 }
157 0x0085 => {
158 match decode_critical_under_temperature_threshold(tlv_value) {
159 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
160 Err(e) => format!("{{\"error\": \"{}\"}}", e),
161 }
162 }
163 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
164 }
165}
166
167pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
172 vec![
173 (0x0080, "CriticalOverTemperatureThreshold"),
174 (0x0081, "MajorOverTemperatureThreshold"),
175 (0x0082, "MinorOverTemperatureThreshold"),
176 (0x0083, "MinorUnderTemperatureThreshold"),
177 (0x0084, "MajorUnderTemperatureThreshold"),
178 (0x0085, "CriticalUnderTemperatureThreshold"),
179 ]
180}
181
182pub fn get_command_list() -> Vec<(u32, &'static str)> {
185 vec![
186 (0x80, "SetTemperatureAlarmThresholds"),
187 ]
188}
189
190pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
191 match cmd_id {
192 0x80 => Some("SetTemperatureAlarmThresholds"),
193 _ => None,
194 }
195}
196
197pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
198 match cmd_id {
199 0x80 => Some(vec![
200 crate::clusters::codec::CommandField { tag: 0, name: "critical_over_temperature_threshold", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
201 crate::clusters::codec::CommandField { tag: 1, name: "major_over_temperature_threshold", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
202 crate::clusters::codec::CommandField { tag: 2, name: "minor_over_temperature_threshold", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
203 crate::clusters::codec::CommandField { tag: 3, name: "minor_under_temperature_threshold", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
204 crate::clusters::codec::CommandField { tag: 4, name: "major_under_temperature_threshold", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
205 crate::clusters::codec::CommandField { tag: 5, name: "critical_under_temperature_threshold", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
206 ]),
207 _ => None,
208 }
209}
210
211pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
212 match cmd_id {
213 0x80 => {
214 let critical_over_temperature_threshold = crate::clusters::codec::json_util::get_opt_i16(args, "critical_over_temperature_threshold")?;
215 let major_over_temperature_threshold = crate::clusters::codec::json_util::get_opt_i16(args, "major_over_temperature_threshold")?;
216 let minor_over_temperature_threshold = crate::clusters::codec::json_util::get_opt_i16(args, "minor_over_temperature_threshold")?;
217 let minor_under_temperature_threshold = crate::clusters::codec::json_util::get_opt_i16(args, "minor_under_temperature_threshold")?;
218 let major_under_temperature_threshold = crate::clusters::codec::json_util::get_opt_i16(args, "major_under_temperature_threshold")?;
219 let critical_under_temperature_threshold = crate::clusters::codec::json_util::get_opt_i16(args, "critical_under_temperature_threshold")?;
220 encode_set_temperature_alarm_thresholds(critical_over_temperature_threshold, major_over_temperature_threshold, minor_over_temperature_threshold, minor_under_temperature_threshold, major_under_temperature_threshold, critical_under_temperature_threshold)
221 }
222 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
223 }
224}
225
226pub async fn set_temperature_alarm_thresholds(conn: &crate::controller::Connection, endpoint: u16, critical_over_temperature_threshold: Option<i16>, major_over_temperature_threshold: Option<i16>, minor_over_temperature_threshold: Option<i16>, minor_under_temperature_threshold: Option<i16>, major_under_temperature_threshold: Option<i16>, critical_under_temperature_threshold: Option<i16>) -> anyhow::Result<()> {
230 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_ALARM, crate::clusters::defs::CLUSTER_TEMPERATURE_ALARM_CMD_ID_SETTEMPERATUREALARMTHRESHOLDS, &encode_set_temperature_alarm_thresholds(critical_over_temperature_threshold, major_over_temperature_threshold, minor_over_temperature_threshold, minor_under_temperature_threshold, major_under_temperature_threshold, critical_under_temperature_threshold)?).await?;
231 Ok(())
232}
233
234pub async fn read_critical_over_temperature_threshold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
236 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_ALARM, crate::clusters::defs::CLUSTER_TEMPERATURE_ALARM_ATTR_ID_CRITICALOVERTEMPERATURETHRESHOLD).await?;
237 decode_critical_over_temperature_threshold(&tlv)
238}
239
240pub async fn read_major_over_temperature_threshold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
242 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_ALARM, crate::clusters::defs::CLUSTER_TEMPERATURE_ALARM_ATTR_ID_MAJOROVERTEMPERATURETHRESHOLD).await?;
243 decode_major_over_temperature_threshold(&tlv)
244}
245
246pub async fn read_minor_over_temperature_threshold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
248 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_ALARM, crate::clusters::defs::CLUSTER_TEMPERATURE_ALARM_ATTR_ID_MINOROVERTEMPERATURETHRESHOLD).await?;
249 decode_minor_over_temperature_threshold(&tlv)
250}
251
252pub async fn read_minor_under_temperature_threshold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
254 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_ALARM, crate::clusters::defs::CLUSTER_TEMPERATURE_ALARM_ATTR_ID_MINORUNDERTEMPERATURETHRESHOLD).await?;
255 decode_minor_under_temperature_threshold(&tlv)
256}
257
258pub async fn read_major_under_temperature_threshold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
260 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_ALARM, crate::clusters::defs::CLUSTER_TEMPERATURE_ALARM_ATTR_ID_MAJORUNDERTEMPERATURETHRESHOLD).await?;
261 decode_major_under_temperature_threshold(&tlv)
262}
263
264pub async fn read_critical_under_temperature_threshold(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
266 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_TEMPERATURE_ALARM, crate::clusters::defs::CLUSTER_TEMPERATURE_ALARM_ATTR_ID_CRITICALUNDERTEMPERATURETHRESHOLD).await?;
267 decode_critical_under_temperature_threshold(&tlv)
268}
269