1#![allow(clippy::too_many_arguments)]
7
8use crate::tlv;
9use anyhow;
10use serde_json;
11
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
16#[repr(u8)]
17pub enum PhysicalMovement {
18 Idle = 0,
20 Moving = 1,
22}
23
24impl PhysicalMovement {
25 pub fn from_u8(value: u8) -> Option<Self> {
27 match value {
28 0 => Some(PhysicalMovement::Idle),
29 1 => Some(PhysicalMovement::Moving),
30 _ => None,
31 }
32 }
33
34 pub fn to_u8(self) -> u8 {
36 self as u8
37 }
38}
39
40impl From<PhysicalMovement> for u8 {
41 fn from(val: PhysicalMovement) -> Self {
42 val as u8
43 }
44}
45
46#[derive(Debug, serde::Serialize)]
49pub struct DPTZ {
50 pub video_stream_id: Option<u8>,
51}
52
53#[derive(Debug, serde::Serialize)]
54pub struct MPTZPreset {
55 pub preset_id: Option<u8>,
56 pub name: Option<String>,
57 pub settings: Option<MPTZ>,
58}
59
60#[derive(Debug, serde::Serialize)]
61pub struct MPTZ {
62 pub pan: Option<i16>,
63 pub tilt: Option<i16>,
64 pub zoom: Option<u8>,
65}
66
67pub fn encode_mptz_set_position(pan: i16, tilt: i16, zoom: u8) -> anyhow::Result<Vec<u8>> {
71 let tlv = tlv::TlvItemEnc {
72 tag: 0,
73 value: tlv::TlvItemValueEnc::StructInvisible(vec![
74 (0, tlv::TlvItemValueEnc::Int16(pan)).into(),
75 (1, tlv::TlvItemValueEnc::Int16(tilt)).into(),
76 (2, tlv::TlvItemValueEnc::UInt8(zoom)).into(),
77 ]),
78 };
79 Ok(tlv.encode()?)
80}
81
82pub fn encode_mptz_relative_move(pan_delta: i16, tilt_delta: i16, zoom_delta: i8) -> anyhow::Result<Vec<u8>> {
84 let tlv = tlv::TlvItemEnc {
85 tag: 0,
86 value: tlv::TlvItemValueEnc::StructInvisible(vec![
87 (0, tlv::TlvItemValueEnc::Int16(pan_delta)).into(),
88 (1, tlv::TlvItemValueEnc::Int16(tilt_delta)).into(),
89 (2, tlv::TlvItemValueEnc::Int8(zoom_delta)).into(),
90 ]),
91 };
92 Ok(tlv.encode()?)
93}
94
95pub fn encode_mptz_move_to_preset(preset_id: u8) -> anyhow::Result<Vec<u8>> {
97 let tlv = tlv::TlvItemEnc {
98 tag: 0,
99 value: tlv::TlvItemValueEnc::StructInvisible(vec![
100 (0, tlv::TlvItemValueEnc::UInt8(preset_id)).into(),
101 ]),
102 };
103 Ok(tlv.encode()?)
104}
105
106pub fn encode_mptz_save_preset(preset_id: u8, name: String) -> anyhow::Result<Vec<u8>> {
108 let tlv = tlv::TlvItemEnc {
109 tag: 0,
110 value: tlv::TlvItemValueEnc::StructInvisible(vec![
111 (0, tlv::TlvItemValueEnc::UInt8(preset_id)).into(),
112 (1, tlv::TlvItemValueEnc::String(name)).into(),
113 ]),
114 };
115 Ok(tlv.encode()?)
116}
117
118pub fn encode_mptz_remove_preset(preset_id: u8) -> anyhow::Result<Vec<u8>> {
120 let tlv = tlv::TlvItemEnc {
121 tag: 0,
122 value: tlv::TlvItemValueEnc::StructInvisible(vec![
123 (0, tlv::TlvItemValueEnc::UInt8(preset_id)).into(),
124 ]),
125 };
126 Ok(tlv.encode()?)
127}
128
129pub fn encode_dptz_set_viewport(video_stream_id: u8) -> anyhow::Result<Vec<u8>> {
131 let tlv = tlv::TlvItemEnc {
132 tag: 0,
133 value: tlv::TlvItemValueEnc::StructInvisible(vec![
134 (0, tlv::TlvItemValueEnc::UInt8(video_stream_id)).into(),
135 ]),
136 };
137 Ok(tlv.encode()?)
138}
139
140pub fn encode_dptz_relative_move(video_stream_id: u8, delta_x: i16, delta_y: i16, zoom_delta: i8) -> anyhow::Result<Vec<u8>> {
142 let tlv = tlv::TlvItemEnc {
143 tag: 0,
144 value: tlv::TlvItemValueEnc::StructInvisible(vec![
145 (0, tlv::TlvItemValueEnc::UInt8(video_stream_id)).into(),
146 (1, tlv::TlvItemValueEnc::Int16(delta_x)).into(),
147 (2, tlv::TlvItemValueEnc::Int16(delta_y)).into(),
148 (3, tlv::TlvItemValueEnc::Int8(zoom_delta)).into(),
149 ]),
150 };
151 Ok(tlv.encode()?)
152}
153
154pub fn decode_mptz_position(inp: &tlv::TlvItemValue) -> anyhow::Result<MPTZ> {
158 if let tlv::TlvItemValue::List(_fields) = inp {
159 let item = tlv::TlvItem { tag: 0, value: inp.clone() };
161 Ok(MPTZ {
162 pan: item.get_int(&[0]).map(|v| v as i16),
163 tilt: item.get_int(&[1]).map(|v| v as i16),
164 zoom: item.get_int(&[2]).map(|v| v as u8),
165 })
166 } else {
167 Err(anyhow::anyhow!("Expected struct fields"))
168 }
169}
170
171pub fn decode_max_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
173 if let tlv::TlvItemValue::Int(v) = inp {
174 Ok(*v as u8)
175 } else {
176 Err(anyhow::anyhow!("Expected UInt8"))
177 }
178}
179
180pub fn decode_mptz_presets(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<MPTZPreset>> {
182 let mut res = Vec::new();
183 if let tlv::TlvItemValue::List(v) = inp {
184 for item in v {
185 res.push(MPTZPreset {
186 preset_id: item.get_int(&[0]).map(|v| v as u8),
187 name: item.get_string_owned(&[1]),
188 settings: {
189 if let Some(nested_tlv) = item.get(&[2]) {
190 if let tlv::TlvItemValue::List(_) = nested_tlv {
191 let nested_item = tlv::TlvItem { tag: 2, value: nested_tlv.clone() };
192 Some(MPTZ {
193 pan: nested_item.get_int(&[0]).map(|v| v as i16),
194 tilt: nested_item.get_int(&[1]).map(|v| v as i16),
195 zoom: nested_item.get_int(&[2]).map(|v| v as u8),
196 })
197 } else {
198 None
199 }
200 } else {
201 None
202 }
203 },
204 });
205 }
206 }
207 Ok(res)
208}
209
210pub fn decode_dptz_streams(inp: &tlv::TlvItemValue) -> anyhow::Result<Vec<DPTZ>> {
212 let mut res = Vec::new();
213 if let tlv::TlvItemValue::List(v) = inp {
214 for item in v {
215 res.push(DPTZ {
216 video_stream_id: item.get_int(&[0]).map(|v| v as u8),
217 });
218 }
219 }
220 Ok(res)
221}
222
223pub fn decode_zoom_max(inp: &tlv::TlvItemValue) -> anyhow::Result<u8> {
225 if let tlv::TlvItemValue::Int(v) = inp {
226 Ok(*v as u8)
227 } else {
228 Err(anyhow::anyhow!("Expected UInt8"))
229 }
230}
231
232pub fn decode_tilt_min(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
234 if let tlv::TlvItemValue::Int(v) = inp {
235 Ok(*v as i16)
236 } else {
237 Err(anyhow::anyhow!("Expected Int16"))
238 }
239}
240
241pub fn decode_tilt_max(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
243 if let tlv::TlvItemValue::Int(v) = inp {
244 Ok(*v as i16)
245 } else {
246 Err(anyhow::anyhow!("Expected Int16"))
247 }
248}
249
250pub fn decode_pan_min(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
252 if let tlv::TlvItemValue::Int(v) = inp {
253 Ok(*v as i16)
254 } else {
255 Err(anyhow::anyhow!("Expected Int16"))
256 }
257}
258
259pub fn decode_pan_max(inp: &tlv::TlvItemValue) -> anyhow::Result<i16> {
261 if let tlv::TlvItemValue::Int(v) = inp {
262 Ok(*v as i16)
263 } else {
264 Err(anyhow::anyhow!("Expected Int16"))
265 }
266}
267
268pub fn decode_movement_state(inp: &tlv::TlvItemValue) -> anyhow::Result<PhysicalMovement> {
270 if let tlv::TlvItemValue::Int(v) = inp {
271 PhysicalMovement::from_u8(*v as u8).ok_or_else(|| anyhow::anyhow!("Invalid enum value"))
272 } else {
273 Err(anyhow::anyhow!("Expected Integer"))
274 }
275}
276
277
278pub fn decode_attribute_json(cluster_id: u32, attribute_id: u32, tlv_value: &crate::tlv::TlvItemValue) -> String {
290 if cluster_id != 0x0552 {
292 return format!("{{\"error\": \"Invalid cluster ID. Expected 0x0552, got {}\"}}", cluster_id);
293 }
294
295 match attribute_id {
296 0x0000 => {
297 match decode_mptz_position(tlv_value) {
298 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
299 Err(e) => format!("{{\"error\": \"{}\"}}", e),
300 }
301 }
302 0x0001 => {
303 match decode_max_presets(tlv_value) {
304 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
305 Err(e) => format!("{{\"error\": \"{}\"}}", e),
306 }
307 }
308 0x0002 => {
309 match decode_mptz_presets(tlv_value) {
310 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
311 Err(e) => format!("{{\"error\": \"{}\"}}", e),
312 }
313 }
314 0x0003 => {
315 match decode_dptz_streams(tlv_value) {
316 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
317 Err(e) => format!("{{\"error\": \"{}\"}}", e),
318 }
319 }
320 0x0004 => {
321 match decode_zoom_max(tlv_value) {
322 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
323 Err(e) => format!("{{\"error\": \"{}\"}}", e),
324 }
325 }
326 0x0005 => {
327 match decode_tilt_min(tlv_value) {
328 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
329 Err(e) => format!("{{\"error\": \"{}\"}}", e),
330 }
331 }
332 0x0006 => {
333 match decode_tilt_max(tlv_value) {
334 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
335 Err(e) => format!("{{\"error\": \"{}\"}}", e),
336 }
337 }
338 0x0007 => {
339 match decode_pan_min(tlv_value) {
340 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
341 Err(e) => format!("{{\"error\": \"{}\"}}", e),
342 }
343 }
344 0x0008 => {
345 match decode_pan_max(tlv_value) {
346 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
347 Err(e) => format!("{{\"error\": \"{}\"}}", e),
348 }
349 }
350 0x0009 => {
351 match decode_movement_state(tlv_value) {
352 Ok(value) => serde_json::to_string(&value).unwrap_or_else(|_| "null".to_string()),
353 Err(e) => format!("{{\"error\": \"{}\"}}", e),
354 }
355 }
356 _ => format!("{{\"error\": \"Unknown attribute ID: {}\"}}", attribute_id),
357 }
358}
359
360pub fn get_attribute_list() -> Vec<(u32, &'static str)> {
365 vec![
366 (0x0000, "MPTZPosition"),
367 (0x0001, "MaxPresets"),
368 (0x0002, "MPTZPresets"),
369 (0x0003, "DPTZStreams"),
370 (0x0004, "ZoomMax"),
371 (0x0005, "TiltMin"),
372 (0x0006, "TiltMax"),
373 (0x0007, "PanMin"),
374 (0x0008, "PanMax"),
375 (0x0009, "MovementState"),
376 ]
377}
378
379pub fn get_command_list() -> Vec<(u32, &'static str)> {
382 vec![
383 (0x00, "MPTZSetPosition"),
384 (0x01, "MPTZRelativeMove"),
385 (0x02, "MPTZMoveToPreset"),
386 (0x03, "MPTZSavePreset"),
387 (0x04, "MPTZRemovePreset"),
388 (0x05, "DPTZSetViewport"),
389 (0x06, "DPTZRelativeMove"),
390 ]
391}
392
393pub fn get_command_name(cmd_id: u32) -> Option<&'static str> {
394 match cmd_id {
395 0x00 => Some("MPTZSetPosition"),
396 0x01 => Some("MPTZRelativeMove"),
397 0x02 => Some("MPTZMoveToPreset"),
398 0x03 => Some("MPTZSavePreset"),
399 0x04 => Some("MPTZRemovePreset"),
400 0x05 => Some("DPTZSetViewport"),
401 0x06 => Some("DPTZRelativeMove"),
402 _ => None,
403 }
404}
405
406pub fn get_command_schema(cmd_id: u32) -> Option<Vec<crate::clusters::codec::CommandField>> {
407 match cmd_id {
408 0x00 => Some(vec![
409 crate::clusters::codec::CommandField { tag: 0, name: "pan", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
410 crate::clusters::codec::CommandField { tag: 1, name: "tilt", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
411 crate::clusters::codec::CommandField { tag: 2, name: "zoom", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
412 ]),
413 0x01 => Some(vec![
414 crate::clusters::codec::CommandField { tag: 0, name: "pan_delta", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
415 crate::clusters::codec::CommandField { tag: 1, name: "tilt_delta", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
416 crate::clusters::codec::CommandField { tag: 2, name: "zoom_delta", kind: crate::clusters::codec::FieldKind::I8, optional: true, nullable: false },
417 ]),
418 0x02 => Some(vec![
419 crate::clusters::codec::CommandField { tag: 0, name: "preset_id", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
420 ]),
421 0x03 => Some(vec![
422 crate::clusters::codec::CommandField { tag: 0, name: "preset_id", kind: crate::clusters::codec::FieldKind::U8, optional: true, nullable: false },
423 crate::clusters::codec::CommandField { tag: 1, name: "name", kind: crate::clusters::codec::FieldKind::String, optional: false, nullable: false },
424 ]),
425 0x04 => Some(vec![
426 crate::clusters::codec::CommandField { tag: 0, name: "preset_id", kind: crate::clusters::codec::FieldKind::U8, optional: false, nullable: false },
427 ]),
428 0x05 => Some(vec![
429 crate::clusters::codec::CommandField { tag: 0, name: "video_stream_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
430 ]),
431 0x06 => Some(vec![
432 crate::clusters::codec::CommandField { tag: 0, name: "video_stream_id", kind: crate::clusters::codec::FieldKind::U32, optional: false, nullable: false },
433 crate::clusters::codec::CommandField { tag: 1, name: "delta_x", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
434 crate::clusters::codec::CommandField { tag: 2, name: "delta_y", kind: crate::clusters::codec::FieldKind::I16, optional: true, nullable: false },
435 crate::clusters::codec::CommandField { tag: 3, name: "zoom_delta", kind: crate::clusters::codec::FieldKind::I8, optional: true, nullable: false },
436 ]),
437 _ => None,
438 }
439}
440
441pub fn encode_command_json(cmd_id: u32, args: &serde_json::Value) -> anyhow::Result<Vec<u8>> {
442 match cmd_id {
443 0x00 => {
444 let pan = crate::clusters::codec::json_util::get_i16(args, "pan")?;
445 let tilt = crate::clusters::codec::json_util::get_i16(args, "tilt")?;
446 let zoom = crate::clusters::codec::json_util::get_u8(args, "zoom")?;
447 encode_mptz_set_position(pan, tilt, zoom)
448 }
449 0x01 => {
450 let pan_delta = crate::clusters::codec::json_util::get_i16(args, "pan_delta")?;
451 let tilt_delta = crate::clusters::codec::json_util::get_i16(args, "tilt_delta")?;
452 let zoom_delta = crate::clusters::codec::json_util::get_i8(args, "zoom_delta")?;
453 encode_mptz_relative_move(pan_delta, tilt_delta, zoom_delta)
454 }
455 0x02 => {
456 let preset_id = crate::clusters::codec::json_util::get_u8(args, "preset_id")?;
457 encode_mptz_move_to_preset(preset_id)
458 }
459 0x03 => {
460 let preset_id = crate::clusters::codec::json_util::get_u8(args, "preset_id")?;
461 let name = crate::clusters::codec::json_util::get_string(args, "name")?;
462 encode_mptz_save_preset(preset_id, name)
463 }
464 0x04 => {
465 let preset_id = crate::clusters::codec::json_util::get_u8(args, "preset_id")?;
466 encode_mptz_remove_preset(preset_id)
467 }
468 0x05 => {
469 let video_stream_id = crate::clusters::codec::json_util::get_u8(args, "video_stream_id")?;
470 encode_dptz_set_viewport(video_stream_id)
471 }
472 0x06 => {
473 let video_stream_id = crate::clusters::codec::json_util::get_u8(args, "video_stream_id")?;
474 let delta_x = crate::clusters::codec::json_util::get_i16(args, "delta_x")?;
475 let delta_y = crate::clusters::codec::json_util::get_i16(args, "delta_y")?;
476 let zoom_delta = crate::clusters::codec::json_util::get_i8(args, "zoom_delta")?;
477 encode_dptz_relative_move(video_stream_id, delta_x, delta_y, zoom_delta)
478 }
479 _ => Err(anyhow::anyhow!("unknown command ID: 0x{:02X}", cmd_id)),
480 }
481}
482
483pub async fn mptz_set_position(conn: &crate::controller::Connection, endpoint: u16, pan: i16, tilt: i16, zoom: u8) -> anyhow::Result<()> {
487 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CMD_ID_MPTZSETPOSITION, &encode_mptz_set_position(pan, tilt, zoom)?).await?;
488 Ok(())
489}
490
491pub async fn mptz_relative_move(conn: &crate::controller::Connection, endpoint: u16, pan_delta: i16, tilt_delta: i16, zoom_delta: i8) -> anyhow::Result<()> {
493 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CMD_ID_MPTZRELATIVEMOVE, &encode_mptz_relative_move(pan_delta, tilt_delta, zoom_delta)?).await?;
494 Ok(())
495}
496
497pub async fn mptz_move_to_preset(conn: &crate::controller::Connection, endpoint: u16, preset_id: u8) -> anyhow::Result<()> {
499 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CMD_ID_MPTZMOVETOPRESET, &encode_mptz_move_to_preset(preset_id)?).await?;
500 Ok(())
501}
502
503pub async fn mptz_save_preset(conn: &crate::controller::Connection, endpoint: u16, preset_id: u8, name: String) -> anyhow::Result<()> {
505 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CMD_ID_MPTZSAVEPRESET, &encode_mptz_save_preset(preset_id, name)?).await?;
506 Ok(())
507}
508
509pub async fn mptz_remove_preset(conn: &crate::controller::Connection, endpoint: u16, preset_id: u8) -> anyhow::Result<()> {
511 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CMD_ID_MPTZREMOVEPRESET, &encode_mptz_remove_preset(preset_id)?).await?;
512 Ok(())
513}
514
515pub async fn dptz_set_viewport(conn: &crate::controller::Connection, endpoint: u16, video_stream_id: u8) -> anyhow::Result<()> {
517 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CMD_ID_DPTZSETVIEWPORT, &encode_dptz_set_viewport(video_stream_id)?).await?;
518 Ok(())
519}
520
521pub async fn dptz_relative_move(conn: &crate::controller::Connection, endpoint: u16, video_stream_id: u8, delta_x: i16, delta_y: i16, zoom_delta: i8) -> anyhow::Result<()> {
523 conn.invoke_request(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_CMD_ID_DPTZRELATIVEMOVE, &encode_dptz_relative_move(video_stream_id, delta_x, delta_y, zoom_delta)?).await?;
524 Ok(())
525}
526
527pub async fn read_mptz_position(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<MPTZ> {
529 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_MPTZPOSITION).await?;
530 decode_mptz_position(&tlv)
531}
532
533pub async fn read_max_presets(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
535 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_MAXPRESETS).await?;
536 decode_max_presets(&tlv)
537}
538
539pub async fn read_mptz_presets(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<MPTZPreset>> {
541 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_MPTZPRESETS).await?;
542 decode_mptz_presets(&tlv)
543}
544
545pub async fn read_dptz_streams(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<Vec<DPTZ>> {
547 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_DPTZSTREAMS).await?;
548 decode_dptz_streams(&tlv)
549}
550
551pub async fn read_zoom_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<u8> {
553 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_ZOOMMAX).await?;
554 decode_zoom_max(&tlv)
555}
556
557pub async fn read_tilt_min(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
559 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_TILTMIN).await?;
560 decode_tilt_min(&tlv)
561}
562
563pub async fn read_tilt_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
565 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_TILTMAX).await?;
566 decode_tilt_max(&tlv)
567}
568
569pub async fn read_pan_min(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
571 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_PANMIN).await?;
572 decode_pan_min(&tlv)
573}
574
575pub async fn read_pan_max(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<i16> {
577 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_PANMAX).await?;
578 decode_pan_max(&tlv)
579}
580
581pub async fn read_movement_state(conn: &crate::controller::Connection, endpoint: u16) -> anyhow::Result<PhysicalMovement> {
583 let tlv = conn.read_request2(endpoint, crate::clusters::defs::CLUSTER_ID_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT, crate::clusters::defs::CLUSTER_CAMERA_AV_SETTINGS_USER_LEVEL_MANAGEMENT_ATTR_ID_MOVEMENTSTATE).await?;
584 decode_movement_state(&tlv)
585}
586