Axis VAPIX
Integration for Axis network devices over the VAPIX HTTP API — fixed and PTZ network cameras, network door stations / video intercoms (the I81xx, A8207-VE, I8016-LVE family and similar), and Axis I/O relay modules. One Axis unit becomes one GEM device. The driver moves PTZ cameras and recalls presets, grabs JPEG snapshots, drives the unit's relay outputs (one GEM zone each), turns privacy masking on and off, mutes and trims the device audio, and keeps a live WebSocket event feed open for I/O, motion, tampering, PIR, audio-trigger, and intercom keypad / PIN / card / call-button events.
Communication is HTTP or HTTPS to the device's /axis-cgi/* endpoints using digest authentication; live events ride a WebSocket on the same host. When you select https, the unit's self-signed certificate is accepted automatically.
What this integration covers
- PTZ control — pan, tilt, zoom (absolute, relative, and continuous "joystick" moves), stop, home, and recall / save / delete of the camera's stored presets.
- Snapshots — grab a JPEG still from the camera at a chosen resolution, compression, and (on multi-sensor units) camera channel, or return just the snapshot URL.
- Relay / I/O control — create one GEM zone per output port and drive it with
open/close/pulse.pulseis the usual "buzz the door open" action (momentarily energizes the strike relay, then releases). - Privacy masking — enable or disable all masks, add / update / remove individual masks, and list the masks currently defined.
- Audio control — mute or unmute the device's audio inputs and/or outputs and set the gain.
- Live events — I/O port changes, motion detection, video tampering, PIR, audio-trigger level, and — on intercoms — keypad PIN entry, RFID/card reads, and call-button presses arrive in real time and surface as device attributes you can build triggers and access logging on.
What this integration does NOT cover
- Continuous video / RTSP streaming. This driver controls the camera and pulls still snapshots; it is not a video recorder or live-stream transcoder. Wire the RTSP stream up separately where GEM consumes camera video.
- Call audio / video (SIP). On a network intercom the two-way voice and video call path runs over SIP through Axis's own apps or a SIP server; GEM monitors the call state and the call button but is not the call endpoint.
- Drawing the privacy mask geometry interactively. GEM can add masks by coordinates and toggle them, but the visual mask editor lives in the Axis device web UI.
Prerequisites
- A VAPIX user on the device with Operator rights for day-to-day control (PTZ, relays, snapshots, events). Administrator rights are required to create, save, or delete PTZ presets (
set_preset/remove_preset). - Digest authentication available on the account — modern AXIS OS firmware disables Basic auth by default, and this driver authenticates with digest.
- HTTP or HTTPS reachability from the GEM controller to the device. The live event feed also opens a WebSocket to the same host, so any firewall between GEM and the camera must allow it.
- For the intercom call-button, PIN, and card events: a network door station / video intercom running a firmware that emits the Axis Intercom event topics (verified against AXIS OS 11.x).
Setup
- In GEM, go to System → Devices → Add Device (Open Devices) and pick Axis VAPIX as the driver.
- Enter the device's Camera IP, Username, and Password (the password is stored encrypted).
- (Optional) Set Port (default 80) and switch Protocol to
httpsif the device requires TLS — when you do, the self-signed certificate is accepted automatically and the event feed upgrades to a secure WebSocket. - Save. The driver connects, runs a one-time I/O discovery (see below), and — unless you turn it off — opens the live event subscription.
- To control relays or a door strike, create one zone per output port, bound to this device, and set its
address(see Mapping I/O ports to zones). The driver does not create these zones for you. - (Optional) Leave Enable Event Subscription on to receive live events. Use Event Filters only if you want to narrow or change the default topic set (see Live events).
On connect the driver also reads the device's own I/O parameter table and auto-fills three read-only signal attributes so you don't have to know the magic port numbers:
- Call Button Port (
call_button_port) — the input port the device labels with Usage Button (an intercom call button). When that port goes active, the call workflow fires. - Door Relay Port (
door_relay_port) — the output port the device labels with Usage Door (the strike relay). Use this value as theaddressof your door zone. - Product Type (
product_type) — the Axis product family (e.g. "Network Video Intercom", "Network Camera"), used to gate intercom-specific behavior.
Discovery only fills these when they are not already set, so you can override any of them by editing the attribute. Setting Call Button Port to an empty string explicitly disables the call workflow.
This driver hints security / access / gate, but a stock GEM install seeds Security, Cameras, Doors, and Gates (not access, and gate is singular against the seeded plural Gates). Because the New Zone editor only pre-selects a subsystem on an exact name match, it pre-selects Security for a new Axis zone. Pick the subsystem that matches the job instead: Doors for a door-strike relay, Gates for a gate relay, Cameras for a camera/PTZ zone, or Security for an alarm/aux output. The subsystem choice sets how the zone's relay state is interpreted (door → locked/unlocked, gate → open/closed) and how it is grouped — it does not change whether the relay fires.
Mapping I/O ports to zones
Create one zone per controllable output and bind it to the Axis device. The zone address is the I/O port number the device exposes — the Door Relay Port value discovered at connect is the exact string to use for the strike relay. A door zone under Doors reports unlocked / locked; a gate zone under Gates reports open / closed.
| Command | Effect on the port | Resulting door-zone state |
|---|---|---|
close | Energizes the output (contact closed) | unlocked |
open | De-energizes the output (contact open) | locked |
pulse | Energizes, holds for delay ms, then releases | momentary unlock (returns to locked) |
open and close act on the relay contact, not directly on a lock state — the semantic state you see on the zone is derived from the subsystem (Doors invert: energized contact = unlocked). For a momentary buzz-in use pulse; its default hold is 500 ms, so for a usable door release set the delay argument higher (for example 3000 for a three-second unlock). If the relay fires the wrong way for your wiring, set the zone's Normally Closed toggle — it inverts both the command sent and the reported state.
The driver keeps a state attribute on each I/O zone, refreshed both by a status poll (every Status Poll Interval (ms), default 3000) and instantly whenever the device reports an I/O port change over the event feed. Camera / PTZ zones carry no relay state and are skipped by the poll — they are organizational; PTZ itself is driven by the commands below.
PTZ control
PTZ commands target a camera channel (the channel argument, default 1; multi-sensor or multi-view devices number their views 1, 2, …). You do not need a zone to move a camera — issue the command against the device from the Commands page, a macro, or a touchpanel button.
- Directional jog —
movewithdirectionset toup,down,left,right,upleft,upright,downleft,downright,home, orstop.stopandhomealso have their own commands. - Absolute / relative positioning —
pan,tilt, andzoomeach take eitherabsolute(go to a position) orrelative(nudge from the current position), plus an optionalspeed(1–100).ptzsetspan,tilt, andzoomto absolute positions in one command. - Joystick moves —
continuous_movetakespan_speedandtilt_speed(−100 to 100) and an optionalzoom_speed; the camera keeps moving until you sendstop. - Presets —
goto_presetrecalls a stored server preset bynameornumber(with optionalspeed).set_presetsaves the current position under aname(sethometo make it the home position), andremove_presetdeletes it byname. Saving and removing presets require an Administrator account. - Position read-back —
query_positionreturns the camera's current pan / tilt / zoom.
Snapshots
snapshot returns a base-64 JPEG still; snapshot_url returns just the image URL (useful when something else fetches the frame). Both accept optional resolution (e.g. 1920x1080), compression (0–100), and camera (the source number on a multi-sensor unit). On a call-button press the driver also captures a snapshot automatically through the Access Log workflow (see Door stations and the call button).
Privacy masking
enable_privacy/disable_privacyturn all privacy masks on or off.add_privacy_maskadds a mask. Setfullscreento cover the whole frame, or give a rectangle aswidth/height(percent of frame) andcenter("x,y"in percent, e.g."50,50"), or an arbitrarypolygonof pixel coordinates ("x1,y1:x2,y2:x3,y3:…").namelabels the mask andcolorsets its fill.update_privacy_maskchanges an existing mask (matched byname);remove_privacy_maskdeletes one byname;list_privacy_masksreturns the masks currently defined.
Audio control
On devices with audio, mute_audio / unmute_audio and set_audio_gain apply to the audio target — all (default), input, or output. set_audio_gain takes a gain value. get_audio_settings returns the device's current audio device structure (useful for confirming which inputs/outputs exist before muting one side).
Live events
When Enable Event Subscription is on (the default), the driver authenticates a WebSocket session and keeps a live event feed open, reconnecting automatically if it drops. It reflects what happens on the device onto device attributes — these are what you build automation triggers and access logging on:
| Attribute | Set when |
|---|---|
call_key / call_press | The call button is pressed — fires the call workflow (access-log entry + snapshot). call_key clears after ~1 second. |
call_state | An intercom call changes state (calling, ringing, established, terminated, …). |
pin | A PIN is entered at the keypad (or via DTMF during a SIP call). Clears after ~1 second. |
pin_granted | The device's entry-list validation result for the last PIN or card (true / false). |
rfid | An RFID / NFC card is presented. Clears after ~1 second so the same card re-triggers. |
last_credential_id / last_credential_source | The matched entry-list credential id and its source (PIN or Card) on a grant/deny. |
I/O port events update the bound zone's state instantly (no waiting for the next poll). The driver subscribes to a default topic set covering I/O ports, motion detection, audio trigger level, video tampering, PIR, and intercom events. Leave Event Filters blank to use that default set. To customize it, enter a JSON array of topic-filter objects, for example:
[{"topicFilter":"tns1:Device/tnsaxis:IO/Port"},{"topicFilter":"tns1:VideoAnalytics/tnsaxis:MotionDetection"}]
The Event Filters field hint reads "comma-separated," but the driver actually expects the JSON array shown above. A comma-separated value is rejected and the driver falls back to the default topic set rather than the topics you typed — so either leave it blank or supply valid JSON.
The start_events and stop_events commands open and close the same feed on demand (for example from a macro), and start_events accepts the same JSON filters argument.
Event feed health
The driver pings the WebSocket every 30 seconds; if the device stops answering (a switch reboot, PoE blip, or camera crash can kill the path without a clean close), it logs vapix event socket heartbeat timeout, drops the socket, and reconnects — so a doorbell or trigger fed by these events recovers on its own. Every connect, close, and reconnect is logged with the close code and the age of the last received event; when diagnosing "events stopped arriving" reports, grep the server logs for vapix event socket. Close code: 1006 is an abnormal network drop, code: 1000 is a device-initiated close (reboot or firmware update), and repeated reconnecting ... attempt: N lines mean the device is unreachable or out of WebSocket sessions.
Door stations and the call button
On an Axis network door station the call button is wired to a GPIO input (or arrives as an intercom CallState event). The driver auto-discovers the call-button port at connect, so on a fresh intercom this works with no manual configuration. When the button is pressed:
call_keyis settrue(and clears after ~1 second) andcall_pressis stamped with the moment of the press.- GEM's Access Control rules of type Call that are attached to this device fire. A call rule needs no credential — it logs the press to the Access Log with an automatic camera snapshot (so the visitor's face lands on the log and the facial-recognition pipeline can attempt an identification) and can run an action you choose, such as a chime macro or a push notification, subject to the rule's cooldown.
To wire this up, create a Call rule on the Access Control page pointing at this device. PIN and card events from an intercom with a keypad or reader surface as the pin / rfid / pin_granted attributes above, which you can drive triggers and macros from.
Commands
Relay / I/O
| Command | Args | What it does |
|---|---|---|
get_state | address | Reads the port and returns the semantic zone state. |
close | address | Energizes the output (contact closed). |
open | address | De-energizes the output (contact open). |
pulse | address, delay | Energizes, waits delay ms (default 500), then releases — the momentary door release. |
PTZ
| Command | Args | What it does |
|---|---|---|
move | channel, direction | Directional jog (up/down/left/right/diagonals/home/stop). |
stop | channel | Stops movement. |
home | channel | Returns to the home position. |
pan | channel, absolute, relative, speed | Pans to an absolute or relative position. |
tilt | channel, absolute, relative, speed | Tilts to an absolute or relative position. |
zoom | channel, absolute, relative, speed | Zooms to an absolute or relative position. |
ptz | channel, pan, tilt, zoom, speed | Sets pan/tilt/zoom to absolute positions in one call. |
continuous_move | channel, pan_speed, tilt_speed, zoom_speed | Joystick move; speeds −100…100; send stop to halt. |
goto_preset | channel, name, number, speed | Recalls a stored preset by name or number. |
set_preset | name, home | Saves the current position as a preset (Administrator only). |
remove_preset | name | Deletes a preset (Administrator only). |
query_position | channel | Returns current pan / tilt / zoom. |
Privacy, audio, snapshots, events, info
| Command | Args | What it does |
|---|---|---|
enable_privacy / disable_privacy | — | Turns all privacy masks on / off. |
add_privacy_mask | name, color, fullscreen, width, height, center, polygon | Adds a privacy mask. |
update_privacy_mask | name, color, width, height, center, polygon | Updates an existing mask. |
remove_privacy_mask | name | Removes a mask by name. |
list_privacy_masks | — | Lists the masks currently defined. |
mute_audio / unmute_audio | target | Mutes / unmutes audio (all / input / output). |
set_audio_gain | gain, target | Sets the audio gain. |
get_audio_settings | — | Returns the device's audio device structure. |
snapshot | resolution, compression, camera | Returns a base-64 JPEG still. |
snapshot_url | resolution, compression, camera | Returns the snapshot URL only. |
start_events / stop_events | filters | Opens / closes the live event feed (filters is the same JSON array). |
device_info | — | Returns the device's full property set (model, firmware, serial, …). |
Attribute reference
Device attributes
| Name | Type | Required | Description |
|---|---|---|---|
ip | string | yes | Device IP address. |
username | string | yes | VAPIX account username. |
password | string | yes | VAPIX account password. Stored encrypted. |
port | int | no | HTTP(S) port (default 80). |
protocol | string | no | http or https (default http). |
status_interval | int | no | I/O zone poll interval in ms (default 3000). |
enable_events | bool | no | Open the live event WebSocket (default true). |
event_filters | string | no | JSON array of topic-filter objects; blank = default topic set. |
call_button_port | string | no | Input port wired to the call button. Auto-discovered; blank disables the call workflow. |
door_relay_port | string | no | Output port wired to the strike relay. Auto-discovered; use as the door zone address. |
product_type | string | no | Axis product family. Auto-discovered, read-only. |
The driver also writes live device attributes as events arrive: call_key, call_press, call_state, pin, pin_granted, rfid, last_credential_id, and last_credential_source (see Live events).
Zone attributes
| Name | Type | Description |
|---|---|---|
address | string | I/O port number for relay/door zones (or camera channel for PTZ zones). Required. |
normally_closed | bool | Invert the command and reported state for NC wiring (default false). |
state | string | Semantic zone state (locked/unlocked, open/closed, …), maintained by the driver. Cataloged, so it autocompletes in the Attribute editor and can drive attribute triggers. |
Troubleshooting
- Every request returns 401 Unauthorized — verify the account has at least Operator rights, and that Digest authentication is available on the device. Modern AXIS OS firmware disables Basic auth by default, and this driver uses digest.
set_preset/remove_presetfail but PTZ moves work — saving and deleting presets requires an Administrator account; an Operator can recall presets but not manage them.- Live events never arrive — confirm Enable Event Subscription is on, that the firewall allows the WebSocket to the device, and (for PIN/card/call events) that the unit is a door station whose firmware emits the Axis Intercom event topics. If you set custom Event Filters, make sure the value is a valid JSON array (a comma-separated string is rejected and falls back to the defaults).
- The relay fires the wrong way (locks when it should release, or vice-versa) — flip the zone's Normally Closed toggle to match NC vs NO wiring, and use
pulse(with adelaylong enough to be useful) for a momentary buzz-in rather than a steadyclose. - The door zone addresses the wrong port — use the auto-discovered Door Relay Port value as the zone
address. Axis port numbering can differ between the parameter list and the control endpoint on some firmware, so ifopen/closehits the wrong output, try the adjacent port number. - The call button does nothing — make sure Call Button Port is set (it auto-discovers from a port labeled Usage Button; an empty value means it is explicitly disabled), and create a Call rule for this device on the Access Control page.
Related documentation
- Devices — adding and configuring the Axis device row.
- Zones — creating one zone per I/O port (or camera channel) and binding it to the device.
- Subsystems — the Doors / Gates / Cameras / Security subsystem the zones belong to.
- Commands — running these commands from the admin UI, macros, or scenes.
- Access Control — the Call rule that turns a call-button press into a logged, snapshotted event with an action.
- Access Log — where call-button presses and credential events are recorded.
- ONVIF — the protocol-level page for cameras integrated over the vendor-neutral ONVIF standard rather than Axis VAPIX.