From 690f86b3bdb53001c7f5bcaefc1ec475567c5507 Mon Sep 17 00:00:00 2001 From: arcnmx Date: Sat, 8 Jun 2024 20:59:31 -0700 Subject: [PATCH] feat(motion): kitchencam lives! --- modules/nixos/motion.nix | 104 ++++++++++++++++++++++++++++++ modules/system/exports/motion.nix | 7 +- nixos/kitchencam.nix | 66 +++++++++++++++++++ systems/kitchencam/default.nix | 5 -- systems/logistics/default.nix | 9 +++ systems/logistics/nixos.nix | 1 + 6 files changed, 185 insertions(+), 7 deletions(-) create mode 100644 modules/nixos/motion.nix create mode 100644 nixos/kitchencam.nix diff --git a/modules/nixos/motion.nix b/modules/nixos/motion.nix new file mode 100644 index 00000000..3bf3ff3f --- /dev/null +++ b/modules/nixos/motion.nix @@ -0,0 +1,104 @@ +{ + pkgs, + config, + gensokyo-zone, + utils, + lib, + ... +}: let + inherit (gensokyo-zone.lib) mapOptionDefaults; + inherit (lib.options) mkOption mkPackageOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge mkAfter mkOptionDefault; + inherit (lib.attrsets) mapAttrsToList; + inherit (lib.meta) getExe; + cfg = config.services.motion; + mkMotionValue = value: + if value == true + then "on" + else if value == false + then "off" + else toString value; + mkMotionSetting = key: value: "${key} ${mkMotionValue value}"; +in { + options.services.motion = with lib.types; { + enable = mkEnableOption "motion"; + package = mkPackageOption pkgs "motion" {}; + dataDir = mkOption { + type = path; + default = "/var/lib/motion"; + }; + user = mkOption { + type = str; + default = "motion"; + }; + group = mkOption { + type = str; + default = "motion"; + }; + settings = mkOption { + type = attrsOf (oneOf [str int bool]); + description = "https://linux.die.net/man/1/motion"; + }; + extraArgs = mkOption { + type = listOf str; + default = []; + }; + extraConfig = mkOption { + type = lines; + default = ""; + }; + configText = mkOption { + type = lines; + internal = true; + }; + configFile = mkOption { + type = path; + }; + }; + config.services.motion = let + configFile = pkgs.writeText "motion.conf" cfg.configText; + in { + settings = mapOptionDefaults { + target_dir = cfg.dataDir; + }; + configFile = mkOptionDefault "${configFile}"; + configText = mkMerge ( + (mapAttrsToList mkMotionSetting cfg.settings) + ++ [(mkAfter cfg.extraConfig)] + ); + }; + config.users = mkIf cfg.enable { + users.motion = { + uid = 916; + group = "motion"; + home = cfg.dataDir; + extraGroups = ["video"]; + }; + groups.motion = { + gid = config.users.users.motion.uid; + }; + }; + config.systemd.services.motion = let + cliArgs = + [ + (getExe cfg.package) + "-n" + "-c" + cfg.configFile + ] + ++ cfg.extraArgs; + in + mkIf cfg.enable { + wantedBy = ["multi-user.target"]; + after = ["network.target"]; + serviceConfig = { + Type = mkOptionDefault "exec"; + Restart = mkOptionDefault "on-failure"; + User = mkOptionDefault cfg.user; + Group = mkOptionDefault cfg.group; + ExecStart = [ + (utils.escapeSystemdExecArgs cliArgs) + ]; + }; + }; +} diff --git a/modules/system/exports/motion.nix b/modules/system/exports/motion.nix index de539373..e803cd96 100644 --- a/modules/system/exports/motion.nix +++ b/modules/system/exports/motion.nix @@ -7,6 +7,9 @@ in { config.exports.services.motion = {config, ...}: { displayName = mkAlmostOptionDefault "Motion"; + nixos = { + serviceAttr = "motion"; + }; defaults.port.listen = mkAlmostOptionDefault "lan"; ports = { default = { @@ -15,10 +18,10 @@ in { status.enable = mkAlmostOptionDefault true; }; stream = { - port = mkAlmostOptionDefault 8081; + port = mkAlmostOptionDefault 41081; protocol = "http"; displayName = mkAlmostOptionDefault "Stream"; - status.enable = mkAlmostOptionDefault true; + #status.enable = mkAlmostOptionDefault true; }; }; }; diff --git a/nixos/kitchencam.nix b/nixos/kitchencam.nix new file mode 100644 index 00000000..a968ca48 --- /dev/null +++ b/nixos/kitchencam.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf mkDefault; + cfg = config.services.motion; + streamPort = 41081; + webPort = 8080; +in { + services.motion = { + enable = mkDefault true; + extraConfig = '' + videodevice /dev/kitchencam + v4l2_palette 8 + width 640 + height 480 + framerate 5 + + text_left kitchen + text_right %Y-%m-%d\n%T-%q + emulate_motion off + threshold 1500 + despeckle_filter EedDl + minimum_motion_frames 1 + event_gap 60 + pre_capture 3 + post_capture 0 + + picture_output off + picture_filename %Y%m%d%H%M%S-%q + + movie_output off + movie_max_time 60 + movie_quality 45 + movie_codec mkv + movie_filename %t-%v-%Y%m%d%H%M%S + + webcontrol_port ${toString webPort} + webcontrol_localhost off + webcontrol_parms 0 + stream_port ${toString streamPort} + stream_localhost off + ipv6_enabled on + ''; + }; + services.udev.extraRules = let + inherit (lib.strings) concatStringsSep; + rules = [ + ''SUBSYSTEM=="video4linux"'' + ''ACTION=="add"'' + ''ATTR{index}=="0"'' + ''ATTRS{idProduct}=="2a25"'' + ''ATTRS{idVendor}=="1224"'' + ''SYMLINK+="kitchencam"'' + ''OWNER="${cfg.user}"'' + ''TAG+="systemd"'' + ''ENV{SYSTEMD_WANTS}="motion.service"'' + ]; + rulesLine = concatStringsSep ", " rules; + in + mkIf cfg.enable rulesLine; + networking.firewall.interfaces.local = mkIf cfg.enable { + allowedTCPPorts = [streamPort webPort]; + }; +} diff --git a/systems/kitchencam/default.nix b/systems/kitchencam/default.nix index cf44dab3..d31d47de 100644 --- a/systems/kitchencam/default.nix +++ b/systems/kitchencam/default.nix @@ -21,11 +21,6 @@ _: { enable = true; ports.public.enable = false; }; - motion = { - id = "kitchen"; - enable = true; - ports.stream.port = 41081; - }; }; }; # XXX: currently unplugged :< diff --git a/systems/logistics/default.nix b/systems/logistics/default.nix index 536d1b48..1c8d41a4 100644 --- a/systems/logistics/default.nix +++ b/systems/logistics/default.nix @@ -4,6 +4,15 @@ _: { modules = [ ./nixos.nix ]; + exports = { + services = { + motion = { + id = "kitchen"; + enable = true; + ports.stream.port = 41081; + }; + }; + }; network.networks = { local = { slaac.postfix = "40c3:23df:e82a:b214"; diff --git a/systems/logistics/nixos.nix b/systems/logistics/nixos.nix index 04668188..12946121 100644 --- a/systems/logistics/nixos.nix +++ b/systems/logistics/nixos.nix @@ -12,6 +12,7 @@ in { nixos.sops nixos.base nixos.barcodebuddy-scanner + nixos.kitchencam ./hardware-configuration.nix ];