From 0db6c45bf9fd34c9f22caf0491fb36a040e3ee33 Mon Sep 17 00:00:00 2001 From: Ryan Steckler Date: Mon, 9 Dec 2024 20:00:58 -0800 Subject: [PATCH] Configurable retries on fetching Frigate clips --- custom_components/llmvision/__init__.py | 8 ++++++- custom_components/llmvision/const.py | 2 ++ custom_components/llmvision/media_handlers.py | 6 ++--- custom_components/llmvision/services.yaml | 24 +++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/custom_components/llmvision/__init__.py b/custom_components/llmvision/__init__.py index 3d94311..5fb9c01 100644 --- a/custom_components/llmvision/__init__.py +++ b/custom_components/llmvision/__init__.py @@ -24,6 +24,8 @@ IMAGE_ENTITY, VIDEO_FILE, EVENT_ID, + FRIGATE_RETRY_ATTEMPTS, + FRIGATE_RETRY_SECONDS, INTERVAL, DURATION, MAX_FRAMES, @@ -227,6 +229,8 @@ def __init__(self, data_call): "\n") if data_call.data.get(EVENT_ID) else None self.interval = int(data_call.data.get(INTERVAL, 2)) self.duration = int(data_call.data.get(DURATION, 10)) + self.frigate_retry_attempts = int(data_call.data.get(FRIGATE_RETRY_ATTEMPTS, 2)) + self.frigate_retry_seconds = int(data_call.data.get(FRIGATE_RETRY_SECONDS, 1)) self.max_frames = int(data_call.data.get(MAX_FRAMES, 3)) self.target_width = data_call.data.get(TARGET_WIDTH, 3840) self.temperature = float(data_call.data.get(TEMPERATURE, 0.3)) @@ -285,7 +289,9 @@ async def video_analyzer(data_call): max_frames=call.max_frames, target_width=call.target_width, include_filename=call.include_filename, - expose_images=call.expose_images + expose_images=call.expose_images, + frigate_retry_attempts=call.frigate_retry_attempts, + frigate_retry_seconds=call.frigate_retry_seconds ) response = await client.make_request(call) await _remember(hass, call, start, response) diff --git a/custom_components/llmvision/const.py b/custom_components/llmvision/const.py index 4bbd7f8..b554ff9 100644 --- a/custom_components/llmvision/const.py +++ b/custom_components/llmvision/const.py @@ -31,6 +31,8 @@ EVENT_ID = 'event_id' INTERVAL = 'interval' DURATION = 'duration' +FRIGATE_RETRY_ATTEMPTS = 'frigate_retry_attempts' +FRIGATE_RETRY_SECONDS = 'frigate_retry_seconds' MAX_FRAMES = 'max_frames' DETAIL = 'detail' TEMPERATURE = 'temperature' diff --git a/custom_components/llmvision/media_handlers.py b/custom_components/llmvision/media_handlers.py index f37ab8c..69a03ab 100644 --- a/custom_components/llmvision/media_handlers.py +++ b/custom_components/llmvision/media_handlers.py @@ -294,7 +294,7 @@ async def add_images(self, image_entities, image_paths, target_width, include_fi raise ServiceValidationError(f"Error: {e}") return self.client - async def add_videos(self, video_paths, event_ids, max_frames, target_width, include_filename, expose_images): + async def add_videos(self, video_paths, event_ids, max_frames, target_width, include_filename, expose_images, frigate_retry_attempts, frigate_retry_seconds): """Wrapper for client.add_frame for videos""" tmp_clips_dir = f"/config/custom_components/{DOMAIN}/tmp_clips" tmp_frames_dir = f"/config/custom_components/{DOMAIN}/tmp_frames" @@ -306,8 +306,8 @@ async def add_videos(self, video_paths, event_ids, max_frames, target_width, inc try: base_url = get_url(self.hass) frigate_url = base_url + "/api/frigate/notifications/" + event_id + "/clip.mp4" - clip_data = await self.client._fetch(frigate_url) - + clip_data = await self.client._fetch(frigate_url, max_retries=frigate_retry_attempts, retry_delay=frigate_retry_seconds) + if not clip_data: raise ServiceValidationError( f"Failed to fetch frigate clip {event_id}") diff --git a/custom_components/llmvision/services.yaml b/custom_components/llmvision/services.yaml index 78ad818..d40bfec 100644 --- a/custom_components/llmvision/services.yaml +++ b/custom_components/llmvision/services.yaml @@ -160,6 +160,30 @@ video_analyzer: selector: text: multiline: true + frigate_retry_attempts: + name: Frigate Retry Attempts + description: How many times to retry fetching the video clip from Frigate. Clips are not always available from Frigate as soon as the event has ended. + Slower machines or longer clips may need additional attempts. Increase this if you see errors fetching the clips from Frigate in your automation traces. + required: false + example: 2 + default: 2 + selector: + number: + min: 1 + max: 10 + step: 1 + frigate_retry_seconds: + name: Frigate Retry Seconds + description: How long to wait between retries to fetch the video clip from Frigate. Clips are not always available from Frigate as soon as the event has ended. + Slower machines or longer clips may need additional attempts. Increase this if you see errors fetching the clips from Frigate in your automation traces. + required: false + example: 1 + default: 1 + selector: + number: + min: 1 + max: 10 + step: 1 max_frames: name: Max Frames description: How many frames to analyze. Picks frames with the most movement.