1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
14#[repr(u8)]
15pub enum ErrorStateEnum {
16 Noerror = 0,
18 Unabletostartorresume = 1,
20 Unabletocompleteoperation = 2,
22 Commandinvalidinstate = 3,
24}
25
26impl ErrorStateEnum {
27 pub fn from_u8(value: u8) -> Option<Self> {
29 match value {
30 0 => Some(ErrorStateEnum::Noerror),
31 1 => Some(ErrorStateEnum::Unabletostartorresume),
32 2 => Some(ErrorStateEnum::Unabletocompleteoperation),
33 3 => Some(ErrorStateEnum::Commandinvalidinstate),
34 _ => None,
35 }
36 }
37
38 pub fn to_u8(self) -> u8 {
40 self as u8
41 }
42}
43
44impl From<ErrorStateEnum> for u8 {
45 fn from(val: ErrorStateEnum) -> Self {
46 val as u8
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
51#[repr(u8)]
52pub enum OperationalStateEnum {
53 Stopped = 0,
55 Running = 1,
57 Paused = 2,
59 Error = 3,
61}
62
63impl OperationalStateEnum {
64 pub fn from_u8(value: u8) -> Option<Self> {
66 match value {
67 0 => Some(OperationalStateEnum::Stopped),
68 1 => Some(OperationalStateEnum::Running),
69 2 => Some(OperationalStateEnum::Paused),
70 3 => Some(OperationalStateEnum::Error),
71 _ => None,
72 }
73 }
74
75 pub fn to_u8(self) -> u8 {
77 self as u8
78 }
79}
80
81impl From<OperationalStateEnum> for u8 {
82 fn from(val: OperationalStateEnum) -> Self {
83 val as u8
84 }
85}
86
87#[derive(Debug, serde::Serialize)]
90pub struct ErrorState {
91 pub error_state_id: Option<ErrorStateEnum>,
92 pub error_state_label: Option<String>,
93 pub error_state_details: Option<String>,
94}
95
96#[derive(Debug, serde::Serialize)]
97pub struct OperationalState {
98 pub operational_state_id: Option<OperationalStateEnum>,
99 pub operational_state_label: Option<String>,
100}
101
102pub fn decode_phase_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<String>> {
108 let mut res = Vec::new();
109 if let tlv::TlvItemValue::List(v) = inp {
110 for item in v {
111 if let tlv::TlvItemValue::String(s) = &item.value {
112 res.push(s.clone());
113 }
114 }
115 }
116 Ok(res)
117}
118
119pub fn decode_current_phase(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
121 if let tlv::TlvItemValue::Int(v) = inp {
122 Ok(Some(*v as u8))
123 } else {
124 Ok(None)
125 }
126}
127
128pub fn decode_countdown_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
130 if let tlv::TlvItemValue::Int(v) = inp {
131 Ok(Some(*v as u32))
132 } else {
133 Ok(None)
134 }
135}
136
137pub fn decode_operational_state_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<OperationalState>> {
139 let mut res = Vec::new();
140 if let tlv::TlvItemValue::List(v) = inp {
141 for item in v {
142 res.push(OperationalState {
143 operational_state_id: item.get_int(&[0]).and_then(|v| OperationalStateEnum::from_u8(v as u8)),
144 operational_state_label: item.get_string_owned(&[1]),
145 });
146 }
147 }
148 Ok(res)
149}
150
151pub fn decode_operational_state(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationalStateEnum> {
153 if let tlv::TlvItemValue::Int(v) = inp {
154 OperationalStateEnum::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
155 } else {
156 Err(anyhow::anyhow!("Expected Integer"))
157 }
158}
159
160pub fn decode_operational_error(inp: &tlv::TlvItemValue) -> anyhow::Result<ErrorState> {
162 if let tlv::TlvItemValue::List(_fields) = inp {
163 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
165 Ok(ErrorState {
166 error_state_id: item.get_int(&[0]).and_then(|v| ErrorStateEnum::from_u8(v as u8)),
167 error_state_label: item.get_string_owned(&[1]),
168 error_state_details: item.get_string_owned(&[2]),
169 })
170 } else {
171 Err(anyhow::anyhow!("Expected struct fields"))
172 }
173}
174
175
176pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
188 if cluster_id != 0x0060 {
190 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0060, got {}\"}}", cluster_id);
191 }
192
193 match attribute_id {
194 0x0000 => {
195 match decode_phase_list(tlv_value) {
196 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
197 Err(e) => format!("{{\"error\": \"{}\"}}", e),
198 }
199 }
200 0x0001 => {
201 match decode_current_phase(tlv_value) {
202 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
203 Err(e) => format!("{{\"error\": \"{}\"}}", e),
204 }
205 }
206 0x0002 => {
207 match decode_countdown_time(tlv_value) {
208 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
209 Err(e) => format!("{{\"error\": \"{}\"}}", e),
210 }
211 }
212 0x0003 => {
213 match decode_operational_state_list(tlv_value) {
214 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
215 Err(e) => format!("{{\"error\": \"{}\"}}", e),
216 }
217 }
218 0x0004 => {
219 match decode_operational_state(tlv_value) {
220 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
221 Err(e) => format!("{{\"error\": \"{}\"}}", e),
222 }
223 }
224 0x0005 => {
225 match decode_operational_error(tlv_value) {
226 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
227 Err(e) => format!("{{\"error\": \"{}\"}}", e),
228 }
229 }
230 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
231 }
232}
233
234pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
239 vec![
240 (0x0000, "PhaseList"),
241 (0x0001, "CurrentPhase"),
242 (0x0002, "CountdownTime"),
243 (0x0003, "OperationalStateList"),
244 (0x0004, "OperationalState"),
245 (0x0005, "OperationalError"),
246 ]
247}
248
249#[derive(Debug, serde::Serialize)]
250pub struct OperationalCommandResponse {
251 pub command_response_state: Option<ErrorState>,
252}
253
254pub fn decode_operational_command_response(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationalCommandResponse> {
258 if let tlv::TlvItemValue::List(_fields) = inp {
259 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
260 Ok(OperationalCommandResponse {
261 command_response_state: {
262 if let Some(nested_tlv) = item.get(&[0]) {
263 if let tlv::TlvItemValue::List(_) = nested_tlv {
264 let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
265 Some(ErrorState {
266 error_state_id: nested_item.get_int(&[0]).and_then(|v| ErrorStateEnum::from_u8(v as u8)),
267 error_state_label: nested_item.get_string_owned(&[1]),
268 error_state_details: nested_item.get_string_owned(&[2]),
269 })
270 } else {
271 None
272 }
273 } else {
274 None
275 }
276 },
277 })
278 } else {
279 Err(anyhow::anyhow!("Expected struct fields"))
280 }
281}
282
283#[derive(Debug, serde::Serialize)]
284pub struct OperationalErrorEvent {
285 pub error_state: Option<ErrorState>,
286}
287
288#[derive(Debug, serde::Serialize)]
289pub struct OperationCompletionEvent {
290 pub completion_error_code: Option<u8>,
291 pub total_operational_time: Option<u32>,
292 pub paused_time: Option<u32>,
293}
294
295pub fn decode_operational_error_event(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationalErrorEvent> {
299 if let tlv::TlvItemValue::List(_fields) = inp {
300 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
301 Ok(OperationalErrorEvent {
302 error_state: {
303 if let Some(nested_tlv) = item.get(&[0]) {
304 if let tlv::TlvItemValue::List(_) = nested_tlv {
305 let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
306 Some(ErrorState {
307 error_state_id: nested_item.get_int(&[0]).and_then(|v| ErrorStateEnum::from_u8(v as u8)),
308 error_state_label: nested_item.get_string_owned(&[1]),
309 error_state_details: nested_item.get_string_owned(&[2]),
310 })
311 } else {
312 None
313 }
314 } else {
315 None
316 }
317 },
318 })
319 } else {
320 Err(anyhow::anyhow!("Expected struct fields"))
321 }
322}
323
324pub fn decode_operation_completion_event(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationCompletionEvent> {
326 if let tlv::TlvItemValue::List(_fields) = inp {
327 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
328 Ok(OperationCompletionEvent {
329 completion_error_code: item.get_int(&[0]).map(|v| v as u8),
330 total_operational_time: item.get_int(&[1]).map(|v| v as u32),
331 paused_time: item.get_int(&[2]).map(|v| v as u32),
332 })
333 } else {
334 Err(anyhow::anyhow!("Expected struct fields"))
335 }
336}
337