ONVIF PTZ proxy service

This is a service that allows to quickly switch a single PTZ remote control between several rooms with ONVIF cameras.

The service is based on the fastapi framework and the onvif-zeep-async library and is a SOAP proxy server with the substitution of authorization data, URL and other fields of the ONVIF protocol.

The service contains Web UI written on Vue3 and RTSP server to avoid conflicts with client programs.

Before begin

Dependencies need to be loaded:

git submodule update --init --recursive

Backend configuration (master-service)

Backend/config.py is used for configuration.

Login service

Separated auth provider is used for API and WebUI access limitation.

Login service should to be launched in separate docker-container without port-forwarding to the host network. This will improve the security of the system.

The auth service could be found in the GitLab repository, but it already included in this project.

login_service = {
    'host': 'ptz-proxy-login',
    'port': 8080,
    'ssl': False
}

Database

The project uses SQLAlchemy to store data. The list of available dialects (databases) could be found on the website.

It's not recommended to use SQLite.

database = {
    'driver': "postgresql+asyncpg",
    'host': "postgres",
    'port': 5432,
    'database': "postgres",
    'user': "postgres",
    'password': "password"
}

Node configuration (slave-service)

ProxyNode/config.py is used for configuration.

Services to proxy

Used to replace fields in a GetCapabilities request. Some programs (e.g. ODM) do not use the host from this request and route all requests through a proxy. Such requests will also be processed, however, correct behavior is guaranteed only for PTZ and Media.

services_to_proxy = {
    'Media',
    'PTZ'
}

Deploy

Typically, docker-compose is used to run all services. An example of docker-compose.yml file is provided.

All services (except frontend-builder) can run on the same host or on separate ones.

The master-service listens on port 8080 inside the container (by default), but there ara no limitations for external ports.

ports:
  - "0.0.0.0:8000:8080"

Nodes listen on port 8081 inside the container for HTTP connections and 8554 for RTSP (by default), but external ports must be different for nodes running on the same host.

External IP and ports must be specified in the database.

ports:
  - "0.0.0.0:8001:8081"
  - "0.0.0.0:8551:8554"

It's recommended to add waiting condition for nodes, running on the same host with master:

depends_on:
  ptz-proxy-master:
    condition: service_started

To build frontend for master-service frontend-builder service can be enabled.

frontend-builder:
image: node:alpine
volumes:
  - ./Frontend:/ptz-proxy/frontend:rw
working_dir: /ptz-proxy/frontend
command: >
  /bin/sh -c
  "npm install && npm run build && npm prune --production"

The frontend-builder service will run on every restart of project. To avoid this behaviour, use command line alternative after clone and version updating.

sudo docker run --rm -v $(pwd)/Frontend:/ptz-proxy/frontend -w /ptz-proxy/frontend node:alpine sh -c "npm install && npm run build && npm prune --production"

To run project use the following command:

sudo docker-compose up -d

The correct startup:

[+] Running 3/3
 ✔ Container ptz-proxy-fastapi-frontend-builder-1  Exited
 ✔ Container ptz-proxy-fastapi-ptz-proxy-master    Running
 ✔ Container ptz-proxy-fastapi-ptz-proxy-node-1    Running