1use crate::tlv;
7use anyhow;
8use serde_json;
9
10
11use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
17#[repr(u8)]
18pub enum BootReason {
19 Unspecified = 0,
21 Poweronreboot = 1,
23 Brownoutreset = 2,
25 Softwarewatchdogreset = 3,
27 Hardwarewatchdogreset = 4,
29 Softwareupdatecompleted = 5,
31 Softwarereset = 6,
33}
34
35impl BootReason {
36 pub fn from_u8(value: u8) -> Option<Self> {
38 match value {
39 0 => Some(BootReason::Unspecified),
40 1 => Some(BootReason::Poweronreboot),
41 2 => Some(BootReason::Brownoutreset),
42 3 => Some(BootReason::Softwarewatchdogreset),
43 4 => Some(BootReason::Hardwarewatchdogreset),
44 5 => Some(BootReason::Softwareupdatecompleted),
45 6 => Some(BootReason::Softwarereset),
46 _ => None,
47 }
48 }
49
50 pub fn to_u8(self) -> u8 {
52 self as u8
53 }
54}
55
56impl From<BootReason> for u8 {
57 fn from(val: BootReason) -> Self {
58 val as u8
59 }
60}
61
62#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
63#[repr(u8)]
64pub enum HardwareFault {
65 Unspecified = 0,
67 Radio = 1,
69 Sensor = 2,
71 Resettableovertemp = 3,
73 Nonresettableovertemp = 4,
75 Powersource = 5,
77 Visualdisplayfault = 6,
79 Audiooutputfault = 7,
81 Userinterfacefault = 8,
83 Nonvolatilememoryerror = 9,
85 Tamperdetected = 10,
87}
88
89impl HardwareFault {
90 pub fn from_u8(value: u8) -> Option<Self> {
92 match value {
93 0 => Some(HardwareFault::Unspecified),
94 1 => Some(HardwareFault::Radio),
95 2 => Some(HardwareFault::Sensor),
96 3 => Some(HardwareFault::Resettableovertemp),
97 4 => Some(HardwareFault::Nonresettableovertemp),
98 5 => Some(HardwareFault::Powersource),
99 6 => Some(HardwareFault::Visualdisplayfault),
100 7 => Some(HardwareFault::Audiooutputfault),
101 8 => Some(HardwareFault::Userinterfacefault),
102 9 => Some(HardwareFault::Nonvolatilememoryerror),
103 10 => Some(HardwareFault::Tamperdetected),
104 _ => None,
105 }
106 }
107
108 pub fn to_u8(self) -> u8 {
110 self as u8
111 }
112}
113
114impl From<HardwareFault> for u8 {
115 fn from(val: HardwareFault) -> Self {
116 val as u8
117 }
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
121#[repr(u8)]
122pub enum InterfaceType {
123 Unspecified = 0,
125 Wifi = 1,
127 Ethernet = 2,
129 Cellular = 3,
131 Thread = 4,
133}
134
135impl InterfaceType {
136 pub fn from_u8(value: u8) -> Option<Self> {
138 match value {
139 0 => Some(InterfaceType::Unspecified),
140 1 => Some(InterfaceType::Wifi),
141 2 => Some(InterfaceType::Ethernet),
142 3 => Some(InterfaceType::Cellular),
143 4 => Some(InterfaceType::Thread),
144 _ => None,
145 }
146 }
147
148 pub fn to_u8(self) -> u8 {
150 self as u8
151 }
152}
153
154impl From<InterfaceType> for u8 {
155 fn from(val: InterfaceType) -> Self {
156 val as u8
157 }
158}
159
160#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
161#[repr(u8)]
162pub enum NetworkFault {
163 Unspecified = 0,
165 Hardwarefailure = 1,
167 Networkjammed = 2,
169 Connectionfailed = 3,
171}
172
173impl NetworkFault {
174 pub fn from_u8(value: u8) -> Option<Self> {
176 match value {
177 0 => Some(NetworkFault::Unspecified),
178 1 => Some(NetworkFault::Hardwarefailure),
179 2 => Some(NetworkFault::Networkjammed),
180 3 => Some(NetworkFault::Connectionfailed),
181 _ => None,
182 }
183 }
184
185 pub fn to_u8(self) -> u8 {
187 self as u8
188 }
189}
190
191impl From<NetworkFault> for u8 {
192 fn from(val: NetworkFault) -> Self {
193 val as u8
194 }
195}
196
197#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
198#[repr(u8)]
199pub enum RadioFault {
200 Unspecified = 0,
202 Wififault = 1,
204 Cellularfault = 2,
206 Threadfault = 3,
208 Nfcfault = 4,
210 Blefault = 5,
212 Ethernetfault = 6,
214}
215
216impl RadioFault {
217 pub fn from_u8(value: u8) -> Option<Self> {
219 match value {
220 0 => Some(RadioFault::Unspecified),
221 1 => Some(RadioFault::Wififault),
222 2 => Some(RadioFault::Cellularfault),
223 3 => Some(RadioFault::Threadfault),
224 4 => Some(RadioFault::Nfcfault),
225 5 => Some(RadioFault::Blefault),
226 6 => Some(RadioFault::Ethernetfault),
227 _ => None,
228 }
229 }
230
231 pub fn to_u8(self) -> u8 {
233 self as u8
234 }
235}
236
237impl From<RadioFault> for u8 {
238 fn from(val: RadioFault) -> Self {
239 val as u8
240 }
241}
242
243#[derive(Debug, serde::Serialize)]
246pub struct NetworkInterface {
247 pub name: Option<String>,
248 pub is_operational: Option<bool>,
249 pub off_premise_services_reachable_i_pv4: Option<bool>,
250 pub off_premise_services_reachable_i_pv6: Option<bool>,
251 pub hardware_address: Option<u8>,
252 pub i_pv4_addresses: Option<Vec<u8>>,
253 pub i_pv6_addresses: Option<Vec<u8>>,
254 pub type_: Option<InterfaceType>,
255}
256
257pub fn encode_test_event_trigger(enable_key: Vec<u8>, event_trigger: u64) -> anyhow::Result<Vec<u8>> {
261 let tlv = tlv::TlvItemEnc {
262 tag: 0,
263 value: tlv::TlvItemValueEnc::StructInvisible(vec![
264 (0, tlv::TlvItemValueEnc::OctetString(enable_key)).into(),
265 (1, tlv::TlvItemValueEnc::UInt64(event_trigger)).into(),
266 ]),
267 };
268 Ok(tlv.encode()?)
269}
270
271pub fn encode_payload_test_request(enable_key: Vec<u8>, value: u8, count: u16) -> anyhow::Result<Vec<u8>> {
273 let tlv = tlv::TlvItemEnc {
274 tag: 0,
275 value: tlv::TlvItemValueEnc::StructInvisible(vec![
276 (0, tlv::TlvItemValueEnc::OctetString(enable_key)).into(),
277 (1, tlv::TlvItemValueEnc::UInt8(value)).into(),
278 (2, tlv::TlvItemValueEnc::UInt16(count)).into(),
279 ]),
280 };
281 Ok(tlv.encode()?)
282}
283
284pub fn decode_network_interfaces(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkInterface>> {
288 let mut res = Vec::new();
289 if let tlv::TlvItemValue::List(v) = inp {
290 for item in v {
291 res.push(NetworkInterface {
292 name: item.get_string_owned(&[0]),
293 is_operational: item.get_bool(&[1]),
294 off_premise_services_reachable_i_pv4: item.get_bool(&[2]),
295 off_premise_services_reachable_i_pv6: item.get_bool(&[3]),
296 hardware_address: item.get_int(&[4]).map(|v| v as u8),
297 i_pv4_addresses: {
298 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[5]) {
299 let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
300 Some(items)
301 } else {
302 None
303 }
304 },
305 i_pv6_addresses: {
306 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
307 let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
308 Some(items)
309 } else {
310 None
311 }
312 },
313 type_: item.get_int(&[7]).and_then(|v| InterfaceType::from_u8(v as u8)),
314 });
315 }
316 }
317 Ok(res)
318}
319
320pub fn decode_reboot_count(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
322 if let tlv::TlvItemValue::Int(v) = inp {
323 Ok(*v as u16)
324 } else {
325 Err(anyhow::anyhow!("Expected UInt16"))
326 }
327}
328
329pub fn decode_up_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
331 if let tlv::TlvItemValue::Int(v) = inp {
332 Ok(*v)
333 } else {
334 Err(anyhow::anyhow!("Expected UInt64"))
335 }
336}
337
338pub fn decode_total_operational_hours(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
340 if let tlv::TlvItemValue::Int(v) = inp {
341 Ok(*v as u32)
342 } else {
343 Err(anyhow::anyhow!("Expected UInt32"))
344 }
345}
346
347pub fn decode_boot_reason(inp: &tlv::TlvItemValue) -> anyhow::Result<BootReason> {
349 if let tlv::TlvItemValue::Int(v) = inp {
350 BootReason::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
351 } else {
352 Err(anyhow::anyhow!("Expected Integer"))
353 }
354}
355
356pub fn decode_active_hardware_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<HardwareFault>> {
358 let mut res = Vec::new();
359 if let tlv::TlvItemValue::List(v) = inp {
360 for item in v {
361 if let tlv::TlvItemValue::Int(i) = &item.value {
362 if let Some(enum_val) = HardwareFault::from_u8(*i as u8) {
363 res.push(enum_val);
364 }
365 }
366 }
367 }
368 Ok(res)
369}
370
371pub fn decode_active_radio_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<RadioFault>> {
373 let mut res = Vec::new();
374 if let tlv::TlvItemValue::List(v) = inp {
375 for item in v {
376 if let tlv::TlvItemValue::Int(i) = &item.value {
377 if let Some(enum_val) = RadioFault::from_u8(*i as u8) {
378 res.push(enum_val);
379 }
380 }
381 }
382 }
383 Ok(res)
384}
385
386pub fn decode_active_network_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkFault>> {
388 let mut res = Vec::new();
389 if let tlv::TlvItemValue::List(v) = inp {
390 for item in v {
391 if let tlv::TlvItemValue::Int(i) = &item.value {
392 if let Some(enum_val) = NetworkFault::from_u8(*i as u8) {
393 res.push(enum_val);
394 }
395 }
396 }
397 }
398 Ok(res)
399}
400
401pub fn decode_test_event_triggers_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
403 if let tlv::TlvItemValue::Bool(v) = inp {
404 Ok(*v)
405 } else {
406 Err(anyhow::anyhow!("Expected Bool"))
407 }
408}
409
410pub fn decode_do_not_use(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
412 if let tlv::TlvItemValue::Int(v) = inp {
413 Ok(*v as u8)
414 } else {
415 Err(anyhow::anyhow!("Expected UInt8"))
416 }
417}
418
419
420pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
432 if cluster_id != 0x0033 {
434 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0033, got {}\"}}", cluster_id);
435 }
436
437 match attribute_id {
438 0x0000 => {
439 match decode_network_interfaces(tlv_value) {
440 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
441 Err(e) => format!("{{\"error\": \"{}\"}}", e),
442 }
443 }
444 0x0001 => {
445 match decode_reboot_count(tlv_value) {
446 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
447 Err(e) => format!("{{\"error\": \"{}\"}}", e),
448 }
449 }
450 0x0002 => {
451 match decode_up_time(tlv_value) {
452 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
453 Err(e) => format!("{{\"error\": \"{}\"}}", e),
454 }
455 }
456 0x0003 => {
457 match decode_total_operational_hours(tlv_value) {
458 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
459 Err(e) => format!("{{\"error\": \"{}\"}}", e),
460 }
461 }
462 0x0004 => {
463 match decode_boot_reason(tlv_value) {
464 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
465 Err(e) => format!("{{\"error\": \"{}\"}}", e),
466 }
467 }
468 0x0005 => {
469 match decode_active_hardware_faults(tlv_value) {
470 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
471 Err(e) => format!("{{\"error\": \"{}\"}}", e),
472 }
473 }
474 0x0006 => {
475 match decode_active_radio_faults(tlv_value) {
476 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
477 Err(e) => format!("{{\"error\": \"{}\"}}", e),
478 }
479 }
480 0x0007 => {
481 match decode_active_network_faults(tlv_value) {
482 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
483 Err(e) => format!("{{\"error\": \"{}\"}}", e),
484 }
485 }
486 0x0008 => {
487 match decode_test_event_triggers_enabled(tlv_value) {
488 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
489 Err(e) => format!("{{\"error\": \"{}\"}}", e),
490 }
491 }
492 0x0009 => {
493 match decode_do_not_use(tlv_value) {
494 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
495 Err(e) => format!("{{\"error\": \"{}\"}}", e),
496 }
497 }
498 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
499 }
500}
501
502pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
507 vec![
508 (0x0000, "NetworkInterfaces"),
509 (0x0001, "RebootCount"),
510 (0x0002, "UpTime"),
511 (0x0003, "TotalOperationalHours"),
512 (0x0004, "BootReason"),
513 (0x0005, "ActiveHardwareFaults"),
514 (0x0006, "ActiveRadioFaults"),
515 (0x0007, "ActiveNetworkFaults"),
516 (0x0008, "TestEventTriggersEnabled"),
517 (0x0009, "DoNotUse"),
518 ]
519}
520
521#[derive(Debug, serde::Serialize)]
522pub struct TimeSnapshotResponse {
523 pub system_time_ms: Option<u8>,
524 pub posix_time_ms: Option<u8>,
525}
526
527#[derive(Debug, serde::Serialize)]
528pub struct PayloadTestResponse {
529 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
530 pub payload: Option<Vec<u8>>,
531}
532
533pub fn decode_time_snapshot_response(inp: &tlv::TlvItemValue) -> anyhow::Result<TimeSnapshotResponse> {
537 if let tlv::TlvItemValue::List(_fields) = inp {
538 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
539 Ok(TimeSnapshotResponse {
540 system_time_ms: item.get_int(&[0]).map(|v| v as u8),
541 posix_time_ms: item.get_int(&[1]).map(|v| v as u8),
542 })
543 } else {
544 Err(anyhow::anyhow!("Expected struct fields"))
545 }
546}
547
548pub fn decode_payload_test_response(inp: &tlv::TlvItemValue) -> anyhow::Result<PayloadTestResponse> {
550 if let tlv::TlvItemValue::List(_fields) = inp {
551 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
552 Ok(PayloadTestResponse {
553 payload: item.get_octet_string_owned(&[0]),
554 })
555 } else {
556 Err(anyhow::anyhow!("Expected struct fields"))
557 }
558}
559
560#[derive(Debug, serde::Serialize)]
561pub struct HardwareFaultChangeEvent {
562 pub current: Option<Vec<HardwareFault>>,
563 pub previous: Option<Vec<HardwareFault>>,
564}
565
566#[derive(Debug, serde::Serialize)]
567pub struct RadioFaultChangeEvent {
568 pub current: Option<Vec<RadioFault>>,
569 pub previous: Option<Vec<RadioFault>>,
570}
571
572#[derive(Debug, serde::Serialize)]
573pub struct NetworkFaultChangeEvent {
574 pub current: Option<Vec<NetworkFault>>,
575 pub previous: Option<Vec<NetworkFault>>,
576}
577
578#[derive(Debug, serde::Serialize)]
579pub struct BootReasonEvent {
580 pub boot_reason: Option<BootReason>,
581}
582
583pub fn decode_hardware_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<HardwareFaultChangeEvent> {
587 if let tlv::TlvItemValue::List(_fields) = inp {
588 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
589 Ok(HardwareFaultChangeEvent {
590 current: {
591 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
592 let items: Vec<HardwareFault> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { HardwareFault::from_u8(*v as u8) } else { None } }).collect();
593 Some(items)
594 } else {
595 None
596 }
597 },
598 previous: {
599 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
600 let items: Vec<HardwareFault> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { HardwareFault::from_u8(*v as u8) } else { None } }).collect();
601 Some(items)
602 } else {
603 None
604 }
605 },
606 })
607 } else {
608 Err(anyhow::anyhow!("Expected struct fields"))
609 }
610}
611
612pub fn decode_radio_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<RadioFaultChangeEvent> {
614 if let tlv::TlvItemValue::List(_fields) = inp {
615 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
616 Ok(RadioFaultChangeEvent {
617 current: {
618 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
619 let items: Vec<RadioFault> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { RadioFault::from_u8(*v as u8) } else { None } }).collect();
620 Some(items)
621 } else {
622 None
623 }
624 },
625 previous: {
626 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
627 let items: Vec<RadioFault> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { RadioFault::from_u8(*v as u8) } else { None } }).collect();
628 Some(items)
629 } else {
630 None
631 }
632 },
633 })
634 } else {
635 Err(anyhow::anyhow!("Expected struct fields"))
636 }
637}
638
639pub fn decode_network_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<NetworkFaultChangeEvent> {
641 if let tlv::TlvItemValue::List(_fields) = inp {
642 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
643 Ok(NetworkFaultChangeEvent {
644 current: {
645 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
646 let items: Vec<NetworkFault> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { NetworkFault::from_u8(*v as u8) } else { None } }).collect();
647 Some(items)
648 } else {
649 None
650 }
651 },
652 previous: {
653 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
654 let items: Vec<NetworkFault> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { NetworkFault::from_u8(*v as u8) } else { None } }).collect();
655 Some(items)
656 } else {
657 None
658 }
659 },
660 })
661 } else {
662 Err(anyhow::anyhow!("Expected struct fields"))
663 }
664}
665
666pub fn decode_boot_reason_event(inp: &tlv::TlvItemValue) -> anyhow::Result<BootReasonEvent> {
668 if let tlv::TlvItemValue::List(_fields) = inp {
669 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
670 Ok(BootReasonEvent {
671 boot_reason: item.get_int(&[0]).and_then(|v| BootReason::from_u8(v as u8)),
672 })
673 } else {
674 Err(anyhow::anyhow!("Expected struct fields"))
675 }
676}
677