From 69434160ab71fde67811d48ef6d43e8e6a5bedeb Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Mon, 10 Jul 2023 16:15:12 -0500 Subject: [PATCH] move ptz specific mp values to ptz_metrics dict --- frigate/app.py | 39 +++++++++++++++++++++---------------- frigate/comms/dispatcher.py | 14 ++++++------- frigate/ptz/autotrack.py | 38 ++++++++++++++++-------------------- frigate/ptz/onvif.py | 30 ++++++++++++++-------------- frigate/types.py | 11 +++++++---- frigate/video.py | 10 ++++++---- 6 files changed, 74 insertions(+), 68 deletions(-) diff --git a/frigate/app.py b/frigate/app.py index 367e89438..ecbf7c2e0 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -48,7 +48,7 @@ from frigate.record.record import manage_recordings from frigate.stats import StatsEmitter, stats_init from frigate.storage import StorageMaintainer from frigate.timeline import TimelineProcessor -from frigate.types import CameraMetricsTypes, FeatureMetricsTypes +from frigate.types import CameraMetricsTypes, FeatureMetricsTypes, PTZMetricsTypes from frigate.version import VERSION from frigate.video import capture_camera, track_camera from frigate.watchdog import FrigateWatchdog @@ -67,6 +67,7 @@ class FrigateApp: self.plus_api = PlusApi() self.camera_metrics: dict[str, CameraMetricsTypes] = {} self.feature_metrics: dict[str, FeatureMetricsTypes] = {} + self.ptz_metrics: dict[str, PTZMetricsTypes] = {} self.processes: dict[str, int] = {} def set_environment_vars(self) -> None: @@ -135,19 +136,6 @@ class FrigateApp: "i", self.config.cameras[camera_name].motion.improve_contrast, ), - "ptz_autotracker_enabled": mp.Value( # type: ignore[typeddict-item] - # issue https://github.com/python/typeshed/issues/8799 - # from mypy 0.981 onwards - "i", - self.config.cameras[camera_name].onvif.autotracking.enabled, - ), - "ptz_stopped": mp.Event(), - "ptz_start_time": mp.Value("d", 0.0), # type: ignore[typeddict-item] - # issue https://github.com/python/typeshed/issues/8799 - # from mypy 0.981 onwards - "ptz_stop_time": mp.Value("d", 0.0), # type: ignore[typeddict-item] - # issue https://github.com/python/typeshed/issues/8799 - # from mypy 0.981 onwards "motion_threshold": mp.Value( # type: ignore[typeddict-item] # issue https://github.com/python/typeshed/issues/8799 # from mypy 0.981 onwards @@ -176,7 +164,22 @@ class FrigateApp: "capture_process": None, "process": None, } - self.camera_metrics[camera_name]["ptz_stopped"].set() + self.ptz_metrics[camera_name] = { + "ptz_autotracker_enabled": mp.Value( # type: ignore[typeddict-item] + # issue https://github.com/python/typeshed/issues/8799 + # from mypy 0.981 onwards + "i", + self.config.cameras[camera_name].onvif.autotracking.enabled, + ), + "ptz_stopped": mp.Event(), + "ptz_start_time": mp.Value("d", 0.0), # type: ignore[typeddict-item] + # issue https://github.com/python/typeshed/issues/8799 + # from mypy 0.981 onwards + "ptz_stop_time": mp.Value("d", 0.0), # type: ignore[typeddict-item] + # issue https://github.com/python/typeshed/issues/8799 + # from mypy 0.981 onwards + } + self.ptz_metrics[camera_name]["ptz_stopped"].set() self.feature_metrics[camera_name] = { "audio_enabled": mp.Value( # type: ignore[typeddict-item] # issue https://github.com/python/typeshed/issues/8799 @@ -323,7 +326,7 @@ class FrigateApp: ) def init_onvif(self) -> None: - self.onvif_controller = OnvifController(self.config, self.camera_metrics) + self.onvif_controller = OnvifController(self.config, self.ptz_metrics) def init_dispatcher(self) -> None: comms: list[Communicator] = [] @@ -337,6 +340,7 @@ class FrigateApp: self.onvif_controller, self.camera_metrics, self.feature_metrics, + self.ptz_metrics, comms, ) @@ -381,7 +385,7 @@ class FrigateApp: self.ptz_autotracker_thread = PtzAutoTrackerThread( self.config, self.onvif_controller, - self.camera_metrics, + self.ptz_metrics, self.stop_event, ) self.ptz_autotracker_thread.start() @@ -432,6 +436,7 @@ class FrigateApp: self.detection_out_events[name], self.detected_frames_queue, self.camera_metrics[name], + self.ptz_metrics[name], ), ) camera_process.daemon = True diff --git a/frigate/comms/dispatcher.py b/frigate/comms/dispatcher.py index 5025df2e6..fc4561d6d 100644 --- a/frigate/comms/dispatcher.py +++ b/frigate/comms/dispatcher.py @@ -6,7 +6,7 @@ from typing import Any, Callable from frigate.config import FrigateConfig from frigate.ptz.onvif import OnvifCommandEnum, OnvifController -from frigate.types import CameraMetricsTypes, FeatureMetricsTypes +from frigate.types import CameraMetricsTypes, FeatureMetricsTypes, PTZMetricsTypes from frigate.util.services import restart_frigate logger = logging.getLogger(__name__) @@ -40,12 +40,14 @@ class Dispatcher: onvif: OnvifController, camera_metrics: dict[str, CameraMetricsTypes], feature_metrics: dict[str, FeatureMetricsTypes], + ptz_metrics: dict[str, PTZMetricsTypes], communicators: list[Communicator], ) -> None: self.config = config self.onvif = onvif self.camera_metrics = camera_metrics self.feature_metrics = feature_metrics + self.ptz_metrics = ptz_metrics self.comms = communicators for comm in self.comms: @@ -165,16 +167,14 @@ class Dispatcher: ptz_autotracker_settings = self.config.cameras[camera_name].onvif.autotracking if payload == "ON": - if not self.camera_metrics[camera_name]["ptz_autotracker_enabled"].value: + if not self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value: logger.info(f"Turning on ptz autotracker for {camera_name}") - self.camera_metrics[camera_name]["ptz_autotracker_enabled"].value = True + self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = True ptz_autotracker_settings.enabled = True elif payload == "OFF": - if self.camera_metrics[camera_name]["ptz_autotracker_enabled"].value: + if self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value: logger.info(f"Turning off ptz autotracker for {camera_name}") - self.camera_metrics[camera_name][ - "ptz_autotracker_enabled" - ].value = False + self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False ptz_autotracker_settings.enabled = False self.publish(f"{camera_name}/ptz_autotracker/state", payload, retain=True) diff --git a/frigate/ptz/autotrack.py b/frigate/ptz/autotrack.py index b3b97d0f7..50ad24ffc 100644 --- a/frigate/ptz/autotrack.py +++ b/frigate/ptz/autotrack.py @@ -15,7 +15,7 @@ from norfair.camera_motion import MotionEstimator, TranslationTransformationGett from frigate.config import CameraConfig, FrigateConfig from frigate.ptz.onvif import OnvifController -from frigate.types import CameraMetricsTypes +from frigate.types import PTZMetricsTypes from frigate.util.image import SharedMemoryFrameManager, intersection_over_union logger = logging.getLogger(__name__) @@ -97,12 +97,12 @@ class PtzAutoTrackerThread(threading.Thread): self, config: FrigateConfig, onvif: OnvifController, - camera_metrics: dict[str, CameraMetricsTypes], + ptz_metrics: dict[str, PTZMetricsTypes], stop_event: MpEvent, ) -> None: threading.Thread.__init__(self) self.name = "ptz_autotracker" - self.ptz_autotracker = PtzAutoTracker(config, onvif, camera_metrics) + self.ptz_autotracker = PtzAutoTracker(config, onvif, ptz_metrics) self.stop_event = stop_event self.config = config @@ -125,11 +125,11 @@ class PtzAutoTracker: self, config: FrigateConfig, onvif: OnvifController, - camera_metrics: CameraMetricsTypes, + ptz_metrics: PTZMetricsTypes, ) -> None: self.config = config self.onvif = onvif - self.camera_metrics = camera_metrics + self.ptz_metrics = ptz_metrics self.tracked_object: dict[str, object] = {} self.tracked_object_previous: dict[str, object] = {} self.object_types = {} @@ -159,17 +159,13 @@ class PtzAutoTracker: if not self.onvif._init_onvif(camera_name): logger.warning(f"Unable to initialize onvif for {camera_name}") cam.onvif.autotracking.enabled = False - self.camera_metrics[camera_name][ - "ptz_autotracker_enabled" - ].value = False + self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False return if not self.onvif.cams[camera_name]["relative_fov_supported"]: cam.onvif.autotracking.enabled = False - self.camera_metrics[camera_name][ - "ptz_autotracker_enabled" - ].value = False + self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False logger.warning( f"Disabling autotracking for {camera_name}: FOV relative movement not supported" ) @@ -214,7 +210,7 @@ class PtzAutoTracker: self.onvif._move_relative(camera, pan, tilt, 1) # Wait until the camera finishes moving - while not self.camera_metrics[camera]["ptz_stopped"].is_set(): + while not self.ptz_metrics[camera]["ptz_stopped"].is_set(): # check if ptz is moving self.onvif.get_camera_status(camera) time.sleep(1 / (self.config.cameras[camera].detect.fps / 2)) @@ -264,8 +260,8 @@ class PtzAutoTracker: self.tracked_object[camera] = obj self.tracked_object_previous[camera] = copy.deepcopy(obj) # only enqueue another move if the camera isn't moving - if self.camera_metrics[camera]["ptz_stopped"].is_set(): - self.camera_metrics[camera]["ptz_stopped"].clear() + if self.ptz_metrics[camera]["ptz_stopped"].is_set(): + self.ptz_metrics[camera]["ptz_stopped"].clear() logger.debug("Autotrack: New object, moving ptz") self._autotrack_move_ptz(camera, obj) @@ -312,7 +308,7 @@ class PtzAutoTracker: f"Distance: {distance}, threshold: {distance_threshold}, iou: {iou}" ) - if (distance < distance_threshold or iou > 0.5) and self.camera_metrics[ + if (distance < distance_threshold or iou > 0.5) and self.ptz_metrics[ camera ]["ptz_stopped"].is_set(): logger.debug( @@ -326,8 +322,8 @@ class PtzAutoTracker: self.tracked_object_previous[camera] = copy.deepcopy(obj) # only enqueue another move if the camera isn't moving - if self.camera_metrics[camera]["ptz_stopped"].is_set(): - self.camera_metrics[camera]["ptz_stopped"].clear() + if self.ptz_metrics[camera]["ptz_stopped"].is_set(): + self.ptz_metrics[camera]["ptz_stopped"].clear() logger.debug("Autotrack: Existing object, moving ptz") self._autotrack_move_ptz(camera, obj) @@ -358,8 +354,8 @@ class PtzAutoTracker: self.tracked_object[camera] = obj self.tracked_object_previous[camera] = copy.deepcopy(obj) # only enqueue another move if the camera isn't moving - if self.camera_metrics[camera]["ptz_stopped"].is_set(): - self.camera_metrics[camera]["ptz_stopped"].clear() + if self.ptz_metrics[camera]["ptz_stopped"].is_set(): + self.ptz_metrics[camera]["ptz_stopped"].clear() logger.debug("Autotrack: Reacquired object, moving ptz") self._autotrack_move_ptz(camera, obj) @@ -384,7 +380,7 @@ class PtzAutoTracker: if not self.autotracker_init[camera]: self._autotracker_setup(self.config.cameras[camera], camera) # regularly update camera status - if not self.camera_metrics[camera]["ptz_stopped"].is_set(): + if not self.ptz_metrics[camera]["ptz_stopped"].is_set(): self.onvif.get_camera_status(camera) # return to preset if tracking is over @@ -399,7 +395,7 @@ class PtzAutoTracker: ) and autotracker_config.return_preset ): - self.camera_metrics[camera]["ptz_stopped"].wait() + self.ptz_metrics[camera]["ptz_stopped"].wait() logger.debug( f"Autotrack: Time is {time.time()}, returning to preset: {autotracker_config.return_preset}" ) diff --git a/frigate/ptz/onvif.py b/frigate/ptz/onvif.py index 403c06a1c..59ce5472f 100644 --- a/frigate/ptz/onvif.py +++ b/frigate/ptz/onvif.py @@ -9,7 +9,7 @@ import numpy from onvif import ONVIFCamera, ONVIFError from frigate.config import FrigateConfig -from frigate.types import CameraMetricsTypes +from frigate.types import PTZMetricsTypes logger = logging.getLogger(__name__) @@ -30,10 +30,10 @@ class OnvifCommandEnum(str, Enum): class OnvifController: def __init__( - self, config: FrigateConfig, camera_metrics: dict[str, CameraMetricsTypes] + self, config: FrigateConfig, ptz_metrics: dict[str, PTZMetricsTypes] ) -> None: self.cams: dict[str, ONVIFCamera] = {} - self.camera_metrics = camera_metrics + self.ptz_metrics = ptz_metrics for cam_name, cam in config.cameras.items(): if not cam.enabled: @@ -216,12 +216,12 @@ class OnvifController: return self.cams[camera_name]["active"] = True - self.camera_metrics[camera_name]["ptz_stopped"].clear() + self.ptz_metrics[camera_name]["ptz_stopped"].clear() logger.debug(f"PTZ start time: {datetime.datetime.now().timestamp()}") - self.camera_metrics[camera_name][ + self.ptz_metrics[camera_name][ "ptz_start_time" ].value = datetime.datetime.now().timestamp() - self.camera_metrics[camera_name]["ptz_stop_time"].value = 0 + self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0 onvif: ONVIFCamera = self.cams[camera_name]["onvif"] move_request = self.cams[camera_name]["relative_move_request"] @@ -266,7 +266,7 @@ class OnvifController: return self.cams[camera_name]["active"] = True - self.camera_metrics[camera_name]["ptz_stopped"].clear() + self.ptz_metrics[camera_name]["ptz_stopped"].clear() move_request = self.cams[camera_name]["move_request"] onvif: ONVIFCamera = self.cams[camera_name]["onvif"] preset_token = self.cams[camera_name]["presets"][preset] @@ -276,7 +276,7 @@ class OnvifController: "PresetToken": preset_token, } ) - self.camera_metrics[camera_name]["ptz_stopped"].set() + self.ptz_metrics[camera_name]["ptz_stopped"].set() self.cams[camera_name]["active"] = False def _zoom(self, camera_name: str, command: OnvifCommandEnum) -> None: @@ -350,25 +350,25 @@ class OnvifController: if status.MoveStatus.PanTilt == "IDLE" and status.MoveStatus.Zoom == "IDLE": self.cams[camera_name]["active"] = False - if not self.camera_metrics[camera_name]["ptz_stopped"].is_set(): - self.camera_metrics[camera_name]["ptz_stopped"].set() + if not self.ptz_metrics[camera_name]["ptz_stopped"].is_set(): + self.ptz_metrics[camera_name]["ptz_stopped"].set() logger.debug(f"PTZ stop time: {datetime.datetime.now().timestamp()}") - self.camera_metrics[camera_name][ + self.ptz_metrics[camera_name][ "ptz_stop_time" ].value = datetime.datetime.now().timestamp() else: self.cams[camera_name]["active"] = True - if self.camera_metrics[camera_name]["ptz_stopped"].is_set(): - self.camera_metrics[camera_name]["ptz_stopped"].clear() + if self.ptz_metrics[camera_name]["ptz_stopped"].is_set(): + self.ptz_metrics[camera_name]["ptz_stopped"].clear() logger.debug(f"PTZ start time: {datetime.datetime.now().timestamp()}") - self.camera_metrics[camera_name][ + self.ptz_metrics[camera_name][ "ptz_start_time" ].value = datetime.datetime.now().timestamp() - self.camera_metrics[camera_name]["ptz_stop_time"].value = 0 + self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0 return { "pan": status.Position.PanTilt.x, diff --git a/frigate/types.py b/frigate/types.py index 9ddcafa04..3940ff056 100644 --- a/frigate/types.py +++ b/frigate/types.py @@ -18,10 +18,6 @@ class CameraMetricsTypes(TypedDict): frame_queue: Queue motion_enabled: Synchronized improve_contrast_enabled: Synchronized - ptz_autotracker_enabled: Synchronized - ptz_stopped: Event - ptz_start_time: Synchronized - ptz_stop_time: Synchronized motion_threshold: Synchronized motion_contour_area: Synchronized process: Optional[Process] @@ -30,6 +26,13 @@ class CameraMetricsTypes(TypedDict): skipped_fps: Synchronized +class PTZMetricsTypes(TypedDict): + ptz_autotracker_enabled: Synchronized + ptz_stopped: Event + ptz_start_time: Synchronized + ptz_stop_time: Synchronized + + class FeatureMetricsTypes(TypedDict): audio_enabled: Synchronized record_enabled: Synchronized diff --git a/frigate/video.py b/frigate/video.py index ded9deb0a..b23fc9318 100755 --- a/frigate/video.py +++ b/frigate/video.py @@ -462,6 +462,7 @@ def track_camera( result_connection, detected_objects_queue, process_info, + ptz_info, ): stop_event = mp.Event() @@ -479,13 +480,14 @@ def track_camera( detection_enabled = process_info["detection_enabled"] motion_enabled = process_info["motion_enabled"] improve_contrast_enabled = process_info["improve_contrast_enabled"] - ptz_autotracker_enabled = process_info["ptz_autotracker_enabled"] - ptz_start_time = process_info["ptz_start_time"] - ptz_stop_time = process_info["ptz_stop_time"] - ptz_stopped = process_info["ptz_stopped"] motion_threshold = process_info["motion_threshold"] motion_contour_area = process_info["motion_contour_area"] + ptz_autotracker_enabled = ptz_info["ptz_autotracker_enabled"] + ptz_start_time = ptz_info["ptz_start_time"] + ptz_stop_time = ptz_info["ptz_stop_time"] + ptz_stopped = ptz_info["ptz_stopped"] + frame_shape = config.frame_shape objects_to_track = config.objects.track object_filters = config.objects.filters