1#![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(u16)]
17pub enum ModeTag {
18 Auto = 0,
19 Quick = 1,
20 Quiet = 2,
21 Lownoise = 3,
22 Lowenergy = 4,
23 Vacation = 5,
24 Min = 6,
25 Max = 7,
26 Night = 8,
27 Day = 9,
28 Bake = 16384,
29 Convection = 16385,
30 Grill = 16386,
31 Roast = 16387,
32 Clean = 16388,
33 ConvectionBake = 16389,
34 ConvectionRoast = 16390,
35 Warming = 16391,
36 Proofing = 16392,
37 Steam = 16393,
38 AirFry = 16394,
39 AirSousVide = 16395,
40 FrozenFood = 16396,
41}
42
43impl ModeTag {
44 pub fn from_u8(value: u8) -> Option<Self> {
46 Self::from_u16(value as u16)
47 }
48
49 pub fn from_u16(value: u16) -> Option<Self> {
51 match value {
52 0 => Some(ModeTag::Auto),
53 1 => Some(ModeTag::Quick),
54 2 => Some(ModeTag::Quiet),
55 3 => Some(ModeTag::Lownoise),
56 4 => Some(ModeTag::Lowenergy),
57 5 => Some(ModeTag::Vacation),
58 6 => Some(ModeTag::Min),
59 7 => Some(ModeTag::Max),
60 8 => Some(ModeTag::Night),
61 9 => Some(ModeTag::Day),
62 16384 => Some(ModeTag::Bake),
63 16385 => Some(ModeTag::Convection),
64 16386 => Some(ModeTag::Grill),
65 16387 => Some(ModeTag::Roast),
66 16388 => Some(ModeTag::Clean),
67 16389 => Some(ModeTag::ConvectionBake),
68 16390 => Some(ModeTag::ConvectionRoast),
69 16391 => Some(ModeTag::Warming),
70 16392 => Some(ModeTag::Proofing),
71 16393 => Some(ModeTag::Steam),
72 16394 => Some(ModeTag::AirFry),
73 16395 => Some(ModeTag::AirSousVide),
74 16396 => Some(ModeTag::FrozenFood),
75 _ => None,
76 }
77 }
78
79 pub fn to_u8(self) -> u8 {
81 self as u8
82 }
83
84 pub fn to_u16(self) -> u16 {
86 self as u16
87 }
88}
89
90impl From<ModeTag> for u16 {
91 fn from(val: ModeTag) -> Self {
92 val as u16
93 }
94}
95
96#[derive(Debug, serde::Serialize)]
99pub struct ModeOption {
100 pub label: Option<u8>,
101 pub mode: Option<u8>,
102 pub mode_tags: Option<u8>,
103}
104
105pub fn decode_supported_modes(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
109 if let tlv::TlvItemValue::Int(v) = inp {
110 Ok(*v as u8)
111 } else {
112 Err(anyhow::anyhow!("Expected UInt8"))
113 }
114}
115
116pub fn decode_current_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
118 if let tlv::TlvItemValue::Int(v) = inp {
119 Ok(*v as u8)
120 } else {
121 Err(anyhow::anyhow!("Expected UInt8"))
122 }
123}
124
125pub fn decode_start_up_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
127 if let tlv::TlvItemValue::Int(v) = inp {
128 Ok(*v as u8)
129 } else {
130 Err(anyhow::anyhow!("Expected UInt8"))
131 }
132}
133
134pub fn decode_on_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
136 if let tlv::TlvItemValue::Int(v) = inp {
137 Ok(*v as u8)
138 } else {
139 Err(anyhow::anyhow!("Expected UInt8"))
140 }
141}
142
143
144pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
156 if cluster_id != 0x0049 {
158 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0049, got {}\"}}", cluster_id);
159 }
160
161 match attribute_id {
162 0x0000 => {
163 match decode_supported_modes(tlv_value) {
164 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
165 Err(e) => format!("{{\"error\": \"{}\"}}", e),
166 }
167 }
168 0x0001 => {
169 match decode_current_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 0x0002 => {
175 match decode_start_up_mode(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 0x0003 => {
181 match decode_on_mode(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, "SupportedModes"),
197 (0x0001, "CurrentMode"),
198 (0x0002, "StartUpMode"),
199 (0x0003, "OnMode"),
200 ]
201}
202
203pub async fn read_supported_modes(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
207 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OVEN_MODE, crate::clusters::defs::CLUSTER_OVEN_MODE_ATTR_ID_SUPPORTEDMODES).await?;
208 decode_supported_modes(&tlv)
209}
210
211pub async fn read_current_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
213 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OVEN_MODE, crate::clusters::defs::CLUSTER_OVEN_MODE_ATTR_ID_CURRENTMODE).await?;
214 decode_current_mode(&tlv)
215}
216
217pub async fn read_start_up_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
219 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OVEN_MODE, crate::clusters::defs::CLUSTER_OVEN_MODE_ATTR_ID_STARTUPMODE).await?;
220 decode_start_up_mode(&tlv)
221}
222
223pub async fn read_on_mode(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
225 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_OVEN_MODE, crate::clusters::defs::CLUSTER_OVEN_MODE_ATTR_ID_ONMODE).await?;
226 decode_on_mode(&tlv)
227}
228