Multiple Scenescape Deployment#
Smart NVR with Scenescape running on separate machines: Smart Intersection (SI) on System 1, NVR stack on System 2. For single-node deployment, see Integrate Scenescape with Smart NVR.
Overview#
Smart NVR maintains a persistent, independent MQTT connection to each SI node.
Events are tagged with the broker id to route them to the correct Frigate camera.
One entry per SI node. In
brokers.yaml,hostis the MQTT broker IP used at runtime;rtsp_hostandrtsp_portare the RTSP stream IP and port, read only bysetup.sh.Camera naming. Frigate cameras must be named
{broker_id}-camera{n}(e.g.si1-camera1). The brokeridmust match this prefix exactly. Theidcan use any prefix (si1,intersection_1, …) as long as it ends with the SI node number, a number from 1 to 20, whichsetup.shuses to pair the node with its RTSP settings.Brokers persist. On startup, the broker manager reads
brokers.yaml, seeds Redis, and starts one connection per enabled broker. The API persists changes back to this file.
Prerequisites#
VSS must be running and reachable from System 2.
See system requirements for hardware prerequisites.
Configuration#
brokers.yaml#
Edit resources/broker-config/brokers.yaml before starting, or manage brokers at
runtime via the API.
# resources/broker-config/brokers.yaml
brokers:
- id: si1 # Must match Frigate camera prefix: si1-camera*
name: Smart Intersection 1
host: <si1_mqtt_ip> # MQTT broker IP
port: 1883
topic: scenescape/data/camera/#
type: scenescape
throttle_interval: 2.0
enabled: true
rtsp_host: <si1_rtsp_ip> # RTSP source IP, read by setup.sh
rtsp_port: 8554 # RTSP source port, read by setup.sh
- id: si2
name: Smart Intersection 2
host: <si2_mqtt_ip>
port: 1883
topic: scenescape/data/camera/#
type: scenescape
throttle_interval: 2.0
enabled: true
rtsp_host: <si2_rtsp_ip>
rtsp_port: 8556 # Nodes can share an IP on different ports
TLS is enabled by default. Broker connections do not use username or password authentication.
Broker fields#
Field |
Required |
Default |
Description |
|---|---|---|---|
|
✅ |
— |
Unique identifier. Must match the Frigate camera name prefix (e.g. |
|
✅ |
— |
Human-readable label. |
|
✅ |
— |
MQTT broker IP address. |
|
✅ |
— |
MQTT topic to subscribe to. |
|
— |
|
MQTT broker port. |
|
— |
|
Event type. Always |
|
— |
|
Enable TLS. Set to |
|
— |
|
Minimum seconds between processed events. |
|
— |
|
Set to |
|
— |
— |
RTSP stream IP. Read by |
|
Required for |
— |
RTSP stream port (1–65535). Read by |
Environment variables#
Variable |
Required |
Default |
Description |
|---|---|---|---|
|
✅ |
— |
Must be |
|
✅ |
— |
VSS service IP. The single nginx proxy serves both summary and search. |
|
— |
|
VSS service port. |
|
— |
auto-generated |
Local Mosquitto username (Frigate ↔ NVR). |
|
— |
auto-generated |
Local Mosquitto password. |
|
— |
|
RTSP IP for si1. Overrides |
|
— |
|
RTSP IP for siN (N ≥ 2). Overrides |
|
— |
|
RTSP port for si1. Overrides |
|
— |
|
RTSP port for siN (N ≥ 2). Overrides |
|
— |
highest node number in |
Number of SI nodes to generate Frigate cameras for (max 20). |
|
— |
|
Local RTSP streamer port for |
|
— |
— |
Legacy: seeds si1 MQTT broker into Redis on startup. Prefer |
|
— |
|
Path to broker config file. |
|
— |
|
Maximum simultaneous in-flight event tasks. |
|
— |
|
Seconds before reconnecting after a broker disconnect. |
In the
SI*variables,Nis the node number: the trailing digits of the brokerid(for example,intersection_2is node 2, soSI2_RTSP_HOSTapplies to it).
Deployment#
System 1 — SI node(s)#
export NVR_SCENESCAPE=true
# export SI_RTSP_HOST=<external_rtsp_ip> # optional: use an external RTSP source
# export RTSP_STREAM_PORT=<port> # optional, default 8554
source setup.sh start-si
Downloads demo videos and starts a local MediaMTX RTSP streamer by default.
Setting SI_RTSP_HOST to a remote IP skips the local streamer.
On exit, the script prints System 1’s IP and MQTT port — use these when adding the broker on System 2.
System 2 — NVR node#
Populate brokers.yaml with host and rtsp_host for each SI node before starting.
export NVR_SCENESCAPE=true
export VSS_IP=<ip>
export VSS_PORT=<port> # optional, default 12345
# Optional: override brokers.yaml rtsp_host/rtsp_port for si1
# export SI_RTSP_HOST=<si1_rtsp_ip>
# export SI_RTSP_PORT=<si1_rtsp_port>
source setup.sh start-nvr
start-nvr reads the SI node count and RTSP IPs from brokers.yaml to generate the
Frigate camera list, and connects to the brokers listed in it. Brokers can still be
added later via POST /brokers/.
Note
Any SI node without an RTSP IP (rtsp_host or SI{N}_RTSP_HOST) is skipped with
a warning. start-nvr exits with an error only if no node has one.
Stop#
source setup.sh stop-nvr # System 2
source setup.sh stop-si # System 1
If a local RTSP streamer is running on System 1, stop-si prompts:
Local RTSP streamer is running. Stop it too? [y/N]
Respond y to stop it, or n to leave it running (source setup.sh stop-streamer
stops it independently).
RTSP Streamer#
To manage the MediaMTX RTSP streamer on System 1 independently of SI services.
start-streamer downloads demo videos if not already present, then starts the streamer.
source setup.sh start-streamer
source setup.sh stop-streamer
Managing brokers at runtime#
The /brokers/ API modifies live broker connections without restarting the stack.
Changes persist to brokers.yaml automatically.
BASE=http://localhost:8000
# List brokers
curl $BASE/brokers/
# Add a broker (starts MQTT connection immediately)
curl -X POST $BASE/brokers/ \
-H "Content-Type: application/json" \
-d '{
"id": "si3",
"name": "Smart Intersection 3",
"host": "<si3_mqtt_ip>",
"topic": "scenescape/data/camera/#",
"rtsp_host": "<si3_rtsp_ip>",
"rtsp_port": 8557
}'
# Update a broker (restarts its MQTT connection)
curl -X PUT $BASE/brokers/si3 \
-H "Content-Type: application/json" \
-d '{
"id": "si3",
"name": "SI 3 updated",
"host": "<si3_ip_updated>",
"topic": "scenescape/data/camera/#",
"enabled": true
}'
# Remove a broker (stops its MQTT connection)
curl -X DELETE $BASE/brokers/si3
Adding a broker via the API updates MQTT routing only. To record video from a new SI node, set its
rtsp_host, then re-runsetup.sh start-nvrto regenerate Frigate camera blocks.
Frigate camera configuration#
setup.sh generates resources/frigate-config/config.yml at startup. It reads the
SI node count from brokers.yaml (highest siN id), then appends 4 camera blocks
per node ({broker_id}-camera1 through camera4):
SI node |
RTSP IP source (in priority order) |
RTSP port source (in priority order) |
|---|---|---|
si1 |
|
|
si2..siN |
|
|
Invalid SI_RTSP_PORT/SI{N}_RTSP_PORT values are ignored with a warning. If every
node is skipped, start-nvr exits with an error. start-nvr also exits with an
error if a resolved node (has an rtsp_host) has no rtsp_port from either source.
Verify integration#
# Confirm all broker tasks started
docker logs nvr-event-router | grep "subscribed to"
# Expected:
# [si1] subscribed to scenescape/data/camera/# at <si1_ip>:1883
# [si2] subscribed to scenescape/data/camera/# at <si2_ip>:1883
# Monitor live events
docker logs nvr-event-router -f | grep "Scenescape event"
# Check reconnection attempts
docker logs nvr-event-router | grep "reconnecting"
Troubleshooting#
Broker connects but no events appear
Verify the broker
idmatches the Frigate camera prefix (e.g.id: si2→si2-camera1..4).Confirm SI is publishing to
scenescape/data/camera/#.
Ignoring broker id '...': it must end with a node number
The broker id in brokers.yaml must end with a number from 1 to 20 (for example si1 or
intersection_2). An id without a trailing number is skipped, and setup.sh start-nvr then fails
with No SI node has a resolvable rtsp_host. A number outside 1–20 is also ignored. Rename the id
(for example intersection → intersection_1) and re-run setup.sh start-nvr.
[siN] connection error: [Errno 111] Connect call failed
MQTT port unreachable. The broker manager retries automatically. Check connectivity:
nc -zv <siN_host> 1883
Frigate cameras show no recordings
RTSP IPs are written into config.yml at startup. If they changed, re-run
setup.sh start-nvr to regenerate the config.
UI shows no Scenescape source
docker exec nvr-event-router-ui env | grep NVR_SCENESCAPE
Confirm NVR_SCENESCAPE=true is exported in the shell running setup.sh start-nvr.
For general issues, see the Troubleshooting Guide.