1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13pub fn encode_set_cooking_parameters(cook_mode: u8, cook_time: u32, power_setting: u8, watt_setting_index: u8, start_after_setting: bool) -> anyhow::Result<Vec<u8>> {
17 let tlv = tlv::TlvItemEnc {
18 tag: 0,
19 value: tlv::TlvItemValueEnc::StructInvisible(vec![
20 (0, tlv::TlvItemValueEnc::UInt8(cook_mode)).into(),
21 (1, tlv::TlvItemValueEnc::UInt32(cook_time)).into(),
22 (2, tlv::TlvItemValueEnc::UInt8(power_setting)).into(),
23 (3, tlv::TlvItemValueEnc::UInt8(watt_setting_index)).into(),
24 (4, tlv::TlvItemValueEnc::Bool(start_after_setting)).into(),
25 ]),
26 };
27 Ok(tlv.encode()?)
28}
29
30pub fn encode_add_more_time(time_to_add: u32) -> anyhow::Result<Vec<u8>> {
32 let tlv = tlv::TlvItemEnc {
33 tag: 0,
34 value: tlv::TlvItemValueEnc::StructInvisible(vec![
35 (0, tlv::TlvItemValueEnc::UInt32(time_to_add)).into(),
36 ]),
37 };
38 Ok(tlv.encode()?)
39}
40
41pub fn decode_cook_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
45 if let tlv::TlvItemValue::Int(v) = inp {
46 Ok(*v as u32)
47 } else {
48 Err(anyhow::anyhow!("Expected UInt32"))
49 }
50}
51
52pub fn decode_max_cook_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
54 if let tlv::TlvItemValue::Int(v) = inp {
55 Ok(*v as u32)
56 } else {
57 Err(anyhow::anyhow!("Expected UInt32"))
58 }
59}
60
61pub fn decode_power_setting(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
63 if let tlv::TlvItemValue::Int(v) = inp {
64 Ok(*v as u8)
65 } else {
66 Err(anyhow::anyhow!("Expected UInt8"))
67 }
68}
69
70pub fn decode_min_power(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
72 if let tlv::TlvItemValue::Int(v) = inp {
73 Ok(*v as u8)
74 } else {
75 Err(anyhow::anyhow!("Expected UInt8"))
76 }
77}
78
79pub fn decode_max_power(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
81 if let tlv::TlvItemValue::Int(v) = inp {
82 Ok(*v as u8)
83 } else {
84 Err(anyhow::anyhow!("Expected UInt8"))
85 }
86}
87
88pub fn decode_power_step(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
90 if let tlv::TlvItemValue::Int(v) = inp {
91 Ok(*v as u8)
92 } else {
93 Err(anyhow::anyhow!("Expected UInt8"))
94 }
95}
96
97pub fn decode_supported_watts(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u16>> {
99 let mut res = Vec::new();
100 if let tlv::TlvItemValue::List(v) = inp {
101 for item in v {
102 if let tlv::TlvItemValue::Int(i) = &item.value {
103 res.push(*i as u16);
104 }
105 }
106 }
107 Ok(res)
108}
109
110pub fn decode_selected_watt_index(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
112 if let tlv::TlvItemValue::Int(v) = inp {
113 Ok(*v as u8)
114 } else {
115 Err(anyhow::anyhow!("Expected UInt8"))
116 }
117}
118
119pub fn decode_watt_rating(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
121 if let tlv::TlvItemValue::Int(v) = inp {
122 Ok(*v as u16)
123 } else {
124 Err(anyhow::anyhow!("Expected UInt16"))
125 }
126}
127
128
129pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
141 if cluster_id != 0x005F {
143 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x005F, got {}\"}}", cluster_id);
144 }
145
146 match attribute_id {
147 0x0000 => {
148 match decode_cook_time(tlv_value) {
149 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
150 Err(e) => format!("{{\"error\": \"{}\"}}", e),
151 }
152 }
153 0x0001 => {
154 match decode_max_cook_time(tlv_value) {
155 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
156 Err(e) => format!("{{\"error\": \"{}\"}}", e),
157 }
158 }
159 0x0002 => {
160 match decode_power_setting(tlv_value) {
161 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
162 Err(e) => format!("{{\"error\": \"{}\"}}", e),
163 }
164 }
165 0x0003 => {
166 match decode_min_power(tlv_value) {
167 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
168 Err(e) => format!("{{\"error\": \"{}\"}}", e),
169 }
170 }
171 0x0004 => {
172 match decode_max_power(tlv_value) {
173 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
174 Err(e) => format!("{{\"error\": \"{}\"}}", e),
175 }
176 }
177 0x0005 => {
178 match decode_power_step(tlv_value) {
179 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
180 Err(e) => format!("{{\"error\": \"{}\"}}", e),
181 }
182 }
183 0x0006 => {
184 match decode_supported_watts(tlv_value) {
185 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
186 Err(e) => format!("{{\"error\": \"{}\"}}", e),
187 }
188 }
189 0x0007 => {
190 match decode_selected_watt_index(tlv_value) {
191 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
192 Err(e) => format!("{{\"error\": \"{}\"}}", e),
193 }
194 }
195 0x0008 => {
196 match decode_watt_rating(tlv_value) {
197 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
198 Err(e) => format!("{{\"error\": \"{}\"}}", e),
199 }
200 }
201 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
202 }
203}
204
205pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
210 vec![
211 (0x0000, "CookTime"),
212 (0x0001, "MaxCookTime"),
213 (0x0002, "PowerSetting"),
214 (0x0003, "MinPower"),
215 (0x0004, "MaxPower"),
216 (0x0005, "PowerStep"),
217 (0x0006, "SupportedWatts"),
218 (0x0007, "SelectedWattIndex"),
219 (0x0008, "WattRating"),
220 ]
221}
222
223pub fn get_command_list() -> Vec<(u32, &'static str)> {
226 vec![
227 (0x00, "SetCookingParameters"),
228 (0x01, "AddMoreTime"),
229 ]
230}
231
232pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
233 match cmd_id {
234 0x00 => Some("SetCookingParameters"),
235 0x01 => Some("AddMoreTime"),
236 _ => None,
237 }
238}
239
240pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
241 match cmd_id {
242 0x00 => Some(vec![
243 crate::clusters::codec::CommandField { tag: 0, name: "cook_mode", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
244 crate::clusters::codec::CommandField { tag: 1, name: "cook_time", kind: crate::clusters::codec::FieldKind::U32, optional: true, nullable: false },
245 crate::clusters::codec::CommandField { tag: 2, name: "power_setting", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
246 crate::clusters::codec::CommandField { tag: 3, name: "watt_setting_index", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
247 crate::clusters::codec::CommandField { tag: 4, name: "start_after_setting", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
248 ]),
249 0x01 => Some(vec![
250 crate::clusters::codec::CommandField { tag: 0, name: "time_to_add", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
251 ]),
252 _ => None,
253 }
254}
255
256pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
257 match cmd_id {
258 0x00 => {
259 let cook_mode = crate::clusters::codec::json_util::get_u8(args, "cook_mode")?;
260 let cook_time = crate::clusters::codec::json_util::get_u32(args, "cook_time")?;
261 let power_setting = crate::clusters::codec::json_util::get_u8(args, "power_setting")?;
262 let watt_setting_index = crate::clusters::codec::json_util::get_u8(args, "watt_setting_index")?;
263 let start_after_setting = crate::clusters::codec::json_util::get_bool(args, "start_after_setting")?;
264 encode_set_cooking_parameters(cook_mode, cook_time, power_setting, watt_setting_index, start_after_setting)
265 }
266 0x01 => {
267 let time_to_add = crate::clusters::codec::json_util::get_u32(args, "time_to_add")?;
268 encode_add_more_time(time_to_add)
269 }
270 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
271 }
272}
273
274pub async fn set_cooking_parameters(conn: &crate::controller::Connection, endpoint: u16, cook_mode: u8, cook_time: u32, power_setting: u8, watt_setting_index: u8, start_after_setting: bool) -> anyhow::Result<()> {
278 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_CMD_ID_SETCOOKINGPARAMETERS, &encode_set_cooking_parameters(cook_mode, cook_time, power_setting, watt_setting_index, start_after_setting)?).await?;
279 Ok(())
280}
281
282pub async fn add_more_time(conn: &crate::controller::Connection, endpoint: u16, time_to_add: u32) -> anyhow::Result<()> {
284 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_CMD_ID_ADDMORETIME, &encode_add_more_time(time_to_add)?).await?;
285 Ok(())
286}
287
288pub async fn read_cook_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
290 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_COOKTIME).await?;
291 decode_cook_time(&tlv)
292}
293
294pub async fn read_max_cook_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
296 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_MAXCOOKTIME).await?;
297 decode_max_cook_time(&tlv)
298}
299
300pub async fn read_power_setting(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
302 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_POWERSETTING).await?;
303 decode_power_setting(&tlv)
304}
305
306pub async fn read_min_power(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
308 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_MINPOWER).await?;
309 decode_min_power(&tlv)
310}
311
312pub async fn read_max_power(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
314 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_MAXPOWER).await?;
315 decode_max_power(&tlv)
316}
317
318pub async fn read_power_step(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
320 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_POWERSTEP).await?;
321 decode_power_step(&tlv)
322}
323
324pub async fn read_supported_watts(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<u16>> {
326 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_SUPPORTEDWATTS).await?;
327 decode_supported_watts(&tlv)
328}
329
330pub async fn read_selected_watt_index(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
332 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_SELECTEDWATTINDEX).await?;
333 decode_selected_watt_index(&tlv)
334}
335
336pub async fn read_watt_rating(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
338 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_MICROWAVE_OVEN_CONTROL, crate::clusters::defs::CLUSTER_MICROWAVE_OVEN_CONTROL_ATTR_ID_WATTRATING).await?;
339 decode_watt_rating(&tlv)
340}
341