chore(motion): clean up settings

This commit is contained in:
arcnmx 2024-06-09 11:21:15 -07:00
parent 690f86b3bd
commit f24b9582f7
4 changed files with 134 additions and 47 deletions

View file

@ -1,4 +1,51 @@
{
let
cameraModule = {
pkgs,
config,
gensokyo-zone,
name,
lib,
lib'motion,
...
}: let
inherit (lib.options) mkOption mkEnableOption;
inherit (lib.modules) mkIf mkMerge mkOptionDefault;
inherit (lib.strings) hasPrefix;
in {
options = with lib.types; {
enable = mkEnableOption "camera" // {
default = true;
};
settings = mkOption {
type = attrsOf (oneOf [str int bool]);
description = "https://motion-project.github.io/motion_config.html";
};
extraConfig = mkOption {
type = lines;
default = "";
};
configText = mkOption {
type = lines;
internal = true;
};
configFile = mkOption {
type = path;
};
};
config = let
configFile = pkgs.writeText "motion.conf" config.configText;
in {
settings = {
videodevice = mkIf (hasPrefix "/" name) (mkOptionDefault name);
};
configFile = mkOptionDefault "${configFile}";
configText = mkMerge (
(lib'motion.mkMotionSettings config.settings)
++ [config.extraConfig]
);
};
};
in {
pkgs,
config,
gensokyo-zone,
@ -6,23 +53,26 @@
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.attrsets) attrValues mapAttrsToList;
inherit (lib.lists) filter;
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}";
lib'motion = config.lib.motion;
in {
options.services.motion = with lib.types; {
enable = mkEnableOption "motion";
package = mkPackageOption pkgs "motion" {};
cameras = mkOption {
type = attrsOf (submoduleWith {
modules = [ cameraModule ];
specialArgs = {
inherit pkgs gensokyo-zone lib'motion;
nixosConfig = config;
};
});
};
dataDir = mkOption {
type = path;
default = "/var/lib/motion";
@ -37,7 +87,7 @@ in {
};
settings = mkOption {
type = attrsOf (oneOf [str int bool]);
description = "https://linux.die.net/man/1/motion";
description = "https://motion-project.github.io/motion_config.html";
};
extraArgs = mkOption {
type = listOf str;
@ -57,14 +107,19 @@ in {
};
config.services.motion = let
configFile = pkgs.writeText "motion.conf" cfg.configText;
enableIPv6 = mkIf config.networking.enableIPv6 (mkOptionDefault true);
enabledCameras = filter (camera: camera.enable) (attrValues cfg.cameras);
in {
settings = mapOptionDefaults {
target_dir = cfg.dataDir;
settings = {
target_dir = mkOptionDefault cfg.dataDir;
ipv6_enabled = enableIPv6;
webcontrol_ipv6 = enableIPv6;
};
configFile = mkOptionDefault "${configFile}";
configText = mkMerge (
(mapAttrsToList mkMotionSetting cfg.settings)
++ [(mkAfter cfg.extraConfig)]
(lib'motion.mkMotionSettings cfg.settings)
++ [cfg.extraConfig]
++ map (camera: mkAfter "camera ${camera.configFile}") enabledCameras
);
};
config.users = mkIf cfg.enable {
@ -101,4 +156,14 @@ in {
];
};
};
config.lib.motion = {
mkMotionValue = value:
if value == true
then "on"
else if value == false
then "off"
else toString value;
mkMotionSetting = key: value: "${key} ${lib'motion.mkMotionValue value}";
mkMotionSettings = mapAttrsToList lib'motion.mkMotionSetting;
};
}

View file

@ -4,11 +4,25 @@
...
}: let
inherit (gensokyo-zone.lib) mkAlmostOptionDefault;
inherit (lib.modules) mkIf;
in {
config.exports.services.motion = {config, ...}: {
displayName = mkAlmostOptionDefault "Motion";
nixos = {
serviceAttr = "motion";
assertions = let
# in motion.conf, `0` represents the port being disabled
configPort = port: if port.enable then port.port else 0;
in mkIf config.enable [
(nixosConfig: {
assertion = configPort config.ports.default == nixosConfig.services.motion.settings.webcontrol_port or 0;
message = "webcontrol port mismatch";
})
(nixosConfig: {
assertion = configPort config.ports.stream == nixosConfig.services.motion.settings.stream_port or 0;
message = "stream port mismatch";
})
];
};
defaults.port.listen = mkAlmostOptionDefault "lan";
ports = {

View file

@ -1,8 +1,10 @@
{
config,
gensokyo-zone,
lib,
...
}: let
inherit (gensokyo-zone.lib) mapDefaults;
inherit (lib.modules) mkIf mkDefault;
cfg = config.services.motion;
streamPort = 41081;
@ -10,39 +12,36 @@
in {
services.motion = {
enable = mkDefault true;
extraConfig = ''
videodevice /dev/kitchencam
v4l2_palette 8
width 640
height 480
framerate 5
settings = mapDefaults {
picture_output = false;
movie_output = false;
picture_filename = "%Y%m%d%H%M%S-%q";
movie_filename = "%t-%v-%Y%m%d%H%M%S";
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
text_right = "%Y-%m-%d\\n%T-%q";
emulate_motion = false;
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
'';
webcontrol_localhost = false;
stream_localhost = false;
webcontrol_parms = 0;
webcontrol_port = webPort;
stream_port = streamPort;
};
cameras.kitchencam.settings = mapDefaults {
videodevice = "/dev/kitchencam";
v4l2_palette = 8;
width = 640;
height = 480;
framerate = 5;
camera_id = 1;
text_left = "kitchen";
};
};
services.udev.extraRules = let
inherit (lib.strings) concatStringsSep;
@ -61,6 +60,6 @@ in {
in
mkIf cfg.enable rulesLine;
networking.firewall.interfaces.local = mkIf cfg.enable {
allowedTCPPorts = [streamPort webPort];
allowedTCPPorts = [cfg.settings.stream_port cfg.settings.webcontrol_port];
};
}

View file

@ -39,6 +39,15 @@ in {
#jack.enable = true;
};
services.motion.cameras.webcam = {
#enable = false;
settings = {
videodevice = "/dev/video0";
camera_id = 2;
text_left = "logistics";
};
};
users.users.logistics = {
uid = 1000;
isNormalUser = true;