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}
153
154#[derive(Debug, serde::Serialize)]
155pub struct ProductAppearance {
156 pub finish: Option<ProductFinish>,
157 pub primary_color: Option<Color>,
158}
159
160pub fn encode_keep_active(stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<Vec<u8>> {
164 let tlv = tlv::TlvItemEnc {
165 tag: 0,
166 value: tlv::TlvItemValueEnc::StructInvisible(vec![
167 (0, tlv::TlvItemValueEnc::UInt32(stay_active_duration)).into(),
168 (1, tlv::TlvItemValueEnc::UInt32(timeout_ms)).into(),
169 ]),
170 };
171 Ok(tlv.encode()?)
172}
173
174pub fn decode_data_model_revision(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
178 if let tlv::TlvItemValue::Int(v) = inp {
179 Ok(*v as u16)
180 } else {
181 Err(anyhow::anyhow!("Expected UInt16"))
182 }
183}
184
185pub fn decode_vendor_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
187 if let tlv::TlvItemValue::String(v) = inp {
188 Ok(v.clone())
189 } else {
190 Err(anyhow::anyhow!("Expected String"))
191 }
192}
193
194pub fn decode_vendor_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
196 if let tlv::TlvItemValue::Int(v) = inp {
197 Ok(*v as u16)
198 } else {
199 Err(anyhow::anyhow!("Expected UInt16"))
200 }
201}
202
203pub fn decode_product_name(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
205 if let tlv::TlvItemValue::String(v) = inp {
206 Ok(v.clone())
207 } else {
208 Err(anyhow::anyhow!("Expected String"))
209 }
210}
211
212pub fn decode_product_id(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
214 if let tlv::TlvItemValue::Int(v) = inp {
215 Ok(*v as u16)
216 } else {
217 Err(anyhow::anyhow!("Expected UInt16"))
218 }
219}
220
221pub fn decode_node_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
223 if let tlv::TlvItemValue::String(v) = inp {
224 Ok(v.clone())
225 } else {
226 Err(anyhow::anyhow!("Expected String"))
227 }
228}
229
230pub fn decode_location(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
232 if let tlv::TlvItemValue::String(v) = inp {
233 Ok(v.clone())
234 } else {
235 Err(anyhow::anyhow!("Expected String"))
236 }
237}
238
239pub fn decode_hardware_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
241 if let tlv::TlvItemValue::Int(v) = inp {
242 Ok(*v as u16)
243 } else {
244 Err(anyhow::anyhow!("Expected UInt16"))
245 }
246}
247
248pub fn decode_hardware_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
250 if let tlv::TlvItemValue::String(v) = inp {
251 Ok(v.clone())
252 } else {
253 Err(anyhow::anyhow!("Expected String"))
254 }
255}
256
257pub fn decode_software_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
259 if let tlv::TlvItemValue::Int(v) = inp {
260 Ok(*v as u32)
261 } else {
262 Err(anyhow::anyhow!("Expected UInt32"))
263 }
264}
265
266pub fn decode_software_version_string(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
268 if let tlv::TlvItemValue::String(v) = inp {
269 Ok(v.clone())
270 } else {
271 Err(anyhow::anyhow!("Expected String"))
272 }
273}
274
275pub fn decode_manufacturing_date(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
277 if let tlv::TlvItemValue::String(v) = inp {
278 Ok(v.clone())
279 } else {
280 Err(anyhow::anyhow!("Expected String"))
281 }
282}
283
284pub fn decode_part_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
286 if let tlv::TlvItemValue::String(v) = inp {
287 Ok(v.clone())
288 } else {
289 Err(anyhow::anyhow!("Expected String"))
290 }
291}
292
293pub fn decode_product_url(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
295 if let tlv::TlvItemValue::String(v) = inp {
296 Ok(v.clone())
297 } else {
298 Err(anyhow::anyhow!("Expected String"))
299 }
300}
301
302pub fn decode_product_label(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
304 if let tlv::TlvItemValue::String(v) = inp {
305 Ok(v.clone())
306 } else {
307 Err(anyhow::anyhow!("Expected String"))
308 }
309}
310
311pub fn decode_serial_number(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
313 if let tlv::TlvItemValue::String(v) = inp {
314 Ok(v.clone())
315 } else {
316 Err(anyhow::anyhow!("Expected String"))
317 }
318}
319
320pub fn decode_local_config_disabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
322 if let tlv::TlvItemValue::Bool(v) = inp {
323 Ok(*v)
324 } else {
325 Err(anyhow::anyhow!("Expected Bool"))
326 }
327}
328
329pub fn decode_reachable(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
331 if let tlv::TlvItemValue::Bool(v) = inp {
332 Ok(*v)
333 } else {
334 Err(anyhow::anyhow!("Expected Bool"))
335 }
336}
337
338pub fn decode_unique_id(inp: &tlv::TlvItemValue) -> anyhow::Result<String> {
340 if let tlv::TlvItemValue::String(v) = inp {
341 Ok(v.clone())
342 } else {
343 Err(anyhow::anyhow!("Expected String"))
344 }
345}
346
347pub fn decode_capability_minima(inp: &tlv::TlvItemValue) -> anyhow::Result<CapabilityMinima> {
349 if let tlv::TlvItemValue::List(_fields) = inp {
350 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
352 Ok(CapabilityMinima {
353 case_sessions_per_fabric: item.get_int(&[0]).map(|v| v as u16),
354 subscriptions_per_fabric: item.get_int(&[1]).map(|v| v as u16),
355 })
356 } else {
357 Err(anyhow::anyhow!("Expected struct fields"))
358 }
359}
360
361pub fn decode_product_appearance(inp: &tlv::TlvItemValue) -> anyhow::Result<ProductAppearance> {
363 if let tlv::TlvItemValue::List(_fields) = inp {
364 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
366 Ok(ProductAppearance {
367 finish: item.get_int(&[0]).and_then(|v| ProductFinish::from_u8(v as u8)),
368 primary_color: item.get_int(&[1]).and_then(|v| Color::from_u8(v as u8)),
369 })
370 } else {
371 Err(anyhow::anyhow!("Expected struct fields"))
372 }
373}
374
375pub fn decode_specification_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
377 if let tlv::TlvItemValue::Int(v) = inp {
378 Ok(*v as u32)
379 } else {
380 Err(anyhow::anyhow!("Expected UInt32"))
381 }
382}
383
384pub fn decode_max_paths_per_invoke(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
386 if let tlv::TlvItemValue::Int(v) = inp {
387 Ok(*v as u16)
388 } else {
389 Err(anyhow::anyhow!("Expected UInt16"))
390 }
391}
392
393pub fn decode_configuration_version(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
395 if let tlv::TlvItemValue::Int(v) = inp {
396 Ok(*v as u32)
397 } else {
398 Err(anyhow::anyhow!("Expected UInt32"))
399 }
400}
401
402
403pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
415 if cluster_id != 0x0039 {
417 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0039, got {}\"}}", cluster_id);
418 }
419
420 match attribute_id {
421 0x0000 => {
422 match decode_data_model_revision(tlv_value) {
423 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
424 Err(e) => format!("{{\"error\": \"{}\"}}", e),
425 }
426 }
427 0x0001 => {
428 match decode_vendor_name(tlv_value) {
429 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
430 Err(e) => format!("{{\"error\": \"{}\"}}", e),
431 }
432 }
433 0x0002 => {
434 match decode_vendor_id(tlv_value) {
435 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
436 Err(e) => format!("{{\"error\": \"{}\"}}", e),
437 }
438 }
439 0x0003 => {
440 match decode_product_name(tlv_value) {
441 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
442 Err(e) => format!("{{\"error\": \"{}\"}}", e),
443 }
444 }
445 0x0004 => {
446 match decode_product_id(tlv_value) {
447 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
448 Err(e) => format!("{{\"error\": \"{}\"}}", e),
449 }
450 }
451 0x0005 => {
452 match decode_node_label(tlv_value) {
453 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
454 Err(e) => format!("{{\"error\": \"{}\"}}", e),
455 }
456 }
457 0x0006 => {
458 match decode_location(tlv_value) {
459 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
460 Err(e) => format!("{{\"error\": \"{}\"}}", e),
461 }
462 }
463 0x0007 => {
464 match decode_hardware_version(tlv_value) {
465 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
466 Err(e) => format!("{{\"error\": \"{}\"}}", e),
467 }
468 }
469 0x0008 => {
470 match decode_hardware_version_string(tlv_value) {
471 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
472 Err(e) => format!("{{\"error\": \"{}\"}}", e),
473 }
474 }
475 0x0009 => {
476 match decode_software_version(tlv_value) {
477 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
478 Err(e) => format!("{{\"error\": \"{}\"}}", e),
479 }
480 }
481 0x000A => {
482 match decode_software_version_string(tlv_value) {
483 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
484 Err(e) => format!("{{\"error\": \"{}\"}}", e),
485 }
486 }
487 0x000B => {
488 match decode_manufacturing_date(tlv_value) {
489 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
490 Err(e) => format!("{{\"error\": \"{}\"}}", e),
491 }
492 }
493 0x000C => {
494 match decode_part_number(tlv_value) {
495 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
496 Err(e) => format!("{{\"error\": \"{}\"}}", e),
497 }
498 }
499 0x000D => {
500 match decode_product_url(tlv_value) {
501 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
502 Err(e) => format!("{{\"error\": \"{}\"}}", e),
503 }
504 }
505 0x000E => {
506 match decode_product_label(tlv_value) {
507 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
508 Err(e) => format!("{{\"error\": \"{}\"}}", e),
509 }
510 }
511 0x000F => {
512 match decode_serial_number(tlv_value) {
513 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
514 Err(e) => format!("{{\"error\": \"{}\"}}", e),
515 }
516 }
517 0x0010 => {
518 match decode_local_config_disabled(tlv_value) {
519 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
520 Err(e) => format!("{{\"error\": \"{}\"}}", e),
521 }
522 }
523 0x0011 => {
524 match decode_reachable(tlv_value) {
525 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
526 Err(e) => format!("{{\"error\": \"{}\"}}", e),
527 }
528 }
529 0x0012 => {
530 match decode_unique_id(tlv_value) {
531 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
532 Err(e) => format!("{{\"error\": \"{}\"}}", e),
533 }
534 }
535 0x0013 => {
536 match decode_capability_minima(tlv_value) {
537 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
538 Err(e) => format!("{{\"error\": \"{}\"}}", e),
539 }
540 }
541 0x0014 => {
542 match decode_product_appearance(tlv_value) {
543 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
544 Err(e) => format!("{{\"error\": \"{}\"}}", e),
545 }
546 }
547 0x0015 => {
548 match decode_specification_version(tlv_value) {
549 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
550 Err(e) => format!("{{\"error\": \"{}\"}}", e),
551 }
552 }
553 0x0016 => {
554 match decode_max_paths_per_invoke(tlv_value) {
555 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
556 Err(e) => format!("{{\"error\": \"{}\"}}", e),
557 }
558 }
559 0x0018 => {
560 match decode_configuration_version(tlv_value) {
561 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
562 Err(e) => format!("{{\"error\": \"{}\"}}", e),
563 }
564 }
565 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
566 }
567}
568
569pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
574 vec![
575 (0x0000, "DataModelRevision"),
576 (0x0001, "VendorName"),
577 (0x0002, "VendorID"),
578 (0x0003, "ProductName"),
579 (0x0004, "ProductID"),
580 (0x0005, "NodeLabel"),
581 (0x0006, "Location"),
582 (0x0007, "HardwareVersion"),
583 (0x0008, "HardwareVersionString"),
584 (0x0009, "SoftwareVersion"),
585 (0x000A, "SoftwareVersionString"),
586 (0x000B, "ManufacturingDate"),
587 (0x000C, "PartNumber"),
588 (0x000D, "ProductURL"),
589 (0x000E, "ProductLabel"),
590 (0x000F, "SerialNumber"),
591 (0x0010, "LocalConfigDisabled"),
592 (0x0011, "Reachable"),
593 (0x0012, "UniqueID"),
594 (0x0013, "CapabilityMinima"),
595 (0x0014, "ProductAppearance"),
596 (0x0015, "SpecificationVersion"),
597 (0x0016, "MaxPathsPerInvoke"),
598 (0x0018, "ConfigurationVersion"),
599 ]
600}
601
602pub fn get_command_list() -> Vec<(u32, &'static str)> {
605 vec![
606 (0x80, "KeepActive"),
607 ]
608}
609
610pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
611 match cmd_id {
612 0x80 => Some("KeepActive"),
613 _ => None,
614 }
615}
616
617pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
618 match cmd_id {
619 0x80 => Some(vec![
620 crate::clusters::codec::CommandField { tag: 0, name: "stay_active_duration", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
621 crate::clusters::codec::CommandField { tag: 1, name: "timeout_ms", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
622 ]),
623 _ => None,
624 }
625}
626
627pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
628 match cmd_id {
629 0x80 => {
630 let stay_active_duration = crate::clusters::codec::json_util::get_u32(args, "stay_active_duration")?;
631 let timeout_ms = crate::clusters::codec::json_util::get_u32(args, "timeout_ms")?;
632 encode_keep_active(stay_active_duration, timeout_ms)
633 }
634 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
635 }
636}
637
638pub async fn keep_active(conn: &crate::controller::Connection, endpoint: u16, stay_active_duration: u32, timeout_ms: u32) -> anyhow::Result<()> {
642 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?;
643 Ok(())
644}
645
646pub async fn read_data_model_revision(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
648 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?;
649 decode_data_model_revision(&tlv)
650}
651
652pub async fn read_vendor_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
654 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?;
655 decode_vendor_name(&tlv)
656}
657
658pub async fn read_vendor_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
660 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?;
661 decode_vendor_id(&tlv)
662}
663
664pub async fn read_product_name(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
666 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?;
667 decode_product_name(&tlv)
668}
669
670pub async fn read_product_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
672 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?;
673 decode_product_id(&tlv)
674}
675
676pub async fn read_node_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
678 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?;
679 decode_node_label(&tlv)
680}
681
682pub async fn read_location(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
684 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?;
685 decode_location(&tlv)
686}
687
688pub async fn read_hardware_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
690 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?;
691 decode_hardware_version(&tlv)
692}
693
694pub async fn read_hardware_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
696 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?;
697 decode_hardware_version_string(&tlv)
698}
699
700pub async fn read_software_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
702 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?;
703 decode_software_version(&tlv)
704}
705
706pub async fn read_software_version_string(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
708 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?;
709 decode_software_version_string(&tlv)
710}
711
712pub async fn read_manufacturing_date(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
714 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?;
715 decode_manufacturing_date(&tlv)
716}
717
718pub async fn read_part_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
720 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?;
721 decode_part_number(&tlv)
722}
723
724pub async fn read_product_url(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
726 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?;
727 decode_product_url(&tlv)
728}
729
730pub async fn read_product_label(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
732 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?;
733 decode_product_label(&tlv)
734}
735
736pub async fn read_serial_number(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
738 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?;
739 decode_serial_number(&tlv)
740}
741
742pub async fn read_local_config_disabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
744 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?;
745 decode_local_config_disabled(&tlv)
746}
747
748pub async fn read_reachable(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
750 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?;
751 decode_reachable(&tlv)
752}
753
754pub async fn read_unique_id(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<String> {
756 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?;
757 decode_unique_id(&tlv)
758}
759
760pub async fn read_capability_minima(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<CapabilityMinima> {
762 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?;
763 decode_capability_minima(&tlv)
764}
765
766pub async fn read_product_appearance(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<ProductAppearance> {
768 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?;
769 decode_product_appearance(&tlv)
770}
771
772pub async fn read_specification_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
774 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?;
775 decode_specification_version(&tlv)
776}
777
778pub async fn read_max_paths_per_invoke(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
780 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?;
781 decode_max_paths_per_invoke(&tlv)
782}
783
784pub async fn read_configuration_version(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
786 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?;
787 decode_configuration_version(&tlv)
788}
789
790#[derive(Debug, serde::Serialize)]
791pub struct StartUpEvent {
792 pub software_version: Option<u32>,
793}
794
795#[derive(Debug, serde::Serialize)]
796pub struct LeaveEvent {
797 pub fabric_index: Option<u8>,
798}
799
800#[derive(Debug, serde::Serialize)]
801pub struct ReachableChangedEvent {
802 pub reachable_new_value: Option<bool>,
803}
804
805#[derive(Debug, serde::Serialize)]
806pub struct ActiveChangedEvent {
807 pub promised_active_duration: Option<u32>,
808}
809
810pub fn decode_start_up_event(inp: &tlv::TlvItemValue) -> anyhow::Result<StartUpEvent> {
814 if let tlv::TlvItemValue::List(_fields) = inp {
815 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
816 Ok(StartUpEvent {
817 software_version: item.get_int(&[0]).map(|v| v as u32),
818 })
819 } else {
820 Err(anyhow::anyhow!("Expected struct fields"))
821 }
822}
823
824pub fn decode_leave_event(inp: &tlv::TlvItemValue) -> anyhow::Result<LeaveEvent> {
826 if let tlv::TlvItemValue::List(_fields) = inp {
827 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
828 Ok(LeaveEvent {
829 fabric_index: item.get_int(&[0]).map(|v| v as u8),
830 })
831 } else {
832 Err(anyhow::anyhow!("Expected struct fields"))
833 }
834}
835
836pub fn decode_reachable_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ReachableChangedEvent> {
838 if let tlv::TlvItemValue::List(_fields) = inp {
839 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
840 Ok(ReachableChangedEvent {
841 reachable_new_value: item.get_bool(&[0]),
842 })
843 } else {
844 Err(anyhow::anyhow!("Expected struct fields"))
845 }
846}
847
848pub fn decode_active_changed_event(inp: &tlv::TlvItemValue) -> anyhow::Result<ActiveChangedEvent> {
850 if let tlv::TlvItemValue::List(_fields) = inp {
851 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
852 Ok(ActiveChangedEvent {
853 promised_active_duration: item.get_int(&[0]).map(|v| v as u32),
854 })
855 } else {
856 Err(anyhow::anyhow!("Expected struct fields"))
857 }
858}
859