Refactor frigate config to add a bunch of features
All checks were successful
Check Flake / check-flake (push) Successful in 2h20m26s

- Enable vaapi GPU video encode/decode support
- Use go2rtc. This allows for watching high resolution camera feeds
- Split nix config into pieces that are easier to understand
- Add utilities for easily adding new cameras in the future
- misc changes
This commit is contained in:
Zuckerberg 2024-06-30 12:49:24 -06:00
parent 91874b9d53
commit 66bfc62566

View File

@ -3,105 +3,153 @@
let let
frigateHostname = "frigate.s0.neet.dev"; frigateHostname = "frigate.s0.neet.dev";
mkEsp32Cam = address: { mkGo2RtcStream = name: url: withAudio: {
ffmpeg = { ${name} = [
input_args = ""; url
inputs = [{ "ffmpeg:${name}#video=copy${if withAudio then "#audio=copy" else ""}"
path = "http://${address}:8080"; ];
roles = [ "detect" "record" ];
}];
output_args.record = "-f segment -pix_fmt yuv420p -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -preset ultrafast -an ";
};
detect = {
enabled = true;
width = 800;
height = 600;
fps = 10;
};
objects = {
track = [ "person" ];
};
}; };
mkDahuaCam = address: { # Assumes camera is set to output:
ffmpeg = { # - rtsp
inputs = [ # - H.264 + AAC
{ # - a downscaled substream for detection
path = "rtsp://admin:{FRIGATE_RTSP_PASSWORD}@${address}/cam/realmonitor?channel=1&subtype=0"; mkCamera = name: primaryUrl: detectUrl: {
roles = [ "record" ]; # Reference https://docs.frigate.video/configuration/reference/
} services.frigate.settings = {
{ cameras.${name} = {
path = "rtsp://admin:{FRIGATE_RTSP_PASSWORD}@${address}/cam/realmonitor?channel=1&subtype=1"; ffmpeg = {
roles = [ "detect" ]; # Camera feeds are relayed through go2rtc
} inputs = [
]; {
}; path = "rtsp://127.0.0.1:8554/${name}";
detect.enabled = true; # input_args = "preset-rtsp-restream";
objects = { input_args = "preset-rtsp-restream-low-latency";
track = [ "person" "dog" ]; roles = [ "record" ];
}; }
}; {
in path = detectUrl;
{ roles = [ "detect" ];
networking.firewall.allowedTCPPorts = [ }
# 1883 # mqtt ];
]; output_args = {
record = "preset-record-generic-audio-copy";
services.frigate = {
enable = true;
hostname = frigateHostname;
settings = {
mqtt = {
enabled = true;
host = "localhost:1883";
};
rtmp.enabled = false;
snapshots = {
enabled = true;
bounding_box = true;
};
record = {
enabled = true;
# sync_recordings = true; # detect if recordings were deleted outside of frigate
retain = {
days = 2; # Keep video for 2 days
mode = "motion";
};
events = {
retain = {
default = 10; # Keep video with detections for 10 days
mode = "motion";
# mode = "active_objects";
}; };
}; };
}; };
cameras = { };
dahlia-cam = mkEsp32Cam "dahlia-cam.lan"; services.go2rtc.settings.streams = lib.mkMerge [
dog-cam = mkDahuaCam "192.168.10.31"; (mkGo2RtcStream name primaryUrl false)
};
# ffmpeg = { # Sadly having the detection stream go through go2rpc too makes the stream unreadable by frigate for some reason.
# hwaccel_args = "preset-vaapi"; # It might need to be re-encoded to work. But I am not interested in wasting the processing power if only frigate
# }; # need the detection stream anyway. So just let frigate grab the stream directly since it works.
detectors.coral = { # (mkGo2RtcStream detectName detectUrl false)
type = "edgetpu"; ];
device = "pci"; };
mkDahuaCamera = name: address:
let
# go2rtc and frigate have a slightly different syntax for inserting env vars. So the URLs are not interchangable :(
# - go2rtc: ${VAR}
# - frigate: {VAR}
primaryUrl = "rtsp://admin:\${FRIGATE_RTSP_PASSWORD}@${address}/cam/realmonitor?channel=1&subtype=0";
detectUrl = "rtsp://admin:{FRIGATE_RTSP_PASSWORD}@${address}/cam/realmonitor?channel=1&subtype=1";
in
mkCamera name primaryUrl detectUrl;
mkEsp32Camera = name: address: {
services.frigate.settings.cameras.${name} = {
ffmpeg = {
input_args = "";
inputs = [{
path = "http://${address}:8080";
roles = [ "detect" "record" ];
}];
output_args.record = "-f segment -pix_fmt yuv420p -segment_time 10 -segment_format mp4 -reset_timestamps 1 -strftime 1 -c:v libx264 -preset ultrafast -an ";
}; };
}; };
}; };
in
lib.mkMerge [
(mkDahuaCamera "dog-cam" "192.168.10.31")
# (mkEsp32Camera "dahlia-cam" "dahlia-cam.lan")
{
services.frigate = {
enable = true;
hostname = frigateHostname;
settings = {
mqtt = {
enabled = true;
host = "localhost:1883";
};
rtmp.enabled = false;
snapshots = {
enabled = true;
bounding_box = true;
};
record = {
enabled = true;
# sync_recordings = true; # detect if recordings were deleted outside of frigate (expensive)
retain = {
days = 2; # Keep video for 2 days
mode = "motion";
};
events = {
retain = {
default = 10; # Keep video with detections for 10 days
mode = "motion";
# mode = "active_objects";
};
};
};
# Make frigate aware of the go2rtc streams
go2rtc.streams = config.services.go2rtc.settings.streams;
detect.enabled = true;
objects = {
track = [ "person" "dog" ];
};
};
};
# Pass in env file with secrets to frigate services.go2rtc = {
systemd.services.frigate.serviceConfig.EnvironmentFile = "/run/agenix/frigate-credentials"; enable = true;
age.secrets.frigate-credentials.file = ../../../secrets/frigate-credentials.age; settings = {
rtsp.listen = ":8554";
webrtc.listen = ":8555";
};
};
# AMD GPU for vaapi # Pass in env file with secrets to frigate/go2rtc
systemd.services.frigate.environment.LIBVA_DRIVER_NAME = "radeonsi"; systemd.services.frigate.serviceConfig.EnvironmentFile = "/run/agenix/frigate-credentials";
systemd.services.go2rtc.serviceConfig.EnvironmentFile = "/run/agenix/frigate-credentials";
age.secrets.frigate-credentials.file = ../../../secrets/frigate-credentials.age;
}
{
# hardware encode/decode with amdgpu vaapi
systemd.services.frigate = {
environment.LIBVA_DRIVER_NAME = "radeonsi";
serviceConfig = {
SupplementaryGroups = [ "render" "video" ]; # for access to dev/dri/*
AmbientCapabilities = "CAP_PERFMON";
};
};
services.frigate.settings.ffmpeg.hwaccel_args = "preset-vaapi";
}
{
# Coral TPU for frigate
services.udev.packages = [ pkgs.libedgetpu ];
users.groups.apex = { };
systemd.services.frigate.environment.LD_LIBRARY_PATH = "${pkgs.libedgetpu}/lib";
systemd.services.frigate.serviceConfig.SupplementaryGroups = [ "apex" ];
# Coral TPU for frigate # Coral PCIe driver
services.udev.packages = [ pkgs.libedgetpu ]; kernel.enableGasketKernelModule = true;
users.groups.apex = { };
systemd.services.frigate.environment.LD_LIBRARY_PATH = "${pkgs.libedgetpu}/lib"; services.frigate.settings.detectors.coral = {
systemd.services.frigate.serviceConfig.SupplementaryGroups = "apex"; type = "edgetpu";
# Coral PCIe driver device = "pci";
kernel.enableGasketKernelModule = true; };
} }
]