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 ClosureError {
16 Physicallyblocked = 0,
18 Blockedbysensor = 1,
20 Temperaturelimited = 2,
22 Maintenancerequired = 3,
24 Internalinterference = 4,
26}
27
28impl ClosureError {
29 pub fn from_u8(value: u8) -> Option<Self> {
31 match value {
32 0 => Some(ClosureError::Physicallyblocked),
33 1 => Some(ClosureError::Blockedbysensor),
34 2 => Some(ClosureError::Temperaturelimited),
35 3 => Some(ClosureError::Maintenancerequired),
36 4 => Some(ClosureError::Internalinterference),
37 _ => None,
38 }
39 }
40
41 pub fn to_u8(self) -> u8 {
43 self as u8
44 }
45}
46
47impl From<ClosureError> for u8 {
48 fn from(val: ClosureError) -> Self {
49 val as u8
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
54#[repr(u8)]
55pub enum CurrentPosition {
56 Fullyclosed = 0,
58 Fullyopened = 1,
60 Partiallyopened = 2,
62 Openedforpedestrian = 3,
64 Openedforventilation = 4,
66 Openedatsignature = 5,
68}
69
70impl CurrentPosition {
71 pub fn from_u8(value: u8) -> Option<Self> {
73 match value {
74 0 => Some(CurrentPosition::Fullyclosed),
75 1 => Some(CurrentPosition::Fullyopened),
76 2 => Some(CurrentPosition::Partiallyopened),
77 3 => Some(CurrentPosition::Openedforpedestrian),
78 4 => Some(CurrentPosition::Openedforventilation),
79 5 => Some(CurrentPosition::Openedatsignature),
80 _ => None,
81 }
82 }
83
84 pub fn to_u8(self) -> u8 {
86 self as u8
87 }
88}
89
90impl From<CurrentPosition> for u8 {
91 fn from(val: CurrentPosition) -> Self {
92 val as u8
93 }
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
97#[repr(u8)]
98pub enum MainState {
99 Stopped = 0,
101 Moving = 1,
103 Waitingformotion = 2,
105 Error = 3,
107 Calibrating = 4,
109 Protected = 5,
111 Disengaged = 6,
113 Setuprequired = 7,
115}
116
117impl MainState {
118 pub fn from_u8(value: u8) -> Option<Self> {
120 match value {
121 0 => Some(MainState::Stopped),
122 1 => Some(MainState::Moving),
123 2 => Some(MainState::Waitingformotion),
124 3 => Some(MainState::Error),
125 4 => Some(MainState::Calibrating),
126 5 => Some(MainState::Protected),
127 6 => Some(MainState::Disengaged),
128 7 => Some(MainState::Setuprequired),
129 _ => None,
130 }
131 }
132
133 pub fn to_u8(self) -> u8 {
135 self as u8
136 }
137}
138
139impl From<MainState> for u8 {
140 fn from(val: MainState) -> Self {
141 val as u8
142 }
143}
144
145#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
146#[repr(u8)]
147pub enum TargetPosition {
148 Movetofullyclosed = 0,
150 Movetofullyopen = 1,
152 Movetopedestrianposition = 2,
154 Movetoventilationposition = 3,
156 Movetosignatureposition = 4,
158}
159
160impl TargetPosition {
161 pub fn from_u8(value: u8) -> Option<Self> {
163 match value {
164 0 => Some(TargetPosition::Movetofullyclosed),
165 1 => Some(TargetPosition::Movetofullyopen),
166 2 => Some(TargetPosition::Movetopedestrianposition),
167 3 => Some(TargetPosition::Movetoventilationposition),
168 4 => Some(TargetPosition::Movetosignatureposition),
169 _ => None,
170 }
171 }
172
173 pub fn to_u8(self) -> u8 {
175 self as u8
176 }
177}
178
179impl From<TargetPosition> for u8 {
180 fn from(val: TargetPosition) -> Self {
181 val as u8
182 }
183}
184
185pub type LatchControlModes = u8;
189
190pub mod latchcontrolmodes {
192 pub const REMOTE_LATCHING: u8 = 0x01;
194 pub const REMOTE_UNLATCHING: u8 = 0x02;
196}
197
198#[derive(Debug, serde::Serialize)]
201pub struct OverallCurrentState {
202 pub position: Option<CurrentPosition>,
203 pub latch: Option<bool>,
204 pub speed: Option<u8>,
205 pub secure_state: Option<bool>,
206}
207
208#[derive(Debug, serde::Serialize)]
209pub struct OverallTargetState {
210 pub position: Option<TargetPosition>,
211 pub latch: Option<bool>,
212 pub speed: Option<u8>,
213}
214
215pub fn encode_move_to(position: TargetPosition, latch: bool, speed: u8) -> anyhow::Result<Vec<u8>> {
219 let tlv = tlv::TlvItemEnc {
220 tag: 0,
221 value: tlv::TlvItemValueEnc::StructInvisible(vec![
222 (0, tlv::TlvItemValueEnc::UInt8(position.to_u8())).into(),
223 (1, tlv::TlvItemValueEnc::Bool(latch)).into(),
224 (2, tlv::TlvItemValueEnc::UInt8(speed)).into(),
225 ]),
226 };
227 Ok(tlv.encode()?)
228}
229
230pub fn decode_countdown_time(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
234 if let tlv::TlvItemValue::Int(v) = inp {
235 Ok(Some(*v as u32))
236 } else {
237 Ok(None)
238 }
239}
240
241pub fn decode_main_state(inp: &tlv::TlvItemValue) -> anyhow::Result<MainState> {
243 if let tlv::TlvItemValue::Int(v) = inp {
244 MainState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
245 } else {
246 Err(anyhow::anyhow!("Expected Integer"))
247 }
248}
249
250pub fn decode_current_error_list(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<ClosureError>> {
252 let mut res = Vec::new();
253 if let tlv::TlvItemValue::List(v) = inp {
254 for item in v {
255 if let tlv::TlvItemValue::Int(i) = &item.value {
256 if let Some(enum_val) = ClosureError::from_u8(*i as u8) {
257 res.push(enum_val);
258 }
259 }
260 }
261 }
262 Ok(res)
263}
264
265pub fn decode_overall_current_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<OverallCurrentState>> {
267 if let tlv::TlvItemValue::List(_fields) = inp {
268 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
270 Ok(Some(OverallCurrentState {
271 position: item.get_int(&[0]).and_then(|v| CurrentPosition::from_u8(v as u8)),
272 latch: item.get_bool(&[1]),
273 speed: item.get_int(&[2]).map(|v| v as u8),
274 secure_state: item.get_bool(&[3]),
275 }))
276 } else {
280 Ok(None)
281 }
283}
284
285pub fn decode_overall_target_state(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<OverallTargetState>> {
287 if let tlv::TlvItemValue::List(_fields) = inp {
288 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
290 Ok(Some(OverallTargetState {
291 position: item.get_int(&[0]).and_then(|v| TargetPosition::from_u8(v as u8)),
292 latch: item.get_bool(&[1]),
293 speed: item.get_int(&[2]).map(|v| v as u8),
294 }))
295 } else {
299 Ok(None)
300 }
302}
303
304pub fn decode_latch_control_modes(inp: &tlv::TlvItemValue) -> anyhow::Result<LatchControlModes> {
306 if let tlv::TlvItemValue::Int(v) = inp {
307 Ok(*v as u8)
308 } else {
309 Err(anyhow::anyhow!("Expected Integer"))
310 }
311}
312
313
314pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
326 if cluster_id != 0x0104 {
328 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0104, got {}\"}}", cluster_id);
329 }
330
331 match attribute_id {
332 0x0000 => {
333 match decode_countdown_time(tlv_value) {
334 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
335 Err(e) => format!("{{\"error\": \"{}\"}}", e),
336 }
337 }
338 0x0001 => {
339 match decode_main_state(tlv_value) {
340 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
341 Err(e) => format!("{{\"error\": \"{}\"}}", e),
342 }
343 }
344 0x0002 => {
345 match decode_current_error_list(tlv_value) {
346 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
347 Err(e) => format!("{{\"error\": \"{}\"}}", e),
348 }
349 }
350 0x0003 => {
351 match decode_overall_current_state(tlv_value) {
352 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
353 Err(e) => format!("{{\"error\": \"{}\"}}", e),
354 }
355 }
356 0x0004 => {
357 match decode_overall_target_state(tlv_value) {
358 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
359 Err(e) => format!("{{\"error\": \"{}\"}}", e),
360 }
361 }
362 0x0005 => {
363 match decode_latch_control_modes(tlv_value) {
364 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
365 Err(e) => format!("{{\"error\": \"{}\"}}", e),
366 }
367 }
368 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
369 }
370}
371
372pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
377 vec![
378 (0x0000, "CountdownTime"),
379 (0x0001, "MainState"),
380 (0x0002, "CurrentErrorList"),
381 (0x0003, "OverallCurrentState"),
382 (0x0004, "OverallTargetState"),
383 (0x0005, "LatchControlModes"),
384 ]
385}
386
387#[derive(Debug, serde::Serialize)]
388pub struct OperationalErrorEvent {
389 pub error_state: Option<Vec<ClosureError>>,
390}
391
392#[derive(Debug, serde::Serialize)]
393pub struct EngageStateChangedEvent {
394 pub engage_value: Option<bool>,
395}
396
397#[derive(Debug, serde::Serialize)]
398pub struct SecureStateChangedEvent {
399 pub secure_value: Option<bool>,
400}
401
402pub fn decode_operational_error_event(inp: &tlv::TlvItemValue) -> anyhow::Result<OperationalErrorEvent> {
406 if let tlv::TlvItemValue::List(_fields) = inp {
407 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
408 Ok(OperationalErrorEvent {
409 error_state: {
410 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
411 let items: Vec<ClosureError> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { ClosureError::from_u8(*v as u8) } else { None } }).collect();
412 Some(items)
413 } else {
414 None
415 }
416 },
417 })
418 } else {
419 Err(anyhow::anyhow!("Expected struct fields"))
420 }
421}
422
423pub fn decode_engage_state_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<EngageStateChangedEvent> {
425 if let tlv::TlvItemValue::List(_fields) = inp {
426 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
427 Ok(EngageStateChangedEvent {
428 engage_value: item.get_bool(&[0]),
429 })
430 } else {
431 Err(anyhow::anyhow!("Expected struct fields"))
432 }
433}
434
435pub fn decode_secure_state_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<SecureStateChangedEvent> {
437 if let tlv::TlvItemValue::List(_fields) = inp {
438 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
439 Ok(SecureStateChangedEvent {
440 secure_value: item.get_bool(&[0]),
441 })
442 } else {
443 Err(anyhow::anyhow!("Expected struct fields"))
444 }
445}
446