I found a post about suspending and then going into hibernate that included a really clever script. Turns out that with NixOS this is even esaier to coordinate as you have systemd so can have a before and after service. I just include this in my /etc/nixos/configuration.nix file and nixos-rebuild; then a systemctl suspend or a close of the lid will cause the hibernate timer to be set.
-
-
Save mattdenner/befcf099f5cfcc06ea04dcdd4969a221 to your computer and use it in GitHub Desktop.
| { config, pkgs, ... }: let | |
| hibernateEnvironment = { | |
| HIBERNATE_SECONDS = "3600"; | |
| HIBERNATE_LOCK = "/var/run/autohibernate.lock"; | |
| }; | |
| in { | |
| systemd.services."awake-after-suspend-for-a-time" = { | |
| description = "Sets up the suspend so that it'll wake for hibernation"; | |
| wantedBy = [ "suspend.target" ]; | |
| before = [ "systemd-suspend.service" ]; | |
| environment = hibernateEnvironment; | |
| script = '' | |
| curtime=$(date +%s) | |
| echo "$curtime $1" >> /tmp/autohibernate.log | |
| echo "$curtime" > $HIBERNATE_LOCK | |
| ${pkgs.utillinux}/bin/rtcwake -m no -s $HIBERNATE_SECONDS | |
| ''; | |
| serviceConfig.Type = "simple"; | |
| }; | |
| systemd.services."hibernate-after-recovery" = { | |
| description = "Hibernates after a suspend recovery due to timeout"; | |
| wantedBy = [ "suspend.target" ]; | |
| after = [ "systemd-suspend.service" ]; | |
| environment = hibernateEnvironment; | |
| script = '' | |
| curtime=$(date +%s) | |
| sustime=$(cat $HIBERNATE_LOCK) | |
| rm $HIBERNATE_LOCK | |
| if [ $(($curtime - $sustime)) -ge $HIBERNATE_SECONDS ] ; then | |
| systemctl hibernate | |
| else | |
| ${pkgs.utillinux}/bin/rtcwake -m no -s 1 | |
| fi | |
| ''; | |
| serviceConfig.Type = "simple"; | |
| }; | |
| } |
To fill in all the background to what I found out, it was specifically fixed in Systemd v253 (released February 15, 2023 but depends on when your distro updated to it).
* systemd-sleep 'HibernateDelaySec=' setting is changed back to
pre-v252's behaviour, and a new 'SuspendEstimationSec=' setting is
added to provide the new initial value for the new automated battery
estimation functionality. If 'HibernateDelaySec=' is set to any value,
the automated estimate (and thus the automated hibernation on low
battery to avoid data loss) functionality will be disabled.
Release page: https://github.com/systemd/systemd/releases/tag/v253
There are a couple more lid options in NixOS:
https://search.nixos.org/options?channel=24.05&from=0&size=50&sort=relevance&type=packages&query=services.logind.lidSwitch
services.logind.lidSwitchExternalPower defaults to what is set for services.logind.lidSwitch so I’m fine with this setting.
services.logind.lidSwitchDocked defaults to ignore which I like as well since I’m often docked to an external monitor so this means I can put the lid down and it doesn’t Suspend.
Has anyone figured out how to get this to work without that awesome before an after script? Its so weird that setting a simple 'suspend-then-hibernate' still won't work on NixOS.
Has anyone figured out how to get this to work without that awesome before an after script? Its so weird that setting a simple 'suspend-then-hibernate' still won't work on NixOS.
Read my 2 replies above. Suspend-then-hibernate works.
@jyap808 thanks a lot for the details :)
I get the feeling that having some basic hardware-configuration updates helps make this tool work efficiently.
I'm having great success with the suspend-then-hibernate in my config:
services.logind.lidSwitch = "suspend-then-hibernate";
I also have zramSwap going:
zramSwap.enable = true; zramSwap.memoryPercent = 50;
A swap partition designated in my hardware-config:
swapDevices = [ { device = "/dev/disk/by-uuid/c4a01f3b-299c-4871-a728-6d19f8106e7b"; } ];
This seems to be allowing my system to function properly. Also, if you haven't updated your hwconfig to opengl, and you happen to have an amd system, check out my full hardware-config:
`# Do not modify this file! It was generated by ‘nixos-generate-config’
and may be overwritten by future invocations. Please make changes
to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "sd_mod" ];
boot.initrd.kernelModules = [ "amdgpu" ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/a64bb1dc-cf69-4d41-89db-98a22ea3cabe";
fsType = "ext4";
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/1284-4374";
fsType = "vfat";
options = [ "fmask=0077" "dmask=0077" ];
};
fileSystems."/efi" =
{ device = "/dev/disk/by-uuid/ACD2-C2B7";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" ];
};
swapDevices =
[ { device = "/dev/disk/by-uuid/c4a01f3b-299c-4871-a728-6d19f8106e7b"; }
];
General AMD GPU/OpenGL support settings, for the 24.11 instructions:
hardware.graphics =
{ enable = true;
enable32Bit = true;
extraPackages = with pkgs; [
libvdpau-va-gl
libva-vdpau-driver
amdvlk
rocmPackages.clr
rocmPackages.clr.icd
libva
];
extraPackages32 = with pkgs; [
driversi686Linux.amdvlk
];
};
Enables DHCP on each ethernet and wireless interface. In case of scripted networking
(the default) this is the recommended approach. When using systemd-networkd it's
still possible to use this option, but it's recommended to use it in conjunction
with explicit per-interface declarations with networking.interfaces.<interface>.useDHCP.
networking.useDHCP = lib.mkDefault true;
networking.interfaces.eno1.useDHCP = lib.mkDefault true;
networking.interfaces.wlp2s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}
`
@jyap808 thats great news ! thanks for the update, will try it out :)