1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum AlarmState {
18 Normal = 0,
20 Warning = 1,
22 Critical = 2,
24}
25
26impl AlarmState {
27 pub fn from_u8(value: u8) -> Option<Self> {
29 match value {
30 0 => Some(AlarmState::Normal),
31 1 => Some(AlarmState::Warning),
32 2 => Some(AlarmState::Critical),
33 _ => None,
34 }
35 }
36
37 pub fn to_u8(self) -> u8 {
39 self as u8
40 }
41}
42
43impl From<AlarmState> for u8 {
44 fn from(val: AlarmState) -> Self {
45 val as u8
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
50#[repr(u8)]
51pub enum ContaminationState {
52 Normal = 0,
54 Low = 1,
56 Warning = 2,
58 Critical = 3,
60}
61
62impl ContaminationState {
63 pub fn from_u8(value: u8) -> Option<Self> {
65 match value {
66 0 => Some(ContaminationState::Normal),
67 1 => Some(ContaminationState::Low),
68 2 => Some(ContaminationState::Warning),
69 3 => Some(ContaminationState::Critical),
70 _ => None,
71 }
72 }
73
74 pub fn to_u8(self) -> u8 {
76 self as u8
77 }
78}
79
80impl From<ContaminationState> for u8 {
81 fn from(val: ContaminationState) -> Self {
82 val as u8
83 }
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
87#[repr(u8)]
88pub enum EndOfService {
89 Normal = 0,
91 Expired = 1,
93}
94
95impl EndOfService {
96 pub fn from_u8(value: u8) -> Option<Self> {
98 match value {
99 0 => Some(EndOfService::Normal),
100 1 => Some(EndOfService::Expired),
101 _ => None,
102 }
103 }
104
105 pub fn to_u8(self) -> u8 {
107 self as u8
108 }
109}
110
111impl From<EndOfService> for u8 {
112 fn from(val: EndOfService) -> Self {
113 val as u8
114 }
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
118#[repr(u8)]
119pub enum ExpressedState {
120 Normal = 0,
122 Smokealarm = 1,
124 Coalarm = 2,
126 Batteryalert = 3,
128 Testing = 4,
130 Hardwarefault = 5,
132 Endofservice = 6,
134 Interconnectsmoke = 7,
136 Interconnectco = 8,
138}
139
140impl ExpressedState {
141 pub fn from_u8(value: u8) -> Option<Self> {
143 match value {
144 0 => Some(ExpressedState::Normal),
145 1 => Some(ExpressedState::Smokealarm),
146 2 => Some(ExpressedState::Coalarm),
147 3 => Some(ExpressedState::Batteryalert),
148 4 => Some(ExpressedState::Testing),
149 5 => Some(ExpressedState::Hardwarefault),
150 6 => Some(ExpressedState::Endofservice),
151 7 => Some(ExpressedState::Interconnectsmoke),
152 8 => Some(ExpressedState::Interconnectco),
153 _ => None,
154 }
155 }
156
157 pub fn to_u8(self) -> u8 {
159 self as u8
160 }
161}
162
163impl From<ExpressedState> for u8 {
164 fn from(val: ExpressedState) -> Self {
165 val as u8
166 }
167}
168
169#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
170#[repr(u8)]
171pub enum MuteState {
172 Notmuted = 0,
174 Muted = 1,
176}
177
178impl MuteState {
179 pub fn from_u8(value: u8) -> Option<Self> {
181 match value {
182 0 => Some(MuteState::Notmuted),
183 1 => Some(MuteState::Muted),
184 _ => None,
185 }
186 }
187
188 pub fn to_u8(self) -> u8 {
190 self as u8
191 }
192}
193
194impl From<MuteState> for u8 {
195 fn from(val: MuteState) -> Self {
196 val as u8
197 }
198}
199
200#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
201#[repr(u8)]
202pub enum Sensitivity {
203 High = 0,
205 Standard = 1,
207 Low = 2,
209}
210
211impl Sensitivity {
212 pub fn from_u8(value: u8) -> Option<Self> {
214 match value {
215 0 => Some(Sensitivity::High),
216 1 => Some(Sensitivity::Standard),
217 2 => Some(Sensitivity::Low),
218 _ => None,
219 }
220 }
221
222 pub fn to_u8(self) -> u8 {
224 self as u8
225 }
226}
227
228impl From<Sensitivity> for u8 {
229 fn from(val: Sensitivity) -> Self {
230 val as u8
231 }
232}
233
234pub fn decode_expressed_state(inp: &tlv::TlvItemValue) -> anyhow::Result<ExpressedState> {
240 if let tlv::TlvItemValue::Int(v) = inp {
241 ExpressedState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
242 } else {
243 Err(anyhow::anyhow!("Expected Integer"))
244 }
245}
246
247pub fn decode_smoke_state(inp: &tlv::TlvItemValue) -> anyhow::Result<AlarmState> {
249 if let tlv::TlvItemValue::Int(v) = inp {
250 AlarmState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
251 } else {
252 Err(anyhow::anyhow!("Expected Integer"))
253 }
254}
255
256pub fn decode_co_state(inp: &tlv::TlvItemValue) -> anyhow::Result<AlarmState> {
258 if let tlv::TlvItemValue::Int(v) = inp {
259 AlarmState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
260 } else {
261 Err(anyhow::anyhow!("Expected Integer"))
262 }
263}
264
265pub fn decode_battery_alert(inp: &tlv::TlvItemValue) -> anyhow::Result<AlarmState> {
267 if let tlv::TlvItemValue::Int(v) = inp {
268 AlarmState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
269 } else {
270 Err(anyhow::anyhow!("Expected Integer"))
271 }
272}
273
274pub fn decode_device_muted(inp: &tlv::TlvItemValue) -> anyhow::Result<MuteState> {
276 if let tlv::TlvItemValue::Int(v) = inp {
277 MuteState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
278 } else {
279 Err(anyhow::anyhow!("Expected Integer"))
280 }
281}
282
283pub fn decode_test_in_progress(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
285 if let tlv::TlvItemValue::Bool(v) = inp {
286 Ok(*v)
287 } else {
288 Err(anyhow::anyhow!("Expected Bool"))
289 }
290}
291
292pub fn decode_hardware_fault_alert(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
294 if let tlv::TlvItemValue::Bool(v) = inp {
295 Ok(*v)
296 } else {
297 Err(anyhow::anyhow!("Expected Bool"))
298 }
299}
300
301pub fn decode_end_of_service_alert(inp: &tlv::TlvItemValue) -> anyhow::Result<EndOfService> {
303 if let tlv::TlvItemValue::Int(v) = inp {
304 EndOfService::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
305 } else {
306 Err(anyhow::anyhow!("Expected Integer"))
307 }
308}
309
310pub fn decode_interconnect_smoke_alarm(inp: &tlv::TlvItemValue) -> anyhow::Result<AlarmState> {
312 if let tlv::TlvItemValue::Int(v) = inp {
313 AlarmState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
314 } else {
315 Err(anyhow::anyhow!("Expected Integer"))
316 }
317}
318
319pub fn decode_interconnect_co_alarm(inp: &tlv::TlvItemValue) -> anyhow::Result<AlarmState> {
321 if let tlv::TlvItemValue::Int(v) = inp {
322 AlarmState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
323 } else {
324 Err(anyhow::anyhow!("Expected Integer"))
325 }
326}
327
328pub fn decode_contamination_state(inp: &tlv::TlvItemValue) -> anyhow::Result<ContaminationState> {
330 if let tlv::TlvItemValue::Int(v) = inp {
331 ContaminationState::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
332 } else {
333 Err(anyhow::anyhow!("Expected Integer"))
334 }
335}
336
337pub fn decode_smoke_sensitivity_level(inp: &tlv::TlvItemValue) -> anyhow::Result<Sensitivity> {
339 if let tlv::TlvItemValue::Int(v) = inp {
340 Sensitivity::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
341 } else {
342 Err(anyhow::anyhow!("Expected Integer"))
343 }
344}
345
346pub fn decode_expiry_date(inp: &tlv::TlvItemValue) -> anyhow::Result<u64> {
348 if let tlv::TlvItemValue::Int(v) = inp {
349 Ok(*v)
350 } else {
351 Err(anyhow::anyhow!("Expected UInt64"))
352 }
353}
354
355
356pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
368 if cluster_id != 0x005C {
370 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x005C, got {}\"}}", cluster_id);
371 }
372
373 match attribute_id {
374 0x0000 => {
375 match decode_expressed_state(tlv_value) {
376 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
377 Err(e) => format!("{{\"error\": \"{}\"}}", e),
378 }
379 }
380 0x0001 => {
381 match decode_smoke_state(tlv_value) {
382 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
383 Err(e) => format!("{{\"error\": \"{}\"}}", e),
384 }
385 }
386 0x0002 => {
387 match decode_co_state(tlv_value) {
388 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
389 Err(e) => format!("{{\"error\": \"{}\"}}", e),
390 }
391 }
392 0x0003 => {
393 match decode_battery_alert(tlv_value) {
394 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
395 Err(e) => format!("{{\"error\": \"{}\"}}", e),
396 }
397 }
398 0x0004 => {
399 match decode_device_muted(tlv_value) {
400 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
401 Err(e) => format!("{{\"error\": \"{}\"}}", e),
402 }
403 }
404 0x0005 => {
405 match decode_test_in_progress(tlv_value) {
406 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
407 Err(e) => format!("{{\"error\": \"{}\"}}", e),
408 }
409 }
410 0x0006 => {
411 match decode_hardware_fault_alert(tlv_value) {
412 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
413 Err(e) => format!("{{\"error\": \"{}\"}}", e),
414 }
415 }
416 0x0007 => {
417 match decode_end_of_service_alert(tlv_value) {
418 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
419 Err(e) => format!("{{\"error\": \"{}\"}}", e),
420 }
421 }
422 0x0008 => {
423 match decode_interconnect_smoke_alarm(tlv_value) {
424 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
425 Err(e) => format!("{{\"error\": \"{}\"}}", e),
426 }
427 }
428 0x0009 => {
429 match decode_interconnect_co_alarm(tlv_value) {
430 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
431 Err(e) => format!("{{\"error\": \"{}\"}}", e),
432 }
433 }
434 0x000A => {
435 match decode_contamination_state(tlv_value) {
436 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
437 Err(e) => format!("{{\"error\": \"{}\"}}", e),
438 }
439 }
440 0x000B => {
441 match decode_smoke_sensitivity_level(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 0x000C => {
447 match decode_expiry_date(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 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
453 }
454}
455
456pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
461 vec![
462 (0x0000, "ExpressedState"),
463 (0x0001, "SmokeState"),
464 (0x0002, "COState"),
465 (0x0003, "BatteryAlert"),
466 (0x0004, "DeviceMuted"),
467 (0x0005, "TestInProgress"),
468 (0x0006, "HardwareFaultAlert"),
469 (0x0007, "EndOfServiceAlert"),
470 (0x0008, "InterconnectSmokeAlarm"),
471 (0x0009, "InterconnectCOAlarm"),
472 (0x000A, "ContaminationState"),
473 (0x000B, "SmokeSensitivityLevel"),
474 (0x000C, "ExpiryDate"),
475 ]
476}
477
478pub fn get_command_list() -> Vec<(u32, &'static str)> {
481 vec![
482 (0x00, "SelfTestRequest"),
483 ]
484}
485
486pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
487 match cmd_id {
488 0x00 => Some("SelfTestRequest"),
489 _ => None,
490 }
491}
492
493pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
494 match cmd_id {
495 0x00 => Some(vec![]),
496 _ => None,
497 }
498}
499
500pub fn encode_command_json(cmd_id: u32, _args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
501 match cmd_id {
502 0x00 => Ok(vec![]),
503 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
504 }
505}
506
507pub async fn self_test_request(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
511 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_CMD_ID_SELFTESTREQUEST, &[]).await?;
512 Ok(())
513}
514
515pub async fn read_expressed_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ExpressedState> {
517 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_EXPRESSEDSTATE).await?;
518 decode_expressed_state(&tlv)
519}
520
521pub async fn read_smoke_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<AlarmState> {
523 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_SMOKESTATE).await?;
524 decode_smoke_state(&tlv)
525}
526
527pub async fn read_co_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<AlarmState> {
529 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_COSTATE).await?;
530 decode_co_state(&tlv)
531}
532
533pub async fn read_battery_alert(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<AlarmState> {
535 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_BATTERYALERT).await?;
536 decode_battery_alert(&tlv)
537}
538
539pub async fn read_device_muted(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<MuteState> {
541 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_DEVICEMUTED).await?;
542 decode_device_muted(&tlv)
543}
544
545pub async fn read_test_in_progress(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
547 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_TESTINPROGRESS).await?;
548 decode_test_in_progress(&tlv)
549}
550
551pub async fn read_hardware_fault_alert(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
553 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_HARDWAREFAULTALERT).await?;
554 decode_hardware_fault_alert(&tlv)
555}
556
557pub async fn read_end_of_service_alert(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<EndOfService> {
559 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_ENDOFSERVICEALERT).await?;
560 decode_end_of_service_alert(&tlv)
561}
562
563pub async fn read_interconnect_smoke_alarm(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<AlarmState> {
565 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_INTERCONNECTSMOKEALARM).await?;
566 decode_interconnect_smoke_alarm(&tlv)
567}
568
569pub async fn read_interconnect_co_alarm(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<AlarmState> {
571 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_INTERCONNECTCOALARM).await?;
572 decode_interconnect_co_alarm(&tlv)
573}
574
575pub async fn read_contamination_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ContaminationState> {
577 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_CONTAMINATIONSTATE).await?;
578 decode_contamination_state(&tlv)
579}
580
581pub async fn read_smoke_sensitivity_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Sensitivity> {
583 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_SMOKESENSITIVITYLEVEL).await?;
584 decode_smoke_sensitivity_level(&tlv)
585}
586
587pub async fn read_expiry_date(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u64> {
589 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_SMOKE_CO_ALARM, crate::clusters::defs::CLUSTER_SMOKE_CO_ALARM_ATTR_ID_EXPIRYDATE).await?;
590 decode_expiry_date(&tlv)
591}
592
593#[derive(Debug, serde::Serialize)]
594pub struct SmokeAlarmEvent {
595 pub alarm_severity_level: Option<AlarmState>,
596}
597
598#[derive(Debug, serde::Serialize)]
599pub struct COAlarmEvent {
600 pub alarm_severity_level: Option<AlarmState>,
601}
602
603#[derive(Debug, serde::Serialize)]
604pub struct LowBatteryEvent {
605 pub alarm_severity_level: Option<AlarmState>,
606}
607
608#[derive(Debug, serde::Serialize)]
609pub struct InterconnectSmokeAlarmEvent {
610 pub alarm_severity_level: Option<AlarmState>,
611}
612
613#[derive(Debug, serde::Serialize)]
614pub struct InterconnectCOAlarmEvent {
615 pub alarm_severity_level: Option<AlarmState>,
616}
617
618pub fn decode_smoke_alarm_event(inp: &tlv::TlvItemValue) -> anyhow::Result<SmokeAlarmEvent> {
622 if let tlv::TlvItemValue::List(_fields) = inp {
623 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
624 Ok(SmokeAlarmEvent {
625 alarm_severity_level: item.get_int(&[0]).and_then(|v| AlarmState::from_u8(v as u8)),
626 })
627 } else {
628 Err(anyhow::anyhow!("Expected struct fields"))
629 }
630}
631
632pub fn decode_co_alarm_event(inp: &tlv::TlvItemValue) -> anyhow::Result<COAlarmEvent> {
634 if let tlv::TlvItemValue::List(_fields) = inp {
635 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
636 Ok(COAlarmEvent {
637 alarm_severity_level: item.get_int(&[0]).and_then(|v| AlarmState::from_u8(v as u8)),
638 })
639 } else {
640 Err(anyhow::anyhow!("Expected struct fields"))
641 }
642}
643
644pub fn decode_low_battery_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LowBatteryEvent> {
646 if let tlv::TlvItemValue::List(_fields) = inp {
647 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
648 Ok(LowBatteryEvent {
649 alarm_severity_level: item.get_int(&[0]).and_then(|v| AlarmState::from_u8(v as u8)),
650 })
651 } else {
652 Err(anyhow::anyhow!("Expected struct fields"))
653 }
654}
655
656pub fn decode_interconnect_smoke_alarm_event(inp: &tlv::TlvItemValue) -> anyhow::Result<InterconnectSmokeAlarmEvent> {
658 if let tlv::TlvItemValue::List(_fields) = inp {
659 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
660 Ok(InterconnectSmokeAlarmEvent {
661 alarm_severity_level: item.get_int(&[0]).and_then(|v| AlarmState::from_u8(v as u8)),
662 })
663 } else {
664 Err(anyhow::anyhow!("Expected struct fields"))
665 }
666}
667
668pub fn decode_interconnect_co_alarm_event(inp: &tlv::TlvItemValue) -> anyhow::Result<InterconnectCOAlarmEvent> {
670 if let tlv::TlvItemValue::List(_fields) = inp {
671 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
672 Ok(InterconnectCOAlarmEvent {
673 alarm_severity_level: item.get_int(&[0]).and_then(|v| AlarmState::from_u8(v as u8)),
674 })
675 } else {
676 Err(anyhow::anyhow!("Expected struct fields"))
677 }
678}
679