Skip to content

Instantly share code, notes, and snippets.

@hawkeye217
Last active September 25, 2024 07:28
Show Gist options
  • Save hawkeye217/152a1d4ba80760dac95d46e143d37112 to your computer and use it in GitHub Desktop.
Save hawkeye217/152a1d4ba80760dac95d46e143d37112 to your computer and use it in GitHub Desktop.
Check if an ONVIF-capable IP PTZ camera supports RelativeMove with FOV
# This script can help you determine if your PTZ is capable of
# working with Frigate NVR's autotracker.
#
# Cameras with a "YES" printed for each parameter at the end of
# the output will likely be supported by Frigate.
#
# Make sure you're using python3 with the onvif-zeep package
# Update the values for your camera below, then run:
# pip3 install onvif-zeep
# python3 ./fovtest.py
from onvif import ONVIFCamera
# UPDATE the IP address, ONVIF port, "admin" and "password" with your camera's details.
mycam = ONVIFCamera('192.168.1.100', 80, 'admin', 'password', '/etc/onvif/wsdl/')
print('Connected to ONVIF camera')
# Create media service object
media = mycam.create_media_service()
print('Created media service object')
print
# Get target profile
media_profiles = media.GetProfiles()
print('Media profiles')
print(media_profiles)
for key, onvif_profile in enumerate(media_profiles):
if (
not onvif_profile.VideoEncoderConfiguration
or onvif_profile.VideoEncoderConfiguration.Encoding != "H264"
):
continue
# Configure PTZ options
if onvif_profile.PTZConfiguration:
if onvif_profile.PTZConfiguration.DefaultContinuousPanTiltVelocitySpace is not None:
media_profile = onvif_profile
token = media_profile.token
print('Chosen token')
print(token)
print
# Create ptz service object
print('Creating PTZ object')
ptz = mycam.create_ptz_service()
print('Created PTZ service object')
print
# Get PTZ configuration options for getting option ranges
request = ptz.create_type("GetConfigurations")
configs = ptz.GetConfigurations(request)[0]
print('PTZ configurations:')
print(configs)
print()
request = ptz.create_type('GetConfigurationOptions')
request.ConfigurationToken = media_profile.PTZConfiguration.token
ptz_configuration_options = ptz.GetConfigurationOptions(request)
print('PTZ configuration options:')
print(ptz_configuration_options)
print()
print('PTZ service capabilities:')
request = ptz.create_type('GetServiceCapabilities')
service_capabilities = ptz.GetServiceCapabilities(request)
print(service_capabilities)
print()
print('PTZ status:')
request = ptz.create_type("GetStatus")
request.ProfileToken = token
status = ptz.GetStatus(request)
print(status)
pantilt_space_id = next(
(
i
for i, space in enumerate(
ptz_configuration_options.Spaces.RelativePanTiltTranslationSpace
)
if "TranslationSpaceFov" in space["URI"]
),
None,
)
zoom_space_id = next(
(
i
for i, space in enumerate(
ptz_configuration_options.Spaces.RelativeZoomTranslationSpace
)
if "TranslationGenericSpace" in space["URI"]
),
None,
)
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
if find_by_key(vars(service_capabilities), "MoveStatus"):
print("YES - GetServiceCapabilities shows that the camera supports MoveStatus.")
else:
print("NO - GetServiceCapabilities shows that the camera does not support MoveStatus.")
# 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)
zoom_status = getattr(status.MoveStatus, "Zoom", None)
if pan_tilt_status is not None and pan_tilt_status == "IDLE" and (
zoom_status is None or zoom_status == "IDLE"
):
print("YES - MoveStatus is reporting IDLE.")
# if it's not an attribute, see if MoveStatus even exists in the status result
if pan_tilt_status is None:
pan_tilt_status = getattr(status.MoveStatus, "MoveStatus", None)
# we're unsupported
if pan_tilt_status is None or (isinstance(pan_tilt_status, str) and pan_tilt_status not in [
"IDLE",
"MOVING",
]):
print("NO - MoveStatus not reporting IDLE or MOVING.")
if pantilt_space_id is not None and configs.DefaultRelativePanTiltTranslationSpace is not None:
print("YES - RelativeMove Pan/Tilt (FOV) is supported.")
else:
print("NO - RelativeMove Pan/Tilt is unsupported.")
if zoom_space_id is not None:
print("YES - RelativeMove Zoom is supported.")
else:
print("NO - RelativeMove Zoom is unsupported.")
@kquinsland
Copy link

For the next guy that struggles, gets stuck / googles their way here:

Amcrest IP4M-1051B with V2.620.00AC000.3.R, Build Date: 2019-12-18 and with V2.620.00AC003.0.R, Build Date: 2022-07-27 gives:

YES - MoveStatus is reporting IDLE.
NO - RelativeMove Pan/Tilt is unsupported.
YES - RelativeMove Zoom is supported.

For a Amcrest IP4M-1041B with V2.800.0000000.15.R, Build Date: 2021-07-16 and with V2.800.00AC003.0.R, Build Date: 2022-08-11 the results are:

YES - MoveStatus is reporting IDLE.
YES - RelativeMove Pan/Tilt (FOV) is supported.
YES - RelativeMove Zoom is supported.

Note: The onvif service port will be the same port as the web interface (80 or 443 probably. not 8000) and you must use the root/admin credentials for onvif control unless you disable auth all-together! ( "security" on these cheap IP cameras is a joke )

