@apocaliss92/scrypted-onvif-rebroadcast 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -4
- package/dist/plugin.zip +0 -0
- package/docs/unique-ip-setup.md +187 -0
- package/package.json +1 -1
- package/.vscode/launch.json +0 -23
- package/.vscode/settings.json +0 -4
- package/.vscode/tasks.json +0 -20
- package/src/cameraMixin.ts +0 -419
- package/src/main.ts +0 -107
- package/src/onvifServer.ts +0 -1324
- package/src/types.ts +0 -41
package/README.md
CHANGED
|
@@ -1,8 +1,101 @@
|
|
|
1
1
|
# Scrypted ONVIF Rebroadcast
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Creates virtual ONVIF-compliant camera devices from Scrypted's RTSP rebroadcast streams, enabling third-party NVRs like **UniFi Protect** to adopt cameras that aren't natively supported.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Wraps Scrypted RTSP rebroadcast streams in ONVIF Profile S endpoints
|
|
8
|
+
- **Unique IP & MAC per camera** via Docker macvlan proxy containers (required for UniFi Protect)
|
|
9
|
+
- Automatic Docker network and proxy container management
|
|
10
|
+
- WS-Discovery for ONVIF auto-detection
|
|
11
|
+
- PTZ, motion events, and object detection forwarded via ONVIF
|
|
12
|
+
- WS-Security and HTTP Basic authentication
|
|
13
|
+
- Persistent IP assignments across restarts
|
|
14
|
+
|
|
15
|
+
## UniFi Protect Setup
|
|
16
|
+
|
|
17
|
+
UniFi Protect identifies third-party cameras by MAC address. To add multiple cameras, each needs a unique IP and MAC on the network. This plugin handles this automatically using Docker macvlan proxy containers.
|
|
18
|
+
|
|
19
|
+
### Prerequisites
|
|
20
|
+
|
|
21
|
+
- Scrypted running in Docker with the **Rebroadcast plugin** installed
|
|
22
|
+
- Docker socket mounted in the Scrypted container (`/var/run/docker.sock`)
|
|
23
|
+
- A network interface available for macvlan (e.g. `br0`)
|
|
24
|
+
|
|
25
|
+
### Docker Socket
|
|
26
|
+
|
|
27
|
+
The plugin needs access to the Docker socket to create proxy containers. Add this path mapping to your Scrypted container:
|
|
28
|
+
|
|
29
|
+
| Container Path | Host Path |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `/var/run/docker.sock` | `/var/run/docker.sock` |
|
|
32
|
+
|
|
33
|
+
### Plugin Settings
|
|
34
|
+
|
|
35
|
+
| Setting | Description | Example |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| **Username / Password** | ONVIF authentication credentials | `admin` / `password` |
|
|
38
|
+
| **Auto-assign unique IPs** | Enable automatic proxy container creation | `true` |
|
|
39
|
+
| **IP range start** | First IP to assign to cameras | `192.168.1.240` |
|
|
40
|
+
| **Network interface** | Parent interface for the macvlan Docker network | `br0` |
|
|
41
|
+
| **Subnet prefix length** | CIDR prefix for the macvlan network | `23` |
|
|
42
|
+
| **Gateway** | Default gateway for the macvlan network | `192.168.1.1` |
|
|
43
|
+
|
|
44
|
+
### IP Range Selection
|
|
45
|
+
|
|
46
|
+
Choose IPs **outside your DHCP pool** on the same subnet as your UniFi controller. For example, if your router assigns `192.168.1.2-200` via DHCP, use `192.168.1.240` as the start.
|
|
5
47
|
|
|
6
|
-
|
|
48
|
+
### How It Works
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
UniFi Protect Docker macvlan proxy Scrypted container
|
|
52
|
+
(192.168.1.x) (192.168.1.240, unique MAC) (192.168.4.40)
|
|
53
|
+
| | |
|
|
54
|
+
|--- ONVIF (port 8000) ---------->|--- TCP proxy (port 18000) --->| ONVIF server
|
|
55
|
+
|--- RTSP (port 554) ---------->|--- TCP proxy (port 42917) -->| RTSP rebroadcast
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Each camera gets its own proxy container with:
|
|
59
|
+
- A unique IP address on your LAN
|
|
60
|
+
- A unique MAC address (deterministic, based on device ID)
|
|
61
|
+
- TCP proxies for both ONVIF (port 8000) and RTSP (port 554+) traffic
|
|
62
|
+
|
|
63
|
+
### Adding Cameras in UniFi Protect
|
|
64
|
+
|
|
65
|
+
1. Install and configure the plugin in Scrypted
|
|
66
|
+
2. Enable "Auto-assign unique IPs" and configure the IP range
|
|
67
|
+
3. The plugin automatically creates proxy containers (visible in Docker)
|
|
68
|
+
4. In UniFi Protect: **Settings > Cameras > Add Camera > ONVIF**
|
|
69
|
+
5. Enter each camera's assigned IP with port `8000`
|
|
70
|
+
6. Enter the ONVIF username/password you configured
|
|
71
|
+
|
|
72
|
+
### Unraid Notes
|
|
73
|
+
|
|
74
|
+
- If your Scrypted container uses `Custom: br0.2` (ipvlan), create the macvlan network on `br0` instead to get unique MACs
|
|
75
|
+
- The plugin creates a Docker network called `onvif_cameras` for the proxy containers
|
|
76
|
+
- Proxy containers are named `onvif-proxy-{deviceId}` and auto-restart
|
|
77
|
+
- The `alpine/socat` image is pulled automatically on first use
|
|
78
|
+
|
|
79
|
+
## Architecture
|
|
80
|
+
|
|
81
|
+
The plugin is a Scrypted **MixinProvider** that attaches to Camera and Doorbell devices:
|
|
82
|
+
|
|
83
|
+
1. **Stream Discovery** - Finds RTSP rebroadcast URLs from the Rebroadcast plugin
|
|
84
|
+
2. **ONVIF Server** - Creates an HTTP server per camera serving ONVIF SOAP endpoints
|
|
85
|
+
3. **Proxy Containers** - Spawns Docker containers with macvlan networking for unique IPs/MACs
|
|
86
|
+
4. **Event Forwarding** - Scrypted motion/detection events are forwarded via ONVIF pull-point subscriptions
|
|
87
|
+
|
|
88
|
+
## Development
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install
|
|
92
|
+
npm run build
|
|
93
|
+
npx scrypted login <scrypted-ip>
|
|
94
|
+
npm run scrypted-deploy <scrypted-ip>
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
[Buy me a coffee!](https://buymeacoffee.com/apocaliss92)
|
|
7
100
|
|
|
8
|
-
[For requests and bugs](https://github.com/apocaliss92/scrypted-onvif-rebroadcast)
|
|
101
|
+
[For requests and bugs](https://github.com/apocaliss92/scrypted-onvif-rebroadcast/issues)
|
package/dist/plugin.zip
ADDED
|
Binary file
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Unique IP / MAC Setup for UniFi Protect
|
|
2
|
+
|
|
3
|
+
UniFi Protect identifies third-party ONVIF cameras by **MAC address**. When multiple virtual cameras share the same host MAC, UniFi sees them as a single device. This guide explains how to configure unique IPs and MACs for each camera so UniFi Protect adopts them as separate devices.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Scrypted running in Docker with the **Rebroadcast** plugin installed
|
|
8
|
+
- Docker socket mounted in the Scrypted container (`/var/run/docker.sock`)
|
|
9
|
+
- A network bridge interface available for macvlan (e.g. `br0`)
|
|
10
|
+
|
|
11
|
+
## How It Works
|
|
12
|
+
|
|
13
|
+
The plugin creates a **Docker macvlan network** and spawns a lightweight **proxy container** (`alpine/socat`) for each camera. Each proxy has:
|
|
14
|
+
|
|
15
|
+
- A **unique IP address** on your LAN
|
|
16
|
+
- A **unique MAC address** (deterministic, based on device ID)
|
|
17
|
+
- TCP proxies for **ONVIF** (port 8000) and **RTSP** (port 554+) traffic
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
UniFi Protect Docker macvlan proxy Scrypted container
|
|
21
|
+
(your LAN) (unique IP + MAC) (internal IP)
|
|
22
|
+
│ │ │
|
|
23
|
+
│── ONVIF (port 8000) ───────▶│── TCP proxy ─────────────────▶│ ONVIF server
|
|
24
|
+
│── RTSP (port 554) ───────▶│── TCP proxy ─────────────────▶│ RTSP rebroadcast
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Step 1: Mount Docker Socket
|
|
28
|
+
|
|
29
|
+
The plugin needs access to Docker to create proxy containers. Add this path mapping to your Scrypted container:
|
|
30
|
+
|
|
31
|
+
| Container Path | Host Path |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `/var/run/docker.sock` | `/var/run/docker.sock` |
|
|
34
|
+
|
|
35
|
+
### Unraid
|
|
36
|
+
Edit the Scrypted container → Add Path → Container: `/var/run/docker.sock`, Host: `/var/run/docker.sock`
|
|
37
|
+
|
|
38
|
+
### Docker Compose
|
|
39
|
+
```yaml
|
|
40
|
+
volumes:
|
|
41
|
+
- /var/run/docker.sock:/var/run/docker.sock
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Docker CLI
|
|
45
|
+
```bash
|
|
46
|
+
docker run ... -v /var/run/docker.sock:/var/run/docker.sock ...
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Step 2: Configure Plugin Settings
|
|
50
|
+
|
|
51
|
+
Open the ONVIF Rebroadcast plugin settings in Scrypted and configure the **IP Allocation** section:
|
|
52
|
+
|
|
53
|
+
| Setting | Description | Example |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| **Auto-assign unique IPs** | Enable automatic proxy container creation | `✓` (checked) |
|
|
56
|
+
| **IP range start** | First IP to assign (must be on the same subnet as your NVR) | `192.168.1.240` |
|
|
57
|
+
| **Network interface** | Parent interface for the macvlan Docker network | `br0` |
|
|
58
|
+
| **Subnet prefix length** | CIDR prefix matching your network | `23` or `24` |
|
|
59
|
+
| **Gateway** | Your network's default gateway | `192.168.1.1` |
|
|
60
|
+
|
|
61
|
+
### Choosing the Right IP Range
|
|
62
|
+
|
|
63
|
+
- Pick IPs **outside your DHCP pool** to avoid conflicts
|
|
64
|
+
- IPs must be on the **same subnet** as your UniFi controller
|
|
65
|
+
- Example: if your router's DHCP range is `192.168.1.2–200`, use `192.168.1.240` as the start
|
|
66
|
+
- Each camera gets the next sequential IP (`.240`, `.241`, `.242`, etc.)
|
|
67
|
+
|
|
68
|
+
### Choosing the Network Interface
|
|
69
|
+
|
|
70
|
+
| Platform | Interface | Notes |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| Unraid (ipvlan on br0.2) | `br0` | Use the main bridge, not the VLAN interface |
|
|
73
|
+
| Docker (bridge network) | `eth0` or `br0` | Check `ip link show` on your host |
|
|
74
|
+
| Synology | `ovs_eth0` or `bond0` | Depends on your network config |
|
|
75
|
+
|
|
76
|
+
> **Important (Unraid):** If your Scrypted container uses `Custom: br0.2` (ipvlan), set the network interface to `br0` — not `br0.2`. ipvlan networks share MAC addresses and won't work with UniFi. The plugin creates a separate macvlan network on `br0` for the proxy containers.
|
|
77
|
+
|
|
78
|
+
## Step 3: Reload the Plugin
|
|
79
|
+
|
|
80
|
+
After saving the settings, reload the ONVIF Rebroadcast plugin. Check the logs for:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Docker socket found — proxy container mode available
|
|
84
|
+
Created macvlan network on br0 (192.168.0.0/23)
|
|
85
|
+
Proxy container onvif-proxy-133: IP=192.168.1.241 MAC=02:cc:30:40:1c:d7 → 192.168.4.40:18000
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Each camera should show its assigned IP and MAC.
|
|
89
|
+
|
|
90
|
+
## Step 4: Add Cameras in UniFi Protect
|
|
91
|
+
|
|
92
|
+
1. Open **UniFi Protect**
|
|
93
|
+
2. Go to the **Devices** list view
|
|
94
|
+
3. Click the **?** icon (help/question mark) next to the view toggle buttons
|
|
95
|
+
4. Click **"Can't Find Your Device?"**
|
|
96
|
+
5. Enter each camera's assigned IP with port **8000** (e.g. `192.168.1.240`)
|
|
97
|
+
6. Enter the ONVIF username and password (configured in the plugin's Authentication settings)
|
|
98
|
+
7. The camera will appear in the device list as a third-party camera (shown with the ONVIF icon)
|
|
99
|
+
8. Click **"Click to Adopt"** to add it
|
|
100
|
+
|
|
101
|
+
Repeat for each camera IP. Each will be recognized as a separate device with its own unique MAC.
|
|
102
|
+
|
|
103
|
+
> **Note:** UniFi will display the camera's actual model number (e.g. "Reolink CX410") as reported by the ONVIF device information.
|
|
104
|
+
|
|
105
|
+
## Step 5: Verify
|
|
106
|
+
|
|
107
|
+
You can verify the proxy containers are running:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
docker ps | grep onvif
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Test connectivity from any device on your network:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
curl -s http://192.168.1.240:8000/onvif/device_service -d '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"><s:Body><GetSystemDateAndTime xmlns="http://www.onvif.org/ver10/device/wsdl"/></s:Body></s:Envelope>'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Troubleshooting
|
|
120
|
+
|
|
121
|
+
### "Docker socket not found"
|
|
122
|
+
Mount `/var/run/docker.sock` in the Scrypted container. See Step 1.
|
|
123
|
+
|
|
124
|
+
### "Failed to create macvlan network: Pool overlaps"
|
|
125
|
+
A Docker network already exists on the same subnet. The plugin will try to find and reuse existing macvlan networks automatically. If it fails, check `docker network ls` and remove stale `onvif_cameras` networks.
|
|
126
|
+
|
|
127
|
+
### Proxy containers not reachable
|
|
128
|
+
- Ensure the IP range is on the **same subnet** as the device trying to connect
|
|
129
|
+
- Check that the **gateway** is correct
|
|
130
|
+
- Verify the **network interface** exists on the Docker host (`ip link show`)
|
|
131
|
+
|
|
132
|
+
### UniFi still shows one camera
|
|
133
|
+
- Confirm proxy containers have unique MACs: `docker inspect onvif-proxy-XXX | grep MacAddress`
|
|
134
|
+
- Remove all existing cameras from UniFi Protect before re-adding
|
|
135
|
+
- The macvlan network must be `macvlan` driver (not `ipvlan`) — check with `docker network inspect onvif_cameras | grep Driver`
|
|
136
|
+
|
|
137
|
+
### Cameras added but no video
|
|
138
|
+
- Check that the Rebroadcast plugin is installed and the camera has RTSP streams configured
|
|
139
|
+
- The RTSP stream URLs are automatically proxied through port 554+ on each camera's IP
|
|
140
|
+
- Verify the RTSP URL works: connect to `rtsp://camera-ip:554/stream-path` with VLC
|
|
141
|
+
|
|
142
|
+
### IP assignments change after restart
|
|
143
|
+
- IP assignments are persistent — stored in Scrypted's plugin storage
|
|
144
|
+
- Once a camera gets an index, it keeps the same IP forever
|
|
145
|
+
- New cameras get the next available index
|
|
146
|
+
|
|
147
|
+
## Architecture Details
|
|
148
|
+
|
|
149
|
+
### Proxy Container Lifecycle
|
|
150
|
+
|
|
151
|
+
- Containers are named `onvif-proxy-{deviceId}`
|
|
152
|
+
- Restart policy: `unless-stopped` (auto-restart on crash)
|
|
153
|
+
- Image: `alpine/socat` (pulled automatically on first use, ~5MB)
|
|
154
|
+
- Each container runs multiple `socat` instances:
|
|
155
|
+
- Port 8000 → Scrypted ONVIF server (internal port)
|
|
156
|
+
- Port 554 → Scrypted RTSP rebroadcast stream 1
|
|
157
|
+
- Port 555 → stream 2, etc.
|
|
158
|
+
|
|
159
|
+
### MAC Address Generation
|
|
160
|
+
|
|
161
|
+
Each camera gets a deterministic MAC address derived from its Scrypted device ID:
|
|
162
|
+
- Format: `02:xx:xx:xx:xx:xx` (locally administered, unicast)
|
|
163
|
+
- Same device ID always produces the same MAC
|
|
164
|
+
- Survives plugin restarts and container recreation
|
|
165
|
+
|
|
166
|
+
### Network Topology
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
┌─────────────────────────────────────────────────────────┐
|
|
170
|
+
│ Docker Host │
|
|
171
|
+
│ │
|
|
172
|
+
│ ┌──────────────┐ ┌──────────────────────────────┐ │
|
|
173
|
+
│ │ Scrypted │ │ onvif_cameras network │ │
|
|
174
|
+
│ │ Container │ │ (macvlan on br0) │ │
|
|
175
|
+
│ │ │ │ │ │
|
|
176
|
+
│ │ ONVIF:18000 │◄────│ Proxy 1: 192.168.1.240:8000 │ │
|
|
177
|
+
│ │ ONVIF:18001 │◄────│ Proxy 2: 192.168.1.241:8000 │ │
|
|
178
|
+
│ │ RTSP:42917 │◄────│ Proxy 1: 192.168.1.240:554 │ │
|
|
179
|
+
│ │ RTSP:43218 │◄────│ Proxy 2: 192.168.1.241:554 │ │
|
|
180
|
+
│ │ │ │ │ │
|
|
181
|
+
│ │ br0.2 ipvlan│ │ Each proxy has unique MAC │ │
|
|
182
|
+
│ │ 192.168.4.40│ │ │ │
|
|
183
|
+
│ └──────────────┘ └──────────────────────────────┘ │
|
|
184
|
+
│ │
|
|
185
|
+
│ br0 ──── Physical NIC ──── Switch ──── UniFi Protect │
|
|
186
|
+
└─────────────────────────────────────────────────────────┘
|
|
187
|
+
```
|
package/package.json
CHANGED
package/.vscode/launch.json
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// Use IntelliSense to learn about possible attributes.
|
|
3
|
-
// Hover to view descriptions of existing attributes.
|
|
4
|
-
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
-
"version": "0.2.0",
|
|
6
|
-
"configurations": [
|
|
7
|
-
{
|
|
8
|
-
"name": "Scrypted Debugger",
|
|
9
|
-
"address": "${config:scrypted.debugHost}",
|
|
10
|
-
"port": 10081,
|
|
11
|
-
"request": "attach",
|
|
12
|
-
"skipFiles": [
|
|
13
|
-
"**/plugin-remote-worker.*",
|
|
14
|
-
"<node_internals>/**"
|
|
15
|
-
],
|
|
16
|
-
"preLaunchTask": "scrypted: deploy+debug",
|
|
17
|
-
"sourceMaps": true,
|
|
18
|
-
"localRoot": "${workspaceFolder}/out",
|
|
19
|
-
"remoteRoot": "/plugin/",
|
|
20
|
-
"type": "node"
|
|
21
|
-
}
|
|
22
|
-
]
|
|
23
|
-
}
|
package/.vscode/settings.json
DELETED
package/.vscode/tasks.json
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
|
3
|
-
// for the documentation about the tasks.json format
|
|
4
|
-
"version": "2.0.0",
|
|
5
|
-
"tasks": [
|
|
6
|
-
{
|
|
7
|
-
"label": "scrypted: deploy+debug",
|
|
8
|
-
"type": "shell",
|
|
9
|
-
"presentation": {
|
|
10
|
-
"echo": true,
|
|
11
|
-
"reveal": "silent",
|
|
12
|
-
"focus": false,
|
|
13
|
-
"panel": "shared",
|
|
14
|
-
"showReuseMessage": true,
|
|
15
|
-
"clear": false
|
|
16
|
-
},
|
|
17
|
-
"command": "npm run scrypted-vscode-launch ${config:scrypted.debugHost}",
|
|
18
|
-
},
|
|
19
|
-
]
|
|
20
|
-
}
|