Hikvision (ISAPI)
GEM controls Hikvision IP cameras and NVRs through the public ISAPI (Integrator Standard API) over HTTP/HTTPS with digest authentication. ISAPI is supported on essentially all modern Hikvision-branded firmware as well as several OEMs (LTS, Hilook, etc.).
For each camera or NVR you add one device; for each video channel you add one zone. A standalone IP camera is a single zone with address = 1.
Prerequisites
- A Hikvision device user account with at least Operator privilege.
- For PTZ commands, the user account must additionally have PTZ permission on the channel — Operator alone is not sufficient.
- ISAPI must be enabled on the device. It is enabled by default on all current firmware; some locked-down installs disable it.
Setup
- Add a new device of type Hikvision (ISAPI) under System → Devices.
- Set:
- Device IP — LAN IP of the camera or NVR.
- Username / Password — local device credentials. The password is stored as a secure attribute.
- Leave Port / Scheme at defaults (
80/http) for most installs. Switch tohttps(port443) if the device only exposes HTTPS.
- Save and reload. The driver will hit
/ISAPI/System/deviceInfoon connect; success is logged and the device is marked online. - Add zones:
- For an NVR, run
get_channelsfirst to enumerate input channels, then add a zone per channel withaddress = 1,2,3, … - For a single IP camera, one zone with
address = 1is enough.
- For an NVR, run
- Optionally set the zone-level
streamattribute tosubto use the lower-resolution stream for snapshots; default ismain.
Attribute reference
Device attributes
| Attribute | Required | Type | Default | Notes |
|---|---|---|---|---|
ip | yes | string | — | LAN IP of the camera or NVR |
username | yes | string | — | Local device account |
password | yes | string (secure) | — | Local device password |
port | no | int | 80 | TCP port for ISAPI (443 for HTTPS) |
scheme | no | enum | http | http or https |
auth_mode | no | enum | digest | Use basic only for very old firmware |
status_interval | no | int | 60000 | Liveness poll period (ms) |
Zone attributes
| Attribute | Required | Type | Notes |
|---|---|---|---|
address | yes | string | Channel number, e.g. 1, 2, 3 |
stream | no | enum (main/sub) | Picks ISAPI ddss stream id; defaults to main |
stream_url | no | string | Optional RTSP/HTTP URL for live preview widgets |
Channel id format
ISAPI uses a 3-digit ddss channel id in URLs, derived from the channel number:
| Human channel | Stream | ISAPI channel id |
|---|---|---|
| 1 | main | 101 |
| 1 | sub | 102 |
| 2 | main | 201 |
| 8 | main | 801 |
The driver converts your zone address (the human channel number) to the ddss form automatically. You only ever supply the human number.
Commands
| Command | Args | Notes |
|---|---|---|
snapshot | address | Returns {content_type: 'image/jpeg', base64: '…'}. Honors zone stream attribute. |
ptz_pan_tilt | address, pan, tilt | Continuous PTZ; pan/tilt are -100..100. |
ptz_zoom | address, zoom | Continuous zoom; -100..100. |
ptz_stop | address | Sends {pan:0, tilt:0, zoom:0} continuous PTZ to halt motion. |
ptz_preset | address, preset | Recall preset id 1-255. |
get_channels | — | NVR: lists /ISAPI/ContentMgmt/InputProxy/channels. IP camera: falls back to /ISAPI/Streaming/channels. |
get_device_info | — | Raw response of /ISAPI/System/deviceInfo (model, firmware, serial). |
Auth model
The driver uses HTTP digest authentication by default — opts.auth = {username, password, sendImmediately:false} against the shared generic_http base. The base library handles the 401 → digest handshake transparently.
If a device runs older firmware that only supports basic auth (you'll see WWW-Authenticate: Basic in the 401), set auth_mode to basic.
Connection and liveness
- On connect the driver reads
/ISAPI/System/deviceInfo. If the camera does not answer (powered off, unreachable, returning a server error), it tries again after 30 seconds, doubling the wait up to 5 minutes, so a camera that comes up after GEM does not need a manual reload. - If the camera refuses the credentials (HTTP 401) at connect, the driver does not retry: Hikvision locks the account after a few wrong attempts. Fix the username/password and reload the device.
- Once connected,
deviceInfois polled everystatus_intervalms (default 60000). After three failed polls in a row the wait doubles each time, up to 5 minutes (or the configured interval, if that is longer); the first successful poll returns to the normal interval. A blank, zero, negative or unreadablestatus_intervalmeans the 60 s default, and values under 1000 are treated as 1000. - A 401 marks the device offline; a 403 does not, because it usually means the account lacks PTZ permission on one channel rather than the device being down.
- With
schemeset tohttpsand noportattribute, the driver uses port 443. An unreadable or out-of-rangeportfalls back to the scheme's default with a warning in the log.
Replies treated as errors
- A PTZ write answered with an ISAPI
ResponseStatuswhosestatusCodeis not1(OK) or7(reboot required) returns an error naming the status, for exampleisapi status 4 (notSupport). - An HTML page answered with a 2xx status (a login page or another web server at that address) returns
unexpected html reply. - A
snapshotreply that is empty, or is an XML/HTML/JSON page instead of an image, returns an error instead of being passed on as a JPEG. - Zone addresses are matched after trimming spaces; an address that does not match one of the device's zones is refused before anything is sent.
Known limitations
- No event subscription yet.
/ISAPI/Event/notification/alertStream(long-lived chunked event push) is not wired in this driver. Liveness polling ondeviceInfois the only background traffic. - No motion / tampering / line-cross hooks. When events land, integrators will surface those as zone attributes.
- PTZ continuous self-stops on most firmware after a few seconds. Always issue
ptz_stopfor predictable behavior. - No relative PTZ. Only
continuousandpresetPTZ paths are exposed; relative PTZ (/ISAPI/PTZCtrl/channels/{id}/relative) is a future addition.
Troubleshooting
| Symptom | Likely cause |
|---|---|
All requests return 401 | Wrong credentials, account locked after repeated failures, or user lacks the Operator role. Hikvision locks accounts after ~5 wrong attempts. |
snapshot returns 404 | Zone address does not match an enabled input channel. Run get_channels to confirm. |
| PTZ commands return 403 | Operator privilege is not enough — the user account needs explicit PTZ permission on that channel. |
| Works on http but not https | Self-signed certs are tolerated by default. If https still fails, the device may only listen on the alternate port (commonly 443 vs 8443). |
| Sporadic timeouts on NVRs | NVRs can be slow under load; raise status_interval to reduce poll pressure. |
Wire format reference
GET /ISAPI/System/deviceInfo Authorization: Digest …
GET /ISAPI/ContentMgmt/InputProxy/channels (NVR)
GET /ISAPI/Streaming/channels (single camera fallback)
GET /ISAPI/Streaming/channels/101/picture → JPEG bytes
PUT /ISAPI/PTZCtrl/channels/101/continuous
<PTZData><pan>40</pan><tilt>0</tilt><zoom>0</zoom></PTZData>
PUT /ISAPI/PTZCtrl/channels/101/presets/3/goto