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 DeviceLoad {
249 pub current_subscriptions: Option<u16>,
250 pub current_subscriptions_for_fabric: Option<u16>,
251 pub total_subscriptions_established: Option<u32>,
252 pub total_interaction_model_messages_sent: Option<u32>,
253 pub total_interaction_model_messages_received: Option<u32>,
254}
255
256#[derive(Debug, serde::Serialize)]
257pub struct NetworkInterface {
258 pub name: Option<String>,
259 pub is_operational: Option<bool>,
260 pub off_premise_services_reachable_i_pv4: Option<bool>,
261 pub off_premise_services_reachable_i_pv6: Option<bool>,
262 pub hardware_address: Option<u8>,
263 pub i_pv4_addresses: Option<Vec<u8>>,
264 pub i_pv6_addresses: Option<Vec<u8>>,
265 pub type_: Option<InterfaceType>,
266}
267
268pub fn encode_test_event_trigger(enable_key: Vec<u8>, event_trigger: u64) -> anyhow::Result<Vec<u8>> {
272 let tlv = tlv::TlvItemEnc {
273 tag: 0,
274 value: tlv::TlvItemValueEnc::StructInvisible(vec![
275 (0, tlv::TlvItemValueEnc::OctetString(enable_key)).into(),
276 (1, tlv::TlvItemValueEnc::UInt64(event_trigger)).into(),
277 ]),
278 };
279 Ok(tlv.encode()?)
280}
281
282pub fn encode_payload_test_request(enable_key: Vec<u8>, value: u8, count: u16) -> anyhow::Result<Vec<u8>> {
284 let tlv = tlv::TlvItemEnc {
285 tag: 0,
286 value: tlv::TlvItemValueEnc::StructInvisible(vec![
287 (0, tlv::TlvItemValueEnc::OctetString(enable_key)).into(),
288 (1, tlv::TlvItemValueEnc::UInt8(value)).into(),
289 (2, tlv::TlvItemValueEnc::UInt16(count)).into(),
290 ]),
291 };
292 Ok(tlv.encode()?)
293}
294
295pub fn decode_network_interfaces(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkInterface>> {
299 let mut res = Vec::new();
300 if let tlv::TlvItemValue::List(v) = inp {
301 for item in v {
302 res.push(NetworkInterface {
303 name: item.get_string_owned(&[0]),
304 is_operational: item.get_bool(&[1]),
305 off_premise_services_reachable_i_pv4: item.get_bool(&[2]),
306 off_premise_services_reachable_i_pv6: item.get_bool(&[3]),
307 hardware_address: item.get_int(&[4]).map(|v| v as u8),
308 i_pv4_addresses: {
309 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[5]) {
310 let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
311 Some(items)
312 } else {
313 None
314 }
315 },
316 i_pv6_addresses: {
317 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[6]) {
318 let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
319 Some(items)
320 } else {
321 None
322 }
323 },
324 type_: item.get_int(&[7]).and_then(|v| InterfaceType::from_u8(v as u8)),
325 });
326 }
327 }
328 Ok(res)
329}
330
331pub fn decode_reboot_count(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
333 if let tlv::TlvItemValue::Int(v) = inp {
334 Ok(*v as u16)
335 } else {
336 Err(anyhow::anyhow!("Expected UInt16"))
337 }
338}
339
340pub fn decode_up_time(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
342 if let tlv::TlvItemValue::Int(v) = inp {
343 Ok(*v)
344 } else {
345 Err(anyhow::anyhow!("Expected UInt64"))
346 }
347}
348
349pub fn decode_total_operational_hours(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
351 if let tlv::TlvItemValue::Int(v) = inp {
352 Ok(*v as u32)
353 } else {
354 Err(anyhow::anyhow!("Expected UInt32"))
355 }
356}
357
358pub fn decode_boot_reason(inp: &tlv::TlvItemValue) -> anyhow::Result<BootReason> {
360 if let tlv::TlvItemValue::Int(v) = inp {
361 BootReason::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
362 } else {
363 Err(anyhow::anyhow!("Expected Integer"))
364 }
365}
366
367pub fn decode_active_hardware_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<HardwareFault>> {
369 let mut res = Vec::new();
370 if let tlv::TlvItemValue::List(v) = inp {
371 for item in v {
372 if let tlv::TlvItemValue::Int(i) = &item.value {
373 if let Some(enum_val) = HardwareFault::from_u8(*i as u8) {
374 res.push(enum_val);
375 }
376 }
377 }
378 }
379 Ok(res)
380}
381
382pub fn decode_active_radio_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<RadioFault>> {
384 let mut res = Vec::new();
385 if let tlv::TlvItemValue::List(v) = inp {
386 for item in v {
387 if let tlv::TlvItemValue::Int(i) = &item.value {
388 if let Some(enum_val) = RadioFault::from_u8(*i as u8) {
389 res.push(enum_val);
390 }
391 }
392 }
393 }
394 Ok(res)
395}
396
397pub fn decode_active_network_faults(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<NetworkFault>> {
399 let mut res = Vec::new();
400 if let tlv::TlvItemValue::List(v) = inp {
401 for item in v {
402 if let tlv::TlvItemValue::Int(i) = &item.value {
403 if let Some(enum_val) = NetworkFault::from_u8(*i as u8) {
404 res.push(enum_val);
405 }
406 }
407 }
408 }
409 Ok(res)
410}
411
412pub fn decode_test_event_triggers_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
414 if let tlv::TlvItemValue::Bool(v) = inp {
415 Ok(*v)
416 } else {
417 Err(anyhow::anyhow!("Expected Bool"))
418 }
419}
420
421pub fn decode_do_not_use(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
423 if let tlv::TlvItemValue::Int(v) = inp {
424 Ok(*v as u8)
425 } else {
426 Err(anyhow::anyhow!("Expected UInt8"))
427 }
428}
429
430pub fn decode_device_load_status(inp: &tlv::TlvItemValue) -> anyhow::Result<DeviceLoad> {
432 if let tlv::TlvItemValue::List(_fields) = inp {
433 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
435 Ok(DeviceLoad {
436 current_subscriptions: item.get_int(&[0]).map(|v| v as u16),
437 current_subscriptions_for_fabric: item.get_int(&[1]).map(|v| v as u16),
438 total_subscriptions_established: item.get_int(&[2]).map(|v| v as u32),
439 total_interaction_model_messages_sent: item.get_int(&[3]).map(|v| v as u32),
440 total_interaction_model_messages_received: item.get_int(&[4]).map(|v| v as u32),
441 })
442 } else {
443 Err(anyhow::anyhow!("Expected struct fields"))
444 }
445}
446
447
448pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
460 if cluster_id != 0x0033 {
462 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0033, got {}\"}}", cluster_id);
463 }
464
465 match attribute_id {
466 0x0000 => {
467 match decode_network_interfaces(tlv_value) {
468 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
469 Err(e) => format!("{{\"error\": \"{}\"}}", e),
470 }
471 }
472 0x0001 => {
473 match decode_reboot_count(tlv_value) {
474 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
475 Err(e) => format!("{{\"error\": \"{}\"}}", e),
476 }
477 }
478 0x0002 => {
479 match decode_up_time(tlv_value) {
480 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
481 Err(e) => format!("{{\"error\": \"{}\"}}", e),
482 }
483 }
484 0x0003 => {
485 match decode_total_operational_hours(tlv_value) {
486 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
487 Err(e) => format!("{{\"error\": \"{}\"}}", e),
488 }
489 }
490 0x0004 => {
491 match decode_boot_reason(tlv_value) {
492 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
493 Err(e) => format!("{{\"error\": \"{}\"}}", e),
494 }
495 }
496 0x0005 => {
497 match decode_active_hardware_faults(tlv_value) {
498 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
499 Err(e) => format!("{{\"error\": \"{}\"}}", e),
500 }
501 }
502 0x0006 => {
503 match decode_active_radio_faults(tlv_value) {
504 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
505 Err(e) => format!("{{\"error\": \"{}\"}}", e),
506 }
507 }
508 0x0007 => {
509 match decode_active_network_faults(tlv_value) {
510 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
511 Err(e) => format!("{{\"error\": \"{}\"}}", e),
512 }
513 }
514 0x0008 => {
515 match decode_test_event_triggers_enabled(tlv_value) {
516 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
517 Err(e) => format!("{{\"error\": \"{}\"}}", e),
518 }
519 }
520 0x0009 => {
521 match decode_do_not_use(tlv_value) {
522 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
523 Err(e) => format!("{{\"error\": \"{}\"}}", e),
524 }
525 }
526 0x000A => {
527 match decode_device_load_status(tlv_value) {
528 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
529 Err(e) => format!("{{\"error\": \"{}\"}}", e),
530 }
531 }
532 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
533 }
534}
535
536pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
541 vec![
542 (0x0000, "NetworkInterfaces"),
543 (0x0001, "RebootCount"),
544 (0x0002, "UpTime"),
545 (0x0003, "TotalOperationalHours"),
546 (0x0004, "BootReason"),
547 (0x0005, "ActiveHardwareFaults"),
548 (0x0006, "ActiveRadioFaults"),
549 (0x0007, "ActiveNetworkFaults"),
550 (0x0008, "TestEventTriggersEnabled"),
551 (0x0009, "DoNotUse"),
552 (0x000A, "DeviceLoadStatus"),
553 ]
554}
555
556pub fn get_command_list() -> Vec<(u32, &'static str)> {
559 vec![
560 (0x00, "TestEventTrigger"),
561 (0x01, "TimeSnapshot"),
562 (0x03, "PayloadTestRequest"),
563 ]
564}
565
566pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
567 match cmd_id {
568 0x00 => Some("TestEventTrigger"),
569 0x01 => Some("TimeSnapshot"),
570 0x03 => Some("PayloadTestRequest"),
571 _ => None,
572 }
573}
574
575pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
576 match cmd_id {
577 0x00 => Some(vec![
578 crate::clusters::codec::CommandField { tag: 0, name: "enable_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
579 crate::clusters::codec::CommandField { tag: 1, name: "event_trigger", kind: crate::clusters::codec::FieldKind::U64, optional: false, nullable: false },
580 ]),
581 0x01 => Some(vec![]),
582 0x03 => Some(vec![
583 crate::clusters::codec::CommandField { tag: 0, name: "enable_key", kind: crate::clusters::codec::FieldKind::OctetString, optional: false, nullable: false },
584 crate::clusters::codec::CommandField { tag: 1, name: "value", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
585 crate::clusters::codec::CommandField { tag: 2, name: "count", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
586 ]),
587 _ => None,
588 }
589}
590
591pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
592 match cmd_id {
593 0x00 => {
594 let enable_key = crate::clusters::codec::json_util::get_octstr(args, "enable_key")?;
595 let event_trigger = crate::clusters::codec::json_util::get_u64(args, "event_trigger")?;
596 encode_test_event_trigger(enable_key, event_trigger)
597 }
598 0x01 => Ok(vec![]),
599 0x03 => {
600 let enable_key = crate::clusters::codec::json_util::get_octstr(args, "enable_key")?;
601 let value = crate::clusters::codec::json_util::get_u8(args, "value")?;
602 let count = crate::clusters::codec::json_util::get_u16(args, "count")?;
603 encode_payload_test_request(enable_key, value, count)
604 }
605 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
606 }
607}
608
609#[derive(Debug, serde::Serialize)]
610pub struct TimeSnapshotResponse {
611 pub system_time_ms: Option<u8>,
612 pub posix_time_ms: Option<u8>,
613}
614
615#[derive(Debug, serde::Serialize)]
616pub struct PayloadTestResponse {
617 #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
618 pub payload: Option<Vec<u8>>,
619}
620
621pub fn decode_time_snapshot_response(inp: &tlv::TlvItemValue) -> anyhow::Result<TimeSnapshotResponse> {
625 if let tlv::TlvItemValue::List(_fields) = inp {
626 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
627 Ok(TimeSnapshotResponse {
628 system_time_ms: item.get_int(&[0]).map(|v| v as u8),
629 posix_time_ms: item.get_int(&[1]).map(|v| v as u8),
630 })
631 } else {
632 Err(anyhow::anyhow!("Expected struct fields"))
633 }
634}
635
636pub fn decode_payload_test_response(inp: &tlv::TlvItemValue) -> anyhow::Result<PayloadTestResponse> {
638 if let tlv::TlvItemValue::List(_fields) = inp {
639 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
640 Ok(PayloadTestResponse {
641 payload: item.get_octet_string_owned(&[0]),
642 })
643 } else {
644 Err(anyhow::anyhow!("Expected struct fields"))
645 }
646}
647
648pub async fn test_event_trigger(conn: &crate::controller::Connection, endpoint: u16, enable_key: Vec<u8>, event_trigger: u64) -> anyhow::Result<()> {
652 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?;
653 Ok(())
654}
655
656pub async fn time_snapshot(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TimeSnapshotResponse> {
658 let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_CMD_ID_TIMESNAPSHOT, &[]).await?;
659 decode_time_snapshot_response(&tlv)
660}
661
662pub async fn payload_test_request(conn: &crate::controller::Connection, endpoint: u16, enable_key: Vec<u8>, value: u8, count: u16) -> anyhow::Result<PayloadTestResponse> {
664 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?;
665 decode_payload_test_response(&tlv)
666}
667
668pub async fn read_network_interfaces(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<NetworkInterface>> {
670 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_NETWORKINTERFACES).await?;
671 decode_network_interfaces(&tlv)
672}
673
674pub async fn read_reboot_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
676 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_REBOOTCOUNT).await?;
677 decode_reboot_count(&tlv)
678}
679
680pub async fn read_up_time(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u64> {
682 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_UPTIME).await?;
683 decode_up_time(&tlv)
684}
685
686pub async fn read_total_operational_hours(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
688 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_TOTALOPERATIONALHOURS).await?;
689 decode_total_operational_hours(&tlv)
690}
691
692pub async fn read_boot_reason(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<BootReason> {
694 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_BOOTREASON).await?;
695 decode_boot_reason(&tlv)
696}
697
698pub async fn read_active_hardware_faults(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<HardwareFault>> {
700 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_ACTIVEHARDWAREFAULTS).await?;
701 decode_active_hardware_faults(&tlv)
702}
703
704pub async fn read_active_radio_faults(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<RadioFault>> {
706 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_ACTIVERADIOFAULTS).await?;
707 decode_active_radio_faults(&tlv)
708}
709
710pub async fn read_active_network_faults(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<NetworkFault>> {
712 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_ACTIVENETWORKFAULTS).await?;
713 decode_active_network_faults(&tlv)
714}
715
716pub async fn read_test_event_triggers_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
718 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_TESTEVENTTRIGGERSENABLED).await?;
719 decode_test_event_triggers_enabled(&tlv)
720}
721
722pub async fn read_do_not_use(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
724 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_DONOTUSE).await?;
725 decode_do_not_use(&tlv)
726}
727
728pub async fn read_device_load_status(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<DeviceLoad> {
730 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_GENERAL_DIAGNOSTICS, crate::clusters::defs::CLUSTER_GENERAL_DIAGNOSTICS_ATTR_ID_DEVICELOADSTATUS).await?;
731 decode_device_load_status(&tlv)
732}
733
734#[derive(Debug, serde::Serialize)]
735pub struct HardwareFaultChangeEvent {
736 pub current: Option<Vec<HardwareFault>>,
737 pub previous: Option<Vec<HardwareFault>>,
738}
739
740#[derive(Debug, serde::Serialize)]
741pub struct RadioFaultChangeEvent {
742 pub current: Option<Vec<RadioFault>>,
743 pub previous: Option<Vec<RadioFault>>,
744}
745
746#[derive(Debug, serde::Serialize)]
747pub struct NetworkFaultChangeEvent {
748 pub current: Option<Vec<NetworkFault>>,
749 pub previous: Option<Vec<NetworkFault>>,
750}
751
752#[derive(Debug, serde::Serialize)]
753pub struct BootReasonEvent {
754 pub boot_reason: Option<BootReason>,
755}
756
757pub fn decode_hardware_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<HardwareFaultChangeEvent> {
761 if let tlv::TlvItemValue::List(_fields) = inp {
762 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
763 Ok(HardwareFaultChangeEvent {
764 current: {
765 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
766 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();
767 Some(items)
768 } else {
769 None
770 }
771 },
772 previous: {
773 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
774 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();
775 Some(items)
776 } else {
777 None
778 }
779 },
780 })
781 } else {
782 Err(anyhow::anyhow!("Expected struct fields"))
783 }
784}
785
786pub fn decode_radio_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<RadioFaultChangeEvent> {
788 if let tlv::TlvItemValue::List(_fields) = inp {
789 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
790 Ok(RadioFaultChangeEvent {
791 current: {
792 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
793 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();
794 Some(items)
795 } else {
796 None
797 }
798 },
799 previous: {
800 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
801 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();
802 Some(items)
803 } else {
804 None
805 }
806 },
807 })
808 } else {
809 Err(anyhow::anyhow!("Expected struct fields"))
810 }
811}
812
813pub fn decode_network_fault_change_event(inp: &tlv::TlvItemValue) -> anyhow::Result<NetworkFaultChangeEvent> {
815 if let tlv::TlvItemValue::List(_fields) = inp {
816 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
817 Ok(NetworkFaultChangeEvent {
818 current: {
819 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[0]) {
820 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();
821 Some(items)
822 } else {
823 None
824 }
825 },
826 previous: {
827 if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
828 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();
829 Some(items)
830 } else {
831 None
832 }
833 },
834 })
835 } else {
836 Err(anyhow::anyhow!("Expected struct fields"))
837 }
838}
839
840pub fn decode_boot_reason_event(inp: &tlv::TlvItemValue) -> anyhow::Result<BootReasonEvent> {
842 if let tlv::TlvItemValue::List(_fields) = inp {
843 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
844 Ok(BootReasonEvent {
845 boot_reason: item.get_int(&[0]).and_then(|v| BootReason::from_u8(v as u8)),
846 })
847 } else {
848 Err(anyhow::anyhow!("Expected struct fields"))
849 }
850}
851
852
853pub fn decode_event_json(cluster_id: u32, event_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
857 if cluster_id != 0x0033 {
858 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0033, got {}\"}}", cluster_id);
859 }
860
861 match event_id {
862 0x00 => {
863 match decode_hardware_fault_change_event(tlv_value) {
864 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
865 Err(e) => format!("{{\"error\": \"{}\"}}", e),
866 }
867 }
868 0x01 => {
869 match decode_radio_fault_change_event(tlv_value) {
870 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
871 Err(e) => format!("{{\"error\": \"{}\"}}", e),
872 }
873 }
874 0x02 => {
875 match decode_network_fault_change_event(tlv_value) {
876 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
877 Err(e) => format!("{{\"error\": \"{}\"}}", e),
878 }
879 }
880 0x03 => {
881 match decode_boot_reason_event(tlv_value) {
882 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
883 Err(e) => format!("{{\"error\": \"{}\"}}", e),
884 }
885 }
886 _ => format!("{{\"error\": \"Unknown event ID: {}\"}}", event_id),
887 }
888}
889
890pub fn get_event_list() -> Vec<(u32, &'static str)> {
895 vec![
896 (0x00, "HardwareFaultChange"),
897 (0x01, "RadioFaultChange"),
898 (0x02, "NetworkFaultChange"),
899 (0x03, "BootReason"),
900 ]
901}
902