Initial commit
This commit is contained in:
commit
1cc5912864
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
description = "Frigate CCTV running in a container.";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-23.05";
|
||||
arion.url = "github:hercules-ci/arion";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, arion, ... }: {
|
||||
nixosModules = rec {
|
||||
default = frigateContainer;
|
||||
frigateContainer = { ... }: {
|
||||
imports = [ arion.nixosModules.arion ./frigate-container.nix ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.frigateContainer;
|
||||
|
||||
makeEnvFile = envVars:
|
||||
let
|
||||
envLines =
|
||||
mapAttrsToList (var: val: ''${var}="${toString val}"'') envVars;
|
||||
in pkgs.writeText "envFile" (concatStringsSep "\n" envLines);
|
||||
|
||||
hostSecrets = config.fudo.secrets.host-secrets."${config.instance.hostname}";
|
||||
|
||||
frigateCfg = toJSON {
|
||||
mqtt = {
|
||||
enabled = true;
|
||||
inherit (cfg.mqtt) host port;
|
||||
password = "{FRIGATE_MQTT_PASSWORD}";
|
||||
};
|
||||
logger.default = cfg.log-level;
|
||||
ffmpeg.hwaccel_args = [ "preset-intel-vaapi" ];
|
||||
cameras = mapAttrs' (_: camOpts:
|
||||
nameValuePair camOpts.name {
|
||||
ffmpeg.inputs = [
|
||||
{
|
||||
path = camOpts.streams.high;
|
||||
roles = [ "record" ];
|
||||
}
|
||||
{
|
||||
path = camOpts.streams.low;
|
||||
roles = [ "detect" ];
|
||||
}
|
||||
];
|
||||
}) cfg.cameras;
|
||||
record = {
|
||||
enabled = true;
|
||||
retain = {
|
||||
days = cfg.retention.default;
|
||||
mode = "motion";
|
||||
};
|
||||
events.retain = {
|
||||
default = cfg.retention.events;
|
||||
mode = "active_objects";
|
||||
objects = cfg.retention.objects;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
options.services.frigateContainer = with types; {
|
||||
enable = mkEnableOption "Enable Frigate CCTV in a container.";
|
||||
|
||||
state-directory = mkOption {
|
||||
type = str;
|
||||
description = "Path at which to store Frigate recordings & data.";
|
||||
};
|
||||
|
||||
log-level = mkOption {
|
||||
type = str;
|
||||
description = "Level at which to output Frigate logs.";
|
||||
default = "error";
|
||||
};
|
||||
|
||||
images = {
|
||||
frigate = mkOption {
|
||||
type = str;
|
||||
description = "Frigate Docker image to run.";
|
||||
};
|
||||
};
|
||||
|
||||
retention = {
|
||||
default = mkOption {
|
||||
type = int;
|
||||
description = "Retention time for all motion, in days.";
|
||||
default = 7;
|
||||
};
|
||||
|
||||
events = mkOption {
|
||||
type = int;
|
||||
description = "Retention time for all detected objects, in days.";
|
||||
default = 14;
|
||||
};
|
||||
|
||||
objects = mkOption {
|
||||
type = attrsOf int;
|
||||
description = "Map of object type to retention time in days.";
|
||||
default = {
|
||||
person = 60;
|
||||
dog = 30;
|
||||
cat = 30;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ports = {
|
||||
frigate = mkOption {
|
||||
type = port;
|
||||
description = "Port on which to listen for Frigate web traffic.";
|
||||
default = 5000;
|
||||
};
|
||||
|
||||
rtsp = mkOption {
|
||||
type = port;
|
||||
description = "Port on which to listen for Frigate RTSP traffic.";
|
||||
default = 8554;
|
||||
};
|
||||
|
||||
webrtc = mkOption {
|
||||
type = port;
|
||||
description = "Port on which to listen for Frigate WebRTC traffic.";
|
||||
default = 8555;
|
||||
};
|
||||
};
|
||||
|
||||
devices = mkOption {
|
||||
type = listOf str;
|
||||
description = "List of devices to pass to the container (for hw accel).";
|
||||
default = [ ];
|
||||
};
|
||||
|
||||
camera-password-file = mkOption {
|
||||
type = str;
|
||||
description =
|
||||
"Path on build host to file containing the camera password.";
|
||||
};
|
||||
|
||||
cameras = let
|
||||
cameraOpts = { name, ... }: {
|
||||
options = {
|
||||
name = mkOption {
|
||||
type = str;
|
||||
description = "Camera name.";
|
||||
default = name;
|
||||
};
|
||||
|
||||
streams = {
|
||||
low = mkOption {
|
||||
type = str;
|
||||
description = "URL of the low-quality stream.";
|
||||
};
|
||||
high = mkOption {
|
||||
type = str;
|
||||
description = "URL of the high-quality stream.";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in mkOption {
|
||||
type = attrsOf (submodule cameraOpts);
|
||||
description = "Cameras for Frigate CCTV to use.";
|
||||
default = { };
|
||||
};
|
||||
|
||||
mqtt = {
|
||||
host = mkOption {
|
||||
type = str;
|
||||
description = "Hostname of the MQTT server.";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = port;
|
||||
description = "Port on which to contact the MQTT server.";
|
||||
};
|
||||
|
||||
username = mkOption {
|
||||
type = str;
|
||||
description = "User as which to connect to server.";
|
||||
};
|
||||
|
||||
password-file = mkOption {
|
||||
type = str;
|
||||
descirption =
|
||||
"File containing password with which to authenticate to MQTT server.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
fudo.secrets.host-secrets."${config.instance.hostname}" = {
|
||||
frigateEnv = {
|
||||
source-file = let
|
||||
camPasswd = readFile cfg.camera-password-file;
|
||||
mqttPasswd = readFile cfg.mqtt.passwd-file;
|
||||
in mkEnvFile {
|
||||
FRIGATE_RTSP_PASSWORD = camPasswd;
|
||||
FRIGATE_MQTT_PASSWORD = mqttPasswd;
|
||||
};
|
||||
target-file = "/run/frigate/camera.passwd";
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation.arion.projects.mastodon.settings = {
|
||||
image = { pkgs, ... }: {
|
||||
project.name = "frigate-cctv";
|
||||
services = {
|
||||
frigate.service = {
|
||||
image = cfg.images.frigate;
|
||||
hostname = "frigate";
|
||||
restart = "always";
|
||||
volumes = [
|
||||
"${frigateCfg}:/config/config.yml"
|
||||
"${cfg.state-directory}:/media/frigate"
|
||||
];
|
||||
devices = cfg.devices;
|
||||
ports = [
|
||||
"${cfg.ports.frigate}:5000"
|
||||
"${cfg.ports.rtsp}:8554"
|
||||
"${cfg.ports.webrtc}:8555/tcp"
|
||||
"${cfg.ports.webrtc}:8555/udp"
|
||||
];
|
||||
env_file = hostSecrets.frigateEnv.target-file;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue