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 AssociationFailureCause {
18 Unknown = 0,
20 Associationfailed = 1,
22 Authenticationfailed = 2,
24 Ssidnotfound = 3,
26}
27
28impl AssociationFailureCause {
29 pub fn from_u8(value: u8) -> Option<Self> {
31 match value {
32 0 => Some(AssociationFailureCause::Unknown),
33 1 => Some(AssociationFailureCause::Associationfailed),
34 2 => Some(AssociationFailureCause::Authenticationfailed),
35 3 => Some(AssociationFailureCause::Ssidnotfound),
36 _ => None,
37 }
38 }
39
40 pub fn to_u8(self) -> u8 {
42 self as u8
43 }
44}
45
46impl From<AssociationFailureCause> for u8 {
47 fn from(val: AssociationFailureCause) -> Self {
48 val as u8
49 }
50}
51
52#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
53#[repr(u8)]
54pub enum ConnectionStatus {
55 Connected = 0,
57 Notconnected = 1,
59}
60
61impl ConnectionStatus {
62 pub fn from_u8(value: u8) -> Option<Self> {
64 match value {
65 0 => Some(ConnectionStatus::Connected),
66 1 => Some(ConnectionStatus::Notconnected),
67 _ => None,
68 }
69 }
70
71 pub fn to_u8(self) -> u8 {
73 self as u8
74 }
75}
76
77impl From<ConnectionStatus> for u8 {
78 fn from(val: ConnectionStatus) -> Self {
79 val as u8
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
84#[repr(u8)]
85pub enum SecurityType {
86 Unspecified = 0,
88 None = 1,
90 Wep = 2,
92 Wpa = 3,
94 Wpa2 = 4,
96 Wpa3 = 5,
98}
99
100impl SecurityType {
101 pub fn from_u8(value: u8) -> Option<Self> {
103 match value {
104 0 => Some(SecurityType::Unspecified),
105 1 => Some(SecurityType::None),
106 2 => Some(SecurityType::Wep),
107 3 => Some(SecurityType::Wpa),
108 4 => Some(SecurityType::Wpa2),
109 5 => Some(SecurityType::Wpa3),
110 _ => None,
111 }
112 }
113
114 pub fn to_u8(self) -> u8 {
116 self as u8
117 }
118}
119
120impl From<SecurityType> for u8 {
121 fn from(val: SecurityType) -> Self {
122 val as u8
123 }
124}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
127#[repr(u8)]
128pub enum WiFiVersion {
129 A = 0,
131 B = 1,
133 G = 2,
135 N = 3,
137 Ac = 4,
139 Ax = 5,
141 Ah = 6,
143}
144
145impl WiFiVersion {
146 pub fn from_u8(value: u8) -> Option<Self> {
148 match value {
149 0 => Some(WiFiVersion::A),
150 1 => Some(WiFiVersion::B),
151 2 => Some(WiFiVersion::G),
152 3 => Some(WiFiVersion::N),
153 4 => Some(WiFiVersion::Ac),
154 5 => Some(WiFiVersion::Ax),
155 6 => Some(WiFiVersion::Ah),
156 _ => None,
157 }
158 }
159
160 pub fn to_u8(self) -> u8 {
162 self as u8
163 }
164}
165
166impl From<WiFiVersion> for u8 {
167 fn from(val: WiFiVersion) -> Self {
168 val as u8
169 }
170}
171
172pub fn decode_bssid(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<Vec<u8>>> {
178 if let tlv::TlvItemValue::OctetString(v) = inp {
179 Ok(Some(v.clone()))
180 } else {
181 Ok(None)
182 }
183}
184
185pub fn decode_security_type(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<SecurityType>> {
187 if let tlv::TlvItemValue::Int(v) = inp {
188 Ok(SecurityType::from_u8(*v as u8))
189 } else {
190 Ok(None)
191 }
192}
193
194pub fn decode_wifi_version(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<WiFiVersion>> {
196 if let tlv::TlvItemValue::Int(v) = inp {
197 Ok(WiFiVersion::from_u8(*v as u8))
198 } else {
199 Ok(None)
200 }
201}
202
203pub fn decode_channel_number(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u16>> {
205 if let tlv::TlvItemValue::Int(v) = inp {
206 Ok(Some(*v as u16))
207 } else {
208 Ok(None)
209 }
210}
211
212pub fn decode_rssi(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<i8>> {
214 if let tlv::TlvItemValue::Int(v) = inp {
215 Ok(Some(*v as i8))
216 } else {
217 Ok(None)
218 }
219}
220
221pub fn decode_beacon_lost_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
223 if let tlv::TlvItemValue::Int(v) = inp {
224 Ok(Some(*v as u32))
225 } else {
226 Ok(None)
227 }
228}
229
230pub fn decode_beacon_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
232 if let tlv::TlvItemValue::Int(v) = inp {
233 Ok(Some(*v as u32))
234 } else {
235 Ok(None)
236 }
237}
238
239pub fn decode_packet_multicast_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
241 if let tlv::TlvItemValue::Int(v) = inp {
242 Ok(Some(*v as u32))
243 } else {
244 Ok(None)
245 }
246}
247
248pub fn decode_packet_multicast_tx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
250 if let tlv::TlvItemValue::Int(v) = inp {
251 Ok(Some(*v as u32))
252 } else {
253 Ok(None)
254 }
255}
256
257pub fn decode_packet_unicast_rx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
259 if let tlv::TlvItemValue::Int(v) = inp {
260 Ok(Some(*v as u32))
261 } else {
262 Ok(None)
263 }
264}
265
266pub fn decode_packet_unicast_tx_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u32>> {
268 if let tlv::TlvItemValue::Int(v) = inp {
269 Ok(Some(*v as u32))
270 } else {
271 Ok(None)
272 }
273}
274
275pub fn decode_current_max_rate(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
277 if let tlv::TlvItemValue::Int(v) = inp {
278 Ok(Some(*v))
279 } else {
280 Ok(None)
281 }
282}
283
284pub fn decode_overrun_count(inp: &tlv::TlvItemValue) -> anyhow::Result<Option<u64>> {
286 if let tlv::TlvItemValue::Int(v) = inp {
287 Ok(Some(*v))
288 } else {
289 Ok(None)
290 }
291}
292
293
294pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
306 if cluster_id != 0x0036 {
308 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0036, got {}\"}}", cluster_id);
309 }
310
311 match attribute_id {
312 0x0000 => {
313 match decode_bssid(tlv_value) {
314 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
315 Err(e) => format!("{{\"error\": \"{}\"}}", e),
316 }
317 }
318 0x0001 => {
319 match decode_security_type(tlv_value) {
320 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
321 Err(e) => format!("{{\"error\": \"{}\"}}", e),
322 }
323 }
324 0x0002 => {
325 match decode_wifi_version(tlv_value) {
326 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
327 Err(e) => format!("{{\"error\": \"{}\"}}", e),
328 }
329 }
330 0x0003 => {
331 match decode_channel_number(tlv_value) {
332 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
333 Err(e) => format!("{{\"error\": \"{}\"}}", e),
334 }
335 }
336 0x0004 => {
337 match decode_rssi(tlv_value) {
338 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
339 Err(e) => format!("{{\"error\": \"{}\"}}", e),
340 }
341 }
342 0x0005 => {
343 match decode_beacon_lost_count(tlv_value) {
344 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
345 Err(e) => format!("{{\"error\": \"{}\"}}", e),
346 }
347 }
348 0x0006 => {
349 match decode_beacon_rx_count(tlv_value) {
350 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
351 Err(e) => format!("{{\"error\": \"{}\"}}", e),
352 }
353 }
354 0x0007 => {
355 match decode_packet_multicast_rx_count(tlv_value) {
356 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
357 Err(e) => format!("{{\"error\": \"{}\"}}", e),
358 }
359 }
360 0x0008 => {
361 match decode_packet_multicast_tx_count(tlv_value) {
362 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
363 Err(e) => format!("{{\"error\": \"{}\"}}", e),
364 }
365 }
366 0x0009 => {
367 match decode_packet_unicast_rx_count(tlv_value) {
368 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
369 Err(e) => format!("{{\"error\": \"{}\"}}", e),
370 }
371 }
372 0x000A => {
373 match decode_packet_unicast_tx_count(tlv_value) {
374 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
375 Err(e) => format!("{{\"error\": \"{}\"}}", e),
376 }
377 }
378 0x000B => {
379 match decode_current_max_rate(tlv_value) {
380 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
381 Err(e) => format!("{{\"error\": \"{}\"}}", e),
382 }
383 }
384 0x000C => {
385 match decode_overrun_count(tlv_value) {
386 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
387 Err(e) => format!("{{\"error\": \"{}\"}}", e),
388 }
389 }
390 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
391 }
392}
393
394pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
399 vec![
400 (0x0000, "BSSID"),
401 (0x0001, "SecurityType"),
402 (0x0002, "WiFiVersion"),
403 (0x0003, "ChannelNumber"),
404 (0x0004, "RSSI"),
405 (0x0005, "BeaconLostCount"),
406 (0x0006, "BeaconRxCount"),
407 (0x0007, "PacketMulticastRxCount"),
408 (0x0008, "PacketMulticastTxCount"),
409 (0x0009, "PacketUnicastRxCount"),
410 (0x000A, "PacketUnicastTxCount"),
411 (0x000B, "CurrentMaxRate"),
412 (0x000C, "OverrunCount"),
413 ]
414}
415
416pub fn get_command_list() -> Vec<(u32, &'static str)> {
419 vec![
420 (0x00, "ResetCounts"),
421 ]
422}
423
424pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
425 match cmd_id {
426 0x00 => Some("ResetCounts"),
427 _ => None,
428 }
429}
430
431pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
432 match cmd_id {
433 0x00 => Some(vec![]),
434 _ => None,
435 }
436}
437
438pub fn encode_command_json(cmd_id: u32, _args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
439 match cmd_id {
440 0x00 => Ok(vec![]),
441 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
442 }
443}
444
445pub async fn reset_counts(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<()> {
449 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_CMD_ID_RESETCOUNTS, &[]).await?;
450 Ok(())
451}
452
453pub async fn read_bssid(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<Vec<u8>>> {
455 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_BSSID).await?;
456 decode_bssid(&tlv)
457}
458
459pub async fn read_security_type(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<SecurityType>> {
461 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_SECURITYTYPE).await?;
462 decode_security_type(&tlv)
463}
464
465pub async fn read_wifi_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<WiFiVersion>> {
467 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_WIFIVERSION).await?;
468 decode_wifi_version(&tlv)
469}
470
471pub async fn read_channel_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u16>> {
473 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_CHANNELNUMBER).await?;
474 decode_channel_number(&tlv)
475}
476
477pub async fn read_rssi(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<i8>> {
479 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_RSSI).await?;
480 decode_rssi(&tlv)
481}
482
483pub async fn read_beacon_lost_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
485 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_BEACONLOSTCOUNT).await?;
486 decode_beacon_lost_count(&tlv)
487}
488
489pub async fn read_beacon_rx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
491 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_BEACONRXCOUNT).await?;
492 decode_beacon_rx_count(&tlv)
493}
494
495pub async fn read_packet_multicast_rx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
497 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETMULTICASTRXCOUNT).await?;
498 decode_packet_multicast_rx_count(&tlv)
499}
500
501pub async fn read_packet_multicast_tx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
503 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETMULTICASTTXCOUNT).await?;
504 decode_packet_multicast_tx_count(&tlv)
505}
506
507pub async fn read_packet_unicast_rx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
509 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETUNICASTRXCOUNT).await?;
510 decode_packet_unicast_rx_count(&tlv)
511}
512
513pub async fn read_packet_unicast_tx_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u32>> {
515 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_PACKETUNICASTTXCOUNT).await?;
516 decode_packet_unicast_tx_count(&tlv)
517}
518
519pub async fn read_current_max_rate(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u64>> {
521 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_CURRENTMAXRATE).await?;
522 decode_current_max_rate(&tlv)
523}
524
525pub async fn read_overrun_count(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Option<u64>> {
527 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_WI_FI_NETWORK_DIAGNOSTICS, crate::clusters::defs::CLUSTER_WI_FI_NETWORK_DIAGNOSTICS_ATTR_ID_OVERRUNCOUNT).await?;
528 decode_overrun_count(&tlv)
529}
530
531#[derive(Debug, serde::Serialize)]
532pub struct DisconnectionEvent {
533 pub reason_code: Option<u16>,
534}
535
536#[derive(Debug, serde::Serialize)]
537pub struct AssociationFailureEvent {
538 pub association_failure_cause: Option<AssociationFailureCause>,
539 pub status: Option<u16>,
540}
541
542#[derive(Debug, serde::Serialize)]
543pub struct ConnectionStatusEvent {
544 pub connection_status: Option<ConnectionStatus>,
545}
546
547pub fn decode_disconnection_event(inp: &tlv::TlvItemValue) -> anyhow::Result<DisconnectionEvent> {
551 if let tlv::TlvItemValue::List(_fields) = inp {
552 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
553 Ok(DisconnectionEvent {
554 reason_code: item.get_int(&[0]).map(|v| v as u16),
555 })
556 } else {
557 Err(anyhow::anyhow!("Expected struct fields"))
558 }
559}
560
561pub fn decode_association_failure_event(inp: &tlv::TlvItemValue) -> anyhow::Result<AssociationFailureEvent> {
563 if let tlv::TlvItemValue::List(_fields) = inp {
564 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
565 Ok(AssociationFailureEvent {
566 association_failure_cause: item.get_int(&[0]).and_then(|v| AssociationFailureCause::from_u8(v as u8)),
567 status: item.get_int(&[1]).map(|v| v as u16),
568 })
569 } else {
570 Err(anyhow::anyhow!("Expected struct fields"))
571 }
572}
573
574pub fn decode_connection_status_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ConnectionStatusEvent> {
576 if let tlv::TlvItemValue::List(_fields) = inp {
577 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
578 Ok(ConnectionStatusEvent {
579 connection_status: item.get_int(&[0]).and_then(|v| ConnectionStatus::from_u8(v as u8)),
580 })
581 } else {
582 Err(anyhow::anyhow!("Expected struct fields"))
583 }
584}
585