nixpkgs/nixos/modules/services/hardware/hddfancontrol.nix
Philip Wilk a135e7366e
nixos/hddfancontrol: loosen pwmPaths and disks types
Use str instead of path for the types, and use script instead of ExecStart for the service.
This lets you use command substitution to automatically select the correct disks and fan controllers at service start.
Useful at hwmonX can change value frequently and spontaneously.
Also lets you replace failed disks without having to change your nix config - only need to reload the service.
2025-07-03 17:16:58 +01:00

203 lines
5.7 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.hddfancontrol;
in
{
meta.maintainers = with lib.maintainers; [ philipwilk ];
imports = [
(lib.mkRemovedOptionModule [
"services"
"hddfancontrol"
"smartctl"
] "Smartctl is now automatically used when necessary, which makes this option redundant")
(lib.mkRemovedOptionModule [
"services"
"hddfancontrol"
"disks"
] "Disks should now be specified per hddfancontrol instance in its attrset")
(lib.mkRemovedOptionModule [
"services"
"hddfancontrol"
"pwmPaths"
] "Pwm Paths should now be specified per hddfancontrol instance in its attrset")
(lib.mkRemovedOptionModule [
"services"
"hddfancontrol"
"logVerbosity"
] "Log Verbosity should now be specified per hddfancontrol instance in its attrset")
(lib.mkRemovedOptionModule [
"services"
"hddfancontrol"
"extraArgs"
] "Extra Args should now be specified per hddfancontrol instance in its attrset")
];
options = {
services.hddfancontrol.enable = lib.mkEnableOption "hddfancontrol daemon";
services.hddfancontrol.settings = lib.mkOption {
type = lib.types.attrsWith {
placeholder = "drive-bay-name";
elemType = (
lib.types.submodule (
{ ... }:
{
options = {
disks = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Drive(s) to get temperature from
Can also use command substitution to automatically grab all matching drives; such as all scsi (sas) drives
'';
example = [
"/dev/sda"
"`find /dev/disk/by-id -name \"scsi*\" -and -not -name \"*-part*\" -printf \"%p \"`"
];
};
pwmPaths = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
PWM filepath(s) to control fan speed (under /sys), followed by initial and fan-stop PWM values
Can also use command substitution to ensure the correct hwmonX is selected on every boot
'';
example = [
"/sys/class/hwmon/hwmon2/pwm1:30:10"
"`echo /sys/devices/platform/nct6775.656/hwmon/hwmon[[:print:]]`/pwm4:80:20"
];
};
logVerbosity = lib.mkOption {
type = lib.types.enum [
"TRACE"
"DEBUG"
"INFO"
"WARN"
"ERROR"
];
default = "INFO";
description = ''
Verbosity of the log level
'';
};
extraArgs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
Extra commandline arguments for hddfancontrol
'';
example = [
"--min-fan-speed-prct=10"
"--interval=1min"
];
};
};
}
)
);
};
default = { };
description = ''
Parameter-sets for each instance of hddfancontrol.
'';
example = lib.literalExpression ''
{
harddrives = {
disks = [
"/dev/sda"
"/dev/sdb"
"/dev/sdc"
];
pwmPaths = [
"/sys/class/hwmon/hwmon1/pwm1:25:10"
];
logVerbosity = "DEBUG";
};
ssddrives = {
disks = [
"/dev/sdd"
"/dev/sde"
"/dev/sdf"
];
pwmPaths = [
"/sys/class/hwmon/hwmon1/pwm2:25:10"
];
extraArgs = [
"--interval=30s"
];
};
}
'';
};
};
config = lib.mkIf cfg.enable (
let
args =
cnf:
lib.concatLists [
[ "-d" ]
cnf.disks
[ "-p" ]
cnf.pwmPaths
cnf.extraArgs
];
createService = cnf: {
description = "HDD fan control";
documentation = [ "man:hddfancontrol(1)" ];
after = [ "hddtemp.service" ];
wants = [ "hddtemp.service" ];
script =
let
argString = lib.strings.concatStringsSep " " (args cnf);
in
"${lib.getExe pkgs.hddfancontrol} -v ${cnf.logVerbosity} daemon ${argString}";
serviceConfig = {
CPUSchedulingPolicy = "rr";
CPUSchedulingPriority = 49;
ProtectSystem = "strict";
PrivateTmp = true;
ProtectHome = true;
SystemCallArchitectures = "native";
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
};
wantedBy = [ "multi-user.target" ];
};
services = lib.attrsets.mergeAttrsList [
(lib.attrsets.mapAttrs' (
name: cnf: lib.nameValuePair "hddfancontrol-${name}" (createService cnf)
) cfg.settings)
{
"hddfancontrol".enable = false;
}
];
in
{
systemd.packages = [ pkgs.hddfancontrol ];
hardware.sensor.hddtemp = {
enable = true;
drives = lib.lists.flatten (lib.attrsets.catAttrs "disks" (lib.attrsets.attrValues cfg.settings));
};
systemd.services = services;
}
);
}