Configuration Guide
All configuration files use YAML format. There are two parts to the configuration of this system:
The Event Notification Server configuration — typically
/etc/zm/zmeventnotification.ymlThe Machine Learning Detection Hook configuration — typically
/etc/zm/objectconfig.yml
The ES comes with a sample ES config file which you should customize as fit. The sample config file is well annotated, so you really should read the comments to get an understanding of what each parameter does. Similarly, the ES also comes with a sample objectconfig.yml file which you should read as well if you are using hooks.
Note
If you are upgrading from an older version that used INI/JSON config files (zmeventnotification.ini,
objectconfig.ini, secrets.ini, es_rules.json), the install.sh script will automatically
migrate them to YAML. See Breaking Changes for details on the migration.
Secrets
Both zmeventnotification.yml and objectconfig.yml support a shared secrets mechanism that keeps
passwords and tokens out of your main config files. This lets you share config files safely without
exposing credentials.
Add a secrets key in the general section of either (or both) config files, pointing to a
secrets file. Then reference any secret by prefixing its name with !.
For example, in /etc/zm/objectconfig.yml (or /etc/zm/zmeventnotification.yml):
general:
secrets: /etc/zm/secrets.yml
portal: "!ZM_PORTAL"
user: "!ZM_USER"
password: "!ZM_PASSWORD"
And /etc/zm/secrets.yml contains:
secrets:
ZMES_PICTURE_URL: "https://mysecretportal/zm/index.php?view=image&eid=EVENTID&fid=objdetect&width=600"
ZM_USER: myusername
ZM_PASSWORD: mypassword
ZM_PORTAL: "https://mysecretportal/zm"
ZM_API_PORTAL: "https://mysecretportal/zm/api"
Any value starting with ! is treated as a secret token and replaced with the
corresponding value from the secrets file.
Secret resolution is recursive — tokens are resolved throughout the
entire config, including inside nested structures like ml_sequence
and stream_sequence. For example, you can use !ALPR_KEY inside
an ALPR model entry:
ml:
ml_sequence:
alpr:
sequence:
- alpr_key: "!ALPR_KEY"
Token matching is case-insensitive: !ZM_USER, !zm_user, and
!Zm_User all match a secret named ZM_USER (or zm_user).
Note
Because ! triggers secret lookup, you cannot use a password beginning with !
directly in the config. Instead, create a token in your secrets file and reference it.
Event Server Configuration
The Event Server is configured via /etc/zm/zmeventnotification.yml.
Key Sections
The file is organized into these sections:
general— secrets file path, base data path, ES control interface settings,skip_monitorsnetwork— WebSocket port and bind addressauth— ZoneMinder user/password authentication and timeoutfcm— Firebase Cloud Messaging for push notifications. Supports proxied delivery (default viafcm_v1_url) or direct delivery using a Google Service Account (fcm_service_account_file). Also controlsreplace_push_messages,fcm_android_priority,fcm_android_ttl,include_profile_in_push, and token storagemqtt— MQTT broker settings with optional TLS (one-way or mutual)ssl— SSL certificate/key for the WebSocket serverpush— third-party push API (e.g. Pushover) viaapi_push_scriptcustomize— event polling intervals, debug levels, picture URL, notification toggleshook— ML hook scripts, notification channel routing,max_parallel_hooks,tag_detected_objects, and user scripts
max_parallel_hooks (default 0 = unlimited) limits how many hook child
processes can run concurrently. When the limit is reached, new events wait until a
slot is free. This is useful for resource-constrained systems where too many
simultaneous ML detections can cause OOM or GPU contention.
Complete Reference
Every key accepted by zmeventnotification.yml, grouped by YAML section.
general — app-level settings
Key |
Default |
Description |
|---|---|---|
|
none |
Path to secrets YAML file for |
|
|
Base path for data directories and scripts |
|
|
Enable ES control interface for dynamic behaviour overrides |
|
|
File to persist ES control admin overrides |
|
none |
Password for accepting control interface connections |
|
|
Auto-restart ES after this many seconds ( |
|
none |
Comma-separated monitor IDs to completely skip ES processing |
network — WebSocket server
Key |
Default |
Description |
|---|---|---|
|
|
WebSocket listening port |
|
|
Bind address (use |
auth — authentication
Key |
Default |
Description |
|---|---|---|
|
|
Check username/password against ZoneMinder database |
|
|
Authentication timeout in seconds |
fcm — Firebase Cloud Messaging
Key |
Default |
Description |
|---|---|---|
|
|
Enable FCM push notifications |
|
|
Use FCM V1 protocol (recommended) |
|
|
Replace previous push for same monitor (collapses notifications) |
|
|
File to persist registered FCM tokens |
|
|
strftime format for notification timestamps |
|
|
Android push priority ( |
|
none |
Android message TTL in seconds (omit for FCM default) |
|
|
Log full push message on the cloud function (debugging only) |
|
|
Unique ID to identify your messages in cloud function logs |
|
(managed zmNinjaNG key) |
Authorization key for the FCM cloud function proxy |
|
(managed zmNinjaNG URL) |
URL of the FCM cloud function proxy |
|
|
Include profile name in push display (iOS subtitle, Android body append) |
|
none |
Path to Google service account JSON for direct FCM (bypasses proxy) |
mqtt — MQTT messaging
Key |
Default |
Description |
|---|---|---|
|
|
Enable MQTT notifications |
|
|
MQTT broker hostname or IP |
|
|
MQTT topic name |
|
none |
MQTT broker username |
|
none |
MQTT broker password |
|
|
Set retain flag on MQTT messages |
|
|
MQTT keep-alive interval in seconds |
|
none |
Path to CA certificate (enables MQTT over TLS) |
|
none |
Path to client certificate (for mutual TLS) |
|
none |
Path to client private key (for mutual TLS) |
|
|
Disable TLS peer verification |
ssl — WebSocket SSL
Key |
Default |
Description |
|---|---|---|
|
|
Enable SSL for the WebSocket server |
|
none |
Path to SSL certificate file |
|
none |
Path to SSL private key file |
push — third-party push API
Key |
Default |
Description |
|---|---|---|
|
|
Enable third-party push notifications (e.g. Pushover) |
|
none |
Script to invoke for push (receives event ID, monitor ID, name, cause, type, image path) |
customize — notification and display
Key |
Default |
Description |
|---|---|---|
|
none |
Path to ES rules YAML file for custom notification routing |
|
|
Display log messages to console |
|
|
Debug verbosity level for ES messages |
|
|
Seconds between event polling checks |
|
|
Seconds between monitor list reloads |
|
|
Read alarm cause from ZM (requires ZM >= 1.31.2) |
|
|
Append event ID to alarm notification title |
|
|
Use custom notification sound |
|
|
Include picture URL in push notifications |
|
none |
URL template for event images (use |
|
none |
Username for picture URL authentication |
|
none |
Password for picture URL authentication |
|
|
Send notifications when events start |
|
|
Send notifications when events end |
|
|
Master on/off switch for ML hooks |
hook — ML hook configuration
Key |
Default |
Description |
|---|---|---|
|
|
Maximum concurrent hook processes ( |
|
none |
Script to run when an event starts |
|
none |
Script to run when an event ends |
|
none |
User script to run after event start hook completes |
|
none |
User script to run after event end hook completes |
|
|
Notification channels when start hook returns 0 ( |
|
|
Notification channels when start hook returns 1 |
|
|
Notification channels when end hook returns 0 |
|
|
Notification channels when end hook returns 1 |
|
|
Only send end notification if start notification was sent |
|
|
Use hook script output as notification text |
|
none |
Comma-separated monitor IDs to skip hooks for |
|
none |
Pass image storage path to hook script (requires ZM >= 1.33) |
|
|
Write detected labels as ZM Tags (requires ZM >= 1.37.44) |
Detection Hook Configuration
The detection hooks are configured via /etc/zm/objectconfig.yml.
Key Sections
The file is organized into these sections:
general— ZM portal/API credentials, data paths, debug images,import_zm_zones,tag_detected_objects,show_modelspush— direct FCM push notifications fromzm_detect(Path 1 only, ZM 1.39.2+). See push_config below for setup details.remote— remote ML server (pyzm.serve) gateway URL, mode, credentials, fallbackml— the detection pipeline:ml.stream_sequence— frame selection:frame_set,resize, retry settingsml.ml_sequence.general— pipeline-wide settings:model_sequence,frame_strategy,disable_locks,match_past_detections,max_detection_size,aliasesml.ml_sequence.<type>— per-typegeneral+sequencelists for object, face, alpr, audio (see Machine Learning Hooks for full details)
monitors— per-monitor overrides forwait,ml_sequence,stream_sequence, andzones(withdetection_patternandignore_pattern)
Direct Push Notifications (push section)
The push section configures direct FCM push notifications
from zm_detect — Path 1 only, requires ZM 1.39.2+. zm_detect reads registered
tokens from ZM’s Notifications table via pyzmNg and sends push notifications through an
FCM cloud function proxy after detection.
Setup steps:
Ensure ZoneMinder is 1.39.2+ (adds the Notifications REST API).
Set
push.enabledtoyesinobjectconfig.yml. The cloud function URL and key are pre-configured with the managed zmNinjaNG defaults (same as the ES) — no additional configuration needed.Register device tokens: client apps (e.g. zmNinjaNG) register FCM tokens via the ZM
/api/notifications.jsonREST endpoint. Tokens are stored in ZM’sNotificationsdatabase table.
If you run your own FCM cloud function proxy, replace fcm_v1_url and
fcm_v1_key with your own values.
zm_detect respects per-token monitor filtering, throttle intervals,
and push state. Invalid tokens are automatically cleaned up.
By default, push notifications are only sent when detection finds a match.
If you use external sensor triggers and want a push even when ML detects
nothing, set push.send_push_on_no_match to yes. The event
cause/reason (e.g. “External Motion”) is used as the notification text.
Complete Reference
Every key accepted by objectconfig.yml, grouped by YAML section.
Keys not listed here will be logged as unrecognized and ignored.
Note
Several keys have been moved or removed in 7.x. See Breaking Changes for details on what changed and migration steps.
general — app-level settings
Consumed by zm_detect.py / utils.py:
Key |
Default |
Description |
|---|---|---|
|
none |
Path to secrets YAML file for |
|
|
Base path for model files and data directories |
|
|
ZoneMinder portal URL (e.g. |
|
|
ZoneMinder API URL (e.g. |
|
none |
ZoneMinder username |
|
none |
ZoneMinder password |
|
|
Accept self-signed SSL certificates |
|
|
Directory for detection images and past-detection files |
|
|
Dict of pyzmNg settings to override (e.g. |
|
|
Seconds to sleep before running detection |
|
|
Show confidence percentage in detection output |
|
|
Show model name in detection output (e.g. |
|
|
Show frame match prefix in detection output: |
|
|
Write annotated image back to ZoneMinder event |
|
|
Write a debug image with all detections to |
|
|
Write detected labels as ZM Tags (requires ZM >= 1.37.44) |
|
|
RGB color for polygon overlays on annotated images |
|
|
Line thickness for polygon overlays (pixels) |
|
|
Import zone definitions from ZoneMinder instead of using config zones |
|
|
When |
push — direct FCM push notifications
Direct push from zm_detect (Path 1 only, requires ZM 1.39.2+).
See push_config above for setup steps.
Key |
Default |
Description |
|---|---|---|
|
|
Enable direct FCM push notifications from |
|
(managed zmNinjaNG URL) |
URL of the FCM cloud function proxy. Replace only if you run your own. |
|
(managed zmNinjaNG key) |
Authorization key for the cloud function proxy. Replace only if you run your own. |
|
|
Collapse notifications per monitor (replaces previous push) |
|
|
Include event image URL in the notification |
|
none |
Picture URL template (use |
|
none |
Username for picture URL authentication |
|
none |
Password for picture URL authentication |
|
|
Include profile name in push display (iOS subtitle, Android body append) |
|
|
Send push notification even when detection finds no matches. Useful for external sensor triggers where you want a notification regardless of ML results. The event cause/reason is used as the notification text. |
|
|
FCM priority for Android ( |
|
none |
Android message TTL in seconds (omit for FCM default) |
remote — remote ML gateway settings
Forwarded to pyzmNg Detector:
Key |
Default |
Description |
|---|---|---|
|
none |
URL of remote |
|
|
|
|
none |
Username for remote gateway authentication |
|
none |
Password for remote gateway authentication |
|
|
Gateway request timeout in seconds |
|
|
Fall back to local detection if remote gateway fails |
ml.stream_sequence — frame extraction
Read by pyzmNg StreamConfig:
Key |
Default |
Description |
|---|---|---|
|
|
Comma-separated list of frames to extract ( |
|
none |
Resize frames to this width (pixels) before detection. Omit for original resolution. |
|
|
Maximum frames to extract ( |
|
|
First frame index to consider |
|
|
Process every Nth frame |
|
|
Contiguous frame errors before giving up |
|
|
Retries per frame on failure |
|
|
Seconds between retries |
|
|
Save extracted frames to disk |
|
|
Directory for saved frames |
|
|
When |
ml.ml_sequence.general — detection pipeline
Read by pyzmNg DetectorConfig:
Key |
Default |
Description |
|---|---|---|
|
|
Comma-separated model types to run ( |
|
|
How to pick the best frame: |
|
|
How to combine results from multiple models of the same type: |
|
|
Disable file-based locking for model execution |
|
|
Deduplicate static objects across successive detections |
|
|
Area difference threshold for past-detection matching |
|
— |
Per-label override (e.g. |
|
|
Labels to never deduplicate (e.g. |
|
none |
Maximum bounding box size to accept (pixels or percentage, e.g. |
|
|
Global regex pattern for accepted labels |
|
|
Groups of labels to treat as equivalent (e.g. |
ml.ml_sequence.<type> — per-type model settings
Each type (object, face, alpr, audio) has a general section for
overrides and a sequence list of model configurations. See Machine Learning Hooks for details
on model-specific keys (object_weights, face_detection_framework,
alpr_service, etc.).
monitors — per-monitor overrides
Any key from the sections above can be overridden per monitor. Dict values
(ml_sequence, stream_sequence) are deep-merged; scalar values are replaced.
See Machine Learning Hooks for zone configuration (detection_pattern, ignore_pattern).
Configuration Tools
Several tools are provided in the tools/ directory of the source tree:
tools/install_doctor.py— post-install diagnostic checker. Validates GPU/CUDA availability, OpenCV version, model file paths, file permissions, SSL certificates, and Perl/Python dependencies. Run automatically byinstall.shat the end of installation. See Path 1: Detection + Optional Push (no ES) for usage.tools/config_migrate_yaml.py— migratesobjectconfig.initoobjectconfig.ymltools/es_config_migrate_yaml.py— migrateszmeventnotification.iniandsecrets.inito their YAML equivalentstools/config_upgrade_yaml.py— merges new keys from example configs into your existing YAML config (used during upgrades to add new options without overwriting your settings)tools/config_edit.py— programmatic config editor
See Breaking Changes for details on the INI-to-YAML migration.