From 07d613ce1803b1f85f03285ce7e8b5f93acacf6e Mon Sep 17 00:00:00 2001 From: fleaz Date: Wed, 31 Jan 2024 21:18:58 +0100 Subject: [PATCH 1/4] python3Packages.onvif-zeep: init at 0.2.12 --- .../python-modules/onvif-zeep/default.nix | 40 +++++++++++++++++++ pkgs/top-level/python-packages.nix | 2 + 2 files changed, 42 insertions(+) create mode 100644 pkgs/development/python-modules/onvif-zeep/default.nix diff --git a/pkgs/development/python-modules/onvif-zeep/default.nix b/pkgs/development/python-modules/onvif-zeep/default.nix new file mode 100644 index 000000000000..c1d60fd6bf26 --- /dev/null +++ b/pkgs/development/python-modules/onvif-zeep/default.nix @@ -0,0 +1,40 @@ +{ 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 ]; + }; +} diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 45683f15df3e..a1f07865abcf 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -8685,6 +8685,8 @@ self: super: with self; { 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 { }; oocsi = callPackage ../development/python-modules/oocsi { }; From e376785642d4a8f4127131af545903f91fef199c Mon Sep 17 00:00:00 2001 From: fleaz Date: Wed, 31 Jan 2024 22:14:46 +0100 Subject: [PATCH 2/4] python3Packages.motmetrics: init at 1.4.0-unstable-20240130 --- .../python-modules/motmetrics/default.nix | 58 +++++++++++++++++++ pkgs/top-level/python-packages.nix | 2 + 2 files changed, 60 insertions(+) create mode 100644 pkgs/development/python-modules/motmetrics/default.nix diff --git a/pkgs/development/python-modules/motmetrics/default.nix b/pkgs/development/python-modules/motmetrics/default.nix new file mode 100644 index 000000000000..36fa2d9a7557 --- /dev/null +++ b/pkgs/development/python-modules/motmetrics/default.nix @@ -0,0 +1,58 @@ +{ 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; [ ]; + }; +} diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index a1f07865abcf..bc0fd5bc4d1a 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -7278,6 +7278,8 @@ self: super: with self; { 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 { }; From b6eaf6269aa88a51cd6124add36afe99aa72af97 Mon Sep 17 00:00:00 2001 From: fleaz Date: Wed, 31 Jan 2024 22:31:08 +0100 Subject: [PATCH 3/4] python3Packages.norfair: init at 2.2.0 --- .../python-modules/norfair/default.nix | 69 +++++++++++++++++++ pkgs/top-level/python-packages.nix | 2 + 2 files changed, 71 insertions(+) create mode 100644 pkgs/development/python-modules/norfair/default.nix diff --git a/pkgs/development/python-modules/norfair/default.nix b/pkgs/development/python-modules/norfair/default.nix new file mode 100644 index 000000000000..17c4e3553531 --- /dev/null +++ b/pkgs/development/python-modules/norfair/default.nix @@ -0,0 +1,69 @@ +{ 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 ]; + }; +} diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index bc0fd5bc4d1a..4dc27ef59a4a 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -8437,6 +8437,8 @@ self: super: with self; { noiseprotocol = callPackage ../development/python-modules/noiseprotocol { }; + norfair = callPackage ../development/python-modules/norfair { }; + normality = callPackage ../development/python-modules/normality { }; nose = callPackage ../development/python-modules/nose { }; From 250078ceba19d576437e46f8e1c1d19acf5dfa78 Mon Sep 17 00:00:00 2001 From: fleaz Date: Thu, 1 Feb 2024 23:09:56 +0100 Subject: [PATCH 4/4] frigate: 0.12.1 -> 0.13.1 Changelog: https://github.com/blakeblackshear/frigate/releases/tag/v0.13.0 https://github.com/blakeblackshear/frigate/releases/tag/v0.13.1 Co-Authored-By: Martin Weinelt --- nixos/modules/services/video/frigate.nix | 135 ++++++++++++++------ nixos/tests/frigate.nix | 9 +- pkgs/applications/video/frigate/default.nix | 57 ++++----- pkgs/applications/video/frigate/web.nix | 8 +- 4 files changed, 136 insertions(+), 73 deletions(-) diff --git a/nixos/modules/services/video/frigate.nix b/nixos/modules/services/video/frigate.nix index b7945282ba09..0c923a20c40c 100644 --- a/nixos/modules/services/video/frigate.nix +++ b/nixos/modules/services/video/frigate.nix @@ -17,7 +17,7 @@ let cfg = config.services.frigate; - format = pkgs.formats.yaml {}; + format = pkgs.formats.yaml { }; filteredConfig = lib.converge (lib.filterAttrsRecursive (_: v: ! lib.elem v [ null ])) cfg.settings; @@ -112,7 +112,7 @@ in }; }; }; - default = {}; + default = { }; description = mdDoc '' Frigate configuration as a nix attribute set. @@ -125,7 +125,7 @@ in config = mkIf cfg.enable { services.nginx = { - enable =true; + enable = true; additionalModules = with pkgs.nginxModules; [ secure-token rtmp @@ -133,31 +133,64 @@ in ]; 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; ''; }; @@ -169,10 +202,6 @@ in 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; ''; @@ -192,27 +221,64 @@ in 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; @@ -224,17 +290,6 @@ in "/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; } @@ -315,6 +370,12 @@ in } } ''; + appendHttpConfig = '' + map $sent_http_content_type $should_not_cache { + 'application/json' 0; + default 1; + } + ''; }; systemd.services.nginx.serviceConfig.SupplementaryGroups = [ @@ -325,7 +386,7 @@ in isSystemUser = true; group = "frigate"; }; - users.groups.frigate = {}; + users.groups.frigate = { }; systemd.services.frigate = { after = [ diff --git a/nixos/tests/frigate.nix b/nixos/tests/frigate.nix index 836fe0d063f8..03bd2b89611d 100644 --- a/nixos/tests/frigate.nix +++ b/nixos/tests/frigate.nix @@ -41,6 +41,7 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : 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"; }; }; }; @@ -51,10 +52,14 @@ import ./make-test-python.nix ({ pkgs, lib, ...} : 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") ''; }) diff --git a/pkgs/applications/video/frigate/default.nix b/pkgs/applications/video/frigate/default.nix index 81798df47f27..6a93401d985d 100644 --- a/pkgs/applications/video/frigate/default.nix +++ b/pkgs/applications/video/frigate/default.nix @@ -3,20 +3,19 @@ , 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 { @@ -35,7 +34,7 @@ let }; # 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="; @@ -46,7 +45,7 @@ let }; # 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="; @@ -59,14 +58,6 @@ python.pkgs.buildPythonApplication rec { 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 @@ -75,58 +66,59 @@ python.pkgs.buildPythonApplication rec { 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 = '' @@ -144,10 +136,15 @@ python.pkgs.buildPythonApplication rec { runHook postInstall ''; - checkInputs = with python.pkgs; [ + nativeCheckInputs = with python.pkgs; [ pytestCheckHook ]; + disabledTests = [ + # Test needs network access + "test_plus_labelmap" + ]; + passthru = { web = frigate-web; inherit python; diff --git a/pkgs/applications/video/frigate/web.nix b/pkgs/applications/video/frigate/web.nix index 01a3e70b436f..be530c5c3637 100644 --- a/pkgs/applications/video/frigate/web.nix +++ b/pkgs/applications/video/frigate/web.nix @@ -11,14 +11,14 @@ buildNpmPackage { 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