diff --git a/frigate/ptz/onvif.py b/frigate/ptz/onvif.py index 67403b02ab..3d2a117393 100644 --- a/frigate/ptz/onvif.py +++ b/frigate/ptz/onvif.py @@ -625,7 +625,12 @@ class OnvifController: move_request.Speed = move_speed - await cam["ptz"].RelativeMove(move_request) + try: + await cam["ptz"].RelativeMove(move_request) + except Exception as e: + logger.warning( + f"Onvif sending relative move request to {camera_name} failed: {e}" + ) # reset after the move request move_request.Translation.PanTilt.x = 0 diff --git a/frigate/test/test_ptz_onvif.py b/frigate/test/test_ptz_onvif.py index 5b6971d63d..a09f7c7d9f 100644 --- a/frigate/test/test_ptz_onvif.py +++ b/frigate/test/test_ptz_onvif.py @@ -195,6 +195,15 @@ class TestManualRelativeMoveMetrics(unittest.IsolatedAsyncioTestCase): ) ) + async def test_failed_move_does_not_raise(self) -> None: + # an exception here ends the autotracker's move queue consumer for good + controller = _make_move_controller(autotracking_enabled=True) + controller.cams[CAMERA]["ptz"].RelativeMove.side_effect = TimeoutError + + await controller._move_relative(CAMERA, 0.25, -0.25, 0, 1) + + self.assertFalse(controller.cams[CAMERA]["active"]) + async def test_metrics_written_when_autotracking_enabled(self) -> None: # get_camera_status resets stop_time once the camera reports IDLE, so the # autotracking path keeps its motion estimation timestamps