Skip to content

Commit 0554882

Browse files
give up
1 parent 2068455 commit 0554882

File tree

4 files changed

+192
-35
lines changed

4 files changed

+192
-35
lines changed

desktop/l/configuration.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@
4040
# GPU fan control
4141
#./gpu-fan-control.nix
4242
# Corsair fan control
43-
#./corsair-fan-control.nix
43+
./corsair-fan-control.nix
4444
#./docker-compose.nix
4545
./docker-daemon.nix
4646
#./smokeping.nix
4747
#./distributed-builds.nix
4848
#./hyprland.nix
4949
./nginx.nix
5050
./ollama-service.nix
51-
./fan2go.nix
51+
#/fan2go.nix
5252
];
5353

5454
boot = {

desktop/l/example.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This is the content of the file.

desktop/l/fan2go.nix

Lines changed: 188 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
# 6. Uses bash parameter expansion: ${var#pattern} and ${var%%pattern}
1818
# 7. No temporary files or delays needed since fan2go is the only liquidctl user
1919
#
20+
# Nix string literals:
21+
# https://nix.dev/manual/nix/2.28/language/string-literals.html#string-literals
22+
# https://nix.dev/manual/nix/2.28/language/string-interpolation.html
23+
# https://github.com/NixOS/nix/blob/master/doc/manual/source/language/string-interpolation.md
24+
#
2025
# See also: https://github.com/arnarg/config/blob/8de65cf5f1649a4fe6893102120ede4363de9bfa/hosts/terra/fan2go.nix
2126
#
2227
#
@@ -30,6 +35,16 @@
3035
# ├── Fan speed 5 0 rpm
3136
# └── Fan speed 6 0 rpm
3237
#
38+
# [das@l:~/nixos/desktop/l]$ liquidctl list -v
39+
# Device #0: Corsair Commander Core XT (broken)
40+
# ├── Vendor ID: 0x1b1c
41+
# ├── Product ID: 0x0c2a
42+
# ├── Release number: 0x0100
43+
# ├── Serial number: 210430f00a0857baae689a262091005f
44+
# ├── Bus: hid
45+
# ├── Address: /dev/hidraw5
46+
# └── Driver: CommanderCore
47+
#
3348
{
3449
lib,
3550
config,
@@ -40,55 +55,182 @@ let
4055

4156
cfg = config.hardware.fan2go;
4257

58+
# Path for the lock file to serialize access to liquidctl.
59+
liquidctlLockFile = "/run/lock/fan2go-liquidctl.lock";
60+
61+
# Vendor ID for the Corsair device to speed up liquidctl commands.
62+
liquidctlVendorId = "0x1b1c";
63+
64+
# Sleep duration between retries for liquidctl commands.
65+
retrySleepDuration = 0.1;
66+
67+
# Debug level for the scripts (0=off, 7=max debug).
68+
debugLevel = 7;
69+
70+
# A reusable bash helper function for logging.
71+
# It checks the DEBUG_LEVEL and prints messages to stderr.
72+
debugLogger = ''
73+
# Set default debug level if not provided.
74+
: "''${DEBUG_LEVEL:=0}" # Use quoted expansion to satisfy shellcheck
75+
: "''${DEBUG_LEVEL:=0}"
76+
LOG_FILE="/tmp/fan2go-debug-$(date +%Y%m%d%H).log"
77+
log_debug() {
78+
# Append message to the log file if debug level is 7 or higher.
79+
if [[ ''${DEBUG_LEVEL} -ge 7 ]]; then echo "[$(date +%T)] DEBUG: $*" >> "$LOG_FILE"; fi
80+
if [[ ''${DEBUG_LEVEL} -ge 7 ]]; then echo "[$(date +%T)] [$$] DEBUG: $*" >> "$LOG_FILE"; fi
81+
}
82+
'';
83+
4384
# Create the bash scripts for fan control
44-
setPwmScript = pkgs.writeText "setPwm.bash" ''
45-
#!${pkgs.bash}/bin/bash
85+
setPwmScript = pkgs.writeShellApplication {
86+
name = "setPwm.bash";
87+
# A single, unified script to wrap all liquidctl interactions,
88+
# preventing race conditions by design.
89+
liquidctlWrapperScript = pkgs.writeShellApplication {
90+
name = "liquidctl-wrapper.bash";
91+
runtimeInputs = [ pkgs.liquidctl pkgs.util-linux pkgs.coreutils ];
92+
text = ''
4693
# Convert fan2go PWM (0-255) to liquidctl percentage (0-100)
47-
percent=$((%pwm% * 100 / 255))
48-
${pkgs.liquidctl}/bin/liquidctl set fan1 speed $percent
49-
'';
94+
# PWM value is passed as the first argument
95+
${debugLogger}
96+
log_debug "setPwm started with argument: $1"
97+
${debugLogger}
98+
ACTION="$1"
99+
log_debug "Wrapper called with action: $ACTION"
50100
51-
getPwmScript = pkgs.writeText "getPwm.bash" ''
52-
#!${pkgs.bash}/bin/bash
101+
# Check if the pwm_value argument was provided.
102+
: "''${1:?PWM value not provided as an argument}"
103+
percent=$(( $1 * 100 / 255 ))
104+
log_debug "Calculated percent: $percent"
105+
for i in {1..3}; do
106+
(
107+
log_debug "Attempt #$i: Acquiring lock and setting fan speed..."
108+
liquidctl --vendor ${liquidctlVendorId} set fan1 speed "$percent" 2>> "$LOG_FILE"
109+
) 200>${liquidctlLockFile} && break
110+
log_debug "Attempt #$i failed. Sleeping for ${toString retrySleepDuration}s."
111+
sleep ${toString retrySleepDuration}
112+
done
113+
'';
114+
};
115+
case "$ACTION" in
116+
set-pwm)
117+
PWM_VALUE="$2"
118+
: "''${PWM_VALUE:?PWM value not provided for set-pwm action}"
119+
percent=$((PWM_VALUE * 100 / 255))
120+
log_debug "Calculated percent: $percent"
121+
for i in {1..3}; do
122+
( flock 200; liquidctl --vendor ${liquidctlVendorId} set fan1 speed "$percent" 2>> "$LOG_FILE" ) 200>${liquidctlLockFile} && break
123+
log_debug "Attempt #$i failed. Sleeping."
124+
sleep ${toString retrySleepDuration}
125+
done
126+
;;
127+
get-pwm|get-rpm)
128+
output=""
129+
for i in {1..3}; do
130+
output=$( ( flock -s 200; liquidctl --vendor ${liquidctlVendorId} status 2>> "$LOG_FILE" ) 200>${liquidctlLockFile} )
131+
[ -n "$output" ] && break
132+
log_debug "Attempt #$i failed (no output). Sleeping."
133+
sleep ${toString retrySleepDuration}
134+
done
135+
log_debug "Raw liquidctl output: $output"
136+
137+
getPwmScript = pkgs.writeShellApplication {
138+
name = "getPwm.bash";
139+
runtimeInputs = [ pkgs.liquidctl pkgs.util-linux pkgs.coreutils ];
140+
text = ''
53141
# Get current fan RPM and convert to PWM value
54-
output=$(${pkgs.liquidctl}/bin/liquidctl status 2>/dev/null)
55-
if [[ $output =~ Fan\ speed\ 1[^0-9]+([0-9]+) ]]; then
56-
rpm=${BASH_REMATCH[1]}
142+
output=""
143+
${debugLogger}
144+
log_debug "getPwm started."
145+
146+
for i in {1..3}; do
147+
output=$( (
148+
log_debug "Attempt #$i: Acquiring lock and getting status..."
149+
flock -s 200 # Use a shared lock for read-only operations
150+
liquidctl --vendor ${liquidctlVendorId} status 2>> "$LOG_FILE"
151+
) 200>${liquidctlLockFile} )
152+
[ -n "$output" ] && break
153+
log_debug "Attempt #$i failed (no output). Sleeping for ${toString retrySleepDuration}s."
154+
sleep ${toString retrySleepDuration}
155+
done
156+
log_debug "Raw liquidctl output: $output"
157+
if [[ $output =~ Fan\ speed\ 1[^0-9]+([0-9]+) ]]; then
158+
rpm=''${BASH_REMATCH[1]}
57159
echo $((rpm * 255 / 2000))
58-
else
59-
echo 0
160+
exit 0
60161
fi
61-
'';
162+
echo 0
163+
if [[ $output =~ Fan\ speed\ 1[^0-9]+([0-9]+) ]]; then
164+
rpm=''${BASH_REMATCH[1]}
165+
if [[ "$ACTION" == "get-pwm" ]]; then
166+
echo $((rpm * 255 / 2000))
167+
else # get-rpm
168+
echo "$rpm"
169+
fi
170+
else
171+
echo 0
172+
fi
173+
;;
174+
*)
175+
log_debug "Unknown action: $ACTION"
176+
exit 1
177+
;;
178+
esac
179+
'';
180+
};
62181

