A simple CLI tool to scan for ONVIF cameras on the local network. It uses WS-Discovery (UDP multicast) to discover devices, then queries the ONVIF Device Service to retrieve: manufacturer, model, serial number, firmware, and the RTSP URL.
- WS-Discovery multicast on the local subnet (automatic, no manual IP input)
- Device query — GetDeviceInformation + GetStreamUri (RTSP URL)
- Output as a table (pretty, default) or JSON (stdout / file)
--rtsp-onlyfilter — only show cameras that successfully returned an RTSP URL- Authenticated scan (
--username/--password) for cameras that require auth - Per-device error isolation — a single camera failing does not break the entire scan
cd onvif-scanner
# Development mode (recommended)
pip install -e .
# Or run directly from source without installing
python -m onvif-scanner --helpRequires Python 3.10+.
# Quick scan, pretty table output (default)
onvif-scan
# JSON to stdout
onvif-scan --output json
# Save to file
onvif-scan --output-file cameras.json
# Longer timeout (large / slow networks)
onvif-scan --timeout 10
# Authenticated scan (to get RTSP URLs from cameras that require auth)
onvif-scan --username admin --password secret
# Only show cameras that have an RTSP URL
onvif-scan --rtsp-only
# Debug logging (WS-Discovery + zeep)
onvif-scan --verbose{
"scan_time": "2026-07-19T10:00:00+07:00",
"scan_duration_seconds": 3.2,
"timeout_seconds": 5,
"camera_count": 2,
"cameras": [
{
"address": "192.168.1.100",
"device_url": "http://192.168.1.100/onvif/device_service",
"manufacturer": "Hikvision",
"model": "DS-2CD2143G2",
"firmware_version": "V5.6.5",
"serial_number": "DS-2CD2143G2-...-VVV111100",
"hardware_id": "880901",
"rtsp_url": "rtsp://192.168.1.100:554/Streaming/Channels/101",
"mac": null,
"scopes": ["onvif://www.onvif.org/Profile/Streaming"],
"authenticated": false,
"error": null
}
]
}| Symptom | Cause | Solution |
|---|---|---|
No ONVIF devices discovered |
Multicast UDP blocked by firewall / different VLAN | Make sure UDP port 3702 (multicast 239.255.255.250:3702) is allowed. The scan must run on the same subnet as the cameras. |
Camera discovered but rtsp_url: null |
Camera requires auth for the Media service | Use --username admin --password <pass> |
| Camera not discovered despite being online | ONVIF disabled in the camera's web UI | Enable ONVIF (Profile S) in the camera settings |
ImportError: wsdiscovery / onvif-zeep |
Dependencies not installed | Re-run pip install -e . |
| Scan is slow (>5s) | Large network / many devices | Increase --timeout 10, or add --rtsp-only to skip device queries |
| zeep error: WSDL download | onvif-zeep requires internet access on first run (to download WSDL) | Ensure internet connectivity, or bundle the WSDL locally and pass wsdl_dir in device.py |
Tested with: Hikvision, Dahua, generic ONVIF Profile S (Arducam, Reolink, Amcrest).
Standards: ONVIF Core Spec + Profile S (Streaming).
onvif_scanner/
├── cli.py # Click CLI + rich output (table/json/file)
├── discovery.py # WS-Discovery multicast via wsdiscovery lib
├── device.py # ONVIF Device Service query via onvif-zeep
└── models.py # dataclass DiscoveredDevice + Camera
Flow: cli.py → discovery.discover_cameras() (UDP multicast) → device.query_device() (HTTP SOAP per camera) → output (table/json/file).
- Multicast only (no unicast IP range probe for cross-VLAN discovery)
- Single username/password (no multi-credential support)
- No auto-registration to the parking DB (
camerastable) — aregistersubcommand could be added - No streaming preview (RTSP URL only, no frame preview)
MIT