Power saving and screen locking in Sway
Pre-requirements
To enable power saving rules described in this post, you need to install these tools:
- swayidle - IDLE management daemon
- swaylock or swaylock-effects - screen locking utility for Wayland compositors
- ddcutil - program for managing monitor settings, such as brightness, color levels, and input source through DDC/CI (Display Data Channel Command Interface)
- power-profiles-daemon
- Makes power profiles handling available over D-Bus
- cpupower - shows and sets processor power related values
Rules
The goal is to implement power saving rules for IDLE state:
- after 2 minutes: lower the brightness of the LCD
- after 4 minutes: lock the screen
- after 5 minutes: turn off LCD displays (turn off DPMS)
- after 30 minutes: suspend operating system
Final configuration
Add these lines to Sway’s config
file:
exec_always killall -9 swayidle && swayidle -w \
timeout 120 'ddcutil detect | awk "/Display/ {print \$2}" | xargs -I{} ddcutil setvcp 10 30 --display {}' \
resume 'ddcutil detect | awk "/Display/ {print \$2}" | xargs -I{} ddcutil setvcp 10 100 --display {}' \
timeout 240 'swaylock -f --fade-in 5 --grace 10' \
timeout 300 'swaymsg "output * dpms off"' \
resume 'swaymsg "output * dpms on"' \
timeout 1800 'systemctl suspend' \
before-sleep 'swaylock -f'
CPU powersaving
-
Enable
power-profiles-daemon
systemctl enable --now power-profiles-daemon
-
Activate power profile:
powerprofilesctl set power-saver
(instead of
power-saver
profile you can use other one; check what profiles are available by executingpowerprofilesctl
without arguments)
How it works
Control LCD through DDC/CI
Modern LCDs have DDC Command Interface implemented.
First, you should detect your displays:
ddcutil detect
Then you can inspect capabilities of DDC, for example:
ddcutil capabilities --display 1
For example, my Dell U2417H returns these capabilities:
Model: U2417H
MCCS version: 2.1
Commands:
Op Code: 01 (VCP Request)
Op Code: 02 (VCP Response)
Op Code: 03 (VCP Set)
Op Code: 07 (Timing Request)
Op Code: 0C (Save Settings)
Op Code: E3 (Capabilities Reply)
Op Code: F3 (Capabilities Request)
VCP Features:
Feature: 02 (New control value)
Feature: 04 (Restore factory defaults)
Feature: 05 (Restore factory brightness/contrast defaults)
Feature: 08 (Restore color defaults)
Feature: 10 (Brightness)
Feature: 12 (Contrast)
Feature: 14 (Select color preset)
Values:
01: sRGB
04: 5000 K
05: 6500 K
06: 7500 K
08: 9300 K
09: 10000 K
0b: User 1
0c: User 2
Feature: 16 (Video gain: Red)
Feature: 18 (Video gain: Green)
Feature: 1A (Video gain: Blue)
Feature: 60 (Input Source)
Values:
10: DisplayPort-2
0f: DisplayPort-1
11: HDMI-1
Feature: AA (Screen Orientation)
Values:
01: 0 degrees
02: 90 degrees
03: 180 degrees
04: 270 degrees
Feature: AC (Horizontal frequency)
Feature: AE (Vertical frequency)
Feature: B6 (Display technology type)
Feature: C6 (Application enable key)
Feature: C8 (Display controller type)
Feature: C9 (Display firmware level)
Feature: D6 (Power mode)
Values:
01: DPM: On, DPMS: Off
04: DPM: Off, DPMS: Off
05: Write only value to turn off display
Feature: DC (Display Mode)
Values:
00: Standard/Default mode
02: Mixed
03: Movie
05: Games
Feature: DF (VCP Version)
Feature: E0 (Manufacturer specific feature)
Feature: E1 (Manufacturer specific feature)
Feature: E2 (Manufacturer specific feature)
Values: 00 01 02 04 0B 0C 0D 0F 10 11 13 14 19 (interpretation unavailable)
Feature: F0 (Manufacturer specific feature)
Values: 08 (interpretation unavailable)
Feature: F1 (Manufacturer specific feature)
Feature: F2 (Manufacturer specific feature)
Feature: FD (Manufacturer specific feature)
We’re looking for VCP 0x10
, which in VESA standard is a feature for
controlling the Brightness, and we’ll use VCP set
command 0x03
to
set a new brightness value.
In the example below, the command is setting brightness (VCP 0x10
) to
75
for LCD #1:
ddcutil setvcp 10 75 --display 1
When setting up timeout command for swayidle
, remember to add command
reversing the state after resume, like:
exec_always swayidle -w \
timeout 120 'ddcutil setvcp 10 30 --display 1' \
resume 'ddcutil setvcp 10 100 --display 1'
You can play with any features you want to control for power saving. Read full VESA DDC/CI Specification for more details.
Swaylock
For locking the screen I recommend to use swaylock
, or more
preferrably – swaylock-effects
.
The example config ~/.config/swaylock/config
could look like:
screenshots
clock
effect-blur=6x6
effect-vignette=0.5:0.5
color=1e1e2e
indicator-idle-visible
indicator-radius=140
indicator-thickness=12
key-hl-color=89b4fa
bs-hl-color=f38ba8
inside-color=313244
inside-clear-color=313244
inside-ver-color=313244
inside-wrong-color=313244
ring-color=45475a
ring-clear-color=89dceb
ring-ver-color=89b4fa
ring-wrong-color=f38ba8
text-color=cdd6f4
text-clear-color=cdd6f4
text-ver-color=cdd6f4
text-wrong-color=cdd6f4
show-failed-attempts
This configuration will take a screenshot, apply blur and vignette, and display the clock.
By using grace
argument, you can set a gap between starting a screen
lock (fading and bluring the screen) and requiring the password to unlock the screen.
So by calling:
swaylock --grace 10 --fade-in 5
the screen will fade in 5 seconds, and require password after 10 seconds.
Remember to add -f
argument (daemonize) when calling in swayidle
.
Without the -f
argument, swayidle
will wait until password is
enetered!
exec_always swayidle -w \
timeout 240 'swaylock -f --fade-in 5 --grace 10'
Turning off LCDs
You can turn on or off LCDs by swaymsg
. Sway’s output
command can
control DPMS directly.
For turn off the LCDs you must call:
swaymsg "output * dpms off"
For turn on the LCDs you must call:
swaymsg "output * dpms on"
Apply these commadns as timeout
and resume
commands of swayidle
:
exec_always swayidle -w \
timeout 300 'swaymsg "output * dpms off"' \
resume 'swaymsg "output * dpms on"'
AMD CPU freq scaling
For AMD CPUs like Ryzen, you must enable amd_pstate
feature in Linux.
To do that you must edit /etc/default/grub
file and enable the feature
in GRUB_CMDLINE_LINUX_DEFAULT
line by adding:
amd_pstate=active
The full command line will look like:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash [...] amd_pstate=active"
Then you must update GRUB:
update-grub
Now you must reboot your PC. To verify if amd_pstate
is working, you
should call in the terminal:
# cat /sys/devices/system/cpu/amd_pstate/status
active