{ config, lib, ... }: let cameras = { "ulfried" = { frigate.record = { enabled = true; continuous.days = 0; alerts.retain = { days = 30; mode = "motion"; }; }; }; "gnisbert" = { }; "taubis" = { frigate = { detect.enabled = true; record = { enabled = true; continuous.days = 1; detections.retain.days = 7; }; }; }; "foeff" = { videoPassthrough = true; frigate.record = { enabled = true; continuous.days = 0; alerts.retain = { days = 30; mode = "motion"; }; }; }; }; # Uppercase camera name for use as systemd credential / env var name varName = name: lib.toUpper (lib.replaceStrings [ "-" ] [ "_" ] name); go2rtcCameraStreams = name: cam: let video = lib.optionalString (cam.videoPassthrough or false) "#video=copy"; in { "${name}" = [ "\${${varName name}_URL}" "ffmpeg:${name}#audio=opus#audio=aac${video}" ]; "${name}_sub" = [ "\${${varName name}_SUB_URL}" "ffmpeg:${name}_sub#audio=opus#audio=aac${video}" ]; }; frigateInputs = name: [ { path = "rtsp://127.0.0.1:8554/${name}?timeout=30"; input_args = "preset-rtsp-generic"; roles = [ "record" ]; } { path = "rtsp://127.0.0.1:8554/${name}_sub?timeout=30"; input_args = "preset-rtsp-generic"; roles = [ "detect" "audio" ]; } ]; # Only cameras with a frigate key get a frigate camera entry frigCameras = lib.filterAttrs (_: cam: cam ? frigate) cameras; in { age.secrets = lib.mkMerge ( lib.mapAttrsToList (name: _: { "camera-${name}-url".file = ../../secrets/camera-${name}-url.age; "camera-${name}-sub-url".file = ../../secrets/camera-${name}-sub-url.age; }) cameras ); systemd.services.go2rtc.serviceConfig.LoadCredential = lib.concatMap (name: [ "${varName name}_URL:${config.age.secrets."camera-${name}-url".path}" "${varName name}_SUB_URL:${config.age.secrets."camera-${name}-sub-url".path}" ]) (lib.attrNames cameras); services.go2rtc = { enable = true; settings = { rtsp.listen = ":8554"; webrtc.listen = ":8555"; streams = lib.foldl' lib.mergeAttrs { } (lib.mapAttrsToList go2rtcCameraStreams cameras); }; }; services.frigate = { enable = true; vaapiDriver = "iHD"; hostname = "kameramann.lan.baubs.net"; settings = { auth.enabled = false; go2rtc.streams = lib.foldl' lib.mergeAttrs { } ( lib.mapAttrsToList (name: _: { "${name}" = [ ]; "${name}_sub" = [ ]; }) cameras ); mqtt = { enabled = true; host = "192.168.178.33"; user = "frigate"; password = "frigate"; }; ffmpeg.hwaccel_args = "preset-vaapi"; detectors.ov_0 = { type = "openvino"; device = "GPU"; }; model = { model_type = "yolo-generic"; width = 320; height = 320; input_tensor = "nchw"; input_dtype = "float"; path = "${./models/yolov9-t-320.onnx}"; labelmap_path = "${./models/coco-80.txt}"; }; detect.enabled = true; snapshots.enabled = true; semantic_search = { enabled = false; model_size = "small"; }; face_recognition = { enabled = true; model_size = "large"; }; lpr.enabled = false; proxy.default_role = "admin"; objects.track = [ "person" "bird" "car" ]; telemetry.stats.intel_gpu_device = "sys:/sys/devices/pci0000:00/0000:00:02.0"; classification.bird.enabled = true; cameras = lib.mapAttrs ( name: cam: cam.frigate // { ffmpeg.inputs = frigateInputs name; } ) frigCameras; }; }; networking.firewall.allowedTCPPorts = [ 5000 1984 80 8555 8554 ]; networking.firewall.allowedUDPPorts = [ 8555 8554 ]; }