EverNVR
Connects GEM to an EverNVR recorder over its HTTPS API. The driver reads the camera list, creates a camera zone per camera, plays live video, fetches live and recorded snapshots, lists recorded ranges, forwards PTZ moves and preset recalls, presses the recorder's button rules, and polls the recorder's events so a person or vehicle on a camera becomes zone state and flags GEM can act on.
It is a snapshot source for the Access Activity
investigation when an access device names it as its NVR, and is listed as evernvr
in the device driver reference.
Prerequisites
- An EverNVR recorder reachable from the GEM controller over HTTPS. The recorder's own certificate is accepted.
- An API token minted on the recorder (Settings → API), bound to the account GEM should act as. A read-only token bound to a viewer is enough for viewing and events; PTZ and button presses need a read-write token bound to an operator.
Live video
When the recorder has RTSP switched on (Settings → RTSP streams on the
recorder, EverNVR after 0.1.80), each zone plays the camera's own H.264 stream
through GEM's relay in video mode: the real frame rate and resolution, remuxed
rather than decoded, so no GPU is involved on the controller, and the recorder
serves it without opening another camera connection. In auto the zone plays
the camera's main stream when it is H.264, otherwise its sub stream when that is,
otherwise the main stream (H.265, which GEM shows as stills). The URL is RTSPS
when the recorder serves it, since it carries the token.
Without RTSP at the recorder, and for a camera with privacy masks (which the
recorder never serves over RTSP, because the masks are not drawn on it), the zone
plays the recorder's MJPEG: stills at the recorder's detection rate. Each zone's
stream_source says which it is and why. Reload the device after switching RTSP
on or off at the recorder.
Setup steps
- On the recorder, Settings → API → New token. Bind it to the account whose cameras GEM should see, and copy the secret; it is shown once.
- Admin → Devices → New, pick the EverNVR driver. Enter the recorder's
host, its port (
443unless it is published elsewhere) and the token. - Save the device. On connect it reads the camera list and creates one zone per
camera the token's account may see. Reload the device to pick up cameras added
later;
list_camerasprints what the recorder reports.
Attribute reference
Device — required
| Attribute | Type | Description |
|---|---|---|
ip | string | Recorder hostname or IP. |
token | string (secure) | API token from the recorder, starting evk_. |
Device — optional
| Attribute | Type | Default | Description |
|---|---|---|---|
port | int | 443 | The recorder's port. |
protocol | string | https | http only on a trusted network with a recorder on plain HTTP. |
status_interval | int (ms) | 3000 | How often /api/events is polled. Blank or 0 means 3000; anything under 1000 is read as 1000. |
rtsp_stream | string | auto | auto (see Live video), main or sub for that RTSP stream, or mjpeg to always play the recorder's MJPEG. |
After connecting the driver writes recorder_version, acts_as (the account and
role the token stands for) and camera_count on the device for reference.
Zone
Zones are created automatically, one per camera; the zone address is the
camera's id on the recorder. A camera the recorder lists without a name gets the label
Camera <id>. The driver syncs these on every connect:
| Attribute | Description |
|---|---|
stream_url | Live RTSP(S) or MJPEG URL with the token as the password. Stored encrypted; never sent to a browser. |
stream_mode | video for an RTSP stream, jpeg for MJPEG. |
stream_source | Which recorder stream the zone plays, such as rtsp main (h264, 1920x1080), or mjpeg: and the reason. |
has_ptz | true when the recorder can move the camera. |
resolution, encoding, device_model | From the recorder's recording profile and camera details. |
And these change as the recorder sees things:
| Attribute | Description |
|---|---|
state | motion while a visit is in progress, clear once the camera has no visit in progress (see Events for older recorders). |
person, car, truck, bus, motorcycle, bicycle, dog, cat, … | 1 while a visit of that kind is in progress, 0 when the last one ends. A visit the recorder relabels before it ends (car, then truck) clears the flag it began with too. On an older recorder a flag clears itself after 120 s, even if the visit is still in progress. |
last_motion | When the last visit began, epoch milliseconds. |
last_label | What the last visit was. |
last_who | The known name the recorder recognized, unrecognized, or blank when it did not judge. |
Commands
| Command | Notes |
|---|---|
snapshot | A JPEG from the recording at datetime, or the live frame with no time. Returns {data, mime} like the other camera drivers. |
thumbnail | The live frame. |
recordings | Recorded ranges between start and stop. |
get_events | Recent visits, newest first, for the zone or the whole recorder. |
web_link | A deep link to the recorder's playback at datetime, or its live view on the camera. A blank or unparseable time links to the live view. |
up / down / left / right, move | A half-second nudge through the recorder's PTZ; move takes direction (up, down, left, right, in, out). |
continuous_move | Velocities pan_speed, tilt_speed, zoom_speed from -1 to 1; the recorder stops the move itself after a short timeout. No velocities means stop. |
stop, zoom_in, zoom_out, center | center aims at a point in the picture, x and y from -1 to 1. |
get_presets, goto_preset, load_preset, home | Recall by name, token, or number in the camera's list. The recorder never creates presets; make them on the camera. |
get_buttons, press_button | The recorder's button rules the token may press. press_button matches the rule's id, label or name, case-insensitively; a blank name is refused (choose a button). |
Every time argument (datetime, start, stop) reads the same way: a number below 1e12 is
epoch seconds, a larger one epoch milliseconds, anything else is parsed as a date (ISO
works best). A blank, whitespace-only or out-of-range time counts as no time, so snapshot
returns the live frame and web_link the live view. recordings defaults stop to now and
start to one hour before stop. A blank address counts as none: the command uses the
zone's own camera, or answers camera address required when it has none.
The recorder never changes a camera's configuration, so there are no privacy-mask commands.
Events
The driver polls /api/events every status_interval and walks new visits oldest
first. On a recorder whose events carry updated_at (EverNVR releases after 0.1.69)
it follows changedSince, which reports each visit when it begins and again when it
ends, so a zone goes clear when the camera's last visit ends, even if newer visits
started in between. A visit that begins and ends between two polls still sets
last_motion and goes motion, then clear. An older recorder only reports visits
by when they began, so the driver misses the end of a visit once a newer one has
started, and takes any end it does see to mean the camera is clear. The driver
switches by itself once the recorder is updated. A poll never starts while the previous one
is still waiting for the recorder. When the recorder stops answering, or rejects the token,
the driver polls less often, doubling the gap up to once a minute, and logs the failure once;
the first answer brings it back to status_interval. A visit whose zone update fails to save
is tried again on the next poll, up to three times, then skipped with a warning so later visits
still arrive. Reaction time is the poll interval;
sub-second reaction would need the recorder's WebSocket feed, which the driver
deliberately does not hold open so a recorder restart never leaves a stale socket.
Troubleshooting
| Symptom | Check |
|---|---|
| The device stays disconnected with "rejected the API token" | The token was revoked on the recorder or its account lost access. Mint a new one. |
PTZ or press_button answers 403 | The token is read-only or bound to a viewer. Mint a read-write token bound to an operator. |
| Fewer zones than cameras | The token's account sees only some cameras; give it the rest under the recorder's Settings → Access and reload the device. |
| No live video | GEM's relay opens the stream URL from the controller itself; check the recorder is reachable from there (for RTSP, its RTSPS port, 8322 by default) and the token is live. Setting rtsp_stream to mjpeg and reloading rules RTSP out. |
| Live video is a slow series of stills | The zone plays MJPEG (see stream_source). Switch RTSP on at the recorder and reload the device. A camera with privacy masks stays on MJPEG. |
snapshot with a time answers 404 | No footage is kept for that moment, or the camera is in intelligence-only mode. |