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 Color {
18 Black = 0,
20 Navy = 1,
22 Green = 2,
24 Teal = 3,
26 Maroon = 4,
28 Purple = 5,
30 Olive = 6,
32 Gray = 7,
34 Blue = 8,
36 Lime = 9,
38 Aqua = 10,
40 Red = 11,
42 Fuchsia = 12,
44 Yellow = 13,
46 White = 14,
48 Nickel = 15,
50 Chrome = 16,
52 Brass = 17,
54 Copper = 18,
56 Silver = 19,
58 Gold = 20,
60}
61
62impl Color {
63 pub fn from_u8(value: u8) -> Option<Self> {
65 match value {
66 0 => Some(Color::Black),
67 1 => Some(Color::Navy),
68 2 => Some(Color::Green),
69 3 => Some(Color::Teal),
70 4 => Some(Color::Maroon),
71 5 => Some(Color::Purple),
72 6 => Some(Color::Olive),
73 7 => Some(Color::Gray),
74 8 => Some(Color::Blue),
75 9 => Some(Color::Lime),
76 10 => Some(Color::Aqua),
77 11 => Some(Color::Red),
78 12 => Some(Color::Fuchsia),
79 13 => Some(Color::Yellow),
80 14 => Some(Color::White),
81 15 => Some(Color::Nickel),
82 16 => Some(Color::Chrome),
83 17 => Some(Color::Brass),
84 18 => Some(Color::Copper),
85 19 => Some(Color::Silver),
86 20 => Some(Color::Gold),
87 _ => None,
88 }
89 }
90
91 pub fn to_u8(self) -> u8 {
93 self as u8
94 }
95}
96
97impl From<Color> for u8 {
98 fn from(val: Color) -> Self {
99 val as u8
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
104#[repr(u8)]
105pub enum ProductFinish {
106 Other = 0,
108 Matte = 1,
110 Satin = 2,
112 Polished = 3,
114 Rugged = 4,
116 Fabric = 5,
118}
119
120impl ProductFinish {
121 pub fn from_u8(value: u8) -> Option<Self> {
123 match value {
124 0 => Some(ProductFinish::Other),
125 1 => Some(ProductFinish::Matte),
126 2 => Some(ProductFinish::Satin),
127 3 => Some(ProductFinish::Polished),
128 4 => Some(ProductFinish::Rugged),
129 5 => Some(ProductFinish::Fabric),
130 _ => None,
131 }
132 }
133
134 pub fn to_u8(self) -> u8 {
136 self as u8
137 }
138}
139
140impl From<ProductFinish> for u8 {
141 fn from(val: ProductFinish) -> Self {
142 val as u8
143 }
144}
145
146#[derive(Debug, serde::Serialize)]
149pub struct CapabilityMinima {
150 pub case_sessions_per_fabric: Option<u16>,
151 pub subscriptions_per_fabric: Option<u16>,
152 pub simultaneous_invocations_supported: Option<u16>,
153 pub simultaneous_writes_supported: Option<u16>,
154 pub read_paths_supported: Option<u16>,
155 pub subscribe_paths_supported: Option<u16>,
156}
157
158#[derive(Debug, serde::Serialize)]
159pub struct ProductAppearance {
160 pub finish: Option<ProductFinish>,
161 pub primary_color: Option<Color>,
162}
163
164pub fn encode_keep_active(stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<Vec<u8>> {
168 let tlv = tlv::TlvItemEnc {
169 tag: 0,
170 value: tlv::TlvItemValueEnc::StructInvisible(vec![
171 (0, tlv::TlvItemValueEnc::UInt32(stay_active_duration)).into(),
172 (1, tlv::TlvItemValueEnc::UInt32(timeout_ms)).into(),
173 ]),
174 };
175 Ok(tlv.encode()?)
176}
177
178pub fn decode_data_model_revision(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
182 if let tlv::TlvItemValue::Int(v) = inp {
183 Ok(*v as u16)
184 } else {
185 Err(anyhow::anyhow!("Expected UInt16"))
186 }
187}
188
189pub fn decode_vendor_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
191 if let tlv::TlvItemValue::String(v) = inp {
192 Ok(v.clone())
193 } else {
194 Err(anyhow::anyhow!("Expected String"))
195 }
196}
197
198pub fn decode_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
200 if let tlv::TlvItemValue::Int(v) = inp {
201 Ok(*v as u16)
202 } else {
203 Err(anyhow::anyhow!("Expected UInt16"))
204 }
205}
206
207pub fn decode_product_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
209 if let tlv::TlvItemValue::String(v) = inp {
210 Ok(v.clone())
211 } else {
212 Err(anyhow::anyhow!("Expected String"))
213 }
214}
215
216pub fn decode_product_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
218 if let tlv::TlvItemValue::Int(v) = inp {
219 Ok(*v as u16)
220 } else {
221 Err(anyhow::anyhow!("Expected UInt16"))
222 }
223}
224
225pub fn decode_node_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
227 if let tlv::TlvItemValue::String(v) = inp {
228 Ok(v.clone())
229 } else {
230 Err(anyhow::anyhow!("Expected String"))
231 }
232}
233
234pub fn decode_location(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
236 if let tlv::TlvItemValue::String(v) = inp {
237 Ok(v.clone())
238 } else {
239 Err(anyhow::anyhow!("Expected String"))
240 }
241}
242
243pub fn decode_hardware_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
245 if let tlv::TlvItemValue::Int(v) = inp {
246 Ok(*v as u16)
247 } else {
248 Err(anyhow::anyhow!("Expected UInt16"))
249 }
250}
251
252pub fn decode_hardware_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
254 if let tlv::TlvItemValue::String(v) = inp {
255 Ok(v.clone())
256 } else {
257 Err(anyhow::anyhow!("Expected String"))
258 }
259}
260
261pub fn decode_software_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
263 if let tlv::TlvItemValue::Int(v) = inp {
264 Ok(*v as u32)
265 } else {
266 Err(anyhow::anyhow!("Expected UInt32"))
267 }
268}
269
270pub fn decode_software_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
272 if let tlv::TlvItemValue::String(v) = inp {
273 Ok(v.clone())
274 } else {
275 Err(anyhow::anyhow!("Expected String"))
276 }
277}
278
279pub fn decode_manufacturing_date(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
281 if let tlv::TlvItemValue::String(v) = inp {
282 Ok(v.clone())
283 } else {
284 Err(anyhow::anyhow!("Expected String"))
285 }
286}
287
288pub fn decode_part_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
290 if let tlv::TlvItemValue::String(v) = inp {
291 Ok(v.clone())
292 } else {
293 Err(anyhow::anyhow!("Expected String"))
294 }
295}
296
297pub fn decode_product_url(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
299 if let tlv::TlvItemValue::String(v) = inp {
300 Ok(v.clone())
301 } else {
302 Err(anyhow::anyhow!("Expected String"))
303 }
304}
305
306pub fn decode_product_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
308 if let tlv::TlvItemValue::String(v) = inp {
309 Ok(v.clone())
310 } else {
311 Err(anyhow::anyhow!("Expected String"))
312 }
313}
314
315pub fn decode_serial_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
317 if let tlv::TlvItemValue::String(v) = inp {
318 Ok(v.clone())
319 } else {
320 Err(anyhow::anyhow!("Expected String"))
321 }
322}
323
324pub fn decode_local_config_disabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
326 if let tlv::TlvItemValue::Bool(v) = inp {
327 Ok(*v)
328 } else {
329 Err(anyhow::anyhow!("Expected Bool"))
330 }
331}
332
333pub fn decode_reachable(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
335 if let tlv::TlvItemValue::Bool(v) = inp {
336 Ok(*v)
337 } else {
338 Err(anyhow::anyhow!("Expected Bool"))
339 }
340}
341
342pub fn decode_unique_id(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
344 if let tlv::TlvItemValue::String(v) = inp {
345 Ok(v.clone())
346 } else {
347 Err(anyhow::anyhow!("Expected String"))
348 }
349}
350
351pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
353 if let tlv::TlvItemValue::List(_fields) = inp {
354 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
356 Ok(CapabilityMinima {
357 case_sessions_per_fabric: item.get_int(&[0]).map(|v| v as u16),
358 subscriptions_per_fabric: item.get_int(&[1]).map(|v| v as u16),
359 simultaneous_invocations_supported: item.get_int(&[2]).map(|v| v as u16),
360 simultaneous_writes_supported: item.get_int(&[3]).map(|v| v as u16),
361 read_paths_supported: item.get_int(&[4]).map(|v| v as u16),
362 subscribe_paths_supported: item.get_int(&[5]).map(|v| v as u16),
363 })
364 } else {
365 Err(anyhow::anyhow!("Expected struct fields"))
366 }
367}
368
369pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
371 if let tlv::TlvItemValue::List(_fields) = inp {
372 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
374 Ok(ProductAppearance {
375 finish: item.get_int(&[0]).and_then(|v| ProductFinish::from_u8(v as u8)),
376 primary_color: item.get_int(&[1]).and_then(|v| Color::from_u8(v as u8)),
377 })
378 } else {
379 Err(anyhow::anyhow!("Expected struct fields"))
380 }
381}
382
383pub fn decode_specification_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
385 if let tlv::TlvItemValue::Int(v) = inp {
386 Ok(*v as u32)
387 } else {
388 Err(anyhow::anyhow!("Expected UInt32"))
389 }
390}
391
392pub fn decode_max_paths_per_invoke(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
394 if let tlv::TlvItemValue::Int(v) = inp {
395 Ok(*v as u16)
396 } else {
397 Err(anyhow::anyhow!("Expected UInt16"))
398 }
399}
400
401pub fn decode_configuration_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
403 if let tlv::TlvItemValue::Int(v) = inp {
404 Ok(*v as u32)
405 } else {
406 Err(anyhow::anyhow!("Expected UInt32"))
407 }
408}
409
410
411pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
423 if cluster_id != 0x0039 {
425 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0039, got {}\"}}", cluster_id);
426 }
427
428 match attribute_id {
429 0x0000 => {
430 match decode_data_model_revision(tlv_value) {
431 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
432 Err(e) => format!("{{\"error\": \"{}\"}}", e),
433 }
434 }
435 0x0001 => {
436 match decode_vendor_name(tlv_value) {
437 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
438 Err(e) => format!("{{\"error\": \"{}\"}}", e),
439 }
440 }
441 0x0002 => {
442 match decode_vendor_id(tlv_value) {
443 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
444 Err(e) => format!("{{\"error\": \"{}\"}}", e),
445 }
446 }
447 0x0003 => {
448 match decode_product_name(tlv_value) {
449 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
450 Err(e) => format!("{{\"error\": \"{}\"}}", e),
451 }
452 }
453 0x0004 => {
454 match decode_product_id(tlv_value) {
455 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
456 Err(e) => format!("{{\"error\": \"{}\"}}", e),
457 }
458 }
459 0x0005 => {
460 match decode_node_label(tlv_value) {
461 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
462 Err(e) => format!("{{\"error\": \"{}\"}}", e),
463 }
464 }
465 0x0006 => {
466 match decode_location(tlv_value) {
467 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
468 Err(e) => format!("{{\"error\": \"{}\"}}", e),
469 }
470 }
471 0x0007 => {
472 match decode_hardware_version(tlv_value) {
473 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
474 Err(e) => format!("{{\"error\": \"{}\"}}", e),
475 }
476 }
477 0x0008 => {
478 match decode_hardware_version_string(tlv_value) {
479 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
480 Err(e) => format!("{{\"error\": \"{}\"}}", e),
481 }
482 }
483 0x0009 => {
484 match decode_software_version(tlv_value) {
485 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
486 Err(e) => format!("{{\"error\": \"{}\"}}", e),
487 }
488 }
489 0x000A => {
490 match decode_software_version_string(tlv_value) {
491 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
492 Err(e) => format!("{{\"error\": \"{}\"}}", e),
493 }
494 }
495 0x000B => {
496 match decode_manufacturing_date(tlv_value) {
497 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
498 Err(e) => format!("{{\"error\": \"{}\"}}", e),
499 }
500 }
501 0x000C => {
502 match decode_part_number(tlv_value) {
503 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
504 Err(e) => format!("{{\"error\": \"{}\"}}", e),
505 }
506 }
507 0x000D => {
508 match decode_product_url(tlv_value) {
509 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
510 Err(e) => format!("{{\"error\": \"{}\"}}", e),
511 }
512 }
513 0x000E => {
514 match decode_product_label(tlv_value) {
515 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
516 Err(e) => format!("{{\"error\": \"{}\"}}", e),
517 }
518 }
519 0x000F => {
520 match decode_serial_number(tlv_value) {
521 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
522 Err(e) => format!("{{\"error\": \"{}\"}}", e),
523 }
524 }
525 0x0010 => {
526 match decode_local_config_disabled(tlv_value) {
527 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
528 Err(e) => format!("{{\"error\": \"{}\"}}", e),
529 }
530 }
531 0x0011 => {
532 match decode_reachable(tlv_value) {
533 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
534 Err(e) => format!("{{\"error\": \"{}\"}}", e),
535 }
536 }
537 0x0012 => {
538 match decode_unique_id(tlv_value) {
539 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
540 Err(e) => format!("{{\"error\": \"{}\"}}", e),
541 }
542 }
543 0x0013 => {
544 match decode_capability_minima(tlv_value) {
545 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
546 Err(e) => format!("{{\"error\": \"{}\"}}", e),
547 }
548 }
549 0x0014 => {
550 match decode_product_appearance(tlv_value) {
551 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
552 Err(e) => format!("{{\"error\": \"{}\"}}", e),
553 }
554 }
555 0x0015 => {
556 match decode_specification_version(tlv_value) {
557 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
558 Err(e) => format!("{{\"error\": \"{}\"}}", e),
559 }
560 }
561 0x0016 => {
562 match decode_max_paths_per_invoke(tlv_value) {
563 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
564 Err(e) => format!("{{\"error\": \"{}\"}}", e),
565 }
566 }
567 0x0018 => {
568 match decode_configuration_version(tlv_value) {
569 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
570 Err(e) => format!("{{\"error\": \"{}\"}}", e),
571 }
572 }
573 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
574 }
575}
576
577pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
582 vec![
583 (0x0000, "DataModelRevision"),
584 (0x0001, "VendorName"),
585 (0x0002, "VendorID"),
586 (0x0003, "ProductName"),
587 (0x0004, "ProductID"),
588 (0x0005, "NodeLabel"),
589 (0x0006, "Location"),
590 (0x0007, "HardwareVersion"),
591 (0x0008, "HardwareVersionString"),
592 (0x0009, "SoftwareVersion"),
593 (0x000A, "SoftwareVersionString"),
594 (0x000B, "ManufacturingDate"),
595 (0x000C, "PartNumber"),
596 (0x000D, "ProductURL"),
597 (0x000E, "ProductLabel"),
598 (0x000F, "SerialNumber"),
599 (0x0010, "LocalConfigDisabled"),
600 (0x0011, "Reachable"),
601 (0x0012, "UniqueID"),
602 (0x0013, "CapabilityMinima"),
603 (0x0014, "ProductAppearance"),
604 (0x0015, "SpecificationVersion"),
605 (0x0016, "MaxPathsPerInvoke"),
606 (0x0018, "ConfigurationVersion"),
607 ]
608}
609
610pub fn get_command_list() -> Vec<(u32, &'static str)> {
613 vec![
614 (0x80, "KeepActive"),
615 ]
616}
617
618pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
619 match cmd_id {
620 0x80 => Some("KeepActive"),
621 _ => None,
622 }
623}
624
625pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
626 match cmd_id {
627 0x80 => Some(vec![
628 crate::clusters::codec::CommandField { tag: 0, name: "stay_active_duration", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
629 crate::clusters::codec::CommandField { tag: 1, name: "timeout_ms", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
630 ]),
631 _ => None,
632 }
633}
634
635pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
636 match cmd_id {
637 0x80 => {
638 let stay_active_duration = crate::clusters::codec::json_util::get_u32(args, "stay_active_duration")?;
639 let timeout_ms = crate::clusters::codec::json_util::get_u32(args, "timeout_ms")?;
640 encode_keep_active(stay_active_duration, timeout_ms)
641 }
642 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
643 }
644}
645
646pub async fn keep_active(conn: &crate::controller::Connection, endpoint: u16, stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<()> {
650 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_CMD_ID_KEEPACTIVE, &encode_keep_active(stay_active_duration, timeout_ms)?).await?;
651 Ok(())
652}
653
654pub async fn read_data_model_revision(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
656 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_DATAMODELREVISION).await?;
657 decode_data_model_revision(&tlv)
658}
659
660pub async fn read_vendor_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
662 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_VENDORNAME).await?;
663 decode_vendor_name(&tlv)
664}
665
666pub async fn read_vendor_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
668 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_VENDORID).await?;
669 decode_vendor_id(&tlv)
670}
671
672pub async fn read_product_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
674 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTNAME).await?;
675 decode_product_name(&tlv)
676}
677
678pub async fn read_product_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
680 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTID).await?;
681 decode_product_id(&tlv)
682}
683
684pub async fn read_node_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
686 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_NODELABEL).await?;
687 decode_node_label(&tlv)
688}
689
690pub async fn read_location(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
692 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_LOCATION).await?;
693 decode_location(&tlv)
694}
695
696pub async fn read_hardware_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
698 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSION).await?;
699 decode_hardware_version(&tlv)
700}
701
702pub async fn read_hardware_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
704 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_HARDWAREVERSIONSTRING).await?;
705 decode_hardware_version_string(&tlv)
706}
707
708pub async fn read_software_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
710 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSION).await?;
711 decode_software_version(&tlv)
712}
713
714pub async fn read_software_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
716 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SOFTWAREVERSIONSTRING).await?;
717 decode_software_version_string(&tlv)
718}
719
720pub async fn read_manufacturing_date(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
722 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_MANUFACTURINGDATE).await?;
723 decode_manufacturing_date(&tlv)
724}
725
726pub async fn read_part_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
728 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PARTNUMBER).await?;
729 decode_part_number(&tlv)
730}
731
732pub async fn read_product_url(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
734 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTURL).await?;
735 decode_product_url(&tlv)
736}
737
738pub async fn read_product_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
740 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTLABEL).await?;
741 decode_product_label(&tlv)
742}
743
744pub async fn read_serial_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
746 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SERIALNUMBER).await?;
747 decode_serial_number(&tlv)
748}
749
750pub async fn read_local_config_disabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
752 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_LOCALCONFIGDISABLED).await?;
753 decode_local_config_disabled(&tlv)
754}
755
756pub async fn read_reachable(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
758 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_REACHABLE).await?;
759 decode_reachable(&tlv)
760}
761
762pub async fn read_unique_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
764 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_UNIQUEID).await?;
765 decode_unique_id(&tlv)
766}
767
768pub async fn read_capability_minima(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CapabilityMinima> {
770 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_CAPABILITYMINIMA).await?;
771 decode_capability_minima(&tlv)
772}
773
774pub async fn read_product_appearance(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ProductAppearance> {
776 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_PRODUCTAPPEARANCE).await?;
777 decode_product_appearance(&tlv)
778}
779
780pub async fn read_specification_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
782 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_SPECIFICATIONVERSION).await?;
783 decode_specification_version(&tlv)
784}
785
786pub async fn read_max_paths_per_invoke(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
788 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_MAXPATHSPERINVOKE).await?;
789 decode_max_paths_per_invoke(&tlv)
790}
791
792pub async fn read_configuration_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
794 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_BRIDGED_DEVICE_BASIC_INFORMATION, crate::clusters::defs::CLUSTER_BRIDGED_DEVICE_BASIC_INFORMATION_ATTR_ID_CONFIGURATIONVERSION).await?;
795 decode_configuration_version(&tlv)
796}
797
798#[derive(Debug, serde::Serialize)]
799pub struct StartUpEvent {
800 pub software_version: Option<u32>,
801}
802
803#[derive(Debug, serde::Serialize)]
804pub struct LeaveEvent {
805 pub fabric_index: Option<u8>,
806}
807
808#[derive(Debug, serde::Serialize)]
809pub struct ReachableChangedEvent {
810 pub reachable_new_value: Option<bool>,
811}
812
813#[derive(Debug, serde::Serialize)]
814pub struct ActiveChangedEvent {
815 pub promised_active_duration: Option<u32>,
816}
817
818pub fn decode_start_up_event(inp: &tlv::TlvItemValue) -> anyhow::Result<StartUpEvent> {
822 if let tlv::TlvItemValue::List(_fields) = inp {
823 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
824 Ok(StartUpEvent {
825 software_version: item.get_int(&[0]).map(|v| v as u32),
826 })
827 } else {
828 Err(anyhow::anyhow!("Expected struct fields"))
829 }
830}
831
832pub fn decode_leave_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LeaveEvent> {
834 if let tlv::TlvItemValue::List(_fields) = inp {
835 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
836 Ok(LeaveEvent {
837 fabric_index: item.get_int(&[0]).map(|v| v as u8),
838 })
839 } else {
840 Err(anyhow::anyhow!("Expected struct fields"))
841 }
842}
843
844pub fn decode_reachable_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ReachableChangedEvent> {
846 if let tlv::TlvItemValue::List(_fields) = inp {
847 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
848 Ok(ReachableChangedEvent {
849 reachable_new_value: item.get_bool(&[0]),
850 })
851 } else {
852 Err(anyhow::anyhow!("Expected struct fields"))
853 }
854}
855
856pub fn decode_active_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ActiveChangedEvent> {
858 if let tlv::TlvItemValue::List(_fields) = inp {
859 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
860 Ok(ActiveChangedEvent {
861 promised_active_duration: item.get_int(&[0]).map(|v| v as u32),
862 })
863 } else {
864 Err(anyhow::anyhow!("Expected struct fields"))
865 }
866}
867
868
869pub fn decode_event_json(cluster_id: u32, event_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
873 if cluster_id != 0x0039 {
874 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0039, got {}\"}}", cluster_id);
875 }
876
877 match event_id {
878 0x00 => {
879 match decode_start_up_event(tlv_value) {
880 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
881 Err(e) => format!("{{\"error\": \"{}\"}}", e),
882 }
883 }
884 0x01 => "{}".to_string(),
885 0x02 => {
886 match decode_leave_event(tlv_value) {
887 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
888 Err(e) => format!("{{\"error\": \"{}\"}}", e),
889 }
890 }
891 0x03 => {
892 match decode_reachable_changed_event(tlv_value) {
893 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
894 Err(e) => format!("{{\"error\": \"{}\"}}", e),
895 }
896 }
897 0x80 => {
898 match decode_active_changed_event(tlv_value) {
899 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
900 Err(e) => format!("{{\"error\": \"{}\"}}", e),
901 }
902 }
903 _ => format!("{{\"error\": \"Unknown event ID: {}\"}}", event_id),
904 }
905}
906
907pub fn get_event_list() -> Vec<(u32, &'static str)> {
912 vec![
913 (0x00, "StartUp"),
914 (0x01, "ShutDown"),
915 (0x02, "Leave"),
916 (0x03, "ReachableChanged"),
917 (0x80, "ActiveChanged"),
918 ]
919}
920