1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11pub fn encode_go_to_lift_value(lift_value: u16) -> anyhow::Result<Vec<u8>> {
15 let tlv = tlv::TlvItemEnc {
16 tag: 0,
17 value: tlv::TlvItemValueEnc::StructInvisible(vec![
18 (0, tlv::TlvItemValueEnc::UInt16(lift_value)).into(),
19 ]),
20 };
21 Ok(tlv.encode()?)
22}
23
24pub fn encode_go_to_lift_percentage(lift_percent100ths_value: u8) -> anyhow::Result<Vec<u8>> {
26 let tlv = tlv::TlvItemEnc {
27 tag: 0,
28 value: tlv::TlvItemValueEnc::StructInvisible(vec![
29 (0, tlv::TlvItemValueEnc::UInt8(lift_percent100ths_value)).into(),
30 ]),
31 };
32 Ok(tlv.encode()?)
33}
34
35pub fn encode_go_to_tilt_value(tilt_value: u16) -> anyhow::Result<Vec<u8>> {
37 let tlv = tlv::TlvItemEnc {
38 tag: 0,
39 value: tlv::TlvItemValueEnc::StructInvisible(vec![
40 (0, tlv::TlvItemValueEnc::UInt16(tilt_value)).into(),
41 ]),
42 };
43 Ok(tlv.encode()?)
44}
45
46pub fn encode_go_to_tilt_percentage(tilt_percent100ths_value: u8) -> anyhow::Result<Vec<u8>> {
48 let tlv = tlv::TlvItemEnc {
49 tag: 0,
50 value: tlv::TlvItemValueEnc::StructInvisible(vec![
51 (0, tlv::TlvItemValueEnc::UInt8(tilt_percent100ths_value)).into(),
52 ]),
53 };
54 Ok(tlv.encode()?)
55}
56
57pub fn decode_type_(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
61 if let tlv::TlvItemValue::Int(v) = inp {
62 Ok(*v as u8)
63 } else {
64 Err(anyhow::anyhow!("Expected Integer"))
65 }
66}
67
68pub fn decode_physical_closed_limit_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
70 if let tlv::TlvItemValue::Int(v) = inp {
71 Ok(*v as u16)
72 } else {
73 Err(anyhow::anyhow!("Expected Integer"))
74 }
75}
76
77pub fn decode_physical_closed_limit_tilt(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
79 if let tlv::TlvItemValue::Int(v) = inp {
80 Ok(*v as u16)
81 } else {
82 Err(anyhow::anyhow!("Expected Integer"))
83 }
84}
85
86pub fn decode_current_position_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
88 if let tlv::TlvItemValue::Int(v) = inp {
89 Ok(Some(*v as u16))
90 } else {
91 Ok(None)
92 }
93}
94
95pub fn decode_current_position_tilt(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
97 if let tlv::TlvItemValue::Int(v) = inp {
98 Ok(Some(*v as u16))
99 } else {
100 Ok(None)
101 }
102}
103
104pub fn decode_number_of_actuations_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
106 if let tlv::TlvItemValue::Int(v) = inp {
107 Ok(*v as u16)
108 } else {
109 Err(anyhow::anyhow!("Expected Integer"))
110 }
111}
112
113pub fn decode_number_of_actuations_tilt(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
115 if let tlv::TlvItemValue::Int(v) = inp {
116 Ok(*v as u16)
117 } else {
118 Err(anyhow::anyhow!("Expected Integer"))
119 }
120}
121
122pub fn decode_config_status(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
124 if let tlv::TlvItemValue::Int(v) = inp {
125 Ok(*v as u8)
126 } else {
127 Err(anyhow::anyhow!("Expected Integer"))
128 }
129}
130
131pub fn decode_current_position_lift_percentage(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
133 if let tlv::TlvItemValue::Int(v) = inp {
134 Ok(Some(*v as u8))
135 } else {
136 Ok(None)
137 }
138}
139
140pub fn decode_current_position_tilt_percentage(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
142 if let tlv::TlvItemValue::Int(v) = inp {
143 Ok(Some(*v as u8))
144 } else {
145 Ok(None)
146 }
147}
148
149pub fn decode_operational_status(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
151 if let tlv::TlvItemValue::Int(v) = inp {
152 Ok(*v as u8)
153 } else {
154 Err(anyhow::anyhow!("Expected Integer"))
155 }
156}
157
158pub fn decode_target_position_lift_percent100ths(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
160 if let tlv::TlvItemValue::Int(v) = inp {
161 Ok(Some(*v as u8))
162 } else {
163 Ok(None)
164 }
165}
166
167pub fn decode_target_position_tilt_percent100ths(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
169 if let tlv::TlvItemValue::Int(v) = inp {
170 Ok(Some(*v as u8))
171 } else {
172 Ok(None)
173 }
174}
175
176pub fn decode_end_product_type(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
178 if let tlv::TlvItemValue::Int(v) = inp {
179 Ok(*v as u8)
180 } else {
181 Err(anyhow::anyhow!("Expected Integer"))
182 }
183}
184
185pub fn decode_current_position_lift_percent100ths(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
187 if let tlv::TlvItemValue::Int(v) = inp {
188 Ok(Some(*v as u8))
189 } else {
190 Ok(None)
191 }
192}
193
194pub fn decode_current_position_tilt_percent100ths(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u8>> {
196 if let tlv::TlvItemValue::Int(v) = inp {
197 Ok(Some(*v as u8))
198 } else {
199 Ok(None)
200 }
201}
202
203pub fn decode_installed_open_limit_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
205 if let tlv::TlvItemValue::Int(v) = inp {
206 Ok(*v as u16)
207 } else {
208 Err(anyhow::anyhow!("Expected Integer"))
209 }
210}
211
212pub fn decode_installed_closed_limit_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
214 if let tlv::TlvItemValue::Int(v) = inp {
215 Ok(*v as u16)
216 } else {
217 Err(anyhow::anyhow!("Expected Integer"))
218 }
219}
220
221pub fn decode_installed_open_limit_tilt(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
223 if let tlv::TlvItemValue::Int(v) = inp {
224 Ok(*v as u16)
225 } else {
226 Err(anyhow::anyhow!("Expected Integer"))
227 }
228}
229
230pub fn decode_installed_closed_limit_tilt(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
232 if let tlv::TlvItemValue::Int(v) = inp {
233 Ok(*v as u16)
234 } else {
235 Err(anyhow::anyhow!("Expected Integer"))
236 }
237}
238
239pub fn decode_velocity_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
241 if let tlv::TlvItemValue::Int(v) = inp {
242 Ok(*v as u8)
243 } else {
244 Err(anyhow::anyhow!("Expected Integer"))
245 }
246}
247
248pub fn decode_acceleration_time_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
250 if let tlv::TlvItemValue::Int(v) = inp {
251 Ok(*v as u8)
252 } else {
253 Err(anyhow::anyhow!("Expected Integer"))
254 }
255}
256
257pub fn decode_deceleration_time_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
259 if let tlv::TlvItemValue::Int(v) = inp {
260 Ok(*v as u8)
261 } else {
262 Err(anyhow::anyhow!("Expected Integer"))
263 }
264}
265
266pub fn decode_mode(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
268 if let tlv::TlvItemValue::Int(v) = inp {
269 Ok(*v as u8)
270 } else {
271 Err(anyhow::anyhow!("Expected Integer"))
272 }
273}
274
275pub fn decode_intermediate_setpoints_lift(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
277 if let tlv::TlvItemValue::Int(v) = inp {
278 Ok(*v as u8)
279 } else {
280 Err(anyhow::anyhow!("Expected Integer"))
281 }
282}
283
284pub fn decode_intermediate_setpoints_tilt(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
286 if let tlv::TlvItemValue::Int(v) = inp {
287 Ok(*v as u8)
288 } else {
289 Err(anyhow::anyhow!("Expected Integer"))
290 }
291}
292
293pub fn decode_safety_status(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
295 if let tlv::TlvItemValue::Int(v) = inp {
296 Ok(*v as u8)
297 } else {
298 Err(anyhow::anyhow!("Expected Integer"))
299 }
300}
301
302
303pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
315 if cluster_id != 0x0102 {
317 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0102, got {}\"}}", cluster_id);
318 }
319
320 match attribute_id {
321 0x0000 => {
322 match decode_type_(tlv_value) {
323 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
324 Err(e) => format!("{{\"error\": \"{}\"}}", e),
325 }
326 }
327 0x0001 => {
328 match decode_physical_closed_limit_lift(tlv_value) {
329 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
330 Err(e) => format!("{{\"error\": \"{}\"}}", e),
331 }
332 }
333 0x0002 => {
334 match decode_physical_closed_limit_tilt(tlv_value) {
335 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
336 Err(e) => format!("{{\"error\": \"{}\"}}", e),
337 }
338 }
339 0x0003 => {
340 match decode_current_position_lift(tlv_value) {
341 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
342 Err(e) => format!("{{\"error\": \"{}\"}}", e),
343 }
344 }
345 0x0004 => {
346 match decode_current_position_tilt(tlv_value) {
347 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
348 Err(e) => format!("{{\"error\": \"{}\"}}", e),
349 }
350 }
351 0x0005 => {
352 match decode_number_of_actuations_lift(tlv_value) {
353 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
354 Err(e) => format!("{{\"error\": \"{}\"}}", e),
355 }
356 }
357 0x0006 => {
358 match decode_number_of_actuations_tilt(tlv_value) {
359 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
360 Err(e) => format!("{{\"error\": \"{}\"}}", e),
361 }
362 }
363 0x0007 => {
364 match decode_config_status(tlv_value) {
365 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
366 Err(e) => format!("{{\"error\": \"{}\"}}", e),
367 }
368 }
369 0x0008 => {
370 match decode_current_position_lift_percentage(tlv_value) {
371 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
372 Err(e) => format!("{{\"error\": \"{}\"}}", e),
373 }
374 }
375 0x0009 => {
376 match decode_current_position_tilt_percentage(tlv_value) {
377 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
378 Err(e) => format!("{{\"error\": \"{}\"}}", e),
379 }
380 }
381 0x000A => {
382 match decode_operational_status(tlv_value) {
383 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
384 Err(e) => format!("{{\"error\": \"{}\"}}", e),
385 }
386 }
387 0x000B => {
388 match decode_target_position_lift_percent100ths(tlv_value) {
389 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
390 Err(e) => format!("{{\"error\": \"{}\"}}", e),
391 }
392 }
393 0x000C => {
394 match decode_target_position_tilt_percent100ths(tlv_value) {
395 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
396 Err(e) => format!("{{\"error\": \"{}\"}}", e),
397 }
398 }
399 0x000D => {
400 match decode_end_product_type(tlv_value) {
401 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
402 Err(e) => format!("{{\"error\": \"{}\"}}", e),
403 }
404 }
405 0x000E => {
406 match decode_current_position_lift_percent100ths(tlv_value) {
407 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
408 Err(e) => format!("{{\"error\": \"{}\"}}", e),
409 }
410 }
411 0x000F => {
412 match decode_current_position_tilt_percent100ths(tlv_value) {
413 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
414 Err(e) => format!("{{\"error\": \"{}\"}}", e),
415 }
416 }
417 0x0010 => {
418 match decode_installed_open_limit_lift(tlv_value) {
419 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
420 Err(e) => format!("{{\"error\": \"{}\"}}", e),
421 }
422 }
423 0x0011 => {
424 match decode_installed_closed_limit_lift(tlv_value) {
425 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
426 Err(e) => format!("{{\"error\": \"{}\"}}", e),
427 }
428 }
429 0x0012 => {
430 match decode_installed_open_limit_tilt(tlv_value) {
431 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
432 Err(e) => format!("{{\"error\": \"{}\"}}", e),
433 }
434 }
435 0x0013 => {
436 match decode_installed_closed_limit_tilt(tlv_value) {
437 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
438 Err(e) => format!("{{\"error\": \"{}\"}}", e),
439 }
440 }
441 0x0014 => {
442 match decode_velocity_lift(tlv_value) {
443 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
444 Err(e) => format!("{{\"error\": \"{}\"}}", e),
445 }
446 }
447 0x0015 => {
448 match decode_acceleration_time_lift(tlv_value) {
449 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
450 Err(e) => format!("{{\"error\": \"{}\"}}", e),
451 }
452 }
453 0x0016 => {
454 match decode_deceleration_time_lift(tlv_value) {
455 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
456 Err(e) => format!("{{\"error\": \"{}\"}}", e),
457 }
458 }
459 0x0017 => {
460 match decode_mode(tlv_value) {
461 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
462 Err(e) => format!("{{\"error\": \"{}\"}}", e),
463 }
464 }
465 0x0018 => {
466 match decode_intermediate_setpoints_lift(tlv_value) {
467 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
468 Err(e) => format!("{{\"error\": \"{}\"}}", e),
469 }
470 }
471 0x0019 => {
472 match decode_intermediate_setpoints_tilt(tlv_value) {
473 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
474 Err(e) => format!("{{\"error\": \"{}\"}}", e),
475 }
476 }
477 0x001A => {
478 match decode_safety_status(tlv_value) {
479 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
480 Err(e) => format!("{{\"error\": \"{}\"}}", e),
481 }
482 }
483 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
484 }
485}
486
487pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
492 vec![
493 (0x0000, "Type"),
494 (0x0001, "PhysicalClosedLimitLift"),
495 (0x0002, "PhysicalClosedLimitTilt"),
496 (0x0003, "CurrentPositionLift"),
497 (0x0004, "CurrentPositionTilt"),
498 (0x0005, "NumberOfActuationsLift"),
499 (0x0006, "NumberOfActuationsTilt"),
500 (0x0007, "ConfigStatus"),
501 (0x0008, "CurrentPositionLiftPercentage"),
502 (0x0009, "CurrentPositionTiltPercentage"),
503 (0x000A, "OperationalStatus"),
504 (0x000B, "TargetPositionLiftPercent100ths"),
505 (0x000C, "TargetPositionTiltPercent100ths"),
506 (0x000D, "EndProductType"),
507 (0x000E, "CurrentPositionLiftPercent100ths"),
508 (0x000F, "CurrentPositionTiltPercent100ths"),
509 (0x0010, "InstalledOpenLimitLift"),
510 (0x0011, "InstalledClosedLimitLift"),
511 (0x0012, "InstalledOpenLimitTilt"),
512 (0x0013, "InstalledClosedLimitTilt"),
513 (0x0014, "VelocityLift"),
514 (0x0015, "AccelerationTimeLift"),
515 (0x0016, "DecelerationTimeLift"),
516 (0x0017, "Mode"),
517 (0x0018, "IntermediateSetpointsLift"),
518 (0x0019, "IntermediateSetpointsTilt"),
519 (0x001A, "SafetyStatus"),
520 ]
521}
522