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.
Last active
March 5, 2024 19:33
-
-
Save mattdenner/befcf099f5cfcc06ea04dcdd4969a221 to your computer and use it in GitHub Desktop.
Suspend and then hibernate after 60 minutes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ 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"; | |
}; | |
} |
I tested it on my nixos setup and works as intended. Many thanks 😁. Was curious as to why before it goes to hibernation it needs to wake up first from suspend.
A small modification on my end in case anyone is interested, here it will only go into hibernation from suspension IF it is not plugged into power source:
{ config, pkgs, ... }:
let
hibernateEnvironment = {
HIBERNATE_SECONDS = "10";
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 only if not on AC power";
wantedBy = [ "suspend.target" ];
before = [ "systemd-suspend.service" ];
environment = hibernateEnvironment;
script = ''
if [ $(cat /sys/class/power_supply/AC/online) -eq 0 ]; then
curtime=$(date +%s)
echo "$curtime $1" >> /tmp/autohibernate.log
echo "$curtime" > $HIBERNATE_LOCK
${pkgs.utillinux}/bin/rtcwake -m no -s $HIBERNATE_SECONDS
else
echo "System is on AC power, skipping wake-up scheduling for hibernation." >> /tmp/autohibernate.log
fi
'';
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";
};
}
Very nice! Note for the 13'' AMD Framework laptop: AC
needs to be ACAD
:)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
this is awesome! suspend-then-hibernate from systemd was first broken by a weird spat between the maintainer and everyone else, then kinda stopped working entirely for me. This config works, with one minor addition you might want to add at some point -- if you have an nvidia card and use the power management systemd services, then hibernate-after-recovery should come after "nvidia-resume.service".