mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-06 19:25:22 +03:00
ensure camera supports ONVIF MoveStatus
This commit is contained in:
parent
1ff1de3f84
commit
c4fa050659
@ -208,6 +208,17 @@ class PtzAutoTracker:
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
movestatus_supported = self.onvif.get_service_capabilities(camera_name)
|
||||||
|
|
||||||
|
if movestatus_supported is None or movestatus_supported.lower() != "true":
|
||||||
|
cam.onvif.autotracking.enabled = False
|
||||||
|
self.ptz_metrics[camera_name]["ptz_autotracker_enabled"].value = False
|
||||||
|
logger.warning(
|
||||||
|
f"Disabling autotracking for {camera_name}: ONVIF MoveStatus not supported"
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
self.onvif.get_camera_status(camera_name)
|
self.onvif.get_camera_status(camera_name)
|
||||||
|
|
||||||
# movement thread per camera
|
# movement thread per camera
|
||||||
|
|||||||
@ -9,6 +9,7 @@ from onvif import ONVIFCamera, ONVIFError
|
|||||||
|
|
||||||
from frigate.config import FrigateConfig, ZoomingModeEnum
|
from frigate.config import FrigateConfig, ZoomingModeEnum
|
||||||
from frigate.types import PTZMetricsTypes
|
from frigate.types import PTZMetricsTypes
|
||||||
|
from frigate.util.builtin import find_by_key
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -83,10 +84,9 @@ class OnvifController:
|
|||||||
logger.debug(f"Onvif config for {camera_name}: {ptz_config}")
|
logger.debug(f"Onvif config for {camera_name}: {ptz_config}")
|
||||||
|
|
||||||
service_capabilities_request = ptz.create_type("GetServiceCapabilities")
|
service_capabilities_request = ptz.create_type("GetServiceCapabilities")
|
||||||
service_capabilities = ptz.GetServiceCapabilities(service_capabilities_request)
|
self.cams[camera_name][
|
||||||
logger.debug(
|
"service_capabilities_request"
|
||||||
f"Onvif service capabilities for {camera_name}: {service_capabilities}"
|
] = service_capabilities_request
|
||||||
)
|
|
||||||
|
|
||||||
fov_space_id = next(
|
fov_space_id = next(
|
||||||
(
|
(
|
||||||
@ -453,7 +453,30 @@ class OnvifController:
|
|||||||
"presets": list(self.cams[camera_name]["presets"].keys()),
|
"presets": list(self.cams[camera_name]["presets"].keys()),
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_camera_status(self, camera_name: str) -> dict[str, any]:
|
def get_service_capabilities(self, camera_name: str) -> None:
|
||||||
|
if camera_name not in self.cams.keys():
|
||||||
|
logger.error(f"Onvif is not setup for {camera_name}")
|
||||||
|
return {}
|
||||||
|
|
||||||
|
if not self.cams[camera_name]["init"]:
|
||||||
|
self._init_onvif(camera_name)
|
||||||
|
|
||||||
|
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
||||||
|
service_capabilities_request = self.cams[camera_name][
|
||||||
|
"service_capabilities_request"
|
||||||
|
]
|
||||||
|
service_capabilities = onvif.get_service("ptz").GetServiceCapabilities(
|
||||||
|
service_capabilities_request
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.debug(
|
||||||
|
f"Onvif service capabilities for {camera_name}: {service_capabilities}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# MoveStatus is required for autotracking - should return "true" if supported
|
||||||
|
return find_by_key(vars(service_capabilities), "MoveStatus")
|
||||||
|
|
||||||
|
def get_camera_status(self, camera_name: str) -> None:
|
||||||
if camera_name not in self.cams.keys():
|
if camera_name not in self.cams.keys():
|
||||||
logger.error(f"Onvif is not setup for {camera_name}")
|
logger.error(f"Onvif is not setup for {camera_name}")
|
||||||
return {}
|
return {}
|
||||||
@ -465,17 +488,28 @@ class OnvifController:
|
|||||||
status_request = self.cams[camera_name]["status_request"]
|
status_request = self.cams[camera_name]["status_request"]
|
||||||
status = onvif.get_service("ptz").GetStatus(status_request)
|
status = onvif.get_service("ptz").GetStatus(status_request)
|
||||||
|
|
||||||
# zooming is optional
|
# there doesn't seem to be an onvif standard with this optional parameter
|
||||||
|
# some cameras can report MoveStatus with or without PanTilt or Zoom attributes
|
||||||
pan_tilt_status = getattr(status.MoveStatus, "PanTilt", None)
|
pan_tilt_status = getattr(status.MoveStatus, "PanTilt", None)
|
||||||
zoom_status = getattr(status.MoveStatus, "Zoom", None)
|
zoom_status = getattr(status.MoveStatus, "Zoom", None)
|
||||||
|
|
||||||
|
# if it's not an attribute, see if MoveStatus even exists in the status result
|
||||||
if pan_tilt_status is None:
|
if pan_tilt_status is None:
|
||||||
|
pan_tilt_status = getattr(status, "MoveStatus", None)
|
||||||
|
|
||||||
|
# we're unsupported
|
||||||
|
if pan_tilt_status is None or pan_tilt_status.lower() not in [
|
||||||
|
"idle",
|
||||||
|
"moving",
|
||||||
|
]:
|
||||||
logger.error(
|
logger.error(
|
||||||
f"Camera {camera_name} does not support the ONVIF GetStatus method. Autotracking will not function correctly and must be disabled in your config."
|
f"Camera {camera_name} does not support the ONVIF GetStatus method. Autotracking will not function correctly and must be disabled in your config."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if pan_tilt_status == "IDLE" and (zoom_status is None or zoom_status == "IDLE"):
|
if pan_tilt_status.lower() == "idle" and (
|
||||||
|
zoom_status is None or zoom_status.lower() == "idle"
|
||||||
|
):
|
||||||
self.cams[camera_name]["active"] = False
|
self.cams[camera_name]["active"] = False
|
||||||
if not self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
|
if not self.ptz_metrics[camera_name]["ptz_stopped"].is_set():
|
||||||
self.ptz_metrics[camera_name]["ptz_stopped"].set()
|
self.ptz_metrics[camera_name]["ptz_stopped"].set()
|
||||||
@ -517,15 +551,3 @@ class OnvifController:
|
|||||||
logger.debug(
|
logger.debug(
|
||||||
f'Camera zoom level: {self.ptz_metrics[camera_name]["ptz_zoom_level"].value}'
|
f'Camera zoom level: {self.ptz_metrics[camera_name]["ptz_zoom_level"].value}'
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
|
||||||
"pan": status.Position.PanTilt.x,
|
|
||||||
"tilt": status.Position.PanTilt.y,
|
|
||||||
"zoom": status.Position.Zoom.x
|
|
||||||
if self.config.cameras[camera_name].onvif.autotracking.zooming
|
|
||||||
else 0,
|
|
||||||
"pantilt_moving": status.MoveStatus.PanTilt,
|
|
||||||
"zoom_moving": status.MoveStatus.Zoom
|
|
||||||
if self.config.cameras[camera_name].onvif.autotracking.zooming
|
|
||||||
else "IDLE",
|
|
||||||
}
|
|
||||||
|
|||||||
@ -249,3 +249,15 @@ def update_yaml(data, key_path, new_value):
|
|||||||
temp[last_key] = new_value
|
temp[last_key] = new_value
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def find_by_key(dictionary, target_key):
|
||||||
|
if target_key in dictionary:
|
||||||
|
return dictionary[target_key]
|
||||||
|
else:
|
||||||
|
for value in dictionary.values():
|
||||||
|
if isinstance(value, dict):
|
||||||
|
result = find_by_key(value, target_key)
|
||||||
|
if result is not None:
|
||||||
|
return result
|
||||||
|
return None
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user