Rework laptop battery/power optimization settings

This commit is contained in:
ItsDrike 2024-04-13 22:18:21 +02:00
parent dd00ed5f70
commit a0bba2e225
Signed by: ItsDrike
GPG key ID: FA2745890B7048C0
4 changed files with 133 additions and 37 deletions

View file

@ -0,0 +1,47 @@
# This sets up power management using auto-cpufreq,
# alongside with upower and power-profiles-daemon.
# Together, this provides a complete alternative to TLP
{ pkgs, lib, config, ...}: let
inherit (lib) mkIf mkDefault;
deviceType = config.myOptions.device.roles.type;
acceptedTypes = ["laptop"];
in {
imports = [
./power-profiles-daemon
];
config = mkIf (builtins.elem deviceType acceptedTypes) {
services = {
# superior power management
auto-cpufreq = {
enable = true;
settings = let
MHz = x: x * 1000;
in {
battery = {
governor = "powersave";
scaling_min_freq = mkDefault (MHz 1200);
scaling_max_freq = mkDefault (MHz 1800);
turbo = "never";
};
charger = {
governor = "performance";
scaling_min_freq = mkDefault (MHz 1800);
scaling_max_freq = mkDefault (MHz 3800);
turbo = "auto";
};
};
};
# DBus service that provides power management support to applications
upower = {
enable = true;
percentageLow = 15;
percentageCritical = 5;
percentageAction = 3;
criticalPowerAction = "Hibernate";
};
};
};
}

View file

@ -0,0 +1,40 @@
# This sets up power management using auto-cpufreq,
# alongside with upower and power-profiles-daemon.
# Together, this provides a complete alternative to TLP
{ pkgs, lib, config, ...}: let
inherit (lib) mkIf;
inherit (lib.modules) mkForce;
inherit (lib.strings) makeBinPath;
deviceType = config.myOptions.device.roles.type;
acceptedTypes = ["laptop"];
in {
config = mkIf (builtins.elem deviceType acceptedTypes) {
# allows changing system behavior based upon user-selected power profiles
# (with `powerprofilesctl` command)
services.power-profiles-daemon.enable = true;
# Power state monitor. Switches power profiles based on charging state.
# Plugged in - performance (if available, falls back to balance)
# Unplugged - balanced, until below 50%, then power-saver
systemd.services."power-monitor" = let
dependencies = with pkgs; [
coreutils
power-profiles-daemon
inotify-tools
jaq
];
in {
description = "Power Monitoring Service";
environment.PATH = mkForce "/run/wrappers/bin:${makeBinPath dependencies}";
script = builtins.readFile ./scripts/power_monitor.sh;
serviceConfig = {
Type = "simple";
Restart = "on-failure";
};
wants = ["power-profiles-daemon.service"];
wantedBy = ["default.target"];
};
};
}

View file

@ -0,0 +1,42 @@
#!/usr/bin/env bash
BAT=$(echo /sys/class/power_supply/BAT*) # only supports single-battery systems
BAT_STATUS="$BAT/status"
BAT_CAP="$BAT/capacity"
POWER_SAVE_PERCENT=50 # Enter power-save mode if on bat and below this capacity
HAS_PERFORMANCE="$(powerprofilesctl list | grep performance)"
# monitor loop
prev=0
while true; do
# read the current state
status="$(cat "$BAT_STATUS")"
capacity="$(cat "$BAT_CAP")"
if [[ $status == "Discharging" ]]; then
if [[ $capacity -le $POWER_SAVE_PERCENT ]]; then
profile="power-saver"
else
profile="balanced"
fi
else
if [[ -n $HAS_PERFORMANCE ]]; then
profile="performance"
else
profile="balanced"
fi
fi
# Set the new profile
if [[ $profile != $prev ]]; then
echo -en "Setting power profile to ${profile}\n"
powerprofilesctl set $profile
prev=$profile
fi
# wait for changes in status or capacity files
# i.e. for the next power change event
inotifywait -qq "$BAT_STATUS" "$BAT_CAP"
done

View file

@ -3,6 +3,10 @@
deviceType = config.myOptions.device.roles.type; deviceType = config.myOptions.device.roles.type;
acceptedTypes = ["laptop"]; acceptedTypes = ["laptop"];
in { in {
imports = [
./auto-cpufreq
];
config = mkIf (builtins.elem deviceType acceptedTypes) { config = mkIf (builtins.elem deviceType acceptedTypes) {
hardware.acpilight.enable = true; hardware.acpilight.enable = true;
@ -15,48 +19,11 @@ in {
# handle ACPI events # handle ACPI events
acpid.enable = true; acpid.enable = true;
# allows changing system behavior based upon user-selected power profiles
power-profiles-daemon.enable = true;
# temperature target on battery # temperature target on battery
undervolt = { undervolt = {
tempBat = 65; # deg C tempBat = 65; # deg C
package = pkgs.undervolt; package = pkgs.undervolt;
}; };
# superior power management
auto-cpufreq = {
enable = true;
# define the profiles
# (you can manually switch between profiles using `powerprofilesctl` cmd)
settings = let
MHz = x: x * 1000;
in {
battery = {
governor = "powersave";
scaling_min_freq = mkDefault (MHz 1200);
scaling_max_freq = mkDefault (MHz 1800);
turbo = "never";
};
charger = {
governor = "performance";
scaling_min_freq = mkDefault (MHz 1800);
scaling_max_freq = mkDefault (MHz 3800);
turbo = "auto";
};
};
};
# DBus service that provides power management support to applications
upower = {
enable = true;
percentageLow = 15;
percentageCritical = 5;
percentageAction = 3;
criticalPowerAction = "Hibernate";
};
}; };
boot = { boot = {