Frigate supports controlling the PTZ (Pan, Tilt, Zoom) of a configured camera using onvif protocol. The purpose of this proxy is to enable Frigate to control PTZ of a non-onvif camera that only supports CGI.
After installing Frigate at home, I've realized that Frigate can stream my old Foscam FI9821P camera but can't control it's PTZ (FI9821P has a limited onvif support). The solution was to create fo2cp (this proxy) to listen to Frigate onvif requests and "translate" those requests to CGI Commands before forwarding them to the camera. Currently fo2cp supports one camera per instance and is made specifically for FI9821P (although it should work for any CGI supported Foscam camera).
To get a local copy up and running follow these simple steps.
The following are to be installed globally.
- tsconfig-paths, typescript, tsx
npm install tsconfig-paths typescript tsx -g
- Create a new directory in your system where fo2cp will be installed. For this guide we will assume you created the directory
~/fo2cp/. - Download the latest release and extract the files to the newly created directory
~/fo2cp/. - Change directory into the installation directory where the
package.jsonfile iscd ~/fo2cp - Install npm packages
npm install - Run the typescript compiler
npx tsc - Start the proxy server
node ./dist/server.mjs
There are two ways to use fo2cp configuration file:
- Editing the default config file at the root installation directory (e.g.
~/fo2cp/appConfig.json5) - Creating a new config file and pass it as argument when starting fo2cp
node ./dist/server.mjs --config='/home/user/myAppConfig.json5'
Important
The fo2cp config file format is JSON5
Here is the default config file:
{
//ip: "0.0.0.0",
port: 3000,
camera: {
ip: "192.168.1.100",
cgiPort: 88,
//cgiUrl: "http://192.168.1.100:88", // [Optional] The cgi url of the camera
isCameraHaveZoom: false, // Set to true if your camera have Zoom capability
cgiPath: "/cgi-bin/CGIProxy.fcgi",
cgiProtocol: "foscam",
user: "operator",
password: "12345678"
}
}
- ip: [optional] This is the ip of the host on which fo2cp is running. Normally you don't need to specify this property. The first detected ipv4 ip address on the host will be used.
- port: The port on which fo2cp will be listening for incoming requests from Frigate.
- camera: The specific camera config.
- ip: The ip of the camera.
- cgiPort: The HTTP port configured in the camera's setup.
- cgiUrl: [optional] The base url of the camera for cgi requests. Normally you don't specify this property. It will be calculated as
http://<ip>:<cgiPort>. - cgiPath: The url path as configured in the camera's setup.
- cgiProtocol: The name of the protocol module located in
src/protocolsdirectory (see details). - user: A user that is configured in the camera's setup. Make sure to use a user that is privileged to execute PTZ commands.
- password: The password that is configured in the camera's setup for the specific user.
In the onvif configuration section, we need to define the fo2cp proxy instead of the actual camera.
The Frigate config is <path-to-frigate-dir>/config/config.yaml (e.g. ~/frigate/config/config.yaml)
cameras:
MYFI9821P: # <------ Name the camera
enabled: true
ffmpeg:
...
detect:
...
onvif:
host: 192.168.1.25
port: 3000
user: 'AAAAAA'
password: 'BBBBBBB'
onvif section properties:
- host: The ip of the host on which the fo2cp proxy server is running.
- port: The port on which the fo2cp proxy server is listening.
- user/password - Must not be blanks, but values will be ignored. fo2cp will use its own configured user/password when communicating with the camera.
CGI Protocols are typescript mudules (*.mts) located in src/protocols directory.
Currently, two CGI protocols are implemented: foscam (src/protocols/foscam.mts) and reolink (src/protocols/reolink.mts).
If you have a non-onvif camera that is not supported by the existing protocols, you can implement a new protocol. Following are the steps for creating a new protocol:
- Think of a name for the protocol (for now, let's assume the name is
myproto). - Create a new empty file
src/protocols/myproto.mts. - A protocol is an implementation of the base abstract class
CGIProtocolAbstract. We first need to import that class and the error class:import {CGIProtocolAbstract, ONVIFError} from '../CGIProtocolAbstract.mjs'; - Now we need to create our class and export it as default. So your file should look like:
import {CGIProtocolAbstract, ONVIFError} from '../CGIProtocolAbstract.mjs'; export default class myproto extends CGIProtocolAbstract { } - Now implement the abstract methods per your camera CGI specifications
- For error handling in your protocol, use
ONVIFErrorto throw an error. E.g.throw new ONVIFError('Oops, something went wrong!');
Tip
Any error text thrown by the protocol using ONVIFError, will be reflected in Frigate system log.
To test/debug the new protocol class, use your browser to navigate to http://<fo2cp-ip>:<fo2cp-port>/testproto?help.
The page will show a list of the abstract methods enabling you to trigger those methods from that page itself.
I'm new to typescript! I actually used this project to learn and practice typescript.
You shouldn't use the code of this project as "the proper" typescript coding :)