1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum BootReason {
21 Unspecified = 0,
23 Poweronreboot = 1,
25 Brownoutreset = 2,
27 Softwarewatchdogreset = 3,
29 Hardwarewatchdogreset = 4,
31 Softwareupdatecompleted = 5,
33 Softwarereset = 6,
35}
36
37impl BootReason {
38 pub fn from_u8(value: u8) -> Option<Self> {
40 match value {
41 0 => Some(BootReason::Unspecified),
42 1 => Some(BootReason::Poweronreboot),
43 2 => Some(BootReason::Brownoutreset),
44 3 => Some(BootReason::Softwarewatchdogreset),
45 4 => Some(BootReason::Hardwarewatchdogreset),
46 5 => Some(BootReason::Softwareupdatecompleted),
47 6 => Some(BootReason::Softwarereset),
48 _ => None,
49 }
50 }
51
52 pub fn to_u8(self) -> u8 {
54 self as u8
55 }
56}
57
58impl From<BootReason> for u8 {
59 fn from(val: BootReason) -> Self {
60 val as u8
61 }
62}
63
64#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
65#[repr(u8)]
66pub enum HardwareFault {
67 Unspecified = 0,
69 Radio = 1,
71 Sensor = 2,
73 Resettableovertemp = 3,
75 Nonresettableovertemp = 4,
77 Powersource = 5,
79 Visualdisplayfault = 6,
81 Audiooutputfault = 7,
83 Userinterfacefault = 8,
85 Nonvolatilememoryerror = 9,
87 Tamperdetected = 10,
89}
90
91impl HardwareFault {
92 pub fn from_u8(value: u8) -> Option<Self> {
94 match value {
95 0 => Some(HardwareFault::Unspecified),
96 1 => Some(HardwareFault::Radio),
97 2 => Some(HardwareFault::Sensor),
98 3 => Some(HardwareFault::Resettableovertemp),
99 4 => Some(HardwareFault::Nonresettableovertemp),
100 5 => Some(HardwareFault::Powersource),
101 6 => Some(HardwareFault::Visualdisplayfault),
102 7 => Some(HardwareFault::Audiooutputfault),
103 8 => Some(HardwareFault::Userinterfacefault),
104 9 => Some(HardwareFault::Nonvolatilememoryerror),
105 10 => Some(HardwareFault::Tamperdetected),
106 _ => None,
107 }
108 }
109
110 pub fn to_u8(self) -> u8 {
112 self as u8
113 }
114}
115
116impl From<HardwareFault> for u8 {
117 fn from(val: HardwareFault) -> Self {
118 val as u8
119 }
120}
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
123#[repr(u8)]
124pub enum InterfaceType {
125 Unspecified = 0,
127 Wifi = 1,
129 Ethernet = 2,
131 Cellular = 3,
133 Thread = 4,
135}
136
137impl InterfaceType {
138 pub fn from_u8(value: u8) -> Option<Self> {
140 match value {
141 0 => Some(InterfaceType::Unspecified),
142 1 => Some(InterfaceType::Wifi),
143 2 => Some(InterfaceType::Ethernet),
144 3 => Some(InterfaceType::Cellular),
145 4 => Some(InterfaceType::Thread),
146 _ => None,
147 }
148 }
149
150 pub fn to_u8(self) -> u8 {
152 self as u8
153 }
154}
155
156impl From<InterfaceType> for u8 {
157 fn from(val: InterfaceType) -> Self {
158 val as u8
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
163#[repr(u8)]
164pub enum NetworkFault {
165 Unspecified = 0,
167 Hardwarefailure = 1,
169 Networkjammed = 2,
171 Connectionfailed = 3,
173}
174
175impl NetworkFault {
176 pub fn from_u8(value: u8) -> Option<Self> {
178 match value {
179 0 => Some(NetworkFault::Unspecified),
180 1 => Some(NetworkFault::Hardwarefailure),
181 2 => Some(NetworkFault::Networkjammed),
182 3 => Some(NetworkFault::Connectionfailed),
183 _ => None,
184 }
185 }
186
187 pub fn to_u8(self) -> u8 {
189 self as u8
190 }
191}
192
193impl From<NetworkFault> for u8 {
194 fn from(val: NetworkFault) -> Self {
195 val as u8
196 }
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
200#[repr(u8)]
201pub enum RadioFault {
202 Unspecified = 0,
204 Wififault = 1,
206 Cellularfault = 2,
208 Threadfault = 3,
210 Nfcfault = 4,
212 Blefault = 5,
214 Ethernetfault = 6,
216}
217
218impl RadioFault {
219 pub fn from_u8(value: u8) -> Option<Self> {
221 match value {
222 0 => Some(RadioFault::Unspecified),
223 1 => Some(RadioFault::Wififault),
224 2 => Some(RadioFault::Cellularfault),
225 3 => Some(RadioFault::Threadfault),
226 4 => Some(RadioFault::Nfcfault),
227 5 => Some(RadioFault::Blefault),
228 6 => Some(RadioFault::Ethernetfault),
229 _ => None,
230 }
231 }
232
233 pub fn to_u8(self) -> u8 {
235 self as u8
236 }
237}
238
239impl From<RadioFault> for u8 {
240 fn from(val: RadioFault) -> Self {
241 val as u8
242 }
243}
244
245#[derive(Debug, serde::Serialize)]
248pub struct NetworkInterface {
249 pub name: Option<String>,
250 pub is_operational: Option<bool>,
251 pub off_premise_services_reachable_i_pv4: Option<bool>,
252 pub off_premise_services_reachable_i_pv6: Option<bool>,
253 pub hardware_address: Option<u8>,
254 pub i_pv4_addresses: Option<Vec<u8>>,
255 pub i_pv6_addresses: Option<Vec<u8>>,
256 pub type_: Option<InterfaceType>,
257}
258
259pub fn encode_test_event_trigger(enable_key: Vec<u8>, event_trigger: u64) -> anyhow::Result<Vec<u8>> {
263 let tlv = tlv::TlvItemEnc {
264 tag: 0,
265 value: tlv::TlvItemValueEnc::StructInvisible(vec![
266 (0, tlv::TlvItemValueEnc::OctetString(enable_key)).into(),
267 (1, tlv::TlvItemValueEnc::UInt64(event_trigger)).into(),
268 ]),
269 };
270 Ok(tlv.encode()?)
271}
272
273pub fn encode_payload_test_request(enable_key: Vec<u8>, value: u8, count: u16) -> anyhow::Result<Vec<u8>> {
275 let tlv = tlv::TlvItemEnc {
276 tag: 0,
277 value: tlv::TlvItemValueEnc::StructInvisible(vec![
278 (0, tlv::TlvItemValueEnc::OctetString(enable_key)).into(),
279 (1, tlv::TlvItemValueEnc::UInt8(value)).into(),
280 (2, tlv::TlvItemValueEnc::UInt16(count)).into(),
281 ]),
282 };
283 Ok(tlv.encode()?)
284}
285
286pub fn decode_network_interfaces(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkInterface>> {
290 let mut res = Vec::new();
291 if let tlv::TlvItemValue::List(v) = inp {
292 for item in v {
293 res.push(NetworkInterface {
294 name: item.get_string_owned(&[0]),
295 is_operational: item.get_bool(&[1]),
296 off_premise_services_reachable_i_pv4: item.get_bool(&[2]),
297 off_premise_services_reachable_i_pv6: item.get_bool(&[3]),
298 hardware_address: item.get_int(&[4]).map(|v| v as u8),
299 i_pv4_addresses: {
300 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[5]) {
301 let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
302 Some(items)
303 } else {
304 None
305 }
306 },
307 i_pv6_addresses: {
308 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
309 let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
310 Some(items)
311 } else {
312 None
313 }
314 },
315 type_: item.get_int(&[7]).and_then(|v| InterfaceType::from_u8(v as u8)),
316 });
317 }
318 }
319 Ok(res)
320}
321
322pub fn decode_reboot_count(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
324 if let tlv::TlvItemValue::Int(v) = inp {
325 Ok(*v as u16)
326 } else {
327 Err(anyhow::anyhow!("Expected UInt16"))
328 }
329}
330
331pub fn decode_up_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
333 if let tlv::TlvItemValue::Int(v) = inp {
334 Ok(*v)
335 } else {
336 Err(anyhow::anyhow!("Expected UInt64"))
337 }
338}
339
340pub fn decode_total_operational_hours(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
342 if let tlv::TlvItemValue::Int(v) = inp {
343 Ok(*v as u32)
344 } else {
345 Err(anyhow::anyhow!("Expected UInt32"))
346 }
347}
348
349pub fn decode_boot_reason(inp: &tlv::TlvItemValue) -> anyhow::Result<BootReason> {
351 if let tlv::TlvItemValue::Int(v) = inp {
352 BootReason::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
353 } else {
354 Err(anyhow::anyhow!("Expected Integer"))
355 }
356}
357
358pub fn decode_active_hardware_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<HardwareFault>> {
360 let mut res = Vec::new();
361 if let tlv::TlvItemValue::List(v) = inp {
362 for item in v {
363 if let tlv::TlvItemValue::Int(i) = &item.value {
364 if let Some(enum_val) = HardwareFault::from_u8(*i as u8) {
365 res.push(enum_val);
366 }
367 }
368 }
369 }
370 Ok(res)
371}
372
373pub fn decode_active_radio_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<RadioFault>> {
375 let mut res = Vec::new();
376 if let tlv::TlvItemValue::List(v) = inp {
377 for item in v {
378 if let tlv::TlvItemValue::Int(i) = &item.value {
379 if let Some(enum_val) = RadioFault::from_u8(*i as u8) {
380 res.push(enum_val);
381 }
382 }
383 }
384 }
385 Ok(res)
386}
387
388pub fn decode_active_network_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkFault>> {
390 let mut res = Vec::new();
391 if let tlv::TlvItemValue::List(v) = inp {
392 for item in v {
393 if let tlv::TlvItemValue::Int(i) = &item.value {
394 if let Some(enum_val) = NetworkFault::from_u8(*i as u8) {
395 res.push(enum_val);
396 }
397 }
398 }
399 }
400 Ok(res)
401}
402
403pub fn decode_test_event_triggers_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
405 if let tlv::TlvItemValue::Bool(v) = inp {
406 Ok(*v)
407 } else {
408 Err(anyhow::anyhow!("Expected Bool"))
409 }
410}
411
412pub fn decode_do_not_use(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
414 if let tlv::TlvItemValue::Int(v) = inp {
415 Ok(*v as u8)
416 } else {
417 Err(anyhow::anyhow!("Expected UInt8"))
418 }
419}
420
421
422pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
434 if cluster_id != 0x0033 {
436 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0033, got {}\"}}", cluster_id);
437 }
438
439 match attribute_id {
440 0x0000 => {
441 match decode_network_interfaces(tlv_value) {
442 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
443 Err(e) => format!("{{\"error\": \"{}\"}}", e),
444 }
445 }
446 0x0001 => {
447 match decode_reboot_count(tlv_value) {
448 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
449 Err(e) => format!("{{\"error\": \"{}\"}}", e),
450 }
451 }
452 0x0002 => {
453 match decode_up_time(tlv_value) {
454 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
455 Err(e) => format!("{{\"error\": \"{}\"}}", e),
456 }
457 }
458 0x0003 => {
459 match decode_total_operational_hours(tlv_value) {
460 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
461 Err(e) => format!("{{\"error\": \"{}\"}}", e),
462 }
463 }
464 0x0004 => {
465 match decode_boot_reason(tlv_value) {
466 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
467 Err(e) => format!("{{\"error\": \"{}\"}}", e),
468 }
469 }
470 0x0005 => {
471 match decode_active_hardware_faults(tlv_value) {
472 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
473 Err(e) => format!("{{\"error\": \"{}\"}}", e),
474 }
475 }
476 0x0006 => {
477 match decode_active_radio_faults(tlv_value) {
478 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
479 Err(e) => format!("{{\"error\": \"{}\"}}", e),
480 }
481 }
482 0x0007 => {
483 match decode_active_network_faults(tlv_value) {
484 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
485 Err(e) => format!("{{\"error\": \"{}\"}}", e),
486 }
487 }
488 0x0008 => {
489 match decode_test_event_triggers_enabled(tlv_value) {
490 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
491 Err(e) => format!("{{\"error\": \"{}\"}}", e),
492 }
493 }
494 0x0009 => {
495 match decode_do_not_use(tlv_value) {
496 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
497 Err(e) => format!("{{\"error\": \"{}\"}}", e),
498 }
499 }
500 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
501 }
502}
503
504pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
509 vec![
510 (0x0000, "NetworkInterfaces"),
511 (0x0001, "RebootCount"),
512 (0x0002, "UpTime"),
513 (0x0003, "TotalOperationalHours"),
514 (0x0004, "BootReason"),
515 (0x0005, "ActiveHardwareFaults"),
516 (0x0006, "ActiveRadioFaults"),
517 (0x0007, "ActiveNetworkFaults"),
518 (0x0008, "TestEventTriggersEnabled"),
519 (0x0009, "DoNotUse"),
520 ]
521}
522
523pub fn get_command_list() -> Vec<(u32, &'static str)> {
526 vec![
527 (0x00, "TestEventTrigger"),
528 (0x01, "TimeSnapshot"),
529 (0x03, "PayloadTestRequest"),
530 ]
531}
532
533pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
534 match cmd_id {
535 0x00 => Some("TestEventTrigger"),
536 0x01 => Some("TimeSnapshot"),
537 0x03 => Some("PayloadTestRequest"),
538 _ => None,
539 }
540}
541
542pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
543 match cmd_id {
544 0x00 => Some(vec![
545 crate::clusters::codec::CommandField { tag: 0, name: "enable_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
546 crate::clusters::codec::CommandField { tag: 1, name: "event_trigger", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
547 ]),
548 0x01 => Some(vec![]),
549 0x03 => Some(vec![
550 crate::clusters::codec::CommandField { tag: 0, name: "enable_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
551 crate::clusters::codec::CommandField { tag: 1, name: "value", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
552 crate::clusters::codec::CommandField { tag: 2, name: "count", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
553 ]),
554 _ => None,
555 }
556}
557
558pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
559 match cmd_id {
560 0x00 => {
561 let enable_key = crate::clusters::codec::json_util::get_octstr(args, "enable_key")?;
562 let event_trigger = crate::clusters::codec::json_util::get_u64(args, "event_trigger")?;
563 encode_test_event_trigger(enable_key, event_trigger)
564 }
565 0x01 => Ok(vec![]),
566 0x03 => {
567 let enable_key = crate::clusters::codec::json_util::get_octstr(args, "enable_key")?;
568 let value = crate::clusters::codec::json_util::get_u8(args, "value")?;
569 let count = crate::clusters::codec::json_util::get_u16(args, "count")?;
570 encode_payload_test_request(enable_key, value, count)
571 }
572 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
573 }
574}
575
576#[derive(Debug, serde::Serialize)]
577pub struct TimeSnapshotResponse {
578 pub system_time_ms: Option<u8>,
579 pub posix_time_ms: Option<u8>,
580}
581
582#[derive(Debug, serde::Serialize)]
583pub struct PayloadTestResponse {
584 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
585 pub payload: Option<Vec<u8>>,
586}
587
588pub fn decode_time_snapshot_response(inp: &tlv::TlvItemValue) -> anyhow::Result<TimeSnapshotResponse> {
592 if let tlv::TlvItemValue::List(_fields) = inp {
593 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
594 Ok(TimeSnapshotResponse {
595 system_time_ms: item.get_int(&[0]).map(|v| v as u8),
596 posix_time_ms: item.get_int(&[1]).map(|v| v as u8),
597 })
598 } else {
599 Err(anyhow::anyhow!("Expected struct fields"))
600 }
601}
602
603pub fn decode_payload_test_response(inp: &tlv::TlvItemValue) -> anyhow::Result<PayloadTestResponse> {
605 if let tlv::TlvItemValue::List(_fields) = inp {
606 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
607 Ok(PayloadTestResponse {
608 payload: item.get_octet_string_owned(&[0]),
609 })
610 } else {
611 Err(anyhow::anyhow!("Expected struct fields"))
612 }
613}
614
615pub async fn test_event_trigger(conn: &crate::controller::Connection, endpoint: u16, enable_key: Vec<u8>, event_trigger: u64) -> anyhow::Result<()> {
619 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_CMD_ID_TESTEVENTTRIGGER, &encode_test_event_trigger(enable_key, event_trigger)?).await?;
620 Ok(())
621}
622
623pub async fn time_snapshot(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TimeSnapshotResponse> {
625 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_CMD_ID_TIMESNAPSHOT, &[]).await?;
626 decode_time_snapshot_response(&tlv)
627}
628
629pub async fn payload_test_request(conn: &crate::controller::Connection, endpoint: u16, enable_key: Vec<u8>, value: u8, count: u16) -> anyhow::Result<PayloadTestResponse> {
631 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_CMD_ID_PAYLOADTESTREQUEST, &encode_payload_test_request(enable_key, value, count)?).await?;
632 decode_payload_test_response(&tlv)
633}
634
635pub async fn read_network_interfaces(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<NetworkInterface>> {
637 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_NETWORKINTERFACES).await?;
638 decode_network_interfaces(&tlv)
639}
640
641pub async fn read_reboot_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
643 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_REBOOTCOUNT).await?;
644 decode_reboot_count(&tlv)
645}
646
647pub async fn read_up_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u64> {
649 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_UPTIME).await?;
650 decode_up_time(&tlv)
651}
652
653pub async fn read_total_operational_hours(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
655 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_TOTALOPERATIONALHOURS).await?;
656 decode_total_operational_hours(&tlv)
657}
658
659pub async fn read_boot_reason(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<BootReason> {
661 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_BOOTREASON).await?;
662 decode_boot_reason(&tlv)
663}
664
665pub async fn read_active_hardware_faults(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<HardwareFault>> {
667 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_ACTIVEHARDWAREFAULTS).await?;
668 decode_active_hardware_faults(&tlv)
669}
670
671pub async fn read_active_radio_faults(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<RadioFault>> {
673 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_ACTIVERADIOFAULTS).await?;
674 decode_active_radio_faults(&tlv)
675}
676
677pub async fn read_active_network_faults(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<NetworkFault>> {
679 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_ACTIVENETWORKFAULTS).await?;
680 decode_active_network_faults(&tlv)
681}
682
683pub async fn read_test_event_triggers_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
685 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_TESTEVENTTRIGGERSENABLED).await?;
686 decode_test_event_triggers_enabled(&tlv)
687}
688
689pub async fn read_do_not_use(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
691 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_DONOTUSE).await?;
692 decode_do_not_use(&tlv)
693}
694
695#[derive(Debug, serde::Serialize)]
696pub struct HardwareFaultChangeEvent {
697 pub current: Option<Vec<HardwareFault>>,
698 pub previous: Option<Vec<HardwareFault>>,
699}
700
701#[derive(Debug, serde::Serialize)]
702pub struct RadioFaultChangeEvent {
703 pub current: Option<Vec<RadioFault>>,
704 pub previous: Option<Vec<RadioFault>>,
705}
706
707#[derive(Debug, serde::Serialize)]
708pub struct NetworkFaultChangeEvent {
709 pub current: Option<Vec<NetworkFault>>,
710 pub previous: Option<Vec<NetworkFault>>,
711}
712
713#[derive(Debug, serde::Serialize)]
714pub struct BootReasonEvent {
715 pub boot_reason: Option<BootReason>,
716}
717
718pub fn decode_hardware_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<HardwareFaultChangeEvent> {
722 if let tlv::TlvItemValue::List(_fields) = inp {
723 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
724 Ok(HardwareFaultChangeEvent {
725 current: {
726 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
727 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();
728 Some(items)
729 } else {
730 None
731 }
732 },
733 previous: {
734 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
735 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();
736 Some(items)
737 } else {
738 None
739 }
740 },
741 })
742 } else {
743 Err(anyhow::anyhow!("Expected struct fields"))
744 }
745}
746
747pub fn decode_radio_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<RadioFaultChangeEvent> {
749 if let tlv::TlvItemValue::List(_fields) = inp {
750 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
751 Ok(RadioFaultChangeEvent {
752 current: {
753 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
754 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();
755 Some(items)
756 } else {
757 None
758 }
759 },
760 previous: {
761 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
762 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();
763 Some(items)
764 } else {
765 None
766 }
767 },
768 })
769 } else {
770 Err(anyhow::anyhow!("Expected struct fields"))
771 }
772}
773
774pub fn decode_network_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<NetworkFaultChangeEvent> {
776 if let tlv::TlvItemValue::List(_fields) = inp {
777 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
778 Ok(NetworkFaultChangeEvent {
779 current: {
780 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
781 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();
782 Some(items)
783 } else {
784 None
785 }
786 },
787 previous: {
788 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
789 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();
790 Some(items)
791 } else {
792 None
793 }
794 },
795 })
796 } else {
797 Err(anyhow::anyhow!("Expected struct fields"))
798 }
799}
800
801pub fn decode_boot_reason_event(inp: &tlv::TlvItemValue) -> anyhow::Result<BootReasonEvent> {
803 if let tlv::TlvItemValue::List(_fields) = inp {
804 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
805 Ok(BootReasonEvent {
806 boot_reason: item.get_int(&[0]).and_then(|v| BootReason::from_u8(v as u8)),
807 })
808 } else {
809 Err(anyhow::anyhow!("Expected struct fields"))
810 }
811}
812