CrOS/modules/quadlets/frigate/default.nix
2025-12-23 15:24:49 -05:00

201 lines
5 KiB
Nix

{
lib,
config,
inputs,
pkgs,
...
}:
let
securePort = builtins.toString (lib.custom.autoport "frigate-secure");
volumePath = "/overseer/services";
sopsFolder = inputs.nix-secrets + "/sops";
frigateConfig = pkgs.writeText "frigate-config.yaml" (
lib.generators.toYAML { } {
auth.enabled = false; # Proxy auth
tls.enabled = false; # off because we're doing ssl through the proxy
proxy = {
logout_url = "https://frigate.wanderingcrow.net/caddy-security/oauth2/generic/logout";
default_role = "viewer";
header_map = {
user = "Remote-User";
role = "Remote-Role";
};
};
mqtt = {
enabled = true;
host = "host.containers.internal";
port = 1883;
};
ui = {
timezone = "America/New_York";
time_format = "24hour";
};
###################
# go2rtc restream #
###################
go2rtc = {
streams = {
wce-0001 = [
"rtsp://thingino:thingino@192.168.150.1:554/ch0"
];
wce-0001_sub = [
"rtsp://thingino:thingino@192.168.150.1:554/ch1"
];
wce-0002 = [
"rtsp://thingino:thingino@192.168.150.2:554/ch0"
];
wce-0002_sub = [
"rtsp://thingino:thingino@192.168.150.2:554/ch1"
];
};
};
#############
# Detectors #
#############
detectors = {
coral = {
type = "edgetpu";
device = "usb";
};
};
objects = {
track = [
"person"
"cat"
"dog"
];
};
review = {
alerts = {
labels = [
"person"
"cat"
];
};
};
####################
# Data Persistence #
####################
record = {
enabled = true;
retain.days = 0; # as per official documentation
alerts.retain.days = 14;
detections.retain.days = 14;
};
#################
# Camera config #
#################
cameras = {
wce-0001 = {
ffmpeg = {
inputs = [
{
path = "rtsp://127.0.0.1:8554/wce-0001";
roles = [ "record" ];
}
{
path = "rtsp://127.0.0.1:8554/wce-0001_sub";
roles = [ "detect" ];
}
];
};
motion = {
enabled = true;
mask = [
"0,0,0.196,0.002,0.195,0.045,0,0.043" # timestamp
"0.898,0,0.896,0.045,1,0.048,0.999,0.002" # uptime
];
};
detect.enabled = true;
record.continuous.days = 7;
review = {
alerts.labels = [ ];
detections.labels = [
"person"
"cat"
];
};
};
wce-0002 = {
ffmpeg = {
inputs = [
{
path = "rtsp://127.0.0.1:8554/wce-0002";
roles = [ "record" ];
}
{
path = "rtsp://127.0.0.1:8554/wce-0002_sub";
roles = [ "detect" ];
}
];
};
motion = {
enabled = true;
mask = [
"0,0,0.196,0.002,0.195,0.045,0,0.043" # timestamp
"0.898,0,0.896,0.045,1,0.048,0.999,0.002" # uptime
];
};
detect.enabled = true;
};
};
}
);
in
{
sops = {
templates."frigate_env".content = ''
FRIGATE_JWT_SECRET=${config.sops.placeholder."frigate/jwt"}
'';
secrets = {
"frigate/jwt" = {
sopsFile = "${sopsFolder}/services.yaml";
};
};
};
systemd.tmpfiles.rules = [
"d ${volumePath}/frigate"
"d ${volumePath}/frigate/media/frigate"
"d ${volumePath}/frigate/db"
"f ${volumePath}/frigate/db/frigate.db"
];
virtualisation.quadlet = {
containers = {
frigate.containerConfig = {
image = "ghcr.io/blakeblackshear/frigate:0.17.0-beta1";
environmentFiles = [ config.sops.templates."frigate_env".path ];
devices = [
"/dev/bus/usb:/dev/bus/usb"
];
shmSize = "612m";
volumes = [
"/etc/localtime:/etc/localtime:ro"
"${volumePath}/frigate/media/frigate:/media/frigate"
"${frigateConfig}:/config/config.yaml:ro" # :ro to set to readonly
"${volumePath}/frigate/db/frigate.db:/config/frigate.db"
];
publishPorts = [
"${securePort}:8971"
];
};
};
};
services.caddy = {
enable = true;
virtualHosts."frigate.wanderingcrow.net".extraConfig = ''
@auth {
path /caddy-security/*
}
route @auth {
authenticate with myportal
}
route /* {
authorize with frigate
reverse_proxy http://localhost:${securePort}
}
'';
};
}