mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-05-30 01:16:42 +02:00
Add MQTT topic for active autotracking (#8419)
* prevent estimate clipping when autotracking * use unclipped estimate in distance function only * remove autotracking velocity changes * publish on init
This commit is contained in:
parent
8b6b83bd62
commit
6eff08eb2d
@ -221,6 +221,10 @@ Topic to turn the PTZ autotracker for a camera on and off. Expected values are `
|
||||
|
||||
Topic with current state of the PTZ autotracker for a camera. Published values are `ON` and `OFF`.
|
||||
|
||||
### `frigate/<camera_name>/ptz_autotracker/active`
|
||||
|
||||
Topic to determine if PTZ autotracker is actively tracking an object. Published values are `ON` and `OFF`.
|
||||
|
||||
### `frigate/<camera_name>/birdseye/set`
|
||||
|
||||
Topic to turn Birdseye for a camera on and off. Expected values are `ON` and `OFF`. Birdseye mode
|
||||
|
@ -191,7 +191,8 @@ class FrigateApp:
|
||||
"i",
|
||||
self.config.cameras[camera_name].onvif.autotracking.enabled,
|
||||
),
|
||||
"ptz_stopped": mp.Event(),
|
||||
"ptz_tracking_active": mp.Event(),
|
||||
"ptz_motor_stopped": mp.Event(),
|
||||
"ptz_reset": mp.Event(),
|
||||
"ptz_start_time": mp.Value("d", 0.0), # type: ignore[typeddict-item]
|
||||
# issue https://github.com/python/typeshed/issues/8799
|
||||
@ -212,7 +213,7 @@ class FrigateApp:
|
||||
# issue https://github.com/python/typeshed/issues/8799
|
||||
# from mypy 0.981 onwards
|
||||
}
|
||||
self.ptz_metrics[camera_name]["ptz_stopped"].set()
|
||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].set()
|
||||
self.feature_metrics[camera_name] = {
|
||||
"audio_enabled": mp.Value( # type: ignore[typeddict-item]
|
||||
# issue https://github.com/python/typeshed/issues/8799
|
||||
@ -444,6 +445,7 @@ class FrigateApp:
|
||||
self.config,
|
||||
self.onvif_controller,
|
||||
self.ptz_metrics,
|
||||
self.dispatcher,
|
||||
self.stop_event,
|
||||
)
|
||||
self.ptz_autotracker_thread.start()
|
||||
|
@ -18,6 +18,7 @@ from norfair.camera_motion import (
|
||||
TranslationTransformationGetter,
|
||||
)
|
||||
|
||||
from frigate.comms.dispatcher import Dispatcher
|
||||
from frigate.config import CameraConfig, FrigateConfig, ZoomingModeEnum
|
||||
from frigate.const import (
|
||||
AUTOTRACKING_MAX_AREA_RATIO,
|
||||
@ -144,11 +145,12 @@ class PtzAutoTrackerThread(threading.Thread):
|
||||
config: FrigateConfig,
|
||||
onvif: OnvifController,
|
||||
ptz_metrics: dict[str, PTZMetricsTypes],
|
||||
dispatcher: Dispatcher,
|
||||
stop_event: MpEvent,
|
||||
) -> None:
|
||||
threading.Thread.__init__(self)
|
||||
self.name = "ptz_autotracker"
|
||||
self.ptz_autotracker = PtzAutoTracker(config, onvif, ptz_metrics)
|
||||
self.ptz_autotracker = PtzAutoTracker(config, onvif, ptz_metrics, dispatcher)
|
||||
self.stop_event = stop_event
|
||||
self.config = config
|
||||
|
||||
@ -175,10 +177,12 @@ class PtzAutoTracker:
|
||||
config: FrigateConfig,
|
||||
onvif: OnvifController,
|
||||
ptz_metrics: PTZMetricsTypes,
|
||||
dispatcher: Dispatcher,
|
||||
) -> None:
|
||||
self.config = config
|
||||
self.onvif = onvif
|
||||
self.ptz_metrics = ptz_metrics
|
||||
self.dispatcher = dispatcher
|
||||
self.tracked_object: dict[str, object] = {}
|
||||
self.tracked_object_history: dict[str, object] = {}
|
||||
self.tracked_object_metrics: dict[str, object] = {}
|
||||
@ -294,6 +298,8 @@ class PtzAutoTracker:
|
||||
if camera_config.onvif.autotracking.calibrate_on_startup:
|
||||
self._calibrate_camera(camera)
|
||||
|
||||
self.ptz_metrics[camera]["ptz_tracking_active"].clear()
|
||||
self.dispatcher.publish(f"{camera}/ptz_autotracker/active", "OFF", retain=False)
|
||||
self.autotracker_init[camera] = True
|
||||
|
||||
def _write_config(self, camera):
|
||||
@ -338,7 +344,7 @@ class PtzAutoTracker:
|
||||
1,
|
||||
)
|
||||
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
zoom_out_values.append(self.ptz_metrics[camera]["ptz_zoom_level"].value)
|
||||
@ -349,7 +355,7 @@ class PtzAutoTracker:
|
||||
1,
|
||||
)
|
||||
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
zoom_in_values.append(self.ptz_metrics[camera]["ptz_zoom_level"].value)
|
||||
@ -367,7 +373,7 @@ class PtzAutoTracker:
|
||||
1,
|
||||
)
|
||||
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
zoom_out_values.append(
|
||||
@ -383,7 +389,7 @@ class PtzAutoTracker:
|
||||
1,
|
||||
)
|
||||
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
zoom_in_values.append(
|
||||
@ -406,10 +412,10 @@ class PtzAutoTracker:
|
||||
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
|
||||
)
|
||||
self.ptz_metrics[camera]["ptz_reset"].set()
|
||||
self.ptz_metrics[camera]["ptz_stopped"].clear()
|
||||
self.ptz_metrics[camera]["ptz_motor_stopped"].clear()
|
||||
|
||||
# Wait until the camera finishes moving
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
for step in range(num_steps):
|
||||
@ -420,7 +426,7 @@ class PtzAutoTracker:
|
||||
self.onvif._move_relative(camera, pan, tilt, 0, 1)
|
||||
|
||||
# Wait until the camera finishes moving
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
stop_time = time.time()
|
||||
|
||||
@ -438,10 +444,10 @@ class PtzAutoTracker:
|
||||
self.config.cameras[camera].onvif.autotracking.return_preset.lower(),
|
||||
)
|
||||
self.ptz_metrics[camera]["ptz_reset"].set()
|
||||
self.ptz_metrics[camera]["ptz_stopped"].clear()
|
||||
self.ptz_metrics[camera]["ptz_motor_stopped"].clear()
|
||||
|
||||
# Wait until the camera finishes moving
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
logger.info(
|
||||
@ -606,7 +612,9 @@ class PtzAutoTracker:
|
||||
self.onvif._move_relative(camera, pan, tilt, 0, 1)
|
||||
|
||||
# Wait until the camera finishes moving
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera][
|
||||
"ptz_motor_stopped"
|
||||
].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
if (
|
||||
@ -616,7 +624,7 @@ class PtzAutoTracker:
|
||||
self.onvif._zoom_absolute(camera, zoom, 1)
|
||||
|
||||
# Wait until the camera finishes moving
|
||||
while not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
while not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
if self.config.cameras[camera].onvif.autotracking.movement_weights:
|
||||
@ -1118,6 +1126,10 @@ class PtzAutoTracker:
|
||||
logger.debug(
|
||||
f"{camera}: New object: {obj.obj_data['id']} {obj.obj_data['box']} {obj.obj_data['frame_time']}"
|
||||
)
|
||||
self.ptz_metrics[camera]["ptz_tracking_active"].set()
|
||||
self.dispatcher.publish(
|
||||
f"{camera}/ptz_autotracker/active", "ON", retain=False
|
||||
)
|
||||
self.tracked_object[camera] = obj
|
||||
|
||||
self.tracked_object_history[camera].append(copy.deepcopy(obj.obj_data))
|
||||
@ -1220,7 +1232,7 @@ class PtzAutoTracker:
|
||||
if not self.autotracker_init[camera]:
|
||||
self._autotracker_setup(self.config.cameras[camera], camera)
|
||||
# regularly update camera status
|
||||
if not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
if not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
# return to preset if tracking is over
|
||||
@ -1243,7 +1255,7 @@ class PtzAutoTracker:
|
||||
while not self.move_queues[camera].empty():
|
||||
self.move_queues[camera].get()
|
||||
|
||||
self.ptz_metrics[camera]["ptz_stopped"].wait()
|
||||
self.ptz_metrics[camera]["ptz_motor_stopped"].wait()
|
||||
logger.debug(
|
||||
f"{camera}: Time is {self.ptz_metrics[camera]['ptz_frame_time'].value}, returning to preset: {autotracker_config.return_preset}"
|
||||
)
|
||||
@ -1253,7 +1265,11 @@ class PtzAutoTracker:
|
||||
)
|
||||
|
||||
# update stored zoom level from preset
|
||||
if not self.ptz_metrics[camera]["ptz_stopped"].is_set():
|
||||
if not self.ptz_metrics[camera]["ptz_motor_stopped"].is_set():
|
||||
self.onvif.get_camera_status(camera)
|
||||
|
||||
self.ptz_metrics[camera]["ptz_tracking_active"].clear()
|
||||
self.dispatcher.publish(
|
||||
f"{camera}/ptz_autotracker/active", "OFF", retain=False
|
||||
)
|
||||
self.ptz_metrics[camera]["ptz_reset"].set()
|
||||
|
@ -299,7 +299,7 @@ class OnvifController:
|
||||
return
|
||||
|
||||
self.cams[camera_name]["active"] = True
|
||||
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
|
||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
||||
logger.debug(
|
||||
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
||||
)
|
||||
@ -366,7 +366,7 @@ class OnvifController:
|
||||
return
|
||||
|
||||
self.cams[camera_name]["active"] = True
|
||||
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
|
||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
||||
self.ptz_metrics[camera_name]["ptz_start_time"].value = 0
|
||||
self.ptz_metrics[camera_name]["ptz_stop_time"].value = 0
|
||||
move_request = self.cams[camera_name]["move_request"]
|
||||
@ -413,7 +413,7 @@ class OnvifController:
|
||||
return
|
||||
|
||||
self.cams[camera_name]["active"] = True
|
||||
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
|
||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
||||
logger.debug(
|
||||
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
||||
)
|
||||
@ -543,8 +543,8 @@ class OnvifController:
|
||||
zoom_status is None or zoom_status.lower() == "idle"
|
||||
):
|
||||
self.cams[camera_name]["active"] = False
|
||||
if not self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
|
||||
self.ptz_metrics[camera_name]["ptz_stopped"].set()
|
||||
if not self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set():
|
||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].set()
|
||||
|
||||
logger.debug(
|
||||
f"{camera_name}: PTZ stop time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
||||
@ -555,8 +555,8 @@ class OnvifController:
|
||||
]["ptz_frame_time"].value
|
||||
else:
|
||||
self.cams[camera_name]["active"] = True
|
||||
if self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
|
||||
self.ptz_metrics[camera_name]["ptz_stopped"].clear()
|
||||
if self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set():
|
||||
self.ptz_metrics[camera_name]["ptz_motor_stopped"].clear()
|
||||
|
||||
logger.debug(
|
||||
f"{camera_name}: PTZ start time: {self.ptz_metrics[camera_name]['ptz_frame_time'].value}"
|
||||
@ -586,7 +586,7 @@ class OnvifController:
|
||||
|
||||
# some hikvision cams won't update MoveStatus, so warn if it hasn't changed
|
||||
if (
|
||||
not self.ptz_metrics[camera_name]["ptz_stopped"].is_set()
|
||||
not self.ptz_metrics[camera_name]["ptz_motor_stopped"].is_set()
|
||||
and not self.ptz_metrics[camera_name]["ptz_reset"].is_set()
|
||||
and self.ptz_metrics[camera_name]["ptz_start_time"].value != 0
|
||||
and self.ptz_metrics[camera_name]["ptz_frame_time"].value
|
||||
|
@ -31,7 +31,8 @@ class CameraMetricsTypes(TypedDict):
|
||||
|
||||
class PTZMetricsTypes(TypedDict):
|
||||
ptz_autotracker_enabled: Synchronized
|
||||
ptz_stopped: Event
|
||||
ptz_tracking_active: Event
|
||||
ptz_motor_stopped: Event
|
||||
ptz_reset: Event
|
||||
ptz_start_time: Synchronized
|
||||
ptz_stop_time: Synchronized
|
||||
|
Loading…
Reference in New Issue
Block a user