@hipitihop
Copy link

hipitihop commented Feb 24, 2024

Also for the next guy that meanders their way here:

Hikvision DS-2DE2A404IW-DE3 it's a PTZ mini dome with:

Firmware Version V5.7.11 build 230612
Encoding Version V7.3 build 220830
Web Version V4.0.1.0 build 220706

I had to do the following:
In Hikvision camera web UI:

  • enable onvif in Integration Protocol
  • switch authentication from digest to digest/WSSE
  • add an onvif user, in my case frigate. With operator or admin rights.

image

In this script:

  • specify same onvif user and password.
  • use port 80 (seems to be the default for Hikvision)
  • I'm on ubuntu 22.04 and so I also had to point to a different path for the WSDL, here '/etc/onvif/wsdl/ but in my case '/usr/local/lib/python3.10/site-packages/wsdl/' otherwise script fails.

After I got the WSDL path right and the script ran, it would give vague unknown fault error. To see what was going on, I also had to add the following to the top of the script, to get more debugging from zeep.

mport logging
from zeep.transports import Transport

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('zeep.transports')
logger.setLevel(logging.DEBUG)

transport = Transport(operation_timeout=10)  # Adjust the timeout as necessary

This is what led me to finally see error from the camera:

...
DEBUG:urllib3.connectionpool:Starting new HTTP connection (1): 192.168.1.79:80
DEBUG:urllib3.connectionpool:http://192.168.1.79:80 "POST /onvif/Media HTTP/1.1" 401 234
DEBUG:zeep.transports:HTTP Response from http://192.168.1.79/onvif/Media (status: 401):
<!DOCTYPE html>
<html><head><title>Document Error: Unauthorized</title></head>
<body><h2>Access Error: 401 -- Unauthorized</h2>
<p>Authentication Error: This onvif request requires authentication information</p>
</body>
</html>
...

This prompted me to change the camera onvif authentication from digest to digest/WSSE.
I'm sure this extra logging will likely help in other scenarios/issues for some people.

With this in place the script finally produced

YES - MoveStatus is reporting IDLE.
YES - RelativeMove Pan/Tilt (FOV) is supported.
YES - RelativeMove Zoom is supported.

And in the frigate web UI with matching onvif configuration and specifying port: 80, I finally see a perfectly working extra control panel
image

@Dvalin21
Copy link

So I purchased a LS-Vision LS-WL342-20X Camera. Its a chinese manufactured camera, but to my surprise it partially works with frigate's onvif functions. I can only get it to tilt up or down, but not pan. Wont zoom, and I dont get the presets selection to the right.

When I ran the script I got the following

