mirror of
https://github.com/blakeblackshear/frigate.git
synced 2025-02-05 00:15:51 +01:00
Upgrade onvif-zeep dependency to use onvif-zeep-async (#15894)
* Upgrade to new dependency * Start onvif work * Update for async calls
This commit is contained in:
parent
0fc1a48230
commit
fa652ca49d
@ -13,7 +13,7 @@ markupsafe == 2.1.*
|
|||||||
python-multipart == 0.0.12
|
python-multipart == 0.0.12
|
||||||
# General
|
# General
|
||||||
mypy == 1.6.1
|
mypy == 1.6.1
|
||||||
onvif_zeep == 0.2.12
|
onvif-zeep-async == 3.1.*
|
||||||
paho-mqtt == 2.1.*
|
paho-mqtt == 2.1.*
|
||||||
pandas == 2.2.*
|
pandas == 2.2.*
|
||||||
peewee == 3.17.*
|
peewee == 3.17.*
|
||||||
|
@ -29,6 +29,7 @@ class LoggerConfig(FrigateBaseModel):
|
|||||||
logging.getLogger().setLevel(self.default.value.upper())
|
logging.getLogger().setLevel(self.default.value.upper())
|
||||||
|
|
||||||
log_levels = {
|
log_levels = {
|
||||||
|
"httpx": LogLevel.error,
|
||||||
"werkzeug": LogLevel.error,
|
"werkzeug": LogLevel.error,
|
||||||
"ws4py": LogLevel.error,
|
"ws4py": LogLevel.error,
|
||||||
**self.logs,
|
**self.logs,
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
"""Configure and control camera via onvif."""
|
"""Configure and control camera via onvif."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from importlib.util import find_spec
|
from importlib.util import find_spec
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import requests
|
from onvif import ONVIFCamera, ONVIFError, ONVIFService
|
||||||
from onvif import ONVIFCamera, ONVIFError
|
|
||||||
from zeep.exceptions import Fault, TransportError
|
from zeep.exceptions import Fault, TransportError
|
||||||
from zeep.transports import Transport
|
|
||||||
|
|
||||||
from frigate.camera import PTZMetrics
|
from frigate.camera import PTZMetrics
|
||||||
from frigate.config import FrigateConfig, ZoomingModeEnum
|
from frigate.config import FrigateConfig, ZoomingModeEnum
|
||||||
@ -49,11 +48,6 @@ class OnvifController:
|
|||||||
|
|
||||||
if cam.onvif.host:
|
if cam.onvif.host:
|
||||||
try:
|
try:
|
||||||
session = requests.Session()
|
|
||||||
session.verify = not cam.onvif.tls_insecure
|
|
||||||
transport = Transport(
|
|
||||||
timeout=10, operation_timeout=10, session=session
|
|
||||||
)
|
|
||||||
self.cams[cam_name] = {
|
self.cams[cam_name] = {
|
||||||
"onvif": ONVIFCamera(
|
"onvif": ONVIFCamera(
|
||||||
cam.onvif.host,
|
cam.onvif.host,
|
||||||
@ -64,7 +58,7 @@ class OnvifController:
|
|||||||
Path(find_spec("onvif").origin).parent / "wsdl"
|
Path(find_spec("onvif").origin).parent / "wsdl"
|
||||||
).replace("dist-packages/onvif", "site-packages"),
|
).replace("dist-packages/onvif", "site-packages"),
|
||||||
adjust_time=cam.onvif.ignore_time_mismatch,
|
adjust_time=cam.onvif.ignore_time_mismatch,
|
||||||
transport=transport,
|
encrypt=not cam.onvif.tls_insecure,
|
||||||
),
|
),
|
||||||
"init": False,
|
"init": False,
|
||||||
"active": False,
|
"active": False,
|
||||||
@ -74,11 +68,12 @@ class OnvifController:
|
|||||||
except ONVIFError as e:
|
except ONVIFError as e:
|
||||||
logger.error(f"Onvif connection to {cam.name} failed: {e}")
|
logger.error(f"Onvif connection to {cam.name} failed: {e}")
|
||||||
|
|
||||||
def _init_onvif(self, camera_name: str) -> bool:
|
async def _init_onvif(self, camera_name: str) -> bool:
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
||||||
|
await onvif.update_xaddrs()
|
||||||
|
|
||||||
# create init services
|
# create init services
|
||||||
media = onvif.create_media_service()
|
media: ONVIFService = await onvif.create_media_service()
|
||||||
logger.debug(f"Onvif media xaddr for {camera_name}: {media.xaddr}")
|
logger.debug(f"Onvif media xaddr for {camera_name}: {media.xaddr}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -92,7 +87,7 @@ class OnvifController:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
profiles = media.GetProfiles()
|
profiles = await media.GetProfiles()
|
||||||
logger.debug(f"Onvif profiles for {camera_name}: {profiles}")
|
logger.debug(f"Onvif profiles for {camera_name}: {profiles}")
|
||||||
except (ONVIFError, Fault, TransportError) as e:
|
except (ONVIFError, Fault, TransportError) as e:
|
||||||
logger.error(
|
logger.error(
|
||||||
@ -101,7 +96,7 @@ class OnvifController:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
profile = None
|
profile = None
|
||||||
for key, onvif_profile in enumerate(profiles):
|
for _, onvif_profile in enumerate(profiles):
|
||||||
if (
|
if (
|
||||||
onvif_profile.VideoEncoderConfiguration
|
onvif_profile.VideoEncoderConfiguration
|
||||||
and onvif_profile.PTZConfiguration
|
and onvif_profile.PTZConfiguration
|
||||||
@ -135,7 +130,8 @@ class OnvifController:
|
|||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
ptz = onvif.create_ptz_service()
|
ptz: ONVIFService = await onvif.create_ptz_service()
|
||||||
|
self.cams[camera_name]["ptz"] = ptz
|
||||||
|
|
||||||
# setup continuous moving request
|
# setup continuous moving request
|
||||||
move_request = ptz.create_type("ContinuousMove")
|
move_request = ptz.create_type("ContinuousMove")
|
||||||
@ -246,7 +242,7 @@ class OnvifController:
|
|||||||
|
|
||||||
# setup existing presets
|
# setup existing presets
|
||||||
try:
|
try:
|
||||||
presets: list[dict] = ptz.GetPresets({"ProfileToken": profile.token})
|
presets: list[dict] = await ptz.GetPresets({"ProfileToken": profile.token})
|
||||||
except ONVIFError as e:
|
except ONVIFError as e:
|
||||||
logger.warning(f"Unable to get presets from camera: {camera_name}: {e}")
|
logger.warning(f"Unable to get presets from camera: {camera_name}: {e}")
|
||||||
presets = []
|
presets = []
|
||||||
@ -325,20 +321,20 @@ class OnvifController:
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.cams[camera_name]["features"] = supported_features
|
self.cams[camera_name]["features"] = supported_features
|
||||||
|
|
||||||
self.cams[camera_name]["init"] = True
|
self.cams[camera_name]["init"] = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _stop(self, camera_name: str) -> None:
|
def _stop(self, camera_name: str) -> None:
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
move_request = self.cams[camera_name]["move_request"]
|
move_request = self.cams[camera_name]["move_request"]
|
||||||
onvif.get_service("ptz").Stop(
|
asyncio.run(
|
||||||
|
self.cams[camera_name]["ptz"].Stop(
|
||||||
{
|
{
|
||||||
"ProfileToken": move_request.ProfileToken,
|
"ProfileToken": move_request.ProfileToken,
|
||||||
"PanTilt": True,
|
"PanTilt": True,
|
||||||
"Zoom": True,
|
"Zoom": True,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
)
|
||||||
self.cams[camera_name]["active"] = False
|
self.cams[camera_name]["active"] = False
|
||||||
|
|
||||||
def _move(self, camera_name: str, command: OnvifCommandEnum) -> None:
|
def _move(self, camera_name: str, command: OnvifCommandEnum) -> None:
|
||||||
@ -353,7 +349,6 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = True
|
self.cams[camera_name]["active"] = True
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
move_request = self.cams[camera_name]["move_request"]
|
move_request = self.cams[camera_name]["move_request"]
|
||||||
|
|
||||||
if command == OnvifCommandEnum.move_left:
|
if command == OnvifCommandEnum.move_left:
|
||||||
@ -376,7 +371,7 @@ class OnvifController:
|
|||||||
}
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
onvif.get_service("ptz").ContinuousMove(move_request)
|
asyncio.run(self.cams[camera_name]["ptz"].ContinuousMove(move_request))
|
||||||
except ONVIFError as e:
|
except ONVIFError as e:
|
||||||
logger.warning(f"Onvif sending move request to {camera_name} failed: {e}")
|
logger.warning(f"Onvif sending move request to {camera_name} failed: {e}")
|
||||||
|
|
||||||
@ -404,7 +399,6 @@ class OnvifController:
|
|||||||
camera_name
|
camera_name
|
||||||
].frame_time.value
|
].frame_time.value
|
||||||
self.ptz_metrics[camera_name].stop_time.value = 0
|
self.ptz_metrics[camera_name].stop_time.value = 0
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
move_request = self.cams[camera_name]["relative_move_request"]
|
move_request = self.cams[camera_name]["relative_move_request"]
|
||||||
|
|
||||||
# function takes in -1 to 1 for pan and tilt, interpolate to the values of the camera.
|
# function takes in -1 to 1 for pan and tilt, interpolate to the values of the camera.
|
||||||
@ -450,7 +444,7 @@ class OnvifController:
|
|||||||
}
|
}
|
||||||
move_request.Translation.Zoom.x = zoom
|
move_request.Translation.Zoom.x = zoom
|
||||||
|
|
||||||
onvif.get_service("ptz").RelativeMove(move_request)
|
asyncio.run(self.cams[camera_name]["ptz"].RelativeMove(move_request))
|
||||||
|
|
||||||
# reset after the move request
|
# reset after the move request
|
||||||
move_request.Translation.PanTilt.x = 0
|
move_request.Translation.PanTilt.x = 0
|
||||||
@ -475,14 +469,15 @@ class OnvifController:
|
|||||||
self.ptz_metrics[camera_name].start_time.value = 0
|
self.ptz_metrics[camera_name].start_time.value = 0
|
||||||
self.ptz_metrics[camera_name].stop_time.value = 0
|
self.ptz_metrics[camera_name].stop_time.value = 0
|
||||||
move_request = self.cams[camera_name]["move_request"]
|
move_request = self.cams[camera_name]["move_request"]
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
preset_token = self.cams[camera_name]["presets"][preset]
|
preset_token = self.cams[camera_name]["presets"][preset]
|
||||||
onvif.get_service("ptz").GotoPreset(
|
asyncio.run(
|
||||||
|
self.cams[camera_name]["ptz"].GotoPreset(
|
||||||
{
|
{
|
||||||
"ProfileToken": move_request.ProfileToken,
|
"ProfileToken": move_request.ProfileToken,
|
||||||
"PresetToken": preset_token,
|
"PresetToken": preset_token,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = False
|
self.cams[camera_name]["active"] = False
|
||||||
|
|
||||||
@ -498,7 +493,6 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = True
|
self.cams[camera_name]["active"] = True
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
move_request = self.cams[camera_name]["move_request"]
|
move_request = self.cams[camera_name]["move_request"]
|
||||||
|
|
||||||
if command == OnvifCommandEnum.zoom_in:
|
if command == OnvifCommandEnum.zoom_in:
|
||||||
@ -506,7 +500,7 @@ class OnvifController:
|
|||||||
elif command == OnvifCommandEnum.zoom_out:
|
elif command == OnvifCommandEnum.zoom_out:
|
||||||
move_request.Velocity = {"Zoom": {"x": -0.5}}
|
move_request.Velocity = {"Zoom": {"x": -0.5}}
|
||||||
|
|
||||||
onvif.get_service("ptz").ContinuousMove(move_request)
|
asyncio.run(self.cams[camera_name]["ptz"].ContinuousMove(move_request))
|
||||||
|
|
||||||
def _zoom_absolute(self, camera_name: str, zoom, speed) -> None:
|
def _zoom_absolute(self, camera_name: str, zoom, speed) -> None:
|
||||||
if "zoom-a" not in self.cams[camera_name]["features"]:
|
if "zoom-a" not in self.cams[camera_name]["features"]:
|
||||||
@ -530,7 +524,6 @@ class OnvifController:
|
|||||||
camera_name
|
camera_name
|
||||||
].frame_time.value
|
].frame_time.value
|
||||||
self.ptz_metrics[camera_name].stop_time.value = 0
|
self.ptz_metrics[camera_name].stop_time.value = 0
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
move_request = self.cams[camera_name]["absolute_move_request"]
|
move_request = self.cams[camera_name]["absolute_move_request"]
|
||||||
|
|
||||||
# function takes in 0 to 1 for zoom, interpolate to the values of the camera.
|
# function takes in 0 to 1 for zoom, interpolate to the values of the camera.
|
||||||
@ -548,7 +541,7 @@ class OnvifController:
|
|||||||
|
|
||||||
logger.debug(f"{camera_name}: Absolute zoom: {zoom}")
|
logger.debug(f"{camera_name}: Absolute zoom: {zoom}")
|
||||||
|
|
||||||
onvif.get_service("ptz").AbsoluteMove(move_request)
|
asyncio.run(self.cams[camera_name]["ptz"].AbsoluteMove(move_request))
|
||||||
|
|
||||||
self.cams[camera_name]["active"] = False
|
self.cams[camera_name]["active"] = False
|
||||||
|
|
||||||
@ -560,7 +553,7 @@ class OnvifController:
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not self.cams[camera_name]["init"]:
|
if not self.cams[camera_name]["init"]:
|
||||||
if not self._init_onvif(camera_name):
|
if not asyncio.run(self._init_onvif(camera_name)):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -590,7 +583,7 @@ class OnvifController:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
if not self.cams[camera_name]["init"]:
|
if not self.cams[camera_name]["init"]:
|
||||||
self._init_onvif(camera_name)
|
asyncio.run(self._init_onvif(camera_name))
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"name": camera_name,
|
"name": camera_name,
|
||||||
@ -604,16 +597,17 @@ class OnvifController:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
if not self.cams[camera_name]["init"]:
|
if not self.cams[camera_name]["init"]:
|
||||||
self._init_onvif(camera_name)
|
asyncio.run(self._init_onvif(camera_name))
|
||||||
|
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
service_capabilities_request = self.cams[camera_name][
|
service_capabilities_request = self.cams[camera_name][
|
||||||
"service_capabilities_request"
|
"service_capabilities_request"
|
||||||
]
|
]
|
||||||
try:
|
try:
|
||||||
service_capabilities = onvif.get_service("ptz").GetServiceCapabilities(
|
service_capabilities = asyncio.run(
|
||||||
|
self.cams[camera_name]["ptz"].GetServiceCapabilities(
|
||||||
service_capabilities_request
|
service_capabilities_request
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Onvif service capabilities for {camera_name}: {service_capabilities}"
|
f"Onvif service capabilities for {camera_name}: {service_capabilities}"
|
||||||
@ -633,12 +627,13 @@ class OnvifController:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
if not self.cams[camera_name]["init"]:
|
if not self.cams[camera_name]["init"]:
|
||||||
self._init_onvif(camera_name)
|
asyncio.run(self._init_onvif(camera_name))
|
||||||
|
|
||||||
onvif: ONVIFCamera = self.cams[camera_name]["onvif"]
|
|
||||||
status_request = self.cams[camera_name]["status_request"]
|
status_request = self.cams[camera_name]["status_request"]
|
||||||
try:
|
try:
|
||||||
status = onvif.get_service("ptz").GetStatus(status_request)
|
status = asyncio.run(
|
||||||
|
self.cams[camera_name]["ptz"].GetStatus(status_request)
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass # We're unsupported, that'll be reported in the next check.
|
pass # We're unsupported, that'll be reported in the next check.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user