5454ATTR_SPEED = "speed"
5555ATTR_MOVE_MODE = "move_mode"
5656ATTR_CONTINUOUS_DURATION = "continuous_duration"
57+ ATTR_PRESET = "preset"
5758
5859DIR_UP = "UP"
5960DIR_DOWN = "DOWN"
6768CONTINUOUS_MOVE = "ContinuousMove"
6869RELATIVE_MOVE = "RelativeMove"
6970ABSOLUTE_MOVE = "AbsoluteMove"
71+ GOTOPRESET_MOVE = "GotoPreset"
7072
7173SERVICE_PTZ = "ptz"
7274
99101 vol .Optional (ATTR_PAN ): vol .In ([DIR_LEFT , DIR_RIGHT ]),
100102 vol .Optional (ATTR_TILT ): vol .In ([DIR_UP , DIR_DOWN ]),
101103 vol .Optional (ATTR_ZOOM ): vol .In ([ZOOM_OUT , ZOOM_IN ]),
102- ATTR_MOVE_MODE : vol .In ([CONTINUOUS_MOVE , RELATIVE_MOVE , ABSOLUTE_MOVE ]),
104+ ATTR_MOVE_MODE : vol .In (
105+ [CONTINUOUS_MOVE , RELATIVE_MOVE , ABSOLUTE_MOVE , GOTOPRESET_MOVE ]
106+ ),
103107 vol .Optional (ATTR_CONTINUOUS_DURATION , default = 0.5 ): cv .small_float ,
104108 vol .Optional (ATTR_DISTANCE , default = 0.1 ): cv .small_float ,
105109 vol .Optional (ATTR_SPEED , default = 0.5 ): cv .small_float ,
110+ vol .Optional (ATTR_PRESET , default = "0" ): cv .string ,
106111 }
107112)
108113
@@ -120,6 +125,7 @@ async def async_handle_ptz(service):
120125 speed = service .data [ATTR_SPEED ]
121126 move_mode = service .data .get (ATTR_MOVE_MODE )
122127 continuous_duration = service .data [ATTR_CONTINUOUS_DURATION ]
128+ preset = service .data [ATTR_PRESET ]
123129 all_cameras = hass .data [ONVIF_DATA ][ENTITIES ]
124130 entity_ids = await async_extract_entity_ids (hass , service )
125131 target_cameras = []
@@ -131,7 +137,7 @@ async def async_handle_ptz(service):
131137 ]
132138 for camera in target_cameras :
133139 await camera .async_perform_ptz (
134- pan , tilt , zoom , distance , speed , move_mode , continuous_duration
140+ pan , tilt , zoom , distance , speed , move_mode , continuous_duration , preset
135141 )
136142
137143 hass .services .async_register (
@@ -435,7 +441,7 @@ def setup_ptz(self):
435441 _LOGGER .debug ("Completed set up of the ONVIF camera component" )
436442
437443 async def async_perform_ptz (
438- self , pan , tilt , zoom , distance , speed , move_mode , continuous_duration
444+ self , pan , tilt , zoom , distance , speed , move_mode , continuous_duration , preset
439445 ):
440446 """Perform a PTZ action on the camera."""
441447 if self ._ptz_service is None :
@@ -447,13 +453,15 @@ async def async_perform_ptz(
447453 tilt_val = distance * TILT_FACTOR .get (tilt , 0 )
448454 zoom_val = distance * ZOOM_FACTOR .get (zoom , 0 )
449455 speed_val = speed
456+ preset_val = preset
450457 _LOGGER .debug (
451- "Calling %s PTZ | Pan = %4.2f | Tilt = %4.2f | Zoom = %4.2f | Speed = %4.2f" ,
458+ "Calling %s PTZ | Pan = %4.2f | Tilt = %4.2f | Zoom = %4.2f | Speed = %4.2f | Preset = %s " ,
452459 move_mode ,
453460 pan_val ,
454461 tilt_val ,
455462 zoom_val ,
456463 speed_val ,
464+ preset_val ,
457465 )
458466 try :
459467 req = self ._ptz_service .create_type (move_mode )
@@ -489,6 +497,13 @@ async def async_perform_ptz(
489497 "Zoom" : {"x" : speed_val },
490498 }
491499 await self ._ptz_service .AbsoluteMove (req )
500+ elif move_mode == GOTOPRESET_MOVE :
501+ req .PresetToken = preset_val
502+ req .Speed = {
503+ "PanTilt" : {"x" : speed_val , "y" : speed_val },
504+ "Zoom" : {"x" : speed_val },
505+ }
506+ await self ._ptz_service .GotoPreset (req )
492507 except exceptions .ONVIFError as err :
493508 if "Bad Request" in err .reason :
494509 self ._ptz_service = None
0 commit comments