Skip to main content

matc/clusters/codec/
camera_av_stream_management.rs

1//! Matter TLV encoders and decoders for Camera AV Stream Management Cluster
2//! Cluster IDs: 0x0551
3//!
4//! This file is automatically generated from CameraAVStreamManagement.xml
5
6#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13// Import serialization helpers for octet strings
14use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16// Enum definitions
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum AudioCodec {
21    /// Open source IETF standard codec.
22    Opus = 0,
23    /// Advanced Audio Coding codec-Low Complexity
24    AacLc = 1,
25}
26
27impl AudioCodec {
28    /// Convert from u8 value
29    pub fn from_u8(value: u8) -> Option<Self> {
30        match value {
31            0 => Some(AudioCodec::Opus),
32            1 => Some(AudioCodec::AacLc),
33            _ => None,
34        }
35    }
36
37    /// Convert to u8 value
38    pub fn to_u8(self) -> u8 {
39        self as u8
40    }
41}
42
43impl From<AudioCodec> for u8 {
44    fn from(val: AudioCodec) -> Self {
45        val as u8
46    }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
50#[repr(u8)]
51pub enum ImageCodec {
52    /// JPEG image codec.
53    Jpeg = 0,
54    /// HEIC image codec.
55    Heic = 1,
56}
57
58impl ImageCodec {
59    /// Convert from u8 value
60    pub fn from_u8(value: u8) -> Option<Self> {
61        match value {
62            0 => Some(ImageCodec::Jpeg),
63            1 => Some(ImageCodec::Heic),
64            _ => None,
65        }
66    }
67
68    /// Convert to u8 value
69    pub fn to_u8(self) -> u8 {
70        self as u8
71    }
72}
73
74impl From<ImageCodec> for u8 {
75    fn from(val: ImageCodec) -> Self {
76        val as u8
77    }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
81#[repr(u8)]
82pub enum TriStateAuto {
83    /// Off
84    Off = 0,
85    /// On
86    On = 1,
87    /// Automatic Operation
88    Auto = 2,
89}
90
91impl TriStateAuto {
92    /// Convert from u8 value
93    pub fn from_u8(value: u8) -> Option<Self> {
94        match value {
95            0 => Some(TriStateAuto::Off),
96            1 => Some(TriStateAuto::On),
97            2 => Some(TriStateAuto::Auto),
98            _ => None,
99        }
100    }
101
102    /// Convert to u8 value
103    pub fn to_u8(self) -> u8 {
104        self as u8
105    }
106}
107
108impl From<TriStateAuto> for u8 {
109    fn from(val: TriStateAuto) -> Self {
110        val as u8
111    }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
115#[repr(u8)]
116pub enum TwoWayTalkSupportType {
117    /// Two-way Talk support is absent.
118    Notsupported = 0,
119    /// Audio in one direction at a time.
120    Halfduplex = 1,
121    /// Audio in both directions simultaneously.
122    Fullduplex = 2,
123}
124
125impl TwoWayTalkSupportType {
126    /// Convert from u8 value
127    pub fn from_u8(value: u8) -> Option<Self> {
128        match value {
129            0 => Some(TwoWayTalkSupportType::Notsupported),
130            1 => Some(TwoWayTalkSupportType::Halfduplex),
131            2 => Some(TwoWayTalkSupportType::Fullduplex),
132            _ => None,
133        }
134    }
135
136    /// Convert to u8 value
137    pub fn to_u8(self) -> u8 {
138        self as u8
139    }
140}
141
142impl From<TwoWayTalkSupportType> for u8 {
143    fn from(val: TwoWayTalkSupportType) -> Self {
144        val as u8
145    }
146}
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
149#[repr(u8)]
150pub enum VideoCodec {
151    /// Advanced Video Coding (H.264) codec.
152    H264 = 0,
153    /// High efficiency Video Coding (H.265) codec.
154    Hevc = 1,
155    /// Versatile Video Coding (H.266) codec.
156    Vvc = 2,
157    /// AOMedia Video 1 codec.
158    Av1 = 3,
159}
160
161impl VideoCodec {
162    /// Convert from u8 value
163    pub fn from_u8(value: u8) -> Option<Self> {
164        match value {
165            0 => Some(VideoCodec::H264),
166            1 => Some(VideoCodec::Hevc),
167            2 => Some(VideoCodec::Vvc),
168            3 => Some(VideoCodec::Av1),
169            _ => None,
170        }
171    }
172
173    /// Convert to u8 value
174    pub fn to_u8(self) -> u8 {
175        self as u8
176    }
177}
178
179impl From<VideoCodec> for u8 {
180    fn from(val: VideoCodec) -> Self {
181        val as u8
182    }
183}
184
185// Struct definitions
186
187#[derive(Debug, serde::Serialize)]
188pub struct AVMetadata {
189    pub utc_time: Option<u64>,
190    pub motion_zones_active: Option<Vec<u16>>,
191    pub black_and_white_active: Option<bool>,
192    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
193    pub user_defined: Option<Vec<u8>>,
194}
195
196#[derive(Debug, serde::Serialize)]
197pub struct AudioCapabilities {
198    pub max_number_of_channels: Option<u8>,
199    pub supported_codecs: Option<Vec<AudioCodec>>,
200    pub supported_sample_rates: Option<Vec<u32>>,
201    pub supported_bit_depths: Option<Vec<u8>>,
202}
203
204#[derive(Debug, serde::Serialize)]
205pub struct AudioStream {
206    pub audio_stream_id: Option<u16>,
207    pub stream_usage: Option<u8>,
208    pub audio_codec: Option<AudioCodec>,
209    pub channel_count: Option<u8>,
210    pub sample_rate: Option<u32>,
211    pub bit_rate: Option<u32>,
212    pub bit_depth: Option<u8>,
213    pub reference_count: Option<u8>,
214}
215
216#[derive(Debug, serde::Serialize)]
217pub struct RateDistortionTradeOffPoints {
218    pub codec: Option<VideoCodec>,
219    pub resolution: Option<VideoResolution>,
220    pub min_bit_rate: Option<u32>,
221}
222
223#[derive(Debug, serde::Serialize)]
224pub struct SnapshotCapabilities {
225    pub resolution: Option<VideoResolution>,
226    pub max_frame_rate: Option<u16>,
227    pub image_codec: Option<ImageCodec>,
228    pub requires_encoded_pixels: Option<bool>,
229    pub requires_hardware_encoder: Option<bool>,
230}
231
232#[derive(Debug, serde::Serialize)]
233pub struct SnapshotStream {
234    pub snapshot_stream_id: Option<u16>,
235    pub image_codec: Option<ImageCodec>,
236    pub frame_rate: Option<u16>,
237    pub min_resolution: Option<VideoResolution>,
238    pub max_resolution: Option<VideoResolution>,
239    pub quality: Option<u8>,
240    pub reference_count: Option<u8>,
241    pub encoded_pixels: Option<bool>,
242    pub hardware_encoder: Option<bool>,
243    pub watermark_enabled: Option<bool>,
244    pub osd_enabled: Option<bool>,
245}
246
247#[derive(Debug, serde::Serialize)]
248pub struct VideoResolution {
249    pub width: Option<u16>,
250    pub height: Option<u16>,
251}
252
253#[derive(Debug, serde::Serialize)]
254pub struct VideoSensorParams {
255    pub sensor_width: Option<u16>,
256    pub sensor_height: Option<u16>,
257    pub max_fps: Option<u16>,
258    pub max_hdrfps: Option<u16>,
259}
260
261#[derive(Debug, serde::Serialize)]
262pub struct VideoStream {
263    pub video_stream_id: Option<u16>,
264    pub stream_usage: Option<u8>,
265    pub video_codec: Option<VideoCodec>,
266    pub min_frame_rate: Option<u16>,
267    pub max_frame_rate: Option<u16>,
268    pub min_resolution: Option<VideoResolution>,
269    pub max_resolution: Option<VideoResolution>,
270    pub min_bit_rate: Option<u32>,
271    pub max_bit_rate: Option<u32>,
272    pub key_frame_interval: Option<u16>,
273    pub watermark_enabled: Option<bool>,
274    pub osd_enabled: Option<bool>,
275    pub reference_count: Option<u8>,
276}
277
278// Command encoders
279
280/// Encode AudioStreamAllocate command (0x00)
281pub fn encode_audio_stream_allocate(stream_usage: u8, audio_codec: AudioCodec, channel_count: u8, sample_rate: u32, bit_rate: u32, bit_depth: u8) -> anyhow::Result<Vec<u8>> {
282    let tlv = tlv::TlvItemEnc {
283        tag: 0,
284        value: tlv::TlvItemValueEnc::StructInvisible(vec![
285        (0, tlv::TlvItemValueEnc::UInt8(stream_usage)).into(),
286        (1, tlv::TlvItemValueEnc::UInt8(audio_codec.to_u8())).into(),
287        (2, tlv::TlvItemValueEnc::UInt8(channel_count)).into(),
288        (3, tlv::TlvItemValueEnc::UInt32(sample_rate)).into(),
289        (4, tlv::TlvItemValueEnc::UInt32(bit_rate)).into(),
290        (5, tlv::TlvItemValueEnc::UInt8(bit_depth)).into(),
291        ]),
292    };
293    Ok(tlv.encode()?)
294}
295
296/// Encode AudioStreamDeallocate command (0x02)
297pub fn encode_audio_stream_deallocate(audio_stream_id: u16) -> anyhow::Result<Vec<u8>> {
298    let tlv = tlv::TlvItemEnc {
299        tag: 0,
300        value: tlv::TlvItemValueEnc::StructInvisible(vec![
301        (0, tlv::TlvItemValueEnc::UInt16(audio_stream_id)).into(),
302        ]),
303    };
304    Ok(tlv.encode()?)
305}
306
307/// Parameters for VideoStreamAllocate command
308pub struct VideoStreamAllocateParams {
309    pub stream_usage: u8,
310    pub video_codec: VideoCodec,
311    pub min_frame_rate: u16,
312    pub max_frame_rate: u16,
313    pub min_resolution: VideoResolution,
314    pub max_resolution: VideoResolution,
315    pub min_bit_rate: u32,
316    pub max_bit_rate: u32,
317    pub key_frame_interval: u16,
318    pub watermark_enabled: bool,
319    pub osd_enabled: bool,
320}
321
322/// Encode VideoStreamAllocate command (0x03)
323pub fn encode_video_stream_allocate(params: VideoStreamAllocateParams) -> anyhow::Result<Vec<u8>> {
324            // Encode struct VideoResolutionStruct
325            let mut min_resolution_fields = Vec::new();
326            if let Some(x) = params.min_resolution.width { min_resolution_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
327            if let Some(x) = params.min_resolution.height { min_resolution_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
328            // Encode struct VideoResolutionStruct
329            let mut max_resolution_fields = Vec::new();
330            if let Some(x) = params.max_resolution.width { max_resolution_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
331            if let Some(x) = params.max_resolution.height { max_resolution_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
332    let tlv = tlv::TlvItemEnc {
333        tag: 0,
334        value: tlv::TlvItemValueEnc::StructInvisible(vec![
335        (0, tlv::TlvItemValueEnc::UInt8(params.stream_usage)).into(),
336        (1, tlv::TlvItemValueEnc::UInt8(params.video_codec.to_u8())).into(),
337        (2, tlv::TlvItemValueEnc::UInt16(params.min_frame_rate)).into(),
338        (3, tlv::TlvItemValueEnc::UInt16(params.max_frame_rate)).into(),
339        (4, tlv::TlvItemValueEnc::StructInvisible(min_resolution_fields)).into(),
340        (5, tlv::TlvItemValueEnc::StructInvisible(max_resolution_fields)).into(),
341        (6, tlv::TlvItemValueEnc::UInt32(params.min_bit_rate)).into(),
342        (7, tlv::TlvItemValueEnc::UInt32(params.max_bit_rate)).into(),
343        (8, tlv::TlvItemValueEnc::UInt16(params.key_frame_interval)).into(),
344        (9, tlv::TlvItemValueEnc::Bool(params.watermark_enabled)).into(),
345        (10, tlv::TlvItemValueEnc::Bool(params.osd_enabled)).into(),
346        ]),
347    };
348    Ok(tlv.encode()?)
349}
350
351/// Encode VideoStreamModify command (0x05)
352pub fn encode_video_stream_modify(video_stream_id: u16, watermark_enabled: Option<bool>, osd_enabled: Option<bool>) -> anyhow::Result<Vec<u8>> {
353    let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
354    tlv_fields.push((0, tlv::TlvItemValueEnc::UInt16(video_stream_id)).into());
355    if let Some(x) = watermark_enabled { tlv_fields.push((1, tlv::TlvItemValueEnc::Bool(x)).into()); }
356    if let Some(x) = osd_enabled { tlv_fields.push((2, tlv::TlvItemValueEnc::Bool(x)).into()); }
357    let tlv = tlv::TlvItemEnc {
358        tag: 0,
359        value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
360    };
361    Ok(tlv.encode()?)
362}
363
364/// Encode VideoStreamDeallocate command (0x06)
365pub fn encode_video_stream_deallocate(video_stream_id: u16) -> anyhow::Result<Vec<u8>> {
366    let tlv = tlv::TlvItemEnc {
367        tag: 0,
368        value: tlv::TlvItemValueEnc::StructInvisible(vec![
369        (0, tlv::TlvItemValueEnc::UInt16(video_stream_id)).into(),
370        ]),
371    };
372    Ok(tlv.encode()?)
373}
374
375/// Encode SnapshotStreamAllocate command (0x07)
376pub fn encode_snapshot_stream_allocate(image_codec: ImageCodec, max_frame_rate: u16, min_resolution: VideoResolution, max_resolution: VideoResolution, quality: u8, watermark_enabled: bool, osd_enabled: bool) -> anyhow::Result<Vec<u8>> {
377            // Encode struct VideoResolutionStruct
378            let mut min_resolution_fields = Vec::new();
379            if let Some(x) = min_resolution.width { min_resolution_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
380            if let Some(x) = min_resolution.height { min_resolution_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
381            // Encode struct VideoResolutionStruct
382            let mut max_resolution_fields = Vec::new();
383            if let Some(x) = max_resolution.width { max_resolution_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
384            if let Some(x) = max_resolution.height { max_resolution_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
385    let tlv = tlv::TlvItemEnc {
386        tag: 0,
387        value: tlv::TlvItemValueEnc::StructInvisible(vec![
388        (0, tlv::TlvItemValueEnc::UInt8(image_codec.to_u8())).into(),
389        (1, tlv::TlvItemValueEnc::UInt16(max_frame_rate)).into(),
390        (2, tlv::TlvItemValueEnc::StructInvisible(min_resolution_fields)).into(),
391        (3, tlv::TlvItemValueEnc::StructInvisible(max_resolution_fields)).into(),
392        (4, tlv::TlvItemValueEnc::UInt8(quality)).into(),
393        (5, tlv::TlvItemValueEnc::Bool(watermark_enabled)).into(),
394        (6, tlv::TlvItemValueEnc::Bool(osd_enabled)).into(),
395        ]),
396    };
397    Ok(tlv.encode()?)
398}
399
400/// Encode SnapshotStreamModify command (0x09)
401pub fn encode_snapshot_stream_modify(snapshot_stream_id: u16, watermark_enabled: Option<bool>, osd_enabled: Option<bool>) -> anyhow::Result<Vec<u8>> {
402    let mut tlv_fields: Vec<tlv::TlvItemEnc> = Vec::new();
403    tlv_fields.push((0, tlv::TlvItemValueEnc::UInt16(snapshot_stream_id)).into());
404    if let Some(x) = watermark_enabled { tlv_fields.push((1, tlv::TlvItemValueEnc::Bool(x)).into()); }
405    if let Some(x) = osd_enabled { tlv_fields.push((2, tlv::TlvItemValueEnc::Bool(x)).into()); }
406    let tlv = tlv::TlvItemEnc {
407        tag: 0,
408        value: tlv::TlvItemValueEnc::StructInvisible(tlv_fields),
409    };
410    Ok(tlv.encode()?)
411}
412
413/// Encode SnapshotStreamDeallocate command (0x0A)
414pub fn encode_snapshot_stream_deallocate(snapshot_stream_id: u16) -> anyhow::Result<Vec<u8>> {
415    let tlv = tlv::TlvItemEnc {
416        tag: 0,
417        value: tlv::TlvItemValueEnc::StructInvisible(vec![
418        (0, tlv::TlvItemValueEnc::UInt16(snapshot_stream_id)).into(),
419        ]),
420    };
421    Ok(tlv.encode()?)
422}
423
424/// Encode SetStreamPriorities command (0x0B)
425pub fn encode_set_stream_priorities(stream_priorities: Vec<u8>) -> anyhow::Result<Vec<u8>> {
426    let tlv = tlv::TlvItemEnc {
427        tag: 0,
428        value: tlv::TlvItemValueEnc::StructInvisible(vec![
429        (0, tlv::TlvItemValueEnc::StructAnon(stream_priorities.into_iter().map(|v| (0, tlv::TlvItemValueEnc::UInt8(v)).into()).collect())).into(),
430        ]),
431    };
432    Ok(tlv.encode()?)
433}
434
435/// Encode CaptureSnapshot command (0x0C)
436pub fn encode_capture_snapshot(snapshot_stream_id: Option<u16>, requested_resolution: VideoResolution) -> anyhow::Result<Vec<u8>> {
437            // Encode struct VideoResolutionStruct
438            let mut requested_resolution_fields = Vec::new();
439            if let Some(x) = requested_resolution.width { requested_resolution_fields.push((0, tlv::TlvItemValueEnc::UInt16(x)).into()); }
440            if let Some(x) = requested_resolution.height { requested_resolution_fields.push((1, tlv::TlvItemValueEnc::UInt16(x)).into()); }
441    let tlv = tlv::TlvItemEnc {
442        tag: 0,
443        value: tlv::TlvItemValueEnc::StructInvisible(vec![
444        (0, tlv::TlvItemValueEnc::UInt16(snapshot_stream_id.unwrap_or(0))).into(),
445        (1, tlv::TlvItemValueEnc::StructInvisible(requested_resolution_fields)).into(),
446        ]),
447    };
448    Ok(tlv.encode()?)
449}
450
451// Attribute decoders
452
453/// Decode MaxConcurrentEncoders attribute (0x0000)
454pub fn decode_max_concurrent_encoders(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
455    if let tlv::TlvItemValue::Int(v) = inp {
456        Ok(*v as u8)
457    } else {
458        Err(anyhow::anyhow!("Expected UInt8"))
459    }
460}
461
462/// Decode MaxEncodedPixelRate attribute (0x0001)
463pub fn decode_max_encoded_pixel_rate(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
464    if let tlv::TlvItemValue::Int(v) = inp {
465        Ok(*v as u32)
466    } else {
467        Err(anyhow::anyhow!("Expected UInt32"))
468    }
469}
470
471/// Decode VideoSensorParams attribute (0x0002)
472pub fn decode_video_sensor_params(inp: &tlv::TlvItemValue) -> anyhow::Result<VideoSensorParams> {
473    if let tlv::TlvItemValue::List(_fields) = inp {
474        // Struct with fields
475        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
476        Ok(VideoSensorParams {
477                sensor_width: item.get_int(&[0]).map(|v| v as u16),
478                sensor_height: item.get_int(&[1]).map(|v| v as u16),
479                max_fps: item.get_int(&[2]).map(|v| v as u16),
480                max_hdrfps: item.get_int(&[3]).map(|v| v as u16),
481        })
482    } else {
483        Err(anyhow::anyhow!("Expected struct fields"))
484    }
485}
486
487/// Decode NightVisionUsesInfrared attribute (0x0003)
488pub fn decode_night_vision_uses_infrared(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
489    if let tlv::TlvItemValue::Bool(v) = inp {
490        Ok(*v)
491    } else {
492        Err(anyhow::anyhow!("Expected Bool"))
493    }
494}
495
496/// Decode MinViewportResolution attribute (0x0004)
497pub fn decode_min_viewport_resolution(inp: &tlv::TlvItemValue) -> anyhow::Result<VideoResolution> {
498    if let tlv::TlvItemValue::List(_fields) = inp {
499        // Struct with fields
500        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
501        Ok(VideoResolution {
502                width: item.get_int(&[0]).map(|v| v as u16),
503                height: item.get_int(&[1]).map(|v| v as u16),
504        })
505    } else {
506        Err(anyhow::anyhow!("Expected struct fields"))
507    }
508}
509
510/// Decode RateDistortionTradeOffPoints attribute (0x0005)
511pub fn decode_rate_distortion_trade_off_points(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<RateDistortionTradeOffPoints>> {
512    let mut res = Vec::new();
513    if let tlv::TlvItemValue::List(v) = inp {
514        for item in v {
515            res.push(RateDistortionTradeOffPoints {
516                codec: item.get_int(&[0]).and_then(|v| VideoCodec::from_u8(v as u8)),
517                resolution: {
518                    if let Some(nested_tlv) = item.get(&[1]) {
519                        if let tlv::TlvItemValue::List(_) = nested_tlv {
520                            let nested_item = tlv::TlvItem { tag: 1, value: nested_tlv.clone() };
521                            Some(VideoResolution {
522                width: nested_item.get_int(&[0]).map(|v| v as u16),
523                height: nested_item.get_int(&[1]).map(|v| v as u16),
524                            })
525                        } else {
526                            None
527                        }
528                    } else {
529                        None
530                    }
531                },
532                min_bit_rate: item.get_int(&[2]).map(|v| v as u32),
533            });
534        }
535    }
536    Ok(res)
537}
538
539/// Decode MaxContentBufferSize attribute (0x0006)
540pub fn decode_max_content_buffer_size(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
541    if let tlv::TlvItemValue::Int(v) = inp {
542        Ok(*v as u32)
543    } else {
544        Err(anyhow::anyhow!("Expected UInt32"))
545    }
546}
547
548/// Decode MicrophoneCapabilities attribute (0x0007)
549pub fn decode_microphone_capabilities(inp: &tlv::TlvItemValue) -> anyhow::Result<AudioCapabilities> {
550    if let tlv::TlvItemValue::List(_fields) = inp {
551        // Struct with fields
552        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
553        Ok(AudioCapabilities {
554                max_number_of_channels: item.get_int(&[0]).map(|v| v as u8),
555                supported_codecs: {
556                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
557                        let items: Vec<AudioCodec> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { AudioCodec::from_u8(*v as u8) } else { None } }).collect();
558                        Some(items)
559                    } else {
560                        None
561                    }
562                },
563                supported_sample_rates: {
564                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
565                        let items: Vec<u32> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u32) } else { None } }).collect();
566                        Some(items)
567                    } else {
568                        None
569                    }
570                },
571                supported_bit_depths: {
572                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[3]) {
573                        let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
574                        Some(items)
575                    } else {
576                        None
577                    }
578                },
579        })
580    } else {
581        Err(anyhow::anyhow!("Expected struct fields"))
582    }
583}
584
585/// Decode SpeakerCapabilities attribute (0x0008)
586pub fn decode_speaker_capabilities(inp: &tlv::TlvItemValue) -> anyhow::Result<AudioCapabilities> {
587    if let tlv::TlvItemValue::List(_fields) = inp {
588        // Struct with fields
589        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
590        Ok(AudioCapabilities {
591                max_number_of_channels: item.get_int(&[0]).map(|v| v as u8),
592                supported_codecs: {
593                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[1]) {
594                        let items: Vec<AudioCodec> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { AudioCodec::from_u8(*v as u8) } else { None } }).collect();
595                        Some(items)
596                    } else {
597                        None
598                    }
599                },
600                supported_sample_rates: {
601                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[2]) {
602                        let items: Vec<u32> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u32) } else { None } }).collect();
603                        Some(items)
604                    } else {
605                        None
606                    }
607                },
608                supported_bit_depths: {
609                    if let Some(tlv::TlvItemValue::List(l)) = item.get(&[3]) {
610                        let items: Vec<u8> = l.iter().filter_map(|e| { if let tlv::TlvItemValue::Int(v) = &e.value { Some(*v as u8) } else { None } }).collect();
611                        Some(items)
612                    } else {
613                        None
614                    }
615                },
616        })
617    } else {
618        Err(anyhow::anyhow!("Expected struct fields"))
619    }
620}
621
622/// Decode TwoWayTalkSupport attribute (0x0009)
623pub fn decode_two_way_talk_support(inp: &tlv::TlvItemValue) -> anyhow::Result<TwoWayTalkSupportType> {
624    if let tlv::TlvItemValue::Int(v) = inp {
625        TwoWayTalkSupportType::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
626    } else {
627        Err(anyhow::anyhow!("Expected Integer"))
628    }
629}
630
631/// Decode SnapshotCapabilities attribute (0x000A)
632pub fn decode_snapshot_capabilities(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<SnapshotCapabilities>> {
633    let mut res = Vec::new();
634    if let tlv::TlvItemValue::List(v) = inp {
635        for item in v {
636            res.push(SnapshotCapabilities {
637                resolution: {
638                    if let Some(nested_tlv) = item.get(&[0]) {
639                        if let tlv::TlvItemValue::List(_) = nested_tlv {
640                            let nested_item = tlv::TlvItem { tag: 0, value: nested_tlv.clone() };
641                            Some(VideoResolution {
642                width: nested_item.get_int(&[0]).map(|v| v as u16),
643                height: nested_item.get_int(&[1]).map(|v| v as u16),
644                            })
645                        } else {
646                            None
647                        }
648                    } else {
649                        None
650                    }
651                },
652                max_frame_rate: item.get_int(&[1]).map(|v| v as u16),
653                image_codec: item.get_int(&[2]).and_then(|v| ImageCodec::from_u8(v as u8)),
654                requires_encoded_pixels: item.get_bool(&[3]),
655                requires_hardware_encoder: item.get_bool(&[4]),
656            });
657        }
658    }
659    Ok(res)
660}
661
662/// Decode MaxNetworkBandwidth attribute (0x000B)
663pub fn decode_max_network_bandwidth(inp: &tlv::TlvItemValue) -> anyhow::Result<u32> {
664    if let tlv::TlvItemValue::Int(v) = inp {
665        Ok(*v as u32)
666    } else {
667        Err(anyhow::anyhow!("Expected UInt32"))
668    }
669}
670
671/// Decode CurrentFrameRate attribute (0x000C)
672pub fn decode_current_frame_rate(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
673    if let tlv::TlvItemValue::Int(v) = inp {
674        Ok(*v as u16)
675    } else {
676        Err(anyhow::anyhow!("Expected UInt16"))
677    }
678}
679
680/// Decode HDRModeEnabled attribute (0x000D)
681pub fn decode_hdr_mode_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
682    if let tlv::TlvItemValue::Bool(v) = inp {
683        Ok(*v)
684    } else {
685        Err(anyhow::anyhow!("Expected Bool"))
686    }
687}
688
689/// Decode SupportedStreamUsages attribute (0x000E)
690pub fn decode_supported_stream_usages(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
691    let mut res = Vec::new();
692    if let tlv::TlvItemValue::List(v) = inp {
693        for item in v {
694            if let tlv::TlvItemValue::Int(i) = &item.value {
695                res.push(*i as u8);
696            }
697        }
698    }
699    Ok(res)
700}
701
702/// Decode AllocatedVideoStreams attribute (0x000F)
703pub fn decode_allocated_video_streams(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<VideoStream>> {
704    let mut res = Vec::new();
705    if let tlv::TlvItemValue::List(v) = inp {
706        for item in v {
707            res.push(VideoStream {
708                video_stream_id: item.get_int(&[0]).map(|v| v as u16),
709                stream_usage: item.get_int(&[1]).map(|v| v as u8),
710                video_codec: item.get_int(&[2]).and_then(|v| VideoCodec::from_u8(v as u8)),
711                min_frame_rate: item.get_int(&[3]).map(|v| v as u16),
712                max_frame_rate: item.get_int(&[4]).map(|v| v as u16),
713                min_resolution: {
714                    if let Some(nested_tlv) = item.get(&[5]) {
715                        if let tlv::TlvItemValue::List(_) = nested_tlv {
716                            let nested_item = tlv::TlvItem { tag: 5, value: nested_tlv.clone() };
717                            Some(VideoResolution {
718                width: nested_item.get_int(&[0]).map(|v| v as u16),
719                height: nested_item.get_int(&[1]).map(|v| v as u16),
720                            })
721                        } else {
722                            None
723                        }
724                    } else {
725                        None
726                    }
727                },
728                max_resolution: {
729                    if let Some(nested_tlv) = item.get(&[6]) {
730                        if let tlv::TlvItemValue::List(_) = nested_tlv {
731                            let nested_item = tlv::TlvItem { tag: 6, value: nested_tlv.clone() };
732                            Some(VideoResolution {
733                width: nested_item.get_int(&[0]).map(|v| v as u16),
734                height: nested_item.get_int(&[1]).map(|v| v as u16),
735                            })
736                        } else {
737                            None
738                        }
739                    } else {
740                        None
741                    }
742                },
743                min_bit_rate: item.get_int(&[7]).map(|v| v as u32),
744                max_bit_rate: item.get_int(&[8]).map(|v| v as u32),
745                key_frame_interval: item.get_int(&[9]).map(|v| v as u16),
746                watermark_enabled: item.get_bool(&[10]),
747                osd_enabled: item.get_bool(&[11]),
748                reference_count: item.get_int(&[12]).map(|v| v as u8),
749            });
750        }
751    }
752    Ok(res)
753}
754
755/// Decode AllocatedAudioStreams attribute (0x0010)
756pub fn decode_allocated_audio_streams(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<AudioStream>> {
757    let mut res = Vec::new();
758    if let tlv::TlvItemValue::List(v) = inp {
759        for item in v {
760            res.push(AudioStream {
761                audio_stream_id: item.get_int(&[0]).map(|v| v as u16),
762                stream_usage: item.get_int(&[1]).map(|v| v as u8),
763                audio_codec: item.get_int(&[2]).and_then(|v| AudioCodec::from_u8(v as u8)),
764                channel_count: item.get_int(&[3]).map(|v| v as u8),
765                sample_rate: item.get_int(&[4]).map(|v| v as u32),
766                bit_rate: item.get_int(&[5]).map(|v| v as u32),
767                bit_depth: item.get_int(&[6]).map(|v| v as u8),
768                reference_count: item.get_int(&[7]).map(|v| v as u8),
769            });
770        }
771    }
772    Ok(res)
773}
774
775/// Decode AllocatedSnapshotStreams attribute (0x0011)
776pub fn decode_allocated_snapshot_streams(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<SnapshotStream>> {
777    let mut res = Vec::new();
778    if let tlv::TlvItemValue::List(v) = inp {
779        for item in v {
780            res.push(SnapshotStream {
781                snapshot_stream_id: item.get_int(&[0]).map(|v| v as u16),
782                image_codec: item.get_int(&[1]).and_then(|v| ImageCodec::from_u8(v as u8)),
783                frame_rate: item.get_int(&[2]).map(|v| v as u16),
784                min_resolution: {
785                    if let Some(nested_tlv) = item.get(&[3]) {
786                        if let tlv::TlvItemValue::List(_) = nested_tlv {
787                            let nested_item = tlv::TlvItem { tag: 3, value: nested_tlv.clone() };
788                            Some(VideoResolution {
789                width: nested_item.get_int(&[0]).map(|v| v as u16),
790                height: nested_item.get_int(&[1]).map(|v| v as u16),
791                            })
792                        } else {
793                            None
794                        }
795                    } else {
796                        None
797                    }
798                },
799                max_resolution: {
800                    if let Some(nested_tlv) = item.get(&[4]) {
801                        if let tlv::TlvItemValue::List(_) = nested_tlv {
802                            let nested_item = tlv::TlvItem { tag: 4, value: nested_tlv.clone() };
803                            Some(VideoResolution {
804                width: nested_item.get_int(&[0]).map(|v| v as u16),
805                height: nested_item.get_int(&[1]).map(|v| v as u16),
806                            })
807                        } else {
808                            None
809                        }
810                    } else {
811                        None
812                    }
813                },
814                quality: item.get_int(&[5]).map(|v| v as u8),
815                reference_count: item.get_int(&[6]).map(|v| v as u8),
816                encoded_pixels: item.get_bool(&[7]),
817                hardware_encoder: item.get_bool(&[8]),
818                watermark_enabled: item.get_bool(&[9]),
819                osd_enabled: item.get_bool(&[10]),
820            });
821        }
822    }
823    Ok(res)
824}
825
826/// Decode StreamUsagePriorities attribute (0x0012)
827pub fn decode_stream_usage_priorities(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<u8>> {
828    let mut res = Vec::new();
829    if let tlv::TlvItemValue::List(v) = inp {
830        for item in v {
831            if let tlv::TlvItemValue::Int(i) = &item.value {
832                res.push(*i as u8);
833            }
834        }
835    }
836    Ok(res)
837}
838
839/// Decode SoftRecordingPrivacyModeEnabled attribute (0x0013)
840pub fn decode_soft_recording_privacy_mode_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
841    if let tlv::TlvItemValue::Bool(v) = inp {
842        Ok(*v)
843    } else {
844        Err(anyhow::anyhow!("Expected Bool"))
845    }
846}
847
848/// Decode SoftLivestreamPrivacyModeEnabled attribute (0x0014)
849pub fn decode_soft_livestream_privacy_mode_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
850    if let tlv::TlvItemValue::Bool(v) = inp {
851        Ok(*v)
852    } else {
853        Err(anyhow::anyhow!("Expected Bool"))
854    }
855}
856
857/// Decode HardPrivacyModeOn attribute (0x0015)
858pub fn decode_hard_privacy_mode_on(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
859    if let tlv::TlvItemValue::Bool(v) = inp {
860        Ok(*v)
861    } else {
862        Err(anyhow::anyhow!("Expected Bool"))
863    }
864}
865
866/// Decode NightVision attribute (0x0016)
867pub fn decode_night_vision(inp: &tlv::TlvItemValue) -> anyhow::Result<TriStateAuto> {
868    if let tlv::TlvItemValue::Int(v) = inp {
869        TriStateAuto::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
870    } else {
871        Err(anyhow::anyhow!("Expected Integer"))
872    }
873}
874
875/// Decode NightVisionIllum attribute (0x0017)
876pub fn decode_night_vision_illum(inp: &tlv::TlvItemValue) -> anyhow::Result<TriStateAuto> {
877    if let tlv::TlvItemValue::Int(v) = inp {
878        TriStateAuto::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
879    } else {
880        Err(anyhow::anyhow!("Expected Integer"))
881    }
882}
883
884/// Decode Viewport attribute (0x0018)
885pub fn decode_viewport(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
886    if let tlv::TlvItemValue::Int(v) = inp {
887        Ok(*v as u8)
888    } else {
889        Err(anyhow::anyhow!("Expected UInt8"))
890    }
891}
892
893/// Decode SpeakerMuted attribute (0x0019)
894pub fn decode_speaker_muted(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
895    if let tlv::TlvItemValue::Bool(v) = inp {
896        Ok(*v)
897    } else {
898        Err(anyhow::anyhow!("Expected Bool"))
899    }
900}
901
902/// Decode SpeakerVolumeLevel attribute (0x001A)
903pub fn decode_speaker_volume_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
904    if let tlv::TlvItemValue::Int(v) = inp {
905        Ok(*v as u8)
906    } else {
907        Err(anyhow::anyhow!("Expected UInt8"))
908    }
909}
910
911/// Decode SpeakerMaxLevel attribute (0x001B)
912pub fn decode_speaker_max_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
913    if let tlv::TlvItemValue::Int(v) = inp {
914        Ok(*v as u8)
915    } else {
916        Err(anyhow::anyhow!("Expected UInt8"))
917    }
918}
919
920/// Decode SpeakerMinLevel attribute (0x001C)
921pub fn decode_speaker_min_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
922    if let tlv::TlvItemValue::Int(v) = inp {
923        Ok(*v as u8)
924    } else {
925        Err(anyhow::anyhow!("Expected UInt8"))
926    }
927}
928
929/// Decode MicrophoneMuted attribute (0x001D)
930pub fn decode_microphone_muted(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
931    if let tlv::TlvItemValue::Bool(v) = inp {
932        Ok(*v)
933    } else {
934        Err(anyhow::anyhow!("Expected Bool"))
935    }
936}
937
938/// Decode MicrophoneVolumeLevel attribute (0x001E)
939pub fn decode_microphone_volume_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
940    if let tlv::TlvItemValue::Int(v) = inp {
941        Ok(*v as u8)
942    } else {
943        Err(anyhow::anyhow!("Expected UInt8"))
944    }
945}
946
947/// Decode MicrophoneMaxLevel attribute (0x001F)
948pub fn decode_microphone_max_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
949    if let tlv::TlvItemValue::Int(v) = inp {
950        Ok(*v as u8)
951    } else {
952        Err(anyhow::anyhow!("Expected UInt8"))
953    }
954}
955
956/// Decode MicrophoneMinLevel attribute (0x0020)
957pub fn decode_microphone_min_level(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
958    if let tlv::TlvItemValue::Int(v) = inp {
959        Ok(*v as u8)
960    } else {
961        Err(anyhow::anyhow!("Expected UInt8"))
962    }
963}
964
965/// Decode MicrophoneAGCEnabled attribute (0x0021)
966pub fn decode_microphone_agc_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
967    if let tlv::TlvItemValue::Bool(v) = inp {
968        Ok(*v)
969    } else {
970        Err(anyhow::anyhow!("Expected Bool"))
971    }
972}
973
974/// Decode ImageRotation attribute (0x0022)
975pub fn decode_image_rotation(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
976    if let tlv::TlvItemValue::Int(v) = inp {
977        Ok(*v as u16)
978    } else {
979        Err(anyhow::anyhow!("Expected UInt16"))
980    }
981}
982
983/// Decode ImageFlipHorizontal attribute (0x0023)
984pub fn decode_image_flip_horizontal(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
985    if let tlv::TlvItemValue::Bool(v) = inp {
986        Ok(*v)
987    } else {
988        Err(anyhow::anyhow!("Expected Bool"))
989    }
990}
991
992/// Decode ImageFlipVertical attribute (0x0024)
993pub fn decode_image_flip_vertical(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
994    if let tlv::TlvItemValue::Bool(v) = inp {
995        Ok(*v)
996    } else {
997        Err(anyhow::anyhow!("Expected Bool"))
998    }
999}
1000
1001/// Decode LocalVideoRecordingEnabled attribute (0x0025)
1002pub fn decode_local_video_recording_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1003    if let tlv::TlvItemValue::Bool(v) = inp {
1004        Ok(*v)
1005    } else {
1006        Err(anyhow::anyhow!("Expected Bool"))
1007    }
1008}
1009
1010/// Decode LocalSnapshotRecordingEnabled attribute (0x0026)
1011pub fn decode_local_snapshot_recording_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1012    if let tlv::TlvItemValue::Bool(v) = inp {
1013        Ok(*v)
1014    } else {
1015        Err(anyhow::anyhow!("Expected Bool"))
1016    }
1017}
1018
1019/// Decode StatusLightEnabled attribute (0x0027)
1020pub fn decode_status_light_enabled(inp: &tlv::TlvItemValue) -> anyhow::Result<bool> {
1021    if let tlv::TlvItemValue::Bool(v) = inp {
1022        Ok(*v)
1023    } else {
1024        Err(anyhow::anyhow!("Expected Bool"))
1025    }
1026}
1027
1028/// Decode StatusLightBrightness attribute (0x0028)
1029pub fn decode_status_light_brightness(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
1030    if let tlv::TlvItemValue::Int(v) = inp {
1031        Ok(*v as u8)
1032    } else {
1033        Err(anyhow::anyhow!("Expected UInt8"))
1034    }
1035}
1036
1037/// Decode ImageRotationDiscreteAngles attribute (0x0029)
1038pub fn decode_image_rotation_discrete_angles(inp: &tlv::TlvItemValue) -> anyhow::Result<u16> {
1039    if let tlv::TlvItemValue::Int(v) = inp {
1040        Ok(*v as u16)
1041    } else {
1042        Err(anyhow::anyhow!("Expected UInt16"))
1043    }
1044}
1045
1046
1047// JSON dispatcher function
1048
1049/// Decode attribute value and return as JSON string
1050///
1051/// # Parameters
1052/// * `cluster_id` - The cluster identifier
1053/// * `attribute_id` - The attribute identifier
1054/// * `tlv_value` - The TLV value to decode
1055///
1056/// # Returns
1057/// JSON string representation of the decoded value or error
1058pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
1059    // Verify this is the correct cluster
1060    if ![0x0551].contains(&cluster_id) {
1061        return format!("{{\"error\": \"Invalid cluster ID. Expected [0x0551], got {}\"}}", cluster_id);
1062    }
1063
1064    match attribute_id {
1065        0x0000 => {
1066            match decode_max_concurrent_encoders(tlv_value) {
1067                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1068                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1069            }
1070        }
1071        0x0001 => {
1072            match decode_max_encoded_pixel_rate(tlv_value) {
1073                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1074                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1075            }
1076        }
1077        0x0002 => {
1078            match decode_video_sensor_params(tlv_value) {
1079                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1080                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1081            }
1082        }
1083        0x0003 => {
1084            match decode_night_vision_uses_infrared(tlv_value) {
1085                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1086                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1087            }
1088        }
1089        0x0004 => {
1090            match decode_min_viewport_resolution(tlv_value) {
1091                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1092                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1093            }
1094        }
1095        0x0005 => {
1096            match decode_rate_distortion_trade_off_points(tlv_value) {
1097                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1098                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1099            }
1100        }
1101        0x0006 => {
1102            match decode_max_content_buffer_size(tlv_value) {
1103                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1104                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1105            }
1106        }
1107        0x0007 => {
1108            match decode_microphone_capabilities(tlv_value) {
1109                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1110                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1111            }
1112        }
1113        0x0008 => {
1114            match decode_speaker_capabilities(tlv_value) {
1115                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1116                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1117            }
1118        }
1119        0x0009 => {
1120            match decode_two_way_talk_support(tlv_value) {
1121                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1122                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1123            }
1124        }
1125        0x000A => {
1126            match decode_snapshot_capabilities(tlv_value) {
1127                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1128                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1129            }
1130        }
1131        0x000B => {
1132            match decode_max_network_bandwidth(tlv_value) {
1133                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1134                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1135            }
1136        }
1137        0x000C => {
1138            match decode_current_frame_rate(tlv_value) {
1139                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1140                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1141            }
1142        }
1143        0x000D => {
1144            match decode_hdr_mode_enabled(tlv_value) {
1145                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1146                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1147            }
1148        }
1149        0x000E => {
1150            match decode_supported_stream_usages(tlv_value) {
1151                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1152                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1153            }
1154        }
1155        0x000F => {
1156            match decode_allocated_video_streams(tlv_value) {
1157                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1158                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1159            }
1160        }
1161        0x0010 => {
1162            match decode_allocated_audio_streams(tlv_value) {
1163                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1164                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1165            }
1166        }
1167        0x0011 => {
1168            match decode_allocated_snapshot_streams(tlv_value) {
1169                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1170                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1171            }
1172        }
1173        0x0012 => {
1174            match decode_stream_usage_priorities(tlv_value) {
1175                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1176                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1177            }
1178        }
1179        0x0013 => {
1180            match decode_soft_recording_privacy_mode_enabled(tlv_value) {
1181                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1182                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1183            }
1184        }
1185        0x0014 => {
1186            match decode_soft_livestream_privacy_mode_enabled(tlv_value) {
1187                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1188                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1189            }
1190        }
1191        0x0015 => {
1192            match decode_hard_privacy_mode_on(tlv_value) {
1193                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1194                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1195            }
1196        }
1197        0x0016 => {
1198            match decode_night_vision(tlv_value) {
1199                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1200                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1201            }
1202        }
1203        0x0017 => {
1204            match decode_night_vision_illum(tlv_value) {
1205                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1206                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1207            }
1208        }
1209        0x0018 => {
1210            match decode_viewport(tlv_value) {
1211                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1212                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1213            }
1214        }
1215        0x0019 => {
1216            match decode_speaker_muted(tlv_value) {
1217                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1218                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1219            }
1220        }
1221        0x001A => {
1222            match decode_speaker_volume_level(tlv_value) {
1223                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1224                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1225            }
1226        }
1227        0x001B => {
1228            match decode_speaker_max_level(tlv_value) {
1229                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1230                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1231            }
1232        }
1233        0x001C => {
1234            match decode_speaker_min_level(tlv_value) {
1235                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1236                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1237            }
1238        }
1239        0x001D => {
1240            match decode_microphone_muted(tlv_value) {
1241                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1242                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1243            }
1244        }
1245        0x001E => {
1246            match decode_microphone_volume_level(tlv_value) {
1247                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1248                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1249            }
1250        }
1251        0x001F => {
1252            match decode_microphone_max_level(tlv_value) {
1253                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1254                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1255            }
1256        }
1257        0x0020 => {
1258            match decode_microphone_min_level(tlv_value) {
1259                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1260                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1261            }
1262        }
1263        0x0021 => {
1264            match decode_microphone_agc_enabled(tlv_value) {
1265                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1266                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1267            }
1268        }
1269        0x0022 => {
1270            match decode_image_rotation(tlv_value) {
1271                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1272                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1273            }
1274        }
1275        0x0023 => {
1276            match decode_image_flip_horizontal(tlv_value) {
1277                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1278                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1279            }
1280        }
1281        0x0024 => {
1282            match decode_image_flip_vertical(tlv_value) {
1283                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1284                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1285            }
1286        }
1287        0x0025 => {
1288            match decode_local_video_recording_enabled(tlv_value) {
1289                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1290                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1291            }
1292        }
1293        0x0026 => {
1294            match decode_local_snapshot_recording_enabled(tlv_value) {
1295                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1296                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1297            }
1298        }
1299        0x0027 => {
1300            match decode_status_light_enabled(tlv_value) {
1301                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1302                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1303            }
1304        }
1305        0x0028 => {
1306            match decode_status_light_brightness(tlv_value) {
1307                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1308                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1309            }
1310        }
1311        0x0029 => {
1312            match decode_image_rotation_discrete_angles(tlv_value) {
1313                Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
1314                Err(e) => format!("{{\"error\": \"{}\"}}", e),
1315            }
1316        }
1317        _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
1318    }
1319}
1320
1321/// Get list of all attributes supported by this cluster
1322///
1323/// # Returns
1324/// Vector of tuples containing (attribute_id, attribute_name)
1325pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
1326    vec![
1327        (0x0000, "MaxConcurrentEncoders"),
1328        (0x0001, "MaxEncodedPixelRate"),
1329        (0x0002, "VideoSensorParams"),
1330        (0x0003, "NightVisionUsesInfrared"),
1331        (0x0004, "MinViewportResolution"),
1332        (0x0005, "RateDistortionTradeOffPoints"),
1333        (0x0006, "MaxContentBufferSize"),
1334        (0x0007, "MicrophoneCapabilities"),
1335        (0x0008, "SpeakerCapabilities"),
1336        (0x0009, "TwoWayTalkSupport"),
1337        (0x000A, "SnapshotCapabilities"),
1338        (0x000B, "MaxNetworkBandwidth"),
1339        (0x000C, "CurrentFrameRate"),
1340        (0x000D, "HDRModeEnabled"),
1341        (0x000E, "SupportedStreamUsages"),
1342        (0x000F, "AllocatedVideoStreams"),
1343        (0x0010, "AllocatedAudioStreams"),
1344        (0x0011, "AllocatedSnapshotStreams"),
1345        (0x0012, "StreamUsagePriorities"),
1346        (0x0013, "SoftRecordingPrivacyModeEnabled"),
1347        (0x0014, "SoftLivestreamPrivacyModeEnabled"),
1348        (0x0015, "HardPrivacyModeOn"),
1349        (0x0016, "NightVision"),
1350        (0x0017, "NightVisionIllum"),
1351        (0x0018, "Viewport"),
1352        (0x0019, "SpeakerMuted"),
1353        (0x001A, "SpeakerVolumeLevel"),
1354        (0x001B, "SpeakerMaxLevel"),
1355        (0x001C, "SpeakerMinLevel"),
1356        (0x001D, "MicrophoneMuted"),
1357        (0x001E, "MicrophoneVolumeLevel"),
1358        (0x001F, "MicrophoneMaxLevel"),
1359        (0x0020, "MicrophoneMinLevel"),
1360        (0x0021, "MicrophoneAGCEnabled"),
1361        (0x0022, "ImageRotation"),
1362        (0x0023, "ImageFlipHorizontal"),
1363        (0x0024, "ImageFlipVertical"),
1364        (0x0025, "LocalVideoRecordingEnabled"),
1365        (0x0026, "LocalSnapshotRecordingEnabled"),
1366        (0x0027, "StatusLightEnabled"),
1367        (0x0028, "StatusLightBrightness"),
1368        (0x0029, "ImageRotationDiscreteAngles"),
1369    ]
1370}
1371
1372// Command listing
1373
1374pub fn get_command_list() -> Vec<(u32, &'static str)> {
1375    vec![
1376        (0x00, "AudioStreamAllocate"),
1377        (0x02, "AudioStreamDeallocate"),
1378        (0x03, "VideoStreamAllocate"),
1379        (0x05, "VideoStreamModify"),
1380        (0x06, "VideoStreamDeallocate"),
1381        (0x07, "SnapshotStreamAllocate"),
1382        (0x09, "SnapshotStreamModify"),
1383        (0x0A, "SnapshotStreamDeallocate"),
1384        (0x0B, "SetStreamPriorities"),
1385        (0x0C, "CaptureSnapshot"),
1386    ]
1387}
1388
1389pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
1390    match cmd_id {
1391        0x00 => Some("AudioStreamAllocate"),
1392        0x02 => Some("AudioStreamDeallocate"),
1393        0x03 => Some("VideoStreamAllocate"),
1394        0x05 => Some("VideoStreamModify"),
1395        0x06 => Some("VideoStreamDeallocate"),
1396        0x07 => Some("SnapshotStreamAllocate"),
1397        0x09 => Some("SnapshotStreamModify"),
1398        0x0A => Some("SnapshotStreamDeallocate"),
1399        0x0B => Some("SetStreamPriorities"),
1400        0x0C => Some("CaptureSnapshot"),
1401        _ => None,
1402    }
1403}
1404
1405pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
1406    match cmd_id {
1407        0x00 => Some(vec![
1408            crate::clusters::codec::CommandField { tag: 0, name: "stream_usage", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
1409            crate::clusters::codec::CommandField { tag: 1, name: "audio_codec", kind: crate::clusters::codec::FieldKind::Enum { name: "AudioCodec", variants: &[(0, "Opus"), (1, "AacLc")] }, optional: false, nullable: false },
1410            crate::clusters::codec::CommandField { tag: 2, name: "channel_count", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
1411            crate::clusters::codec::CommandField { tag: 3, name: "sample_rate", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
1412            crate::clusters::codec::CommandField { tag: 4, name: "bit_rate", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
1413            crate::clusters::codec::CommandField { tag: 5, name: "bit_depth", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
1414        ]),
1415        0x02 => Some(vec![
1416            crate::clusters::codec::CommandField { tag: 0, name: "audio_stream_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1417        ]),
1418        0x03 => Some(vec![
1419            crate::clusters::codec::CommandField { tag: 0, name: "stream_usage", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
1420            crate::clusters::codec::CommandField { tag: 1, name: "video_codec", kind: crate::clusters::codec::FieldKind::Enum { name: "VideoCodec", variants: &[(0, "H264"), (1, "Hevc"), (2, "Vvc"), (3, "Av1")] }, optional: false, nullable: false },
1421            crate::clusters::codec::CommandField { tag: 2, name: "min_frame_rate", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1422            crate::clusters::codec::CommandField { tag: 3, name: "max_frame_rate", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1423            crate::clusters::codec::CommandField { tag: 4, name: "min_resolution", kind: crate::clusters::codec::FieldKind::Struct { name: "VideoResolutionStruct" }, optional: false, nullable: false },
1424            crate::clusters::codec::CommandField { tag: 5, name: "max_resolution", kind: crate::clusters::codec::FieldKind::Struct { name: "VideoResolutionStruct" }, optional: false, nullable: false },
1425            crate::clusters::codec::CommandField { tag: 6, name: "min_bit_rate", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
1426            crate::clusters::codec::CommandField { tag: 7, name: "max_bit_rate", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
1427            crate::clusters::codec::CommandField { tag: 8, name: "key_frame_interval", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1428            crate::clusters::codec::CommandField { tag: 9, name: "watermark_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: false, nullable: false },
1429            crate::clusters::codec::CommandField { tag: 10, name: "osd_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: false, nullable: false },
1430        ]),
1431        0x05 => Some(vec![
1432            crate::clusters::codec::CommandField { tag: 0, name: "video_stream_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1433            crate::clusters::codec::CommandField { tag: 1, name: "watermark_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
1434            crate::clusters::codec::CommandField { tag: 2, name: "osd_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
1435        ]),
1436        0x06 => Some(vec![
1437            crate::clusters::codec::CommandField { tag: 0, name: "video_stream_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1438        ]),
1439        0x07 => Some(vec![
1440            crate::clusters::codec::CommandField { tag: 0, name: "image_codec", kind: crate::clusters::codec::FieldKind::Enum { name: "ImageCodec", variants: &[(0, "Jpeg"), (1, "Heic")] }, optional: false, nullable: false },
1441            crate::clusters::codec::CommandField { tag: 1, name: "max_frame_rate", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1442            crate::clusters::codec::CommandField { tag: 2, name: "min_resolution", kind: crate::clusters::codec::FieldKind::Struct { name: "VideoResolutionStruct" }, optional: false, nullable: false },
1443            crate::clusters::codec::CommandField { tag: 3, name: "max_resolution", kind: crate::clusters::codec::FieldKind::Struct { name: "VideoResolutionStruct" }, optional: false, nullable: false },
1444            crate::clusters::codec::CommandField { tag: 4, name: "quality", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
1445            crate::clusters::codec::CommandField { tag: 5, name: "watermark_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: false, nullable: false },
1446            crate::clusters::codec::CommandField { tag: 6, name: "osd_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: false, nullable: false },
1447        ]),
1448        0x09 => Some(vec![
1449            crate::clusters::codec::CommandField { tag: 0, name: "snapshot_stream_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1450            crate::clusters::codec::CommandField { tag: 1, name: "watermark_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
1451            crate::clusters::codec::CommandField { tag: 2, name: "osd_enabled", kind: crate::clusters::codec::FieldKind::Bool, optional: true, nullable: false },
1452        ]),
1453        0x0A => Some(vec![
1454            crate::clusters::codec::CommandField { tag: 0, name: "snapshot_stream_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: false },
1455        ]),
1456        0x0B => Some(vec![
1457            crate::clusters::codec::CommandField { tag: 0, name: "stream_priorities", kind: crate::clusters::codec::FieldKind::List { entry_type: "StreamUsageEnum" }, optional: false, nullable: false },
1458        ]),
1459        0x0C => Some(vec![
1460            crate::clusters::codec::CommandField { tag: 0, name: "snapshot_stream_id", kind: crate::clusters::codec::FieldKind::U16, optional: false, nullable: true },
1461            crate::clusters::codec::CommandField { tag: 1, name: "requested_resolution", kind: crate::clusters::codec::FieldKind::Struct { name: "VideoResolutionStruct" }, optional: false, nullable: false },
1462        ]),
1463        _ => None,
1464    }
1465}
1466
1467pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
1468    match cmd_id {
1469        0x00 => {
1470        let stream_usage = crate::clusters::codec::json_util::get_u8(args, "stream_usage")?;
1471        let audio_codec = {
1472            let n = crate::clusters::codec::json_util::get_u64(args, "audio_codec")?;
1473            AudioCodec::from_u8(n as u8).ok_or_else(|| anyhow::anyhow!("invalid AudioCodec: {}", n))?
1474        };
1475        let channel_count = crate::clusters::codec::json_util::get_u8(args, "channel_count")?;
1476        let sample_rate = crate::clusters::codec::json_util::get_u32(args, "sample_rate")?;
1477        let bit_rate = crate::clusters::codec::json_util::get_u32(args, "bit_rate")?;
1478        let bit_depth = crate::clusters::codec::json_util::get_u8(args, "bit_depth")?;
1479        encode_audio_stream_allocate(stream_usage, audio_codec, channel_count, sample_rate, bit_rate, bit_depth)
1480        }
1481        0x02 => {
1482        let audio_stream_id = crate::clusters::codec::json_util::get_u16(args, "audio_stream_id")?;
1483        encode_audio_stream_deallocate(audio_stream_id)
1484        }
1485        0x03 => Err(anyhow::anyhow!("command \"VideoStreamAllocate\" has complex args: use raw mode")),
1486        0x05 => {
1487        let video_stream_id = crate::clusters::codec::json_util::get_u16(args, "video_stream_id")?;
1488        let watermark_enabled = crate::clusters::codec::json_util::get_opt_bool(args, "watermark_enabled")?;
1489        let osd_enabled = crate::clusters::codec::json_util::get_opt_bool(args, "osd_enabled")?;
1490        encode_video_stream_modify(video_stream_id, watermark_enabled, osd_enabled)
1491        }
1492        0x06 => {
1493        let video_stream_id = crate::clusters::codec::json_util::get_u16(args, "video_stream_id")?;
1494        encode_video_stream_deallocate(video_stream_id)
1495        }
1496        0x07 => Err(anyhow::anyhow!("command \"SnapshotStreamAllocate\" has complex args: use raw mode")),
1497        0x09 => {
1498        let snapshot_stream_id = crate::clusters::codec::json_util::get_u16(args, "snapshot_stream_id")?;
1499        let watermark_enabled = crate::clusters::codec::json_util::get_opt_bool(args, "watermark_enabled")?;
1500        let osd_enabled = crate::clusters::codec::json_util::get_opt_bool(args, "osd_enabled")?;
1501        encode_snapshot_stream_modify(snapshot_stream_id, watermark_enabled, osd_enabled)
1502        }
1503        0x0A => {
1504        let snapshot_stream_id = crate::clusters::codec::json_util::get_u16(args, "snapshot_stream_id")?;
1505        encode_snapshot_stream_deallocate(snapshot_stream_id)
1506        }
1507        0x0B => Err(anyhow::anyhow!("command \"SetStreamPriorities\" has complex args: use raw mode")),
1508        0x0C => Err(anyhow::anyhow!("command \"CaptureSnapshot\" has complex args: use raw mode")),
1509        _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
1510    }
1511}
1512
1513#[derive(Debug, serde::Serialize)]
1514pub struct AudioStreamAllocateResponse {
1515    pub audio_stream_id: Option<u16>,
1516}
1517
1518#[derive(Debug, serde::Serialize)]
1519pub struct VideoStreamAllocateResponse {
1520    pub video_stream_id: Option<u16>,
1521}
1522
1523#[derive(Debug, serde::Serialize)]
1524pub struct SnapshotStreamAllocateResponse {
1525    pub snapshot_stream_id: Option<u16>,
1526}
1527
1528#[derive(Debug, serde::Serialize)]
1529pub struct CaptureSnapshotResponse {
1530    #[serde(serialize_with = "serialize_opt_bytes_as_hex")]
1531    pub data: Option<Vec<u8>>,
1532    pub image_codec: Option<ImageCodec>,
1533    pub resolution: Option<VideoResolution>,
1534}
1535
1536// Command response decoders
1537
1538/// Decode AudioStreamAllocateResponse command response (01)
1539pub fn decode_audio_stream_allocate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<AudioStreamAllocateResponse> {
1540    if let tlv::TlvItemValue::List(_fields) = inp {
1541        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
1542        Ok(AudioStreamAllocateResponse {
1543                audio_stream_id: item.get_int(&[0]).map(|v| v as u16),
1544        })
1545    } else {
1546        Err(anyhow::anyhow!("Expected struct fields"))
1547    }
1548}
1549
1550/// Decode VideoStreamAllocateResponse command response (04)
1551pub fn decode_video_stream_allocate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<VideoStreamAllocateResponse> {
1552    if let tlv::TlvItemValue::List(_fields) = inp {
1553        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
1554        Ok(VideoStreamAllocateResponse {
1555                video_stream_id: item.get_int(&[0]).map(|v| v as u16),
1556        })
1557    } else {
1558        Err(anyhow::anyhow!("Expected struct fields"))
1559    }
1560}
1561
1562/// Decode SnapshotStreamAllocateResponse command response (08)
1563pub fn decode_snapshot_stream_allocate_response(inp: &tlv::TlvItemValue) -> anyhow::Result<SnapshotStreamAllocateResponse> {
1564    if let tlv::TlvItemValue::List(_fields) = inp {
1565        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
1566        Ok(SnapshotStreamAllocateResponse {
1567                snapshot_stream_id: item.get_int(&[0]).map(|v| v as u16),
1568        })
1569    } else {
1570        Err(anyhow::anyhow!("Expected struct fields"))
1571    }
1572}
1573
1574/// Decode CaptureSnapshotResponse command response (0D)
1575pub fn decode_capture_snapshot_response(inp: &tlv::TlvItemValue) -> anyhow::Result<CaptureSnapshotResponse> {
1576    if let tlv::TlvItemValue::List(_fields) = inp {
1577        let item = tlv::TlvItem { tag: 0, value: inp.clone() };
1578        Ok(CaptureSnapshotResponse {
1579                data: item.get_octet_string_owned(&[0]),
1580                image_codec: item.get_int(&[1]).and_then(|v| ImageCodec::from_u8(v as u8)),
1581                resolution: {
1582                    if let Some(nested_tlv) = item.get(&[2]) {
1583                        if let tlv::TlvItemValue::List(_) = nested_tlv {
1584                            let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
1585                            Some(VideoResolution {
1586                width: nested_item.get_int(&[0]).map(|v| v as u16),
1587                height: nested_item.get_int(&[1]).map(|v| v as u16),
1588                            })
1589                        } else {
1590                            None
1591                        }
1592                    } else {
1593                        None
1594                    }
1595                },
1596        })
1597    } else {
1598        Err(anyhow::anyhow!("Expected struct fields"))
1599    }
1600}
1601
1602// Typed facade (invokes + reads)
1603
1604/// Invoke `AudioStreamAllocate` command on cluster `Camera AV Stream Management`.
1605pub async fn audio_stream_allocate(conn: &crate::controller::Connection, endpoint: u16, stream_usage: u8, audio_codec: AudioCodec, channel_count: u8, sample_rate: u32, bit_rate: u32, bit_depth: u8) -> anyhow::Result<AudioStreamAllocateResponse> {
1606    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_AUDIOSTREAMALLOCATE, &encode_audio_stream_allocate(stream_usage, audio_codec, channel_count, sample_rate, bit_rate, bit_depth)?).await?;
1607    decode_audio_stream_allocate_response(&tlv)
1608}
1609
1610/// Invoke `AudioStreamDeallocate` command on cluster `Camera AV Stream Management`.
1611pub async fn audio_stream_deallocate(conn: &crate::controller::Connection, endpoint: u16, audio_stream_id: u16) -> anyhow::Result<()> {
1612    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_AUDIOSTREAMDEALLOCATE, &encode_audio_stream_deallocate(audio_stream_id)?).await?;
1613    Ok(())
1614}
1615
1616/// Invoke `VideoStreamAllocate` command on cluster `Camera AV Stream Management`.
1617pub async fn video_stream_allocate(conn: &crate::controller::Connection, endpoint: u16, params: VideoStreamAllocateParams) -> anyhow::Result<VideoStreamAllocateResponse> {
1618    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_VIDEOSTREAMALLOCATE, &encode_video_stream_allocate(params)?).await?;
1619    decode_video_stream_allocate_response(&tlv)
1620}
1621
1622/// Invoke `VideoStreamModify` command on cluster `Camera AV Stream Management`.
1623pub async fn video_stream_modify(conn: &crate::controller::Connection, endpoint: u16, video_stream_id: u16, watermark_enabled: Option<bool>, osd_enabled: Option<bool>) -> anyhow::Result<()> {
1624    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_VIDEOSTREAMMODIFY, &encode_video_stream_modify(video_stream_id, watermark_enabled, osd_enabled)?).await?;
1625    Ok(())
1626}
1627
1628/// Invoke `VideoStreamDeallocate` command on cluster `Camera AV Stream Management`.
1629pub async fn video_stream_deallocate(conn: &crate::controller::Connection, endpoint: u16, video_stream_id: u16) -> anyhow::Result<()> {
1630    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_VIDEOSTREAMDEALLOCATE, &encode_video_stream_deallocate(video_stream_id)?).await?;
1631    Ok(())
1632}
1633
1634/// Invoke `SnapshotStreamAllocate` command on cluster `Camera AV Stream Management`.
1635pub async fn snapshot_stream_allocate(conn: &crate::controller::Connection, endpoint: u16, image_codec: ImageCodec, max_frame_rate: u16, min_resolution: VideoResolution, max_resolution: VideoResolution, quality: u8, watermark_enabled: bool, osd_enabled: bool) -> anyhow::Result<SnapshotStreamAllocateResponse> {
1636    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_SNAPSHOTSTREAMALLOCATE, &encode_snapshot_stream_allocate(image_codec, max_frame_rate, min_resolution, max_resolution, quality, watermark_enabled, osd_enabled)?).await?;
1637    decode_snapshot_stream_allocate_response(&tlv)
1638}
1639
1640/// Invoke `SnapshotStreamModify` command on cluster `Camera AV Stream Management`.
1641pub async fn snapshot_stream_modify(conn: &crate::controller::Connection, endpoint: u16, snapshot_stream_id: u16, watermark_enabled: Option<bool>, osd_enabled: Option<bool>) -> anyhow::Result<()> {
1642    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_SNAPSHOTSTREAMMODIFY, &encode_snapshot_stream_modify(snapshot_stream_id, watermark_enabled, osd_enabled)?).await?;
1643    Ok(())
1644}
1645
1646/// Invoke `SnapshotStreamDeallocate` command on cluster `Camera AV Stream Management`.
1647pub async fn snapshot_stream_deallocate(conn: &crate::controller::Connection, endpoint: u16, snapshot_stream_id: u16) -> anyhow::Result<()> {
1648    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_SNAPSHOTSTREAMDEALLOCATE, &encode_snapshot_stream_deallocate(snapshot_stream_id)?).await?;
1649    Ok(())
1650}
1651
1652/// Invoke `SetStreamPriorities` command on cluster `Camera AV Stream Management`.
1653pub async fn set_stream_priorities(conn: &crate::controller::Connection, endpoint: u16, stream_priorities: Vec<u8>) -> anyhow::Result<()> {
1654    conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_SETSTREAMPRIORITIES, &encode_set_stream_priorities(stream_priorities)?).await?;
1655    Ok(())
1656}
1657
1658/// Invoke `CaptureSnapshot` command on cluster `Camera AV Stream Management`.
1659pub async fn capture_snapshot(conn: &crate::controller::Connection, endpoint: u16, snapshot_stream_id: Option<u16>, requested_resolution: VideoResolution) -> anyhow::Result<CaptureSnapshotResponse> {
1660    let tlv = conn.invoke_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_CMD_ID_CAPTURESNAPSHOT, &encode_capture_snapshot(snapshot_stream_id, requested_resolution)?).await?;
1661    decode_capture_snapshot_response(&tlv)
1662}
1663
1664/// Read `MaxConcurrentEncoders` attribute from cluster `Camera AV Stream Management`.
1665pub async fn read_max_concurrent_encoders(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1666    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MAXCONCURRENTENCODERS).await?;
1667    decode_max_concurrent_encoders(&tlv)
1668}
1669
1670/// Read `MaxEncodedPixelRate` attribute from cluster `Camera AV Stream Management`.
1671pub async fn read_max_encoded_pixel_rate(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
1672    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MAXENCODEDPIXELRATE).await?;
1673    decode_max_encoded_pixel_rate(&tlv)
1674}
1675
1676/// Read `VideoSensorParams` attribute from cluster `Camera AV Stream Management`.
1677pub async fn read_video_sensor_params(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<VideoSensorParams> {
1678    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_VIDEOSENSORPARAMS).await?;
1679    decode_video_sensor_params(&tlv)
1680}
1681
1682/// Read `NightVisionUsesInfrared` attribute from cluster `Camera AV Stream Management`.
1683pub async fn read_night_vision_uses_infrared(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1684    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_NIGHTVISIONUSESINFRARED).await?;
1685    decode_night_vision_uses_infrared(&tlv)
1686}
1687
1688/// Read `MinViewportResolution` attribute from cluster `Camera AV Stream Management`.
1689pub async fn read_min_viewport_resolution(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<VideoResolution> {
1690    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MINVIEWPORTRESOLUTION).await?;
1691    decode_min_viewport_resolution(&tlv)
1692}
1693
1694/// Read `RateDistortionTradeOffPoints` attribute from cluster `Camera AV Stream Management`.
1695pub async fn read_rate_distortion_trade_off_points(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<RateDistortionTradeOffPoints>> {
1696    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_RATEDISTORTIONTRADEOFFPOINTS).await?;
1697    decode_rate_distortion_trade_off_points(&tlv)
1698}
1699
1700/// Read `MaxContentBufferSize` attribute from cluster `Camera AV Stream Management`.
1701pub async fn read_max_content_buffer_size(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
1702    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MAXCONTENTBUFFERSIZE).await?;
1703    decode_max_content_buffer_size(&tlv)
1704}
1705
1706/// Read `MicrophoneCapabilities` attribute from cluster `Camera AV Stream Management`.
1707pub async fn read_microphone_capabilities(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<AudioCapabilities> {
1708    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MICROPHONECAPABILITIES).await?;
1709    decode_microphone_capabilities(&tlv)
1710}
1711
1712/// Read `SpeakerCapabilities` attribute from cluster `Camera AV Stream Management`.
1713pub async fn read_speaker_capabilities(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<AudioCapabilities> {
1714    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SPEAKERCAPABILITIES).await?;
1715    decode_speaker_capabilities(&tlv)
1716}
1717
1718/// Read `TwoWayTalkSupport` attribute from cluster `Camera AV Stream Management`.
1719pub async fn read_two_way_talk_support(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TwoWayTalkSupportType> {
1720    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_TWOWAYTALKSUPPORT).await?;
1721    decode_two_way_talk_support(&tlv)
1722}
1723
1724/// Read `SnapshotCapabilities` attribute from cluster `Camera AV Stream Management`.
1725pub async fn read_snapshot_capabilities(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<SnapshotCapabilities>> {
1726    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SNAPSHOTCAPABILITIES).await?;
1727    decode_snapshot_capabilities(&tlv)
1728}
1729
1730/// Read `MaxNetworkBandwidth` attribute from cluster `Camera AV Stream Management`.
1731pub async fn read_max_network_bandwidth(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u32> {
1732    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MAXNETWORKBANDWIDTH).await?;
1733    decode_max_network_bandwidth(&tlv)
1734}
1735
1736/// Read `CurrentFrameRate` attribute from cluster `Camera AV Stream Management`.
1737pub async fn read_current_frame_rate(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
1738    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_CURRENTFRAMERATE).await?;
1739    decode_current_frame_rate(&tlv)
1740}
1741
1742/// Read `HDRModeEnabled` attribute from cluster `Camera AV Stream Management`.
1743pub async fn read_hdr_mode_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1744    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_HDRMODEENABLED).await?;
1745    decode_hdr_mode_enabled(&tlv)
1746}
1747
1748/// Read `SupportedStreamUsages` attribute from cluster `Camera AV Stream Management`.
1749pub async fn read_supported_stream_usages(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<u8>> {
1750    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SUPPORTEDSTREAMUSAGES).await?;
1751    decode_supported_stream_usages(&tlv)
1752}
1753
1754/// Read `AllocatedVideoStreams` attribute from cluster `Camera AV Stream Management`.
1755pub async fn read_allocated_video_streams(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<VideoStream>> {
1756    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_ALLOCATEDVIDEOSTREAMS).await?;
1757    decode_allocated_video_streams(&tlv)
1758}
1759
1760/// Read `AllocatedAudioStreams` attribute from cluster `Camera AV Stream Management`.
1761pub async fn read_allocated_audio_streams(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<AudioStream>> {
1762    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_ALLOCATEDAUDIOSTREAMS).await?;
1763    decode_allocated_audio_streams(&tlv)
1764}
1765
1766/// Read `AllocatedSnapshotStreams` attribute from cluster `Camera AV Stream Management`.
1767pub async fn read_allocated_snapshot_streams(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<SnapshotStream>> {
1768    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_ALLOCATEDSNAPSHOTSTREAMS).await?;
1769    decode_allocated_snapshot_streams(&tlv)
1770}
1771
1772/// Read `StreamUsagePriorities` attribute from cluster `Camera AV Stream Management`.
1773pub async fn read_stream_usage_priorities(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<u8>> {
1774    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_STREAMUSAGEPRIORITIES).await?;
1775    decode_stream_usage_priorities(&tlv)
1776}
1777
1778/// Read `SoftRecordingPrivacyModeEnabled` attribute from cluster `Camera AV Stream Management`.
1779pub async fn read_soft_recording_privacy_mode_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1780    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SOFTRECORDINGPRIVACYMODEENABLED).await?;
1781    decode_soft_recording_privacy_mode_enabled(&tlv)
1782}
1783
1784/// Read `SoftLivestreamPrivacyModeEnabled` attribute from cluster `Camera AV Stream Management`.
1785pub async fn read_soft_livestream_privacy_mode_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1786    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SOFTLIVESTREAMPRIVACYMODEENABLED).await?;
1787    decode_soft_livestream_privacy_mode_enabled(&tlv)
1788}
1789
1790/// Read `HardPrivacyModeOn` attribute from cluster `Camera AV Stream Management`.
1791pub async fn read_hard_privacy_mode_on(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1792    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_HARDPRIVACYMODEON).await?;
1793    decode_hard_privacy_mode_on(&tlv)
1794}
1795
1796/// Read `NightVision` attribute from cluster `Camera AV Stream Management`.
1797pub async fn read_night_vision(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TriStateAuto> {
1798    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_NIGHTVISION).await?;
1799    decode_night_vision(&tlv)
1800}
1801
1802/// Read `NightVisionIllum` attribute from cluster `Camera AV Stream Management`.
1803pub async fn read_night_vision_illum(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<TriStateAuto> {
1804    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_NIGHTVISIONILLUM).await?;
1805    decode_night_vision_illum(&tlv)
1806}
1807
1808/// Read `Viewport` attribute from cluster `Camera AV Stream Management`.
1809pub async fn read_viewport(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1810    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_VIEWPORT).await?;
1811    decode_viewport(&tlv)
1812}
1813
1814/// Read `SpeakerMuted` attribute from cluster `Camera AV Stream Management`.
1815pub async fn read_speaker_muted(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1816    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SPEAKERMUTED).await?;
1817    decode_speaker_muted(&tlv)
1818}
1819
1820/// Read `SpeakerVolumeLevel` attribute from cluster `Camera AV Stream Management`.
1821pub async fn read_speaker_volume_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1822    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SPEAKERVOLUMELEVEL).await?;
1823    decode_speaker_volume_level(&tlv)
1824}
1825
1826/// Read `SpeakerMaxLevel` attribute from cluster `Camera AV Stream Management`.
1827pub async fn read_speaker_max_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1828    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SPEAKERMAXLEVEL).await?;
1829    decode_speaker_max_level(&tlv)
1830}
1831
1832/// Read `SpeakerMinLevel` attribute from cluster `Camera AV Stream Management`.
1833pub async fn read_speaker_min_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1834    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_SPEAKERMINLEVEL).await?;
1835    decode_speaker_min_level(&tlv)
1836}
1837
1838/// Read `MicrophoneMuted` attribute from cluster `Camera AV Stream Management`.
1839pub async fn read_microphone_muted(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1840    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MICROPHONEMUTED).await?;
1841    decode_microphone_muted(&tlv)
1842}
1843
1844/// Read `MicrophoneVolumeLevel` attribute from cluster `Camera AV Stream Management`.
1845pub async fn read_microphone_volume_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1846    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MICROPHONEVOLUMELEVEL).await?;
1847    decode_microphone_volume_level(&tlv)
1848}
1849
1850/// Read `MicrophoneMaxLevel` attribute from cluster `Camera AV Stream Management`.
1851pub async fn read_microphone_max_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1852    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MICROPHONEMAXLEVEL).await?;
1853    decode_microphone_max_level(&tlv)
1854}
1855
1856/// Read `MicrophoneMinLevel` attribute from cluster `Camera AV Stream Management`.
1857pub async fn read_microphone_min_level(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1858    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MICROPHONEMINLEVEL).await?;
1859    decode_microphone_min_level(&tlv)
1860}
1861
1862/// Read `MicrophoneAGCEnabled` attribute from cluster `Camera AV Stream Management`.
1863pub async fn read_microphone_agc_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1864    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_MICROPHONEAGCENABLED).await?;
1865    decode_microphone_agc_enabled(&tlv)
1866}
1867
1868/// Read `ImageRotation` attribute from cluster `Camera AV Stream Management`.
1869pub async fn read_image_rotation(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
1870    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_IMAGEROTATION).await?;
1871    decode_image_rotation(&tlv)
1872}
1873
1874/// Read `ImageFlipHorizontal` attribute from cluster `Camera AV Stream Management`.
1875pub async fn read_image_flip_horizontal(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1876    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_IMAGEFLIPHORIZONTAL).await?;
1877    decode_image_flip_horizontal(&tlv)
1878}
1879
1880/// Read `ImageFlipVertical` attribute from cluster `Camera AV Stream Management`.
1881pub async fn read_image_flip_vertical(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1882    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_IMAGEFLIPVERTICAL).await?;
1883    decode_image_flip_vertical(&tlv)
1884}
1885
1886/// Read `LocalVideoRecordingEnabled` attribute from cluster `Camera AV Stream Management`.
1887pub async fn read_local_video_recording_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1888    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_LOCALVIDEORECORDINGENABLED).await?;
1889    decode_local_video_recording_enabled(&tlv)
1890}
1891
1892/// Read `LocalSnapshotRecordingEnabled` attribute from cluster `Camera AV Stream Management`.
1893pub async fn read_local_snapshot_recording_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1894    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_LOCALSNAPSHOTRECORDINGENABLED).await?;
1895    decode_local_snapshot_recording_enabled(&tlv)
1896}
1897
1898/// Read `StatusLightEnabled` attribute from cluster `Camera AV Stream Management`.
1899pub async fn read_status_light_enabled(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<bool> {
1900    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_STATUSLIGHTENABLED).await?;
1901    decode_status_light_enabled(&tlv)
1902}
1903
1904/// Read `StatusLightBrightness` attribute from cluster `Camera AV Stream Management`.
1905pub async fn read_status_light_brightness(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
1906    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_STATUSLIGHTBRIGHTNESS).await?;
1907    decode_status_light_brightness(&tlv)
1908}
1909
1910/// Read `ImageRotationDiscreteAngles` attribute from cluster `Camera AV Stream Management`.
1911pub async fn read_image_rotation_discrete_angles(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u16> {
1912    let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_STREAM_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_STREAM_MANAGEMENT_ATTR_ID_IMAGEROTATIONDISCRETEANGLES).await?;
1913    decode_image_rotation_discrete_angles(&tlv)
1914}
1915