feat(power): suspend-then-hibernate 1h on battery (#115)
All checks were successful
Check / eval (push) Successful in 6m16s
All checks were successful
Check / eval (push) Successful in 6m16s
Human decision: 1h delay, battery only, Preferences enable/disable. Wire systemd suspend-then-hibernate + HibernateDelaySec=1h + HibernateOnACPower=false when settings.power.suspendThenHibernate is on and boot.resumeDevice is set. Lid: s2h undocked, plain suspend on AC. nomarchy-suspend for hypridle + Power menu (live state). LUKS unlock before encrypted hibernate so s2h→disk is not double-password. state-bridges assert the policy; HARDWARE-QUEUE #115 + suggested order. V1: nix flake check --no-build. V3: bag-carry on hardware.
This commit is contained in:
65
pkgs/nomarchy-suspend/default.nix
Normal file
65
pkgs/nomarchy-suspend/default.nix
Normal file
@@ -0,0 +1,65 @@
|
||||
{ lib
|
||||
, writeShellScriptBin
|
||||
, coreutils
|
||||
, gnugrep
|
||||
, jq
|
||||
, systemd
|
||||
}:
|
||||
|
||||
# Smart suspend (#115): on battery, with hibernate available and the
|
||||
# in-flake toggle on, enter suspend-then-hibernate (1h → hibernate via
|
||||
# systemd.sleep HibernateDelaySec). Otherwise plain suspend.
|
||||
#
|
||||
# Reads the *live* state.json (menu may have flipped before rebuild);
|
||||
# logind lid policy still needs a system rebuild to match (power.nix).
|
||||
writeShellScriptBin "nomarchy-suspend" ''
|
||||
set -euo pipefail
|
||||
PATH=${lib.makeBinPath [ coreutils gnugrep jq systemd ]}:$PATH
|
||||
|
||||
on_ac() {
|
||||
local f
|
||||
for f in /sys/class/power_supply/*/online; do
|
||||
[ -r "$f" ] && [ "$(cat "$f")" = "1" ] && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
can_hibernate() {
|
||||
# Prefer logind's live answer (swap + resume wiring).
|
||||
local v
|
||||
v=$(busctl get-property org.freedesktop.login1 \
|
||||
/org/freedesktop/login1 org.freedesktop.login1.Manager \
|
||||
CanHibernate 2>/dev/null || true)
|
||||
case "$v" in
|
||||
"s \"yes\"") return 0 ;;
|
||||
esac
|
||||
# Offline / early-boot fallback: resume= on the kernel cmdline.
|
||||
grep -q '[[:space:]]resume=' /proc/cmdline 2>/dev/null \
|
||||
|| grep -q '^resume=' /proc/cmdline 2>/dev/null
|
||||
}
|
||||
|
||||
want_s2h() {
|
||||
# Default on (absent key / no state file) — bag-carry drains less without
|
||||
# a Preferences trip; menu writes false to opt out.
|
||||
local st v="" found=0
|
||||
for st in \
|
||||
"''${NOMARCHY_PATH:-$HOME/.nomarchy}/state.json" \
|
||||
/home/*/.nomarchy/state.json
|
||||
do
|
||||
[ -r "$st" ] || continue
|
||||
found=1
|
||||
v=$(jq -r '.settings.power.suspendThenHibernate // true' "$st" 2>/dev/null || true)
|
||||
break
|
||||
done
|
||||
[ "$found" -eq 0 ] && return 0
|
||||
case "$v" in
|
||||
false|False|0) return 1 ;;
|
||||
*) return 0 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
if want_s2h && ! on_ac && can_hibernate; then
|
||||
exec systemctl suspend-then-hibernate
|
||||
fi
|
||||
exec systemctl suspend
|
||||
''
|
||||
Reference in New Issue
Block a user