Connected to ONVIF camera
Created media service object
Media profiles
[{
    'Name': 'FixedProfile01',
    'VideoSourceConfiguration': {
        'Name': 'VideoSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'VideoSource001',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 1920,
            'height': 1080
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSourceConfiguration001',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'AudioSource001',
        '_value_1': None,
        'token': 'AudioSourceConfiguration001',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder01',
        'UseCount': 2,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 1920,
            'Height': 1080
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 15,
            'EncodingInterval': 1,
            'BitrateLimit': 2
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder01',
        'UseCount': 2,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 8000,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': None,
    'PTZConfiguration': {
        'Name': 'PTZConfiguration01',
        'UseCount': 2,
        'NodeToken': 'PTZNode01',
        'DefaultAbsolutePantTiltPositionSpace': None,
        'DefaultAbsoluteZoomPositionSpace': None,
        'DefaultRelativePanTiltTranslationSpace': None,
        'DefaultRelativeZoomTranslationSpace': None,
        'DefaultContinuousPanTiltVelocitySpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace',
        'DefaultContinuousZoomVelocitySpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace',
        'DefaultPTZSpeed': None,
        'DefaultPTZTimeout': datetime.timedelta(seconds=10),
        'PanTiltLimits': None,
        'ZoomLimits': None,
        'Extension': None,
        'token': 'PTZConfig001',
        '_attr_1': {
    }
    },
    'MetadataConfiguration': None,
    'Extension': None,
    'token': 'FixedProfile001',
    'fixed': True,
    '_attr_1': {
}
}, {
    'Name': 'FixedProfile02',
    'VideoSourceConfiguration': {
        'Name': 'VideoSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'VideoSource001',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 784,
            'height': 440
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSourceConfiguration001',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'AudioSource001',
        '_value_1': None,
        'token': 'AudioSourceConfiguration001',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder02',
        'UseCount': 2,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 784,
            'Height': 440
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 15,
            'EncodingInterval': 1,
            'BitrateLimit': 2
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoderConfiguration002',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder01',
        'UseCount': 2,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 8000,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': None,
    'PTZConfiguration': {
        'Name': 'PTZConfiguration01',
        'UseCount': 2,
        'NodeToken': 'PTZNode01',
        'DefaultAbsolutePantTiltPositionSpace': None,
        'DefaultAbsoluteZoomPositionSpace': None,
        'DefaultRelativePanTiltTranslationSpace': None,
        'DefaultRelativeZoomTranslationSpace': None,
        'DefaultContinuousPanTiltVelocitySpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace',
        'DefaultContinuousZoomVelocitySpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace',
        'DefaultPTZSpeed': None,
        'DefaultPTZTimeout': datetime.timedelta(seconds=10),
        'PanTiltLimits': None,
        'ZoomLimits': None,
        'Extension': None,
        'token': 'PTZConfig001',
        '_attr_1': {
    }
    },
    'MetadataConfiguration': None,
    'Extension': None,
    'token': 'FixedProfile002',
    'fixed': True,
    '_attr_1': {
}
}, {
    'Name': 'FixedProfile03',
    'VideoSourceConfiguration': {
        'Name': 'VideoSourceConfiguration02',
        'UseCount': 2,
        'SourceToken': 'VideoSource002',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 1920,
            'height': 1080
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSourceConfiguration002',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'AudioSource001',
        '_value_1': None,
        'token': 'AudioSourceConfiguration001',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder03',
        'UseCount': 2,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 1920,
            'Height': 1080
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 15,
            'EncodingInterval': 1,
            'BitrateLimit': 2
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoderConfiguration003',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder01',
        'UseCount': 2,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 8000,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': None,
    'PTZConfiguration': None,
    'MetadataConfiguration': None,
    'Extension': None,
    'token': 'FixedProfile003',
    'fixed': True,
    '_attr_1': {
}
}, {
    'Name': 'FixedProfile04',
    'VideoSourceConfiguration': {
        'Name': 'VideoSourceConfiguration02',
        'UseCount': 2,
        'SourceToken': 'VideoSource002',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 784,
            'height': 440
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSourceConfiguration002',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'AudioSource001',
        '_value_1': None,
        'token': 'AudioSourceConfiguration001',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder04',
        'UseCount': 2,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 784,
            'Height': 440
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 15,
            'EncodingInterval': 1,
            'BitrateLimit': 2
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoderConfiguration004',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder01',
        'UseCount': 2,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 8000,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': None,
    'PTZConfiguration': None,
    'MetadataConfiguration': None,
    'Extension': None,
    'token': 'FixedProfile004',
    'fixed': True,
    '_attr_1': {
}
}, {
    'Name': 'FixedProfile05',
    'VideoSourceConfiguration': {
        'Name': 'VideoSourceConfiguration03',
        'UseCount': 2,
        'SourceToken': 'VideoSource003',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 1920,
            'height': 1080
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSourceConfiguration003',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'AudioSource001',
        '_value_1': None,
        'token': 'AudioSourceConfiguration001',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder05',
        'UseCount': 2,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 1920,
            'Height': 1080
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 15,
            'EncodingInterval': 1,
            'BitrateLimit': 2
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoderConfiguration005',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder01',
        'UseCount': 2,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 8000,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': None,
    'PTZConfiguration': None,
    'MetadataConfiguration': None,
    'Extension': None,
    'token': 'FixedProfile005',
    'fixed': True,
    '_attr_1': {
}
}, {
    'Name': 'FixedProfile06',
    'VideoSourceConfiguration': {
        'Name': 'VideoSourceConfiguration03',
        'UseCount': 2,
        'SourceToken': 'VideoSource003',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 784,
            'height': 440
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSourceConfiguration003',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'AudioSource001',
        '_value_1': None,
        'token': 'AudioSourceConfiguration001',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder06',
        'UseCount': 2,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 784,
            'Height': 440
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 15,
            'EncodingInterval': 1,
            'BitrateLimit': 2
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoderConfiguration006',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder01',
        'UseCount': 2,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 8000,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': None,
    'PTZConfiguration': None,
    'MetadataConfiguration': None,
    'Extension': None,
    'token': 'FixedProfile006',
    'fixed': True,
    '_attr_1': {
}
}, {
    'Name': 'axxon0',
    'VideoSourceConfiguration': {
        'Name': 'VideoSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'VideoSource001',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 784,
            'height': 440
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSourceConfiguration001',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSourceConfiguration01',
        'UseCount': 2,
        'SourceToken': 'AudioSource001',
        '_value_1': None,
        'token': 'AudioSourceConfiguration001',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder01',
        'UseCount': 2,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 1920,
            'Height': 1080
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 15,
            'EncodingInterval': 1,
            'BitrateLimit': 2
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder01',
        'UseCount': 2,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 8000,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.0.0.123',
                'IPv6Address': None
            },
            'Port': 8600,
            'TTL': 120,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoderConfiguration001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': None,
    'PTZConfiguration': {
        'Name': 'PTZConfiguration01',
        'UseCount': 2,
        'NodeToken': 'PTZNode01',
        'DefaultAbsolutePantTiltPositionSpace': None,
        'DefaultAbsoluteZoomPositionSpace': None,
        'DefaultRelativePanTiltTranslationSpace': None,
        'DefaultRelativeZoomTranslationSpace': None,
        'DefaultContinuousPanTiltVelocitySpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace',
        'DefaultContinuousZoomVelocitySpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace',
        'DefaultPTZSpeed': None,
        'DefaultPTZTimeout': datetime.timedelta(seconds=10),
        'PanTiltLimits': None,
        'ZoomLimits': None,
        'Extension': None,
        'token': 'PTZConfig001',
        '_attr_1': {
    }
    },
    'MetadataConfiguration': None,
    'Extension': None,
    'token': 'axxon0',
    'fixed': False,
    '_attr_1': {
}
}]
Chosen token
axxon0
Creating PTZ object
Created PTZ service object
Traceback (most recent call last):
  File "/home/keith/./fovtest.py", line 53, in <module>
    configs = ptz.GetConfigurations(request)[0]
  File "/home/keith/.local/lib/python3.10/site-packages/zeep/xsd/valueobjects.py", line 140, in __getitem__
    return self.__values__[key]
KeyError: 0

It looks like it didn't complete. Right as it got to Creating PTZ Object it stops. Any suggestions? Thanks

@hawkeye217
Copy link
Author

I made some recent fixes to Frigate to bypass lots of these autotracking-specific checks and allow users with less capable cameras to still use PTZ controls. You can cherry-pick the fix yourself if you're familiar with how to do that, or you can just wait for the fixes in the next release of Frigate.

@Dvalin21
Copy link

I made some recent fixes to Frigate to bypass lots of these autotracking-specific checks and allow users with less capable cameras to still use PTZ controls. You can cherry-pick the fix yourself if you're familiar with how to do that, or you can just wait for the fixes in the next release of Frigate.

Yeah, Ill have to wait until the next release, but good news for many!! Thank you sir for you contributions!!

@rushi-kharade
Copy link

Can I enable / disable auto_tracking using python onvif-zeep lib?

@hawkeye217
Copy link
Author

Can I enable / disable auto_tracking using python onvif-zeep lib?

No.

@rushi-kharade
Copy link

@JonGilmore
Copy link

Just double checking here, my dahua PTZ (PTZ425DB-AT) reports back the following details, but relative doesn't seem to work. absolute does indeed work, but it'd be ideal if concurrent pan/tilt/zoom worked. Is this expected? Am I misunderstanding what this script is checking? Thanks!

YES - GetServiceCapabilities shows that the camera supports MoveStatus.
YES - MoveStatus is reporting IDLE.
YES - RelativeMove Pan/Tilt (FOV) is supported.
YES - RelativeMove Zoom is supported.

@hawkeye217
Copy link
Author

Unless Dahua updated their firmware and changed something, it should work if everything says YES. The autotracking code in Frigate hasn't changed at all since 0.13.

Are you sure the camera is not all the way zoomed out already? The PTZ425DB-AT has a fairly narrow field of view even when fully zoomed out. I used to have that one before I returned it for that reason. The onboard autotracking on that is pretty nice, though - much better than anything Frigate will ever be able to do through ONVIF.

If you still can't get it to work, feel free to open a support discussion on Frigate's github and we can take a look at some debug logs.

@JonGilmore
Copy link

Thanks buddy, I haven’t tried the onboard auto tracking yet, just went straight to frigate. It’s definitely zoomed out all the way, and like you’re saying, it’s got a very narrow field of view. I’m curious what ptz you switched to? I’d like something that supports more than 4x optical zoom, but there just aren’t a lot out there that aren’t absolutely gigantic

@hawkeye217
Copy link
Author

Yeah, exactly. I loved the zoom capabilities of the PTZ425DB-AT, but I ended up going with the PTZ1A4M-4X-S2, which is what I developed autotracking in Frigate with. It's much smaller and while there are times I wish I had more zoom, I'm decently pleased with the 4x.

@GroteGehaktBal
Copy link

I've bought a Dahua DH-SD2A500HB-GN-A-PV-S2 since Dahua is listed as best compatibility in the frigate docs. But I can't seem to get autotracking to work. Would there be any way to fix this? I'm already running the latest firmware (V2.811.0000013.0.R.231220)
The camera will track me once the first time I enable auto tracking and then it will stop tracking.
Frigate gives me this warning: Camera garage does not support the ONVIF GetStatus method. Autotracking will not function correctly and must be disabled in your config.

And when I ran the fovtest.py I got this result:

Connected to ONVIF camera
Created media service object
Media profiles
[{
    'Name': 'Profile000',
    'VideoSourceConfiguration': {
        'Name': 'VideoSource000',
        'UseCount': 2,
        'SourceToken': 'VideoSource000',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 2048,
            'height': 1536
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSource000',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSource000',
        'UseCount': 2,
        'SourceToken': 'AudioSource000',
        '_value_1': None,
        'token': 'AudioSource000',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder000',
        'UseCount': 1,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 2560,
            'Height': 1920
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 20,
            'EncodingInterval': 1,
            'BitrateLimit': 8192
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.1.2.4',
                'IPv6Address': None
            },
            'Port': 40000,
            'TTL': 64,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoder000',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder000',
        'UseCount': 1,
        'Encoding': 'G711',
        'Bitrate': 128,
        'SampleRate': 32,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.1.2.4',
                'IPv6Address': None
            },
            'Port': 40002,
            'TTL': 64,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoder000',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': {
        'Name': 'Analytics000',
        'UseCount': 2,
        'AnalyticsEngineConfiguration': {
            'AnalyticsModule': [
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '70'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bb9080>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                },
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '0'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bb9200>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                },
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '0'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bb9f80>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                },
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '0'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bba9c0>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                }
            ],
            'Extension': None,
            '_attr_1': None
        },
        'RuleEngineConfiguration': {
            'Rule': [
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'MinCount',
                                'Value': '20'
                            },
                            {
                                'Name': 'AlarmOnDelay',
                                'Value': '1000'
                            },
                            {
                                'Name': 'AlarmOffDelay',
                                'Value': '1000'
                            },
                            {
                                'Name': 'ActiveCells',
                                'Value': '0P8A8A=='
                            }
                        ],
                        'ElementItem': [],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'Region1',
                    'Type': 'tt:CellMotionDetector'
                }
            ],
            'Extension': None,
            '_attr_1': None
        },
        '_value_1': None,
        'token': 'Analytics000',
        '_attr_1': {
    }
    },
    'PTZConfiguration': {
        'Name': 'PTZ000',
        'UseCount': 2,
        'NodeToken': 'PTZ000',
        'DefaultAbsolutePantTiltPositionSpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace',
        'DefaultAbsoluteZoomPositionSpace': None,
        'DefaultRelativePanTiltTranslationSpace': None,
        'DefaultRelativeZoomTranslationSpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace',
        'DefaultContinuousPanTiltVelocitySpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace',
        'DefaultContinuousZoomVelocitySpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace',
        'DefaultPTZSpeed': {
            'PanTilt': {
                'x': 0.8,
                'y': 0.8,
                'space': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace'
            },
            'Zoom': {
                'x': 0.8,
                'space': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace'
            }
        },
        'DefaultPTZTimeout': datetime.timedelta(seconds=10),
        'PanTiltLimits': {
            'Range': {
                'URI': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace',
                'XRange': {
                    'Min': -1.0,
                    'Max': 1.0
                },
                'YRange': {
                    'Min': -1.0,
                    'Max': 1.0
                }
            }
        },
        'ZoomLimits': None,
        'Extension': None,
        'token': 'PTZ000',
        '_attr_1': {
            'MoveRamp': '0',
            'PresetRamp': '0',
            'PresetTourRamp': '0'
        }
    },
    'MetadataConfiguration': {
        'Name': 'Metadata000',
        'UseCount': 1,
        'PTZStatus': {
            'Status': False,
            'Position': False,
            '_attr_1': None
        },
        'Events': {
            'Filter': {
                '_value_1': [
                    {
                        '_value_1': None,
                        'Dialect': 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet',
                        '_attr_1': {
                    }
                    }
                ]
            },
            'SubscriptionPolicy': None,
            '_value_1': None,
            '_attr_1': None
        },
        'Analytics': True,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.1.2.4',
                'IPv6Address': None
            },
            'Port': 40000,
            'TTL': 64,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'AnalyticsEngineConfiguration': None,
        'Extension': None,
        'token': 'Metadata000',
        '_attr_1': {
            'CompressionType': 'None',
            'GeoLocation': 'false'
        }
    },
    'Extension': {
        '_value_1': [
            {
                'Name': 'AudioOutput000',
                'UseCount': 2,
                'OutputToken': 'AudioOutput000',
                'SendPrimacy': 'www.onvif.org/ver20/HalfDuplex/Auto',
                'OutputLevel': 97,
                '_value_1': None,
                'token': 'AudioOutput000',
                '_attr_1': {
            }
            },
            {
                'Name': 'AudioDecoder000',
                'UseCount': 1,
                '_value_1': None,
                'token': 'AudioDecoder000',
                '_attr_1': {
            }
            }
        ],
        'AudioOutputConfiguration': None,
        'AudioDecoderConfiguration': None,
        'Extension': None,
        '_attr_1': None
    },
    'token': 'Profile000',
    'fixed': True,
    '_attr_1': {
}
}, {
    'Name': 'Profile001',
    'VideoSourceConfiguration': {
        'Name': 'VideoSource000',
        'UseCount': 2,
        'SourceToken': 'VideoSource000',
        'Bounds': {
            'x': 0,
            'y': 0,
            'width': 2048,
            'height': 1536
        },
        '_value_1': None,
        'Extension': None,
        'token': 'VideoSource000',
        '_attr_1': {
    }
    },
    'AudioSourceConfiguration': {
        'Name': 'AudioSource000',
        'UseCount': 2,
        'SourceToken': 'AudioSource000',
        '_value_1': None,
        'token': 'AudioSource000',
        '_attr_1': {
    }
    },
    'VideoEncoderConfiguration': {
        'Name': 'VideoEncoder001',
        'UseCount': 1,
        'Encoding': 'H264',
        'Resolution': {
            'Width': 704,
            'Height': 576
        },
        'Quality': 4.0,
        'RateControl': {
            'FrameRateLimit': 20,
            'EncodingInterval': 1,
            'BitrateLimit': 1024
        },
        'MPEG4': None,
        'H264': {
            'GovLength': 30,
            'H264Profile': 'Main'
        },
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.1.2.4',
                'IPv6Address': None
            },
            'Port': 40016,
            'TTL': 64,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'VideoEncoder001',
        '_attr_1': {
    }
    },
    'AudioEncoderConfiguration': {
        'Name': 'AudioEncoder001',
        'UseCount': 1,
        'Encoding': 'G711',
        'Bitrate': 32,
        'SampleRate': 8,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.1.2.4',
                'IPv6Address': None
            },
            'Port': 40018,
            'TTL': 64,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'token': 'AudioEncoder001',
        '_attr_1': {
    }
    },
    'VideoAnalyticsConfiguration': {
        'Name': 'Analytics000',
        'UseCount': 2,
        'AnalyticsEngineConfiguration': {
            'AnalyticsModule': [
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '70'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bc6780>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                },
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '0'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bba100>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                },
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '0'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bc6080>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                },
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'Sensitivity',
                                'Value': '0'
                            }
                        ],
                        'ElementItem': [
                            {
                                '_value_1': <Element {http://www.onvif.org/ver10/schema}CellLayout at 0x104bc6cc0>,
                                'Name': 'Layout'
                            }
                        ],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'MyCellMotionEngine',
                    'Type': 'tt:CellMotionEngine'
                }
            ],
            'Extension': None,
            '_attr_1': None
        },
        'RuleEngineConfiguration': {
            'Rule': [
                {
                    'Parameters': {
                        'SimpleItem': [
                            {
                                'Name': 'MinCount',
                                'Value': '20'
                            },
                            {
                                'Name': 'AlarmOnDelay',
                                'Value': '1000'
                            },
                            {
                                'Name': 'AlarmOffDelay',
                                'Value': '1000'
                            },
                            {
                                'Name': 'ActiveCells',
                                'Value': '0P8A8A=='
                            }
                        ],
                        'ElementItem': [],
                        'Extension': None,
                        '_attr_1': None
                    },
                    'Name': 'Region1',
                    'Type': 'tt:CellMotionDetector'
                }
            ],
            'Extension': None,
            '_attr_1': None
        },
        '_value_1': None,
        'token': 'Analytics000',
        '_attr_1': {
    }
    },
    'PTZConfiguration': {
        'Name': 'PTZ000',
        'UseCount': 2,
        'NodeToken': 'PTZ000',
        'DefaultAbsolutePantTiltPositionSpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace',
        'DefaultAbsoluteZoomPositionSpace': None,
        'DefaultRelativePanTiltTranslationSpace': None,
        'DefaultRelativeZoomTranslationSpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace',
        'DefaultContinuousPanTiltVelocitySpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace',
        'DefaultContinuousZoomVelocitySpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace',
        'DefaultPTZSpeed': {
            'PanTilt': {
                'x': 0.8,
                'y': 0.8,
                'space': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace'
            },
            'Zoom': {
                'x': 0.8,
                'space': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace'
            }
        },
        'DefaultPTZTimeout': datetime.timedelta(seconds=10),
        'PanTiltLimits': {
            'Range': {
                'URI': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace',
                'XRange': {
                    'Min': -1.0,
                    'Max': 1.0
                },
                'YRange': {
                    'Min': -1.0,
                    'Max': 1.0
                }
            }
        },
        'ZoomLimits': None,
        'Extension': None,
        'token': 'PTZ000',
        '_attr_1': {
            'MoveRamp': '0',
            'PresetRamp': '0',
            'PresetTourRamp': '0'
        }
    },
    'MetadataConfiguration': {
        'Name': 'Metadata001',
        'UseCount': 1,
        'PTZStatus': {
            'Status': False,
            'Position': False,
            '_attr_1': None
        },
        'Events': {
            'Filter': {
                '_value_1': [
                    {
                        '_value_1': None,
                        'Dialect': 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet',
                        '_attr_1': {
                    }
                    }
                ]
            },
            'SubscriptionPolicy': None,
            '_value_1': None,
            '_attr_1': None
        },
        'Analytics': True,
        'Multicast': {
            'Address': {
                'Type': 'IPv4',
                'IPv4Address': '224.1.2.4',
                'IPv6Address': None
            },
            'Port': 40016,
            'TTL': 64,
            'AutoStart': False,
            '_value_1': None,
            '_attr_1': None
        },
        'SessionTimeout': datetime.timedelta(seconds=60),
        '_value_1': None,
        'AnalyticsEngineConfiguration': None,
        'Extension': None,
        'token': 'Metadata001',
        '_attr_1': {
            'CompressionType': 'None',
            'GeoLocation': 'false'
        }
    },
    'Extension': {
        '_value_1': [
            {
                'Name': 'AudioOutput000',
                'UseCount': 2,
                'OutputToken': 'AudioOutput000',
                'SendPrimacy': 'www.onvif.org/ver20/HalfDuplex/Auto',
                'OutputLevel': 97,
                '_value_1': None,
                'token': 'AudioOutput000',
                '_attr_1': {
            }
            },
            {
                'Name': 'AudioDecoder001',
                'UseCount': 1,
                '_value_1': None,
                'token': 'AudioDecoder001',
                '_attr_1': {
            }
            }
        ],
        'AudioOutputConfiguration': None,
        'AudioDecoderConfiguration': None,
        'Extension': None,
        '_attr_1': None
    },
    'token': 'Profile001',
    'fixed': True,
    '_attr_1': {
}
}]
Chosen token
Profile001
Creating PTZ object
Created PTZ service object
PTZ configurations:
{
    'Name': 'PTZ000',
    'UseCount': 2,
    'NodeToken': 'PTZ000',
    'DefaultAbsolutePantTiltPositionSpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace',
    'DefaultAbsoluteZoomPositionSpace': None,
    'DefaultRelativePanTiltTranslationSpace': None,
    'DefaultRelativeZoomTranslationSpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace',
    'DefaultContinuousPanTiltVelocitySpace': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/VelocityGenericSpace',
    'DefaultContinuousZoomVelocitySpace': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace',
    'DefaultPTZSpeed': {
        'PanTilt': {
            'x': 0.8,
            'y': 0.8,
            'space': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace'
        },
        'Zoom': {
            'x': 0.8,
            'space': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace'
        }
    },
    'DefaultPTZTimeout': datetime.timedelta(seconds=10),
    'PanTiltLimits': {
        'Range': {
            'URI': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace',
            'XRange': {
                'Min': -1.0,
                'Max': 1.0
            },
            'YRange': {
                'Min': -1.0,
                'Max': 1.0
            }
        }
    },
    'ZoomLimits': None,
    'Extension': None,
    'token': 'PTZ000',
    '_attr_1': {
        'MoveRamp': '0',
        'PresetRamp': '0',
        'PresetTourRamp': '0'
    }
}

