ONVIF:Example:FindDevice
lastmod 2024-10-14created 2021-10-1322 edits
Notes on how to find cameras on the network and communicate with them over ONVIF. The code uses Python.
For the official ONVIF documentation, see the ONVIF Application Programmer's Guide.1
The WSDL specs of ONVIF can be downloaded from Network Interface Specifications - ONVIF or Github - onvif/specs.
Device Discovery
First check whether the device exists on the network. The spec used for this is WS-Discovery, and the Python library used is WSDiscovery.
It works over TCP and UDP port 3702 and uses the IP multicast address 239.255.255.250 or FF02::C; the actual communication is done with SOAP-over-UDP.
The code is as follows:
from wsdiscovery.discovery import ThreadedWSDiscovery as WSDiscovery
wsd = WSDiscovery()
wsd.start()
services = wsd.searchServices()
for service in services:
for address in service.getXAddrs():
print(service.getEPR() + ":" + address)
The output looks like this:
urn:uuid:03590000-e4f9-11b4-8389-5803fb986fcf:http://192.168.0.201/onvif/device_service
urn:uuid:03590000-e4f9-11b4-8389-5803fb986fcf:http://[fe80::5a03:fbff:fe98:6fcf]/onvif/device_service
urn:uuid:78c2c020-78c2-4c02-801d-78c2c0201d75:http://192.168.0.50/onvif/device_service
urn:uuid:594333b6-5750-4471-b3aa-bec2042940c6:http://192.168.0.61:5357/594333b6-5750-4471-b3aa-bec2042940c6/
Remember the device's UUID and the address for the WSDL.
WSDL Device Management
Get various information about the device through the WSDL device management service. It works over SOAP. Uses the zeep library.
from zeep import Client
wsdl = "http://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl"
client = Client(wsdl=wsdl)
service = client.create_service("{http://www.onvif.org/ver10/device/wsdl}DeviceBinding", "http://192.168.0.50/onvif/device_service")
print(service.GetCapabilities())
For the arguments to Client.create_service, see zeep#Client.create_service.
Device information can be obtained through the WSDL spec (devicemgmt.wsdl).
Importantly, Media-related information can be obtained through the GetCapabilities() SOAP API.
The output looks like this:
{
...
'Media': {
'XAddr': 'http://192.168.0.50/onvif/device_service',
'StreamingCapabilities': {
'RTPMulticast': True,
'RTP_TCP': True,
'RTP_RTSP_TCP': True,
'Extension': None,
'_attr_1': None
},
'_value_1': None,
'Extension': None,
'_attr_1': None
},
...
Remember the XAddr and StreamingCapabilities above. They are needed at the last step, when getting the stream address.
Getting media profile information
Get media information through the media.wsdl spec. If needed, add authentication information such as UsernameToken, HTTPBasicAuth, or HTTPDigestAuth.
from zeep import Client
from zeep.wsse.username import UsernameToken
wsdl = "http://www.onvif.org/ver10/media/wsdl/media.wsdl"
client = Client(wsdl=wsdl, wsse=UsernameToken("admin", "0000", use_digest=True))
service = client.create_service("{http://www.onvif.org/ver10/media/wsdl}MediaBinding", "http://192.168.0.50/onvif/device_service")
profiles = service.GetProfiles()
print(profiles)
The profiles are printed as follows:
Remember the token name of the profile to use for streaming. Above, it is "Profile1".
Note that wsse is a keyword indicating the pre-OASIS version.
Getting the stream URI
After getting the token name above, get the stream URI as follows.
factory = client.type_factory("http://www.onvif.org/ver10/schema")
transport = factory.Transport(Protocol='RTSP')
setup = factory.StreamSetup(Stream='RTP-Unicast', Transport=transport)
result = service.GetStreamUri(StreamSetup=setup, ProfileToken='Profile1')
print(result)
The result is printed as follows:
{
'Uri': 'rtsp://192.168.0.50:554/media/1/1/Profile1',
'InvalidAfterConnect': False,
'InvalidAfterReboot': True,
'Timeout': datetime.timedelta(0),
'_value_1': None,
'_attr_1': None
}
The list of Transport Protocols is as follows:
<xs:simpleType name="TransportProtocol">
<xs:restriction base="xs:string">
<xs:enumeration value="UDP"/>
<xs:enumeration value="TCP"/>
<xs:enumeration value="RTSP"/>
<xs:enumeration value="HTTP"/>
</xs:restriction>
</xs:simpleType>
The list of StreamSetup Streams is as follows:
<xs:simpleType name="StreamType">
<xs:restriction base="xs:string">
<xs:enumeration value="RTP-Unicast"/>
<xs:enumeration value="RTP-Multicast"/>
</xs:restriction>
</xs:simpleType>
Getting a snapshot
Call GetSnapshotUri with the profile token.
The following object is returned.
{
'Uri': 'http://192.168.0.50/snapshot/1/snapshot.jpg',
'InvalidAfterConnect': False,
'InvalidAfterReboot': False,
'Timeout': datetime.timedelta(0),
'_value_1': None,
'_attr_1': None
}
Open the URI above.
Code samples
- python-onvif-zeep - https://github.com/FalkTannhaeuser/python-onvif-zeep
- valkka - https://github.com/elsampsa/valkka-core
See also
- ONVIF
- zeep - (Python SOAP/WSDL Client)
- WSDiscovery - (Python WS-Discovery Library)
Favorite site
- [Recommended] ONVIF, SOAP, and web services 2 (ONVIF, SOAP)
- ONVIF Application Programmer's Guide (PDF) 3