P/change_battery_threshold_nixos_boot

Playing with the laptop I wanted to change permanently /sys/class/power_supply/BAT0/change_battery_end_threshold to 80.

power-profiles-daemon does not have an interface to it. This is an exploration of the different methods I tried

TLP

TLP has a nix definition available. However it is incompatible with power-profiles-daemon, part of gnome.

 services.tlp = {
       enable = true;
       settings = {
         STOP_CHARGE_TRESH_BAT0=80;
         START_CHARGE_THRESH_BAT0=40;
       };
 };

boot.kernel.sysctl

Adding a sysctl entry seems trivial.

boot.kernel.sysctl = { "class.power_supply.BAT0.charge_control_end_threshold" = 80;};

However boot.kernel.sysctl only works for /proc/sys

https://discourse.nixos.org/t/setting-sysfs-parameters-in-nixos/14135

As a startup user service

I tried with a tiny user service. It didn’t work as it had no permissions

systemd.user.services.update_charge_control_threshold = {
  description = "Update charge control threshold";
  script = ''
      echo 80 > /sys/class/power_supply/BAT0/charge_control_end_threshold
  '';
  wantedBy = [ "multi-user.target" ]; # starts after login
};

https://www.reddit.com/r/NixOS/comments/rezf0s/how_to_run_script_on_startup/?rdt=41534

activation script

Activation scripts are meant to run very early during the boot operations. Too early, in fact, the file is not there when I tried.

 system.activationScripts.script.text = ''
     echo 80 > /sys/class/power_supply/BAT0/charge_control_end_threshold
 '';

https://discourse.nixos.org/t/system-activationscripts/22924

postboot command

Similar to activation scripts, the file wasn’t there:

 boot.postBootCommands = ''
      echo 80 > /sys/class/power_supply/BAT0/charge_control_end_threshold
 '';

one shot guix service?

Similar to the user service, it has no root privileges so I got an error message.

systemd.services.set_battery_threshold = {
  script = ''
     echo 80 > /sys/class/power_supply/BAT0/charge_control_end_threshold
  '';
  wantedBy = ["multi-user.target"];
  serviceConfig = {
    Type = "oneshot";
  };
};

https://www.reddit.com/r/NixOS/comments/jgfozg/how_to_run_arbitrary_setup_tasks_for_nixos/

udev rule

It worked. It waits until the module is loaded and then runs the code. There are some restrictions so it won’t allow /bin/sh https://wiki.archlinux.org/title/Laptop/ASUS

Cheating in nixos to call bash in the rule

https://unix.stackexchange.com/questions/186862/how-to-add-scripts-for-udev-to-run

The final result was:

services.udev.extraRules = ''
  ACTION=="add", KERNEL=="asus-nb-wmi", RUN+="${pkgs.bash}/bin/bash -c 'echo 80 > /sys/class/power_supply/BAT?/charge_control_end_threshold'"
'';