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"; | |
}; | |
} |
This works but I did some more reading and testing.
It looks like hibernate-then-suspend was broken for a while in 2022 in systemd but they have since fixed it. This has caused a lot of confusion.
You can add this:
systemd.sleep.extraConfig = ''
HibernateDelaySec=60min
'';
systemctl suspend
will still just Suspend so the default lid action will still be to Suspend. systemctl suspend-then-hibernate
works with the configuration setting in place.
To then change the default lid behavior, you then need to:
services.logind.lidSwitch = "suspend-then-hibernate";
@jyap808 thats great news ! thanks for the update, will try it out :)
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 :)
Very nice! Note for the 13'' AMD Framework laptop:
AC
needs to beACAD
:)