PTZ configuration options:
{
    'Spaces': {
        'AbsolutePanTiltPositionSpace': [],
        'AbsoluteZoomPositionSpace': [],
        'RelativePanTiltTranslationSpace': [],
        'RelativeZoomTranslationSpace': [
            {
                'URI': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/TranslationGenericSpace',
                'XRange': {
                    'Min': -1.0,
                    'Max': 1.0
                }
            }
        ],
        'ContinuousPanTiltVelocitySpace': [],
        'ContinuousZoomVelocitySpace': [
            {
                'URI': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/VelocityGenericSpace',
                'XRange': {
                    'Min': -1.0,
                    'Max': 1.0
                }
            }
        ],
        'PanTiltSpeedSpace': [],
        'ZoomSpeedSpace': [
            {
                'URI': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace',
                'XRange': {
                    'Min': 0.0,
                    'Max': 1.0
                }
            }
        ],
        'Extension': None,
        '_attr_1': None,
        '_raw_elements': deque([<Element {http://www.onvif.org/ver10/schema}AbsolutePanTiltPositionSpace at 0x104d57300>, <Element {http://www.onvif.org/ver10/schema}ContinuousPanTiltVelocitySpace at 0x104d571c0>, <Element {http://www.onvif.org/ver10/schema}PanTiltSpeedSpace at 0x104d57680>])
    },
    'PTZTimeout': {
        'Min': datetime.timedelta(seconds=1),
        'Max': datetime.timedelta(seconds=10)
    },
    '_value_1': None,
    'PTControlDirection': None,
    'Extension': None,
    '_attr_1': None
}

PTZ service capabilities:
{
    '_value_1': None,
    'EFlip': False,
    'Reverse': False,
    'GetCompatibleConfigurations': True,
    '_attr_1': {
        'MoveStatus': 'true',
        'StatusPosition': 'true'
    }
}

PTZ status:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/onvif/client.py", line 23, in wrapped
    return func(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/onvif/client.py", line 153, in wrapped
    return call(params, callback)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/onvif/client.py", line 140, in call
    ret = func(**params)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/zeep/proxy.py", line 46, in __call__
    return self._proxy._binding.send(
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/zeep/wsdl/bindings/soap.py", line 135, in send
    return self.process_reply(client, operation_obj, response)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/zeep/wsdl/bindings/soap.py", line 229, in process_reply
    return self.process_error(doc, operation)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/zeep/wsdl/bindings/soap.py", line 391, in process_error
    raise Fault(
zeep.exceptions.Fault: No such PTZ node

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/peterriemersma/Documents/projectdir/testproj/onviftest/./fovtest.py", line 71, in <module>
    status = ptz.GetStatus(request)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/onvif/client.py", line 26, in wrapped
    raise ONVIFError(err)
onvif.exceptions.ONVIFError: Unknown error: No such PTZ node

@hawkeye217
Copy link
Author

DH-SD2A500HB-GN-A-PV-S2

It doesn't look like this low-end Dahua camera supports relative movement. It's missing two necessary firmware features to support Frigate's autotracking.

@GroteGehaktBal
Copy link

Thank you for your reply @hawkeye217

Is there any other similar camera that you can recommend?

@hawkeye217
Copy link
Author

Thank you for your reply @hawkeye217

Is there any other similar camera that you can recommend?

Users have reported success with the higher end Dahuas as well as many Amcrest models. I developed autotracking using the EmpireTech PTZ1A4M-4X-S2.

@Studmuffin1134
Copy link

Studmuffin1134 commented Aug 27, 2024

Im on windows with vs code how do i get this script to run i get this error after changing the location of the wsdl to where it is found in windows
PS C:\Users\ThePlague\Documents\osm2sqlite-master\src_py> & C:/Users/ThePlague/AppData/Local/Programs/Python/Python312/python.exe c:/Users/ThePlague/Documents/osm2sqlite-master/src_py/onviftest.py
File "c:\Users\ThePlague\Documents\osm2sqlite-master\src_py\onviftest.py", line 15
mycam = ONVIFCamera('192.168.10.213', 80, 'ThePlague', ,"C:\User\ThePlague\AppData\Local\Programs\Python\Python312\Lib\site-packages\wsdl\devicemgmt.wsdl")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX escape
PS C:\Users\ThePlague\Documents\osm2sqlite-master\src_py>

@hawkeye217
Copy link
Author

Try double backslashes? C:\\User\\ThePlague\\AppData\\Local\\Programs\\Python\\Python312\\Lib\\site-packages\\wsdl\\devicemgmt.wsdl

@Studmuffin1134
Copy link

Sadly that did not work no it cant even find the file

@galandilias
Copy link

galandilias commented Aug 28, 2024

I have just tested Dahua Hero H4C for autotrack - and as for Picoo SD2A500HB model result is the same...

PTZ status:
Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/onvif/client.py", line 23, in wrapped
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/onvif/client.py", line 153, in wrapped
    return call(params, callback)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/onvif/client.py", line 140, in call
    ret = func(**params)
          ^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/zeep/proxy.py", line 46, in __call__
    return self._proxy._binding.send(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/zeep/wsdl/bindings/soap.py", line 135, in send
    return self.process_reply(client, operation_obj, response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/zeep/wsdl/bindings/soap.py", line 229, in process_reply
    return self.process_error(doc, operation)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/zeep/wsdl/bindings/soap.py", line 391, in process_error
    raise Fault(
zeep.exceptions.Fault: No such PTZ node

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/ptztest.py", line 71, in <module>
    status = ptz.GetStatus(request)
             ^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/onvif/client.py", line 26, in wrapped
    raise ONVIFError(err)
onvif.exceptions.ONVIFError: Unknown error: No such PTZ node

@Studmuffin1134
Copy link

the question is. is it hte code or is that itended

@hawkeye217
Copy link
Author

A user recently posted above this with a similar error on a low-end Dahua. I bet yours is similar in that it does not have the necessary features to support autotracking.

@klipper-vp
Copy link

klipper-vp commented Aug 29, 2024

How is this script implemented on the frigate?
Or is it just to see if the camera is compatible with the frigate NVR? I tested it on my camera and everything went well, but I don't know how to make it work on the frigate..

exe log:
PTZ status:
{
'Position': {
'PanTilt': {
'x': 1998.7,
'y': 60.0,
'space': 'http://www.onvif.org/ver10/tptz/PanTiltSpaces/PositionGenericSpace'
},
'Zoom': {
'x': 1.0,
'space': 'http://www.onvif.org/ver10/tptz/ZoomSpaces/PositionGenericSpace'
}
},
'MoveStatus': {
'PanTilt': 'IDLE',
'Zoom': 'IDLE'
},
'Error': None,
'UtcTime': datetime.datetime(2024, 8, 29, 20, 52, 16, tzinfo=<isodate.tzinfo.Utc object at 0xf46df310>), '_value_1': None, '_attr_1': None } YES - GetServiceCapabilities shows that the camera supports MoveStatus.
YES - MoveStatus is reporting IDLE.
YES - RelativeMove Pan/Tilt (FOV) is supported.
YES - RelativeMove Zoom is supported.

@hawkeye217
Copy link
Author

See the Frigate docs. This script just tests for the correct ONVIF support for Frigate's autotracking.

@klipper-vp
Copy link

Muito obrigado mesmo, pelo logs da minha camera e para funcionar?
Thank you very much indeed, for the logs of my camera and for it to work?

@CancunManny
Copy link

When I run the script I get the following response, does that mean my camera wouldn't work, or does it mean code not working prpoperly? I didn't get any yes or no;s.

Traceback (most recent call last):
  File "/home/manny/Downloads/./fovtest.py", line 15, in <module>
    mycam = ONVIFCamera('http://10.69.69.10', 80, 'myuser', 'mypw', '/etc/onvif/wsdl/')
  File "/usr/local/lib/python3.10/dist-packages/onvif/client.py", line 216, in __init__
    self.update_xaddrs()
  File "/usr/local/lib/python3.10/dist-packages/onvif/client.py", line 223, in update_xaddrs
    self.devicemgmt  = self.create_devicemgmt_service()
  File "/usr/local/lib/python3.10/dist-packages/onvif/client.py", line 333, in create_devicemgmt_service
    return self.create_onvif_service('devicemgmt', from_template)
  File "/usr/local/lib/python3.10/dist-packages/onvif/client.py", line 312, in create_onvif_service
    xaddr, wsdl_file, binding_name = self.get_definition(name, portType)
  File "/usr/local/lib/python3.10/dist-packages/onvif/client.py", line 292, in get_definition
    raise ONVIFError('No such file: %s' % wsdlpath)
onvif.exceptions.ONVIFError: Unknown error: No such file: /etc/onvif/wsdl/devicemgmt.wsdl```

@hawkeye217
Copy link
Author

You need to specify the correct wsdl directory location, not every installation of python's onvif-zeep package places it in /etc/onvif/wsdl. However, if you don't want to use the script, you can set up autotracking in Frigate according to the docs and the logs will indicate whether your camera is supported or not.

@CancunManny
Copy link

CancunManny commented Sep 21, 2024

@hawkeye217 Thank you for the quick reply. I have an old LaView cam (over 7 years old), which later I found out is a generic camera sold under different brands. Some years back I had zoneminder as my DVR. It took me a while to get the pan/tilt working but if I remember correctly I was able to use hikvision's profile to get it to work.

Today, after I left the comment here I found that I could set up pan/tilt without autotracking. On my config files I added the following

    onvif:
      host: 10.0.10.10
      port: 8000
      user: admin
      password: password

I did put in the correct ip, user and pw. After I restarted frigate it started but buggy. When I went to the pan/tilt camera it would show the controls box underneath the video "loading", but nothing would load. If I clicked on anything to get out of the screen the url on the browser would change, but not the display. I would have to reload the page to be able to get out of that camera view.

I then went into the camera configuration and verified port 8000 was setup as server on the camera. I am guessing that camera isn't onvif compatible, and zoneminder was using a different method to control the camera.

@hawkeye217
Copy link
Author

Most likely zoneminder was using the Hikvision ISAPI, which is different than ONVIF.

@proosth
Copy link

proosth commented Sep 24, 2024

in the frigate web UI with m

Great info. Thank you. I've got the same camera and PTZ is now working in Frigate.

Did you get the "auto tracking" feature working with this PTZ camera in Frigate?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment