default.nix (6793B) - Raw
1 { 2 lib, 3 pkgs, 4 config, 5 ... 6 }: 7 let 8 cfg = config.mj.services.frigate; 9 sklypas = "0.312,1,0.311,0.269,0.354,0.172,0.396,0.154,0.431,0.102,0.495,0.044,0.61,0.039,0.774,0.097,0.837,0.219,0.758,0.995"; 10 11 proberScript = pkgs.writeShellApplication { 12 name = "go2rtc-prober"; 13 runtimeInputs = with pkgs; [ 14 systemd 15 ffmpeg_7-headless 16 ]; 17 text = '' 18 set -x 19 while true; do 20 FAILED=0 21 22 for input in vno4-dome-{panorama,ptz}-{orig,high,low}; do 23 timeout 30s \ 24 ffprobe -hide_banner "rtsp://localhost:8554/''${input}" || FAILED=1 25 done 26 27 [[ "$FAILED" == 1 ]] && systemctl restart --no-block go2rtc.service 28 29 sleep 5m 30 done 31 ''; 32 }; 33 in 34 { 35 options.mj.services.frigate = with lib.types; { 36 enable = lib.mkEnableOption "enable frigate"; 37 secretsEnv = lib.mkOption { type = path; }; 38 }; 39 40 config = lib.mkIf cfg.enable { 41 mj.base.unitstatus.units = [ 42 "go2rtc" 43 "frigate" 44 ]; 45 46 systemd.services = { 47 go2rtc-prober = { 48 wantedBy = [ "multi-user.target" ]; 49 serviceConfig = { 50 ExecStart = lib.getExe proberScript; 51 RestartSec = 300; 52 Restart = "always"; 53 }; 54 }; 55 go2rtc = { 56 preStart = "ln -sf $CREDENTIALS_DIRECTORY/secrets.env /run/go2rtc/secrets.env"; 57 environment = { 58 # Set HOME so Mesa can find cache directory 59 HOME = "/var/cache/go2rtc"; 60 # Force AMD VAAPI driver 61 LIBVA_DRIVER_NAME = "radeonsi"; 62 }; 63 serviceConfig = { 64 EnvironmentFile = [ "-/run/go2rtc/secrets.env" ]; 65 RuntimeDirectory = "go2rtc"; 66 CacheDirectory = "go2rtc"; # Mesa shader cache at /var/cache/go2rtc 67 LoadCredential = [ "secrets.env:${cfg.secretsEnv}" ]; 68 # Ensure access to GPU devices 69 SupplementaryGroups = [ 70 "render" 71 "video" 72 ]; 73 }; 74 }; 75 }; 76 77 services.go2rtc = { 78 enable = true; 79 settings = { 80 # Pin to FFmpeg 7 due to FFmpeg 8 RTSP issues in NixOS 25.11 81 # https://github.com/NixOS/nixpkgs/blob/master/doc/release-notes/rl-2511.section.md#L351 82 ffmpeg.bin = lib.getExe pkgs.ffmpeg_7-headless; 83 84 # https://github.com/AlexxIT/go2rtc/issues/831 85 #log = { 86 # format = "text"; 87 # level = "trace"; 88 #}; 89 streams = { 90 "vno4-dome-panorama-orig" = [ 91 "ffmpeg:rtsp://frigate:\${FRIGATE_RTSP_PASSWORD}@192.168.188.10/cam/realmonitor?channel=1&subtype=2" 92 ]; 93 "vno4-dome-panorama-high" = [ 94 "ffmpeg:rtsp://localhost:8554/vno4-dome-panorama-orig#hardware=vaapi#video=h264" 95 ]; 96 "vno4-dome-panorama-low" = [ 97 "ffmpeg:rtsp://localhost:8554/vno4-dome-panorama-orig#hardware=vaapi#video=h264#width=1280" 98 ]; 99 "vno4-dome-ptz-orig" = [ 100 "ffmpeg:rtsp://frigate:\${FRIGATE_RTSP_PASSWORD}@192.168.188.10/cam/realmonitor?channel=2&subtype=2#video=copy#audio=copy" 101 ]; 102 "vno4-dome-ptz-high" = [ 103 "ffmpeg:rtsp://localhost:8554/vno4-dome-ptz-orig#hardware=vaapi#video=h264#audio=copy" 104 ]; 105 "vno4-dome-ptz-low" = [ 106 "ffmpeg:rtsp://localhost:8554/vno4-dome-ptz-orig#hardware=vaapi#video=h264#width=1280#audio=copy" 107 ]; 108 }; 109 }; 110 }; 111 112 services.frigate = { 113 enable = true; 114 hostname = "r1.jakstys.lt"; 115 vaapiDriver = "radeonsi"; # AMD GPU VAAPI driver 116 settings = { 117 #ui.strftime_fmt = "%F %T"; 118 # Pin to FFmpeg 7 due to FFmpeg 8 RTSP issues in NixOS 25.11 119 ffmpeg.path = pkgs.ffmpeg_7-headless; 120 ffmpeg.hwaccel_args = "preset-vaapi"; 121 telemetry.version_check = false; 122 123 mqtt = { 124 enabled = true; 125 host = "::"; 126 }; 127 128 detect = { 129 enabled = true; 130 fps = 5; 131 }; 132 133 detectors = { 134 coral = { 135 type = "edgetpu"; 136 device = "usb"; 137 enabled = true; 138 }; 139 }; 140 141 record = { 142 enabled = true; 143 sync_recordings = true; 144 retain = { 145 days = 2; 146 mode = "all"; 147 }; 148 alerts = { 149 retain = { 150 days = 5; 151 mode = "motion"; 152 }; 153 }; 154 detections = { 155 retain = { 156 days = 5; 157 mode = "motion"; 158 }; 159 }; 160 }; 161 162 cameras = { 163 vno4-dome-panorama = 164 let 165 masks = [ 166 "0.269,0.285,0.235,0.567,0.194,0.634,0.095,1,0,1,0,0,0.321,0,0.323,0.222" 167 "0.766,1,0.855,0.123,0.818,0.104,0.818,0,1,0,1,1" 168 ]; 169 in 170 { 171 enabled = true; 172 motion.mask = masks; 173 objects = { 174 mask = masks; 175 track = [ 176 "bicycle" 177 "car" 178 "person" 179 ]; 180 }; 181 zones.sklypas.coordinates = sklypas; 182 183 review = { 184 alerts.required_zones = [ "sklypas" ]; 185 detections.required_zones = [ "sklypas" ]; 186 }; 187 188 ffmpeg = { 189 output_args = { 190 record = "preset-record-generic"; 191 }; 192 inputs = [ 193 { 194 path = "rtsp://localhost:8554/vno4-dome-panorama-high"; 195 roles = [ "record" ]; 196 } 197 { 198 path = "rtsp://localhost:8554/vno4-dome-panorama-low"; 199 roles = [ "detect" ]; 200 } 201 ]; 202 }; 203 }; 204 205 vno4-dome-ptz = 206 let 207 masks = [ "0.666,0.095,1,0.095,1,0,0.666,0" ]; 208 in 209 { 210 enabled = true; 211 motion.mask = masks; 212 objects.mask = masks; 213 214 audio = { 215 enabled = true; 216 #listen = [ "speech" ]; 217 }; 218 219 ffmpeg = { 220 output_args = { 221 record = "preset-record-generic-audio-copy"; 222 }; 223 inputs = [ 224 { 225 path = "rtsp://localhost:8554/vno4-dome-ptz-high"; 226 roles = [ 227 "record" 228 "audio" 229 ]; 230 } 231 { 232 path = "rtsp://localhost:8554/vno4-dome-ptz-low"; 233 roles = [ "detect" ]; 234 } 235 ]; 236 }; 237 }; 238 }; 239 240 }; 241 }; 242 243 }; 244 }