63-
getRpmScript = pkgs.writeText "getRpm.bash" ''
64-
#!${pkgs.bash}/bin/bash
182+
getRpmScript = pkgs.writeShellApplication {
183+
name = "getRpm.bash";
184+
runtimeInputs = [ pkgs.liquidctl pkgs.util-linux pkgs.coreutils ];
185+
text = ''
65186
# Get current fan RPM value
66-
output=$(${pkgs.liquidctl}/bin/liquidctl status 2>/dev/null)
67-
if [[ $output =~ Fan\ speed\ 1[^0-9]+([0-9]+) ]]; then
68-
rpm=${BASH_REMATCH[1]}
69-
echo $rpm
70-
else
71-
echo 0
187+
output=""
188+
${debugLogger}
189+
log_debug "getRpm started."
190+
191+
for i in {1..3}; do
192+
output=$( (
193+
log_debug "Attempt #$i: Acquiring lock and getting status..."
194+
flock -s 200 # Use a shared lock for read-only operations
195+
liquidctl --vendor ${liquidctlVendorId} status 2>> "$LOG_FILE"
196+
) 200>${liquidctlLockFile} )
197+
[ -n "$output" ] && break
198+
log_debug "Attempt #$i failed (no output). Sleeping for ${toString retrySleepDuration}s."
199+
sleep ${toString retrySleepDuration}
200+
done
201+
log_debug "Raw liquidctl output: $output"
202+
if [[ $output =~ Fan\ speed\ 1[^0-9]+([0-9]+) ]]; then
203+
rpm=''${BASH_REMATCH[1]}
204+
echo "$rpm"
205+
exit 0
72206
fi
73-
'';
207+
echo 0
208+
'';
209+
};
74210

