1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13use crate::clusters::helpers::{serialize_opt_bytes_as_hex};
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
19#[repr(u8)]
20pub enum AudioCodec {
21 Opus = 0,
23 AacLc = 1,
25}
26
27impl AudioCodec {
28 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 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 = 0,
54 Heic = 1,
56}
57
58impl ImageCodec {
59 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 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 = 0,
85 On = 1,
87 Auto = 2,
89}
90
91impl TriStateAuto {
92 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 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 Notsupported = 0,
119 Halfduplex = 1,
121 Fullduplex = 2,
123}
124
125impl TwoWayTalkSupportType {
126 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 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 H264 = 0,
153 Hevc = 1,
155 Vvc = 2,
157 Av1 = 3,
159}
160
161impl VideoCodec {
162 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 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#[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
278pub 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
296pub 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
307pub 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
322pub fn encode_video_stream_allocate(params: VideoStreamAllocateParams) -> anyhow::Result<Vec<u8>> {
324 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 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
351pub 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
364pub 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
375pub 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 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 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
400pub 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
413pub 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
424pub 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
435pub fn encode_capture_snapshot(snapshot_stream_id: Option<u16>, requested_resolution: VideoResolution) -> anyhow::Result<Vec<u8>> {
437 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
451pub 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
462pub 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
471pub fn decode_video_sensor_params(inp: &tlv::TlvItemValue) -> anyhow::Result<VideoSensorParams> {
473 if let tlv::TlvItemValue::List(_fields) = inp {
474 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
487pub 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
496pub fn decode_min_viewport_resolution(inp: &tlv::TlvItemValue) -> anyhow::Result<VideoResolution> {
498 if let tlv::TlvItemValue::List(_fields) = inp {
499 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
510pub 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
539pub 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
548pub fn decode_microphone_capabilities(inp: &tlv::TlvItemValue) -> anyhow::Result<AudioCapabilities> {
550 if let tlv::TlvItemValue::List(_fields) = inp {
551 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
585pub fn decode_speaker_capabilities(inp: &tlv::TlvItemValue) -> anyhow::Result<AudioCapabilities> {
587 if let tlv::TlvItemValue::List(_fields) = inp {
588 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
622pub 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
631pub 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
662pub 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
671pub 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
680pub 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
689pub 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
702pub 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
755pub 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
775pub 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
826pub 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
839pub 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
848pub 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
857pub 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
866pub 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
875pub 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
884pub 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
893pub 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
902pub 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
911pub 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
920pub 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
929pub 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
938pub 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
947pub 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
956pub 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
965pub 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
974pub 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
983pub 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
992pub 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
1001pub 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
1010pub 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
1019pub 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
1028pub 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
1037pub 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
1047pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
1059 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
1321pub 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
1372pub 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
1536pub 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
1550pub 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
1562pub 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
1574pub 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
1602pub 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
1610pub 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
1616pub 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
1622pub 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
1628pub 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
1634pub 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
1640pub 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
1646pub 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
1652pub 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
1658pub 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
1664pub 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
1670pub 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
1676pub 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
1682pub 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
1688pub 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
1694pub 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
1700pub 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
1706pub 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
1712pub 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
1718pub 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
1724pub 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
1730pub 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
1736pub 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
1742pub 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
1748pub 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
1754pub 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
1760pub 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
1766pub 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
1772pub 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
1778pub 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
1784pub 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
1790pub 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
1796pub 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
1802pub 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
1808pub 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
1814pub 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
1820pub 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
1826pub 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
1832pub 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
1838pub 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
1844pub 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
1850pub 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
1856pub 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
1862pub 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
1868pub 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
1874pub 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
1880pub 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
1886pub 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
1892pub 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
1898pub 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
1904pub 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
1910pub 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