Merge pull request #286287 from fleaz/frigate-update

frigate: 0.12.1 -> 0.13.1

Changed files
+309 -73
nixos
modules
services
video
tests
pkgs
applications
video
development
python-modules
motmetrics
norfair
onvif-zeep
top-level
+98 -37
nixos/modules/services/video/frigate.nix
···
cfg = config.services.frigate;
-
format = pkgs.formats.yaml {};
+
format = pkgs.formats.yaml { };
filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! lib.elem v [ null ])) cfg.settings;
···
};
};
};
-
default = {};
+
default = { };
description = mdDoc ''
Frigate configuration as a nix attribute set.
···
config = mkIf cfg.enable {
services.nginx = {
-
enable =true;
+
enable = true;
additionalModules = with pkgs.nginxModules; [
secure-token
rtmp
···
];
recommendedProxySettings = mkDefault true;
recommendedGzipSettings = mkDefault true;
+
mapHashBucketSize = mkDefault 128;
upstreams = {
frigate-api.servers = {
-
"127.0.0.1:5001" = {};
+
"127.0.0.1:5001" = { };
};
frigate-mqtt-ws.servers = {
-
"127.0.0.1:5002" = {};
+
"127.0.0.1:5002" = { };
};
frigate-jsmpeg.servers = {
-
"127.0.0.1:8082" = {};
+
"127.0.0.1:8082" = { };
};
frigate-go2rtc.servers = {
-
"127.0.0.1:1984" = {};
+
"127.0.0.1:1984" = { };
};
};
-
# Based on https://github.com/blakeblackshear/frigate/blob/v0.12.0/docker/rootfs/usr/local/nginx/conf/nginx.conf
+
proxyCachePath."frigate" = {
+
enable = true;
+
keysZoneSize = "10m";
+
keysZoneName = "frigate_api_cache";
+
maxSize = "10m";
+
inactive = "1m";
+
levels = "1:2";
+
};
+
# Based on https://github.com/blakeblackshear/frigate/blob/v0.13.1/docker/main/rootfs/usr/local/nginx/conf/nginx.conf
virtualHosts."${cfg.hostname}" = {
locations = {
"/api/" = {
proxyPass = "http://frigate-api/";
+
extraConfig = ''
+
proxy_cache frigate_api_cache;
+
proxy_cache_lock on;
+
proxy_cache_use_stale updating;
+
proxy_cache_valid 200 5s;
+
proxy_cache_bypass $http_x_cache_bypass;
+
proxy_no_cache $should_not_cache;
+
add_header X-Cache-Status $upstream_cache_status;
+
+
location /api/vod/ {
+
proxy_pass http://frigate-api/vod/;
+
proxy_cache off;
+
}
+
+
location /api/stats {
+
access_log off;
+
rewrite ^/api/(.*)$ $1 break;
+
proxy_pass http://frigate-api;
+
}
+
+
location /api/version {
+
access_log off;
+
rewrite ^/api/(.*)$ $1 break;
+
proxy_pass http://frigate-api;
+
}
+
'';
};
"~* /api/.*\.(jpg|jpeg|png)$" = {
proxyPass = "http://frigate-api";
extraConfig = ''
-
add_header 'Access-Control-Allow-Origin' '*';
-
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
rewrite ^/api/(.*)$ $1 break;
'';
};
···
secure_token $args;
secure_token_types application/vnd.apple.mpegurl;
-
add_header Access-Control-Allow-Headers '*';
-
add_header Access-Control-Expose-Headers 'Server,range,Content-Length,Content-Range';
-
add_header Access-Control-Allow-Methods 'GET, HEAD, OPTIONS';
-
add_header Access-Control-Allow-Origin '*';
add_header Cache-Control "no-store";
expires off;
'';
···
proxyPass = "http://frigate-go2rtc/";
proxyWebsockets = true;
};
+
# frigate lovelace card uses this path
+
"/live/mse/api/ws" = {
+
proxyPass = "http://frigate-go2rtc/api/ws";
+
proxyWebsockets = true;
+
extraConfig = ''
+
limit_except GET {
+
deny all;
+
}
+
'';
+
};
"/live/webrtc/" = {
proxyPass = "http://frigate-go2rtc/";
proxyWebsockets = true;
};
+
"/live/webrtc/api/ws" = {
+
proxyPass = "http://frigate-go2rtc/api/ws";
+
proxyWebsockets = true;
+
extraConfig = ''
+
limit_except GET {
+
deny all;
+
}
+
'';
+
};
+
# pass through go2rtc player
+
"/live/webrtc/webrtc.html" = {
+
proxyPass = "http://frigate-go2rtc/webrtc.html";
+
proxyWebsockets = true;
+
extraConfig = ''
+
limit_except GET {
+
deny all;
+
}
+
'';
+
};
+
"/api/go2rtc/api" = {
+
proxyPass = "http://frigate-go2rtc/api";
+
proxyWebsockets = true;
+
extraConfig = ''
+
limit_except GET {
+
deny all;
+
}
+
'';
+
};
+
# integrationn uses this to add webrtc candidate
+
"/api/go2rtc/webrtc" = {
+
proxyPass = "http://frigate-go2rtc/api/webrtc";
+
proxyWebsockets = true;
+
extraConfig = ''
+
limit_except GET {
+
deny all;
+
}
+
'';
+
};
"/cache/" = {
alias = "/var/cache/frigate/";
};
"/clips/" = {
root = "/var/lib/frigate";
extraConfig = ''
-
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
-
add_header 'Access-Control-Allow-Credentials' 'true';
-
add_header 'Access-Control-Expose-Headers' 'Content-Length';
-
if ($request_method = 'OPTIONS') {
-
add_header 'Access-Control-Allow-Origin' "$http_origin";
-
add_header 'Access-Control-Max-Age' 1728000;
-
add_header 'Content-Type' 'text/plain charset=UTF-8';
-
add_header 'Content-Length' 0;
-
return 204;
-
}
-
types {
video/mp4 mp4;
image/jpeg jpg;
···
"/recordings/" = {
root = "/var/lib/frigate";
extraConfig = ''
-
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
-
add_header 'Access-Control-Allow-Credentials' 'true';
-
add_header 'Access-Control-Expose-Headers' 'Content-Length';
-
if ($request_method = 'OPTIONS') {
-
add_header 'Access-Control-Allow-Origin' "$http_origin";
-
add_header 'Access-Control-Max-Age' 1728000;
-
add_header 'Content-Type' 'text/plain charset=UTF-8';
-
add_header 'Content-Length' 0;
-
return 204;
-
}
-
types {
video/mp4 mp4;
}
···
}
}
'';
+
appendHttpConfig = ''
+
map $sent_http_content_type $should_not_cache {
+
'application/json' 0;
+
default 1;
+
}
+
'';
};
systemd.services.nginx.serviceConfig.SupplementaryGroups = [
···
isSystemUser = true;
group = "frigate";
};
-
users.groups.frigate = {};
+
users.groups.frigate = { };
systemd.services.frigate = {
after = [
+7 -2
nixos/tests/frigate.nix
···
serviceConfig = {
DynamicUser = true;
ExecStart = "${lib.getBin pkgs.ffmpeg-headless}/bin/ffmpeg -re -f lavfi -i smptebars=size=800x600:rate=10 -f mpegts -listen 1 http://0.0.0.0:8080";
+
Restart = "always";
};
};
};
···
machine.wait_for_unit("frigate.service")
+
# Frigate startup
machine.wait_for_open_port(5001)
-
machine.succeed("curl http://localhost:5001")
+
# nginx startup
+
machine.wait_for_open_port(80)
-
machine.wait_for_file("/var/cache/frigate/test-*.mp4")
+
machine.succeed("curl http://localhost")
+
+
machine.wait_for_file("/var/cache/frigate/test@*.mp4")
'';
})
+27 -30
pkgs/applications/video/frigate/default.nix
···
, python3
, fetchFromGitHub
, fetchurl
-
, fetchpatch
, frigate
, nixosTests
}:
let
-
version = "0.12.1";
+
version = "0.13.1";
src = fetchFromGitHub {
#name = "frigate-${version}-source";
owner = "blakeblackshear";
repo = "frigate";
rev = "refs/tags/v${version}";
-
hash = "sha256-kNvYsHoObi6b9KT/LYhTGK4uJ/uAHnYhyoQkiXIA/s8=";
+
hash = "sha256-2J7DhnYDX9ubbsk0qhji/vIKDouy9IqQztzbdPj2kxo=";
};
frigate-web = callPackage ./web.nix {
···
};
# Tensorflow Lite models
-
# https://github.com/blakeblackshear/frigate/blob/v0.12.0/Dockerfile#L88-L91
+
# https://github.com/blakeblackshear/frigate/blob/v0.13.0/docker/main/Dockerfile#L96-L97
tflite_cpu_model = fetchurl {
url = "https://github.com/google-coral/test_data/raw/release-frogfish/ssdlite_mobiledet_coco_qat_postprocess.tflite";
hash = "sha256-kLszpjTgQZFMwYGapd+ZgY5sOWxNLblSwP16nP/Eck8=";
···
};
# OpenVino models
-
# https://github.com/blakeblackshear/frigate/blob/v0.12.0/Dockerfile#L92-L95
+
# https://github.com/blakeblackshear/frigate/blob/v0.13.0/docker/main/Dockerfile#L101
openvino_model = fetchurl {
url = "https://github.com/openvinotoolkit/open_model_zoo/raw/master/data/dataset_classes/coco_91cl_bkgr.txt";
hash = "sha256-5Cj2vEiWR8Z9d2xBmVoLZuNRv4UOuxHSGZQWTJorXUQ=";
···
inherit src;
-
patches = [
-
(fetchpatch {
-
# numpy 1.24 compat
-
url = "https://github.com/blakeblackshear/frigate/commit/cb73d0cd392990448811c7212bc5f09be411fc69.patch";
-
hash = "sha256-Spt7eRosmTN8zyJ2uVme5HPVy2TKgBtvbQ6tp6PaNac=";
-
})
-
];
-
postPatch = ''
echo 'VERSION = "${version}"' > frigate/version.py
···
substituteInPlace frigate/const.py \
--replace "/media/frigate" "/var/lib/frigate" \
-
--replace "/tmp/cache" "/var/cache/frigate/"
+
--replace "/tmp/cache" "/var/cache/frigate" \
+
--replace "/config" "/var/lib/frigate" \
+
--replace "{CONFIG_DIR}/model_cache" "/var/cache/frigate/model_cache"
substituteInPlace frigate/http.py \
-
--replace "/opt/frigate" "${placeholder "out"}/${python.sitePackages}" \
-
--replace "/tmp/cache/" "/var/cache/frigate/"
+
--replace "/opt/frigate" "${placeholder "out"}/${python.sitePackages}"
substituteInPlace frigate/output.py \
--replace "/opt/frigate" "${placeholder "out"}/${python.sitePackages}"
-
substituteInPlace frigate/record.py \
-
--replace "/tmp/cache" "/var/cache/frigate"
-
substituteInPlace frigate/detectors/detector_config.py \
--replace "/labelmap.txt" "${placeholder "out"}/share/frigate/labelmap.txt"
-
substituteInPlace frigate/detectors/plugins/edgetpu_tfl.py \
+
substituteInPlace frigate/config.py \
+
--replace "/cpu_model.tflite" "${tflite_cpu_model}" \
--replace "/edgetpu_model.tflite" "${tflite_edgetpu_model}"
-
substituteInPlace frigate/detectors/plugins/cpu_tfl.py \
-
--replace "/cpu_model.tflite" "${tflite_cpu_model}"
-
-
substituteInPlace frigate/ffmpeg_presets.py --replace \
-
'"-timeout" if os.path.exists(BTBN_PATH) else "-stimeout"' \
-
'"-timeout"'
+
substituteInPlace frigate/test/test_config.py \
+
--replace "(MODEL_CACHE_DIR" "('/build/model_cache'" \
+
--replace "/config/model_cache" "/build/model_cache"
'';
dontBuild = true;
propagatedBuildInputs = with python.pkgs; [
-
# requirements.txt
+
# docker/main/requirements.txt
scikit-build
-
# requirements-wheel.txt
+
# docker/main/requirements-wheel.txt
click
flask
imutils
matplotlib
+
norfair
numpy
+
onvif-zeep
opencv4
openvino
paho-mqtt
peewee
peewee-migrate
psutil
+
py3nvml
pydantic
+
pytz
pyyaml
requests
+
ruamel-yaml
scipy
setproctitle
tensorflow
tzlocal
+
unidecode
ws4py
-
zeroconf
];
installPhase = ''
···
runHook postInstall
'';
-
checkInputs = with python.pkgs; [
+
nativeCheckInputs = with python.pkgs; [
pytestCheckHook
+
];
+
+
disabledTests = [
+
# Test needs network access
+
"test_plus_labelmap"
];
passthru = {
+4 -4
pkgs/applications/video/frigate/web.nix
···
postPatch = ''
substituteInPlace package.json \
-
--replace "--base=/BASE_PATH/" ""
+
--replace-fail "--base=/BASE_PATH/" ""
substituteInPlace src/routes/Storage.jsx \
-
--replace "/media/frigate" "/var/lib/frigate" \
-
--replace "/tmp/cache" "/var/cache/frigate"
+
--replace-fail "/media/frigate" "/var/lib/frigate" \
+
--replace-fail "/tmp/cache" "/var/cache/frigate"
'';
-
npmDepsHash = "sha256-fvRxpQjSEzd2CnoEOVgQcB6MJJ4dcjN8bOaacHjCdwU=";
+
npmDepsHash = "sha256-+36quezGArqIM9dM+UihwcIgmE3EVmJQThuicLgDW4A=";
installPhase = ''
cp -rv dist/ $out
+58
pkgs/development/python-modules/motmetrics/default.nix
···
+
{ lib
+
, buildPythonPackage
+
, fetchFromGitHub
+
+
# build-system
+
, setuptools
+
+
# dependencies
+
, numpy
+
, pandas
+
, scipy
+
, xmltodict
+
+
# tests
+
, pytestCheckHook
+
, pytest-benchmark
+
}:
+
+
buildPythonPackage rec {
+
pname = "motmetrics";
+
version = "1.4.0-unstable-20240130";
+
pyproject = true;
+
+
src = fetchFromGitHub {
+
owner = "cheind";
+
repo = "py-motmetrics";
+
# latest release is not compatible with pandas 2.0
+
rev = "7210fcce0be1b76c96a62f6fe4ddbc90d944eacb";
+
hash = "sha256-7LKLHXWgW4QpivAgzvWl6qEG0auVvpiZ6bfDViCKsFY=";
+
};
+
+
nativeBuildInputs = [
+
setuptools
+
];
+
+
propagatedBuildInputs = [
+
numpy
+
pandas
+
scipy
+
xmltodict
+
];
+
+
nativeCheckInputs = [
+
pytestCheckHook
+
pytest-benchmark
+
];
+
+
pythonImportsCheck = [
+
"motmetrics"
+
];
+
+
meta = with lib; {
+
description = "Bar_chart: Benchmark multiple object trackers (MOT) in Python";
+
homepage = "https://github.com/cheind/py-motmetrics";
+
license = licenses.mit;
+
maintainers = with maintainers; [ ];
+
};
+
}
+69
pkgs/development/python-modules/norfair/default.nix
···
+
{ lib
+
, buildPythonPackage
+
, fetchFromGitHub
+
, poetry-core
+
, filterpy
+
, importlib-metadata
+
, numpy
+
, rich
+
, scipy
+
, motmetrics
+
, opencv4
+
, pytestCheckHook
+
, pythonRelaxDepsHook
+
}:
+
+
buildPythonPackage rec {
+
pname = "norfair";
+
version = "2.2.0";
+
pyproject = true;
+
+
src = fetchFromGitHub {
+
owner = "tryolabs";
+
repo = "norfair";
+
rev = "v${version}";
+
hash = "sha256-aKB5TYSLW7FOXIy9u2hK7px6eEmIQdKPrhChKaU1uYs=";
+
};
+
+
nativeBuildInputs = [
+
poetry-core
+
pythonRelaxDepsHook
+
];
+
+
pythonRelaxDeps = [
+
"rich"
+
];
+
+
propagatedBuildInputs = [
+
filterpy
+
importlib-metadata
+
numpy
+
rich
+
scipy
+
];
+
+
passthru.optional-dependencies = {
+
metrics = [
+
motmetrics
+
];
+
video = [
+
opencv4
+
];
+
};
+
+
nativeCheckInputs = [
+
pytestCheckHook
+
];
+
+
pythonImportsCheck = [
+
"norfair"
+
];
+
+
meta = with lib; {
+
description = "Lightweight Python library for adding real-time multi-object tracking to any detector";
+
changelog = "https://github.com/tryolabs/norfair/releases/tag/v${version}";
+
homepage = "https://github.com/tryolabs/norfair";
+
license = licenses.bsd3;
+
maintainers = with maintainers; [ fleaz ];
+
};
+
}
+40
pkgs/development/python-modules/onvif-zeep/default.nix
···
+
{ lib
+
, buildPythonPackage
+
, fetchPypi
+
, setuptools
+
, zeep
+
}:
+
+
buildPythonPackage rec {
+
pname = "onvif-zeep";
+
version = "0.2.12";
+
pyproject = true;
+
+
src = fetchPypi {
+
pname = "onvif_zeep";
+
inherit version;
+
hash = "sha256-qou8Aqc+qlCJSwwY45+o0xilg6ZkxlvzWzyAKdHEC0k=";
+
};
+
+
nativeBuildInputs = [
+
setuptools
+
];
+
+
propagatedBuildInputs = [
+
zeep
+
];
+
+
pythonImportsCheck = [
+
"onvif"
+
];
+
+
# Tests require hardware
+
doCheck = false;
+
+
meta = with lib; {
+
description = "Python Client for ONVIF Camera";
+
homepage = "https://github.com/quatanium/python-onvif";
+
license = licenses.mit;
+
maintainers = with maintainers; [ fleaz ];
+
};
+
}
+6
pkgs/top-level/python-packages.nix
···
mortgage = callPackage ../development/python-modules/mortgage { };
+
motmetrics = callPackage ../development/python-modules/motmetrics { };
+
motionblinds = callPackage ../development/python-modules/motionblinds { };
motioneye-client = callPackage ../development/python-modules/motioneye-client { };
···
noiseprotocol = callPackage ../development/python-modules/noiseprotocol { };
+
norfair = callPackage ../development/python-modules/norfair { };
+
normality = callPackage ../development/python-modules/normality { };
nose = callPackage ../development/python-modules/nose { };
···
};
onnxruntime-tools = callPackage ../development/python-modules/onnxruntime-tools { };
+
+
onvif-zeep = callPackage ../development/python-modules/onvif-zeep { };
onvif-zeep-async = callPackage ../development/python-modules/onvif-zeep-async { };