1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.services.hddfancontrol;
10in
11
12{
13 meta.maintainers = with lib.maintainers; [ philipwilk ];
14
15 imports = [
16 (lib.mkRemovedOptionModule [
17 "services"
18 "hddfancontrol"
19 "smartctl"
20 ] "Smartctl is now automatically used when necessary, which makes this option redundant")
21 (lib.mkRemovedOptionModule [
22 "services"
23 "hddfancontrol"
24 "disks"
25 ] "Disks should now be specified per hddfancontrol instance in its attrset")
26 (lib.mkRemovedOptionModule [
27 "services"
28 "hddfancontrol"
29 "pwmPaths"
30 ] "Pwm Paths should now be specified per hddfancontrol instance in its attrset")
31 (lib.mkRemovedOptionModule [
32 "services"
33 "hddfancontrol"
34 "logVerbosity"
35 ] "Log Verbosity should now be specified per hddfancontrol instance in its attrset")
36 (lib.mkRemovedOptionModule [
37 "services"
38 "hddfancontrol"
39 "extraArgs"
40 ] "Extra Args should now be specified per hddfancontrol instance in its attrset")
41 ];
42
43 options = {
44 services.hddfancontrol.enable = lib.mkEnableOption "hddfancontrol daemon";
45
46 services.hddfancontrol.settings = lib.mkOption {
47 type = lib.types.attrsWith {
48 placeholder = "drive-bay-name";
49 elemType = (
50 lib.types.submodule (
51 { ... }:
52 {
53 options = {
54 disks = lib.mkOption {
55 type = lib.types.listOf lib.types.path;
56 default = [ ];
57 description = ''
58 Drive(s) to get temperature from
59 '';
60 example = [ "/dev/sda" ];
61 };
62
63 pwmPaths = lib.mkOption {
64 type = lib.types.listOf lib.types.path;
65 default = [ ];
66 description = ''
67 PWM filepath(s) to control fan speed (under /sys), followed by initial and fan-stop PWM values
68 '';
69 example = [ "/sys/class/hwmon/hwmon2/pwm1:30:10" ];
70 };
71
72 logVerbosity = lib.mkOption {
73 type = lib.types.enum [
74 "TRACE"
75 "DEBUG"
76 "INFO"
77 "WARN"
78 "ERROR"
79 ];
80 default = "INFO";
81 description = ''
82 Verbosity of the log level
83 '';
84 };
85
86 extraArgs = lib.mkOption {
87 type = lib.types.listOf lib.types.str;
88 default = [ ];
89 description = ''
90 Extra commandline arguments for hddfancontrol
91 '';
92 example = [
93 "--min-fan-speed-prct=10"
94 "--interval=1min"
95 ];
96 };
97 };
98 }
99 )
100 );
101 };
102 default = { };
103 description = ''
104 Parameter-sets for each instance of hddfancontrol.
105 '';
106 example = lib.literalExpression ''
107 {
108 harddrives = {
109 disks = [
110 "/dev/sda"
111 "/dev/sdb"
112 "/dev/sdc"
113 ];
114 pwmPaths = [
115 "/sys/class/hwmon/hwmon1/pwm1:25:10"
116 ];
117 logVerbosity = "DEBUG";
118 };
119 ssddrives = {
120 disks = [
121 "/dev/sdd"
122 "/dev/sde"
123 "/dev/sdf"
124 ];
125 pwmPaths = [
126 "/sys/class/hwmon/hwmon1/pwm2:25:10"
127 ];
128 extraArgs = [
129 "--interval=30s"
130 ];
131 };
132 }
133 '';
134 };
135 };
136
137 config = lib.mkIf cfg.enable (
138 let
139 args =
140 cnf:
141 lib.concatLists [
142 [ "-d" ]
143 cnf.disks
144 [ "-p" ]
145 cnf.pwmPaths
146 cnf.extraArgs
147 ];
148
149 createService = cnf: {
150 description = "HDD fan control";
151 documentation = [ "man:hddfancontrol(1)" ];
152 after = [ "hddtemp.service" ];
153 wants = [ "hddtemp.service" ];
154 serviceConfig = {
155 ExecStart = "${lib.getExe pkgs.hddfancontrol} -v ${cnf.logVerbosity} daemon ${lib.escapeShellArgs (args cnf)}";
156
157 CPUSchedulingPolicy = "rr";
158 CPUSchedulingPriority = 49;
159
160 ProtectSystem = "strict";
161 PrivateTmp = true;
162 ProtectHome = true;
163 SystemCallArchitectures = "native";
164 MemoryDenyWriteExecute = true;
165 NoNewPrivileges = true;
166 };
167 wantedBy = [ "multi-user.target" ];
168 };
169
170 services = lib.attrsets.mergeAttrsList [
171 (lib.attrsets.mapAttrs' (
172 name: cnf: lib.nameValuePair "hddfancontrol-${name}" (createService cnf)
173 ) cfg.settings)
174 {
175 "hddfancontrol".enable = false;
176 }
177 ];
178 in
179 {
180 systemd.packages = [ pkgs.hddfancontrol ];
181
182 hardware.sensor.hddtemp = {
183 enable = true;
184 drives = lib.lists.flatten (lib.attrsets.catAttrs "disks" (lib.attrsets.attrValues cfg.settings));
185 };
186
187 systemd.services = services;
188 }
189 );
190}