75211
# Create a shellcheck validation script
76-
shellcheckScript = pkgs.writeText "check-fan-scripts.sh" ''
77-
#!${pkgs.bash}/bin/bash
212+
shellcheckScript = pkgs.writeShellApplication {
213+
name = "check-fan-scripts.sh";
214+
runtimeInputs = [ pkgs.shellcheck ];
215+
text = ''
78216
# Shellcheck validation for fan control scripts
79217
echo "Running shellcheck on fan control scripts..."
80218
81219
echo "Checking setPwm script..."
82-
${pkgs.shellcheck}/bin/shellcheck ${setPwmScript} || exit 1
220+
shellcheck ${setPwmScript}/bin/setPwm.bash || exit 1
221+
shellcheck ${liquidctlWrapperScript}/bin/liquidctl-wrapper.bash || exit 1
83222
84223
echo "Checking getPwm script..."
85-
${pkgs.shellcheck}/bin/shellcheck ${getPwmScript} || exit 1
224+
shellcheck ${getPwmScript}/bin/getPwm.bash || exit 1
225+
shellcheck ${liquidctlWrapperScript}/bin/liquidctl-wrapper.bash || exit 1
86226
87227
echo "Checking getRpm script..."
88-
${pkgs.shellcheck}/bin/shellcheck ${getRpmScript} || exit 1
228+
shellcheck ${getRpmScript}/bin/getRpm.bash || exit 1
229+
shellcheck ${liquidctlWrapperScript}/bin/liquidctl-wrapper.bash || exit 1
89230
90231
echo "All scripts passed shellcheck validation!"
91-
'';
232+
'';
233+
};
92234

93235
fan2goConfig = pkgs.writeText "fan2go.yaml" ''
94236
#
@@ -107,15 +249,28 @@ let
107249
# We use a shell command to convert the 0-255 PWM value from fan2go
108250
# into a 0-100 percentage for liquidctl.
109251
setPwm:
110-
exec: "${setPwmScript}"
252+
exec: "${setPwmScript}/bin/setPwm.bash"
253+
args: ["%pwm%"]
254+
exec: "${liquidctlWrapperScript}/bin/liquidctl-wrapper.bash"
255+
args: ["set-pwm", "%pwm%"]
256+
env:
257+
DEBUG_LEVEL: "${toString debugLevel}"
111258
# The `getPwm` command should return the current PWM value.
112259
# Since liquidctl doesn't provide PWM directly, we convert from the RPM value.
113260
getPwm:
114-
exec: "${getPwmScript}"
261+
exec: "${getPwmScript}/bin/getPwm.bash"
262+
exec: "${liquidctlWrapperScript}/bin/liquidctl-wrapper.bash"
263+
args: ["get-pwm"]
264+
env:
265+
DEBUG_LEVEL: "${toString debugLevel}"
115266
# The `getRpm` command gets the current RPM value from liquidctl.
116267
# This helps fan2go understand the fan's current state.
117268
getRpm:
118-
exec: "${getRpmScript}"
269+
exec: "${getRpmScript}/bin/getRpm.bash"
270+
exec: "${liquidctlWrapperScript}/bin/liquidctl-wrapper.bash"
271+
args: ["get-rpm"]
272+
env:
273+
DEBUG_LEVEL: "${toString debugLevel}"
119274
# Fan speed is a percentage for liquidctl
120275
min: 10
121276
max: 100
@@ -211,14 +366,15 @@ in
211366
after = [ "lm_sensors.service" ];
212367

213368
serviceConfig = {
214-
ExecStartPre = "${shellcheckScript}";
369+
ExecStartPre = "${shellcheckScript}/bin/check-fan-scripts.sh";
215370
ExecStart = lib.concatStringsSep " " [
216371
"${pkgs.fan2go}/bin/fan2go"
217372
"-c"
218373
"${fan2goConfig}"
219374
"--no-style"
220375
];
221376

377+
Environment = [ "GOMEMLIMIT=45MiB" ];
222378
MemoryHigh = "48M";
223379
MemoryMax = "64M";
224380
CPUQuota = "50%";

desktop/l/hardware-configuration.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,6 @@
4848
#https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/hardware/decklink.nix
4949

5050
# see also fan2go.nix
51-
hardware.fan2go.enable = true;
51+
#hardware.fan2go.enable = true;
5252

5353
}

0 commit comments

Comments
 (0)