nixos-config/modules/fancontrol.nix

153 lines
4.6 KiB
Nix

# SPDX-FileCopyrightText: 2023 Simon Bruder <simon@sbruder.de>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
{ config, lib, pkgs, ... }:
let
cfg = config.sbruder.fancontrol;
in
{
options.sbruder.fancontrol = {
enable = lib.mkEnableOption "afancontrol based fancontrol";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.afancontrol;
description = "The afancontrol package to use.";
};
interval = lib.mkOption {
type = lib.types.int;
default = 1;
description = "Interval in seconds the fan speeds should be calculated and set.";
};
enableDefaultMapping = lib.mkEnableOption "the default mapping, mapping all sensors to all fans";
fans = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options = {
pwmFile = lib.mkOption {
type = lib.types.path;
description = "File to write the PWM duty cycle to.";
};
pwmLineStart = lib.mkOption {
type = lib.types.int;
default = 0;
description = "PWM value at which the linear correlation of PWM/RPM starts.";
};
pwmLineEnd = lib.mkOption {
type = lib.types.int;
default = 255;
description = "PWM value at which the linear correlation of PWM/RPM ends.";
};
rpmFile = lib.mkOption {
type = lib.types.path;
description = "File to read the fan RPM from.";
};
neverStop = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to stop the fan on speed 0% (otherwise runs with pwmLineStart).";
};
};
});
default = { };
};
sensors = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options = {
file = lib.mkOption {
type = lib.types.path;
description = "File to read the temperature (in m°C) from.";
};
min = lib.mkOption {
type = lib.types.int;
description = "Temperature at which the fan speed is lowest.";
};
max = lib.mkOption {
type = lib.types.int;
description = "Temperature at which the fan speed is highest.";
};
};
});
default = { };
};
mappings = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule {
options = {
fans = lib.mkOption {
type = lib.types.listOf (lib.types.str);
description = "Fans to map.";
};
sensors = lib.mkOption {
type = lib.types.listOf (lib.types.str);
description = "Sensors to map.";
};
};
});
default =
if cfg.enableDefaultMapping then {
all = {
fans = lib.attrNames cfg.fans;
sensors = lib.attrNames cfg.sensors;
};
} else { };
};
};
config = lib.mkIf cfg.enable {
# makes some assumptions
#systemd.packages = [ cfg.package ];
systemd.services.afancontrol = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
LimitNOFILE = 8192;
ExecStartPre = "${cfg.package}/bin/afancontrol daemon --test";
ExecStart = "${cfg.package}/bin/afancontrol daemon --pidfile /run/afancontrol.pid";
PIDFile = "/run/afancontrol.pid";
Restart = "always";
};
};
environment.etc."afancontrol/afancontrol.conf".text = lib.generators.toINI
{
mkKeyValue = lib.generators.mkKeyValueDefault
{
mkValueString = v:
if lib.isList v then lib.concatMapStringsSep ", " toString v
else lib.generators.mkValueStringDefault { } v;
}
":";
}
({
daemon = {
interval = 1;
};
actions = {
report_cmd = "true";
};
} // (lib.mapAttrs'
(name: config: lib.nameValuePair "fan: ${name}" {
type = "linux";
pwm = config.pwmFile;
fan_input = config.rpmFile;
pwm_line_start = config.pwmLineStart;
pwm_line_end = config.pwmLineEnd;
never_stop = config.neverStop;
})
cfg.fans
) // (lib.mapAttrs'
(name: config: lib.nameValuePair "temp: ${name}" {
type = "file";
path = config.file;
inherit (config) min max;
})
cfg.sensors
) // (lib.mapAttrs'
(name: config: lib.nameValuePair "mapping: ${name}" {
inherit (config) fans;
temps = config.sensors;
})
cfg.mappings
));
};
}