Power Management
Power Management & Idle Orchestration
A universal, role-aware power management system orchestrating system sleep, hardware suspend, and desktop idle behaviors across diverse hosts.
This repository features a unified power management architecture centered at modules/services/system/power-management.nix. It dynamically adjusts CPU governors, sleep delays, lid behaviors, and Wayland idle daemons based on the host’s explicitly defined profile role and hardware tags.
🏗️ Architecture
Instead of hardcoding power behavior per host, the system evaluates the profile configuration (config.modules.profiles):
- Role (
modules.profiles.role): Determines if a system is aserver,board,workstation/pc,workstation/laptop, orportable. - Hardware (
modules.profiles.hardware): Identifies specific hardware form factors (e.g.,pc/laptop), enabling or disabling device-specific daemon optimizations. - Caffeine State: A dynamic, runtime-toggleable state to temporarily suspend sleep behaviors.
Evaluation Logic
The core logic dynamically asserts canSleep and isLaptop:
- Servers (
role = "server") & Workstation Servers (role = "workstation/server"):canSleepis set tofalse. The system will never attempt to suspend or hibernate, regardless of timeouts. Desktop locks still occur if active. - SBCs (
role = "board"):canSleepis set tofalse. Uses apowersaveCPU governor to reduce thermals, but remains continually active (useful for services like AdGuard Home). - Laptops & Portable Media (
role = "workstation/laptop"orrole = "portable"):canSleepis set totrue. Enablespower-profiles-daemon, explicitly disablestlpto prevent conflicts, handles lid switches (suspendon close,lockon external power). - Workstations (
role = "workstation/pc"):canSleepis set totrue. Uses theperformanceCPU governor and participates in standard idle/sleep timeouts.
💤 Idle & Suspend Flow
When canSleep evaluates to true, the system employs a synchronized suspend-then-hibernate strategy.
Desktop Idle Timeouts
Wayland idle managers (swayidle for standard compositors, hypridle for Hyprland/Niri) are configured under modules.services.desktop.
- Lock Screen (30-40 min): The system issues a
hey hook idle --on lockevent. - Auto-Sleep (30-40 min): A
timeoutlistener is fired. Instead of natively commanding systemd to sleep, it invokes a safety check against the user’s Caffeine status. If Caffeine is off,systemctl suspend-then-hibernateis triggered.
Systemd Hook Orchestration
Instead of binding visual lockdown effects directly to the idle timer (which causes desyncs during manual sleeps or lid-closes), the system uses systemd sleep hooks:
before-sleepEvent: Whensystemctl suspendis triggered,systemdemits abefore-sleepsignal.- Zsh Bridge: The idle daemon catches this signal and runs
hey hook idle --on sleep(viabin/hooks/idle.zsh). - Preparation: The script pauses active media (
playerctl -a pause), emits a shutdown sound, disables active VRR/tearing, and fires the screen locker before the hardware halts.
☕ Caffeine Mode (Presentation Mode)
Users can actively inhibit the auto-sleep behavior by toggling Caffeine Mode.
- Toggle Command:
hey .toggle-caffeine(Bound toMod+Shift+Ion Hyprland and Niri). - Mechanism: The script alters a persistent
tmpfsstate variable (hey vars set caffeine true) and touches a flat-file/tmp/caffeine_statefor external UI modules (like DMS Shell) to read. - Execution Check: The idle daemon’s auto-sleep command natively reads this state:
if [ "$(${heyBin} vars get caffeine)" != "true" ]; then systemctl suspend-then-hibernate; fi. If true, it silently exits. The screen will still automatically lock, but the hardware will remain awake.
🔧 Resolving Conflicts (TLP vs. PPD)
We strictly standardize on power-profiles-daemon for modern laptops. Tools like powertop (auto-tune service) and tlp are actively disabled (services.tlp.enable = mkForce false;) to prevent complex USB-suspension bugs and governor overriding conflicts.