Backlight: Difference between revisions

From NixOS Wiki
imported>Samueldr
m WIP, cleaning and re-working sections
m add source link to ddcci overlay
 
(15 intermediate revisions by 12 users not shown)
Line 1: Line 1:
{{expansion}}
== Introduction ==
This page documents methods for controlling backlight (aka screen brightness) and tips to control it via hotkeys.
This page documents methods for controlling backlight (aka screen brightness) and tips to control it via hotkeys.
== Kernel native ==
Some laptops, using a recent enough kernel, will automatically handle increasing and decreasing the backlight using the hot keys. The following tools will allow scripting or controlling the backlight using other means, if desired.
== Desktop Environment native ==
Some desktop environments will handle querying and setting the backlight, including configuring the backlight keys. These include at least: Plasma (KDE) and XFCE. It may be needed to configure or start some desktop environment-specific services.


== <code>xbacklight</code> ==
== <code>xbacklight</code> ==
Line 16: Line 22:
== <code>light</code> ==
== <code>light</code> ==


<code>light</code> does not use X to change the light settings. This can be used in situations where the X service isn't available. While it does not use X, it will need some privileges to work. This means that it needs to either be installed in a specific way (with a SUID wrapper) or used using <code>sudo</code>, or ran with superuser privileges.
<code>light</code> does not use X to change the light settings. This can be used in situations where the X service isn't available. While it does not use X, it will need some privileges to work.


To enable the use of <code>light</code> with SUID wrappers, add this to your <tt>configuration.nix</tt>.
To enable the use of <code>light</code>, add this to your <tt>configuration.nix</tt> and make sure that your user is a member of the <code>video</code> group.


<syntaxhighlight lang=nix>
<syntaxhighlight lang=nix>
Line 25: Line 31:


The following commands will allow you to test <code>light</code>:
The following commands will allow you to test <code>light</code>:
*<code>light -U 30</code> — the screen should become darker.
* <code>light -U 30</code> — the screen should become darker.
*<code>light -A 30</code> — the screen should become brighter.
* <code>light -A 30</code> — the screen should become brighter.


Be careful using <code>light -U</code>, as you might turn your backlight completely off! You will not be able to see what you're typing anymore.
Be careful using <code>light -U</code>, as you might turn your backlight completely off! You will not be able to see what you're typing anymore.
== <code>brightnessctl</code> ==
{{nixos:package|brightnessctl}} ([https://github.com/Hummer12007/brightnessctl homepage]) is another option, which, like <code>light</code>, would work even without X or on Wayland.
You can use it by simply installing the package. Since <code>brightnessctl</code> supports the systemd-logind API it should work out of the box (i.e. without installing any udev rules or using a setuid wrapper).
The following commands will allow you to test <code>brightnessctl</code>:
* <code> brightnessctl set 5%-</code> - the screen should become darker.
* <code> brightnessctl set 5%+</code> - the screen should become brighter.
If you get an error like <code>Failed to set brightness: Protocol error</code>, check that you are using the right device. You can get a list of the devices with running <code>brightnessctl -l</code> and then specify the device with <code>-d deviceName</code>.
Example: <code>brightnessctl set 5%- -d intel_backlight</code>
== External Monitors  ==
The DDC/CI (I2C) interface may be available to control the brightness of your external monitor. There are two ways to do this:
=== Via <code>ddcutil</code> ===
<syntaxhighlight lang=shell>
$ sudo modprobe i2c-dev
$ nix-shell -p ddcutil --command "sudo ddcutil --bus=MYBUSNUM setvcp 10 MYBRIGHTNESSPCT"
</syntaxhighlight>
You can find the correct bus number by examining the paths in <code>/sys/bus/i2c/devices</code>. e.g. to control the <code>DP4</code> device below use device <code>17</code>.
<syntaxhighlight lang=shell>
$ ls -l /sys/bus/i2c/devices/
lrwxrwxrwx - root  2 Nov 12:34 i2c-13 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-eDP-1/i2c-13
lrwxrwxrwx - root  2 Nov 12:34 i2c-14 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-1/i2c-14
lrwxrwxrwx - root  2 Nov 12:34 i2c-15 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-2/i2c-15
lrwxrwxrwx - root  2 Nov 12:34 i2c-16 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-3/i2c-16
lrwxrwxrwx - root  2 Nov 12:34 i2c-17 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-4/i2c-17
</syntaxhighlight>
All together: <syntaxhighlight lang=shell>
nix-shell -p ddcutil --command "sudo ddcutil --bus=17 setvcp 10 65"
</syntaxhighlight>
You can then bind this to a hotkey or similar. <code>sudo</code> may be avoidable if your user is in the correct group, or udev rules have set the appropriate <code>/sys</code> permissions.
Add <code>i2c-dev</code> to <code>boot.kernelModules</code> and {{nixos:package|ddcutil}} to your system packages to make permanent.
=== Via <code>ddcci-driver</code> ===
A [https://gitlab.com/ddcci-driver-linux/ddcci-driver-linux driver] exists which exposes the ddcci control as a more standard <code>backlight</code> device, allowing it to be controlled by standard utilities such as <code>brightnessctl</code>. e.g. when setup:
<syntaxhighlight lang=shell>
$ find /sys/class/backlight
/sys/class/backlight
/sys/class/backlight/ddcci17
/sys/class/backlight/intel_backlight
$ brightnessctl --device=ddcci17 set 100%
Updated device 'ddcci17':
Device 'ddcci17' of class 'backlight':
Current brightness: 100 (100%)
Max brightness: 100
</syntaxhighlight>
Get the i2c name:
<syntaxhighlight lang=shell>
$ cat /sys/bus/i2c/devices/i2c-17/name                   
AUX USBC4/DDI TC4/PHY TC4
</syntaxhighlight>
<syntaxhighlight lang=nix>
boot.extraModulePackages = with config.boot.kernelPackages; [ ddcci-driver ];
boot.kernelModules = [ "ddcci-backlight" ];
services.udev.extraRules = let
      bash = "${pkgs.bash}/bin/bash";
      ddcciDev = "AUX USBC4/DDI TC4/PHY TC4";                                                                                                     
      ddcciNode = "/sys/bus/i2c/devices/i2c-17/new_device";
    in ''
      SUBSYSTEM=="i2c", ACTION=="add", ATTR{name}=="${ddcciDev}", RUN+="${bash} -c 'sleep 30; printf ddcci\ 0x37 > ${ddcciNode}'"
    '';
</syntaxhighlight>
Device autodetection is tricky with i2c so we need to trigger it manually with the <code>0x37</code> code. The <code>sleep</code> is often unfortunately necessary.
The driver has had some issues with kernels > 6.8, the below overlay should allow it to build if you encounter issues ([https://gitlab.com/ddcci-driver-linux/ddcci-driver-linux/-/merge_requests/17 source]).
<syntaxhighlight lang=nix>
  nixpkgs.overlays = [
      (self: super: {
        linuxPackages_latest = super.linuxPackages_latest.extend (lpself: lpsuper: {
          ddcci-driver = super.linuxPackages_latest.ddcci-driver.overrideAttrs (oldAttrs: {
            version = super.linuxPackages_latest.ddcci-driver.version + "-FIXED";
            src = pkgs.fetchFromGitLab {
              owner = "ddcci-driver-linux";
              repo = "ddcci-driver-linux";
              rev = "0233e1ee5eddb4b8a706464f3097bad5620b65f4";
              hash = "sha256-Osvojt8UE+cenOuMoSY+T+sODTAAKkvY/XmBa5bQX88=";
            };
            patches = [
              (pkgs.fetchpatch {
                name = "ddcci-e0605c9cdff7bf3fe9587434614473ba8b7e5f63.patch";
                url = "https://gitlab.com/nullbytepl/ddcci-driver-linux/-/commit/e0605c9cdff7bf3fe9587434614473ba8b7e5f63.patch";
                hash = "sha256-sTq03HtWQBd7Wy4o1XbdmMjXQE2dG+1jajx4HtwBHjM=";                                                                     
              })
            ];
          });
        });
      })
    ];
</syntaxhighlight>
== <code>/sys/class/backlight/...</code> ==
The <code>/sys/class/backlight/*/brightness</code> files are a built-in way to set brightness. Use them e.g. with:
<syntaxhighlight lang=bash>
  sudo tee /sys/class/backlight/intel_backlight/brightness <<< 300
</syntaxhighlight>
to set the brightness to <code>300</code>, where the maximum is stored in <code>brightness_max</code>. You can set file permissions e.g. with a udev rule, if you don't want to use sudo. Here is an example udev rule, where you will likely have to replace intel_backlight, with the name in your /sys/class/backlight/:
<syntaxhighlight lang=nix>
  services.udev.extraRules = ''
    ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", MODE="0666", RUN+="${pkgs.coreutils}/bin/chmod a+w /sys/class/backlight/%k/brightness"
  '';
</syntaxhighlight>


== Tips ==
== Tips ==
Line 34: Line 163:
=== Key mapping ===
=== Key mapping ===


Once the backend functionality of controlling the backlight is verified, you can assign that to an actual key. Different laptops and keyboards may map the hotkeys to different key codes.
While controlling the backlight via the command line is useful, it would be preferable to control it using key bindings. This is especially true considering most laptops have backlight control keys.


== Key mapping - obtain key codes via xev ==
There are two main choices to add key bindings, using a system-level service like [[actkbd]] or using an X session tool, either provided by your [[:Category:Desktop environment|Desktop environment]], [[Window manager]] or a tool like [[xbindkeys]].
While logged into an X session:<br />
<code>nix-shell -p xorg.xev</code><br />
<code>xev</code><br />
Xev reports key codes, but they did not seem to be the right codes for use with actkbd.


== Key mapping - obtain key codes via actkbd ==
Depending on the tools that work for controlling the backlight you will be able to choose one of those options.
First enable the actkbd service (see below).<br />
To read key codes via actkbd, you need to select the right input event provider from /dev/input/. Each input device generating input events has it's own entry there, enumerated with an number. To find out which one generates the events from the hotkeys, it is viable (if tedious) to run the below command with each available entry, and see which one generates event notifications when pressing the brightness hotkeys:<br />
<code>actkbd -v9 -n -s -d /dev/input/event<number></code><br />
Once you discover the right one, it will report key presses like so:<br />
<code>Event: <number>:key</code><br />
<code>Event: <number>:rel</code><br />
Those represent the key-press and key-release actions. The number is the key code to use for mapping.


== Key mapping - map via actkbd service ==
{| class="wikitable"
To map keys using actkbd service and the <code>light</code> program, add the following to your configuration.nix file:<br />
|-
<syntaxhighlight lang="nix">services.actkbd = {
!  
  enable = true;
| <code>light</code>
  bindings = [
| <code>xbacklight</code>
    {keys = [ <brightnessDown> ]; events = [ "key" ]; command = "run/wrappers/bin/light -U 10";}
|-
    {keys = [ <brightnessUp> ]; events = [ "key" ]; command = "run/wrappers/bin/light -A 10";}
! System service
  ];
| Yes
};</syntaxhighlight>
| With hacks
Where <brightnessUp> and <brightnessDown> are the key codes obtained before.
|-
! X session
| Yes
| Yes
|}


== Working configuration on Lenovo T440 ==
Follows, an example mapping for use with actkbd:
To enable backlight control on a Lenovo T440, add to configuration.nix:<br />


<syntaxhighlight lang="nix">programs.light.enable = true;
{{note|This was verified to work with
services.actkbd = {
 
  enable = true;
* NixOS 18.03 on a Lenovo T440 and
  bindings = [
* NixOS 19.09pre173166.373488e6f4c on a Lenovo X240
  { keys = [ 224 ]; events = [ "key" ]; command = "/run/wrappers/bin/light -A 10"; }
 
  { keys = [ 225 ]; events = [ "key" ]; command = "/run/wrappers/bin/light -U 10"; }
it may work on other models, but is unconfirmed. See [[actkbd]] for details on finding out the proper key bindings. Also check if the path to the light binary is correct.}}
  ];
 
};</syntaxhighlight>
<syntaxhighlight lang=nix>
Tested with NixOS 18.03, and in combination with lightdm & i3.
  programs.light.enable = true;
  services.actkbd = {
    enable = true;
    bindings = [
      { keys = [ 224 ]; events = [ "key" ]; command = "/run/current-system/sw/bin/light -A 10"; }
      { keys = [ 225 ]; events = [ "key" ]; command = "/run/current-system/sw/bin/light -U 10"; }
    ];
  };
</syntaxhighlight>
 
== OLED Screens ==
 
OLED screens do not have a backlight, but their perceived brightness can be changed via xrandr:
 
* <code>xrandr --output <output> --brightness .5</code> - dim to 50%
* <code>xrandr --output <output> --brightness 1</code> - no dimming


== See also ==
== See also ==


* [https://wiki.archlinux.org/index.php/backlight Arch Linux wiki page about the backlight]
* [https://wiki.archlinux.org/index.php/backlight Arch Linux wiki page about the backlight]
[[category:hardware]]

Latest revision as of 17:05, 2 November 2024

This page documents methods for controlling backlight (aka screen brightness) and tips to control it via hotkeys.

Kernel native

Some laptops, using a recent enough kernel, will automatically handle increasing and decreasing the backlight using the hot keys. The following tools will allow scripting or controlling the backlight using other means, if desired.

Desktop Environment native

Some desktop environments will handle querying and setting the backlight, including configuring the backlight keys. These include at least: Plasma (KDE) and XFCE. It may be needed to configure or start some desktop environment-specific services.

xbacklight

xbacklight uses X to change the light settings. This can be inconvenient in some situations, e.g. for use with the services.actkbd service, which doesn't know about the X session. It, though, has an history of being more compatible with different hardware, especially newer hardware[citation needed]

To install xbacklight globally, add this to your configuration.nix.

  environment.systemPackages = with pkgs; [ xorg.xbacklight ];

Alternatively, use nix-env -iA nixos.xorg.xbacklight to install it to your user profile.

light

light does not use X to change the light settings. This can be used in situations where the X service isn't available. While it does not use X, it will need some privileges to work.

To enable the use of light, add this to your configuration.nix and make sure that your user is a member of the video group.

  programs.light.enable = true;

The following commands will allow you to test light:

  • light -U 30 — the screen should become darker.
  • light -A 30 — the screen should become brighter.

Be careful using light -U, as you might turn your backlight completely off! You will not be able to see what you're typing anymore.

brightnessctl

brightnessctl (homepage) is another option, which, like light, would work even without X or on Wayland.

You can use it by simply installing the package. Since brightnessctl supports the systemd-logind API it should work out of the box (i.e. without installing any udev rules or using a setuid wrapper).

The following commands will allow you to test brightnessctl:

  • brightnessctl set 5%- - the screen should become darker.
  • brightnessctl set 5%+ - the screen should become brighter.

If you get an error like Failed to set brightness: Protocol error, check that you are using the right device. You can get a list of the devices with running brightnessctl -l and then specify the device with -d deviceName.

Example: brightnessctl set 5%- -d intel_backlight

External Monitors

The DDC/CI (I2C) interface may be available to control the brightness of your external monitor. There are two ways to do this:

Via ddcutil

$ sudo modprobe i2c-dev
$ nix-shell -p ddcutil --command "sudo ddcutil --bus=MYBUSNUM setvcp 10 MYBRIGHTNESSPCT"

You can find the correct bus number by examining the paths in /sys/bus/i2c/devices. e.g. to control the DP4 device below use device 17.

$ ls -l /sys/bus/i2c/devices/
lrwxrwxrwx - root  2 Nov 12:34 i2c-13 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-eDP-1/i2c-13
lrwxrwxrwx - root  2 Nov 12:34 i2c-14 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-1/i2c-14
lrwxrwxrwx - root  2 Nov 12:34 i2c-15 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-2/i2c-15
lrwxrwxrwx - root  2 Nov 12:34 i2c-16 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-3/i2c-16
lrwxrwxrwx - root  2 Nov 12:34 i2c-17 -> ../../../devices/pci0000:00/0000:00:02.0/drm/card1/card1-DP-4/i2c-17

All together:

nix-shell -p ddcutil --command "sudo ddcutil --bus=17 setvcp 10 65"

You can then bind this to a hotkey or similar. sudo may be avoidable if your user is in the correct group, or udev rules have set the appropriate /sys permissions.

Add i2c-dev to boot.kernelModules and ddcutil to your system packages to make permanent.

Via ddcci-driver

A driver exists which exposes the ddcci control as a more standard backlight device, allowing it to be controlled by standard utilities such as brightnessctl. e.g. when setup:

$ find /sys/class/backlight
/sys/class/backlight
/sys/class/backlight/ddcci17
/sys/class/backlight/intel_backlight

$ brightnessctl --device=ddcci17 set 100%
Updated device 'ddcci17':
Device 'ddcci17' of class 'backlight':
	Current brightness: 100 (100%)
	Max brightness: 100

Get the i2c name:

$ cat /sys/bus/i2c/devices/i2c-17/name                     
AUX USBC4/DDI TC4/PHY TC4
boot.extraModulePackages = with config.boot.kernelPackages; [ ddcci-driver ];
boot.kernelModules = [ "ddcci-backlight" ];
services.udev.extraRules = let
      bash = "${pkgs.bash}/bin/bash";
      ddcciDev = "AUX USBC4/DDI TC4/PHY TC4";                                                                                                      
      ddcciNode = "/sys/bus/i2c/devices/i2c-17/new_device";
    in ''
      SUBSYSTEM=="i2c", ACTION=="add", ATTR{name}=="${ddcciDev}", RUN+="${bash} -c 'sleep 30; printf ddcci\ 0x37 > ${ddcciNode}'"
    '';

Device autodetection is tricky with i2c so we need to trigger it manually with the 0x37 code. The sleep is often unfortunately necessary.

The driver has had some issues with kernels > 6.8, the below overlay should allow it to build if you encounter issues (source).

  nixpkgs.overlays = [
      (self: super: {
        linuxPackages_latest = super.linuxPackages_latest.extend (lpself: lpsuper: {
          ddcci-driver = super.linuxPackages_latest.ddcci-driver.overrideAttrs (oldAttrs: {
            version = super.linuxPackages_latest.ddcci-driver.version + "-FIXED";
            src = pkgs.fetchFromGitLab {
              owner = "ddcci-driver-linux";
              repo = "ddcci-driver-linux";
              rev = "0233e1ee5eddb4b8a706464f3097bad5620b65f4";
              hash = "sha256-Osvojt8UE+cenOuMoSY+T+sODTAAKkvY/XmBa5bQX88=";
            };
            patches = [
              (pkgs.fetchpatch {
                name = "ddcci-e0605c9cdff7bf3fe9587434614473ba8b7e5f63.patch";
                url = "https://gitlab.com/nullbytepl/ddcci-driver-linux/-/commit/e0605c9cdff7bf3fe9587434614473ba8b7e5f63.patch";
                hash = "sha256-sTq03HtWQBd7Wy4o1XbdmMjXQE2dG+1jajx4HtwBHjM=";                                                                      
              })
            ];
          });
        });
      })
    ];

/sys/class/backlight/...

The /sys/class/backlight/*/brightness files are a built-in way to set brightness. Use them e.g. with:

  sudo tee /sys/class/backlight/intel_backlight/brightness <<< 300

to set the brightness to 300, where the maximum is stored in brightness_max. You can set file permissions e.g. with a udev rule, if you don't want to use sudo. Here is an example udev rule, where you will likely have to replace intel_backlight, with the name in your /sys/class/backlight/:

  services.udev.extraRules = ''
    ACTION=="add", SUBSYSTEM=="backlight", KERNEL=="intel_backlight", MODE="0666", RUN+="${pkgs.coreutils}/bin/chmod a+w /sys/class/backlight/%k/brightness"
  '';

Tips

Key mapping

While controlling the backlight via the command line is useful, it would be preferable to control it using key bindings. This is especially true considering most laptops have backlight control keys.

There are two main choices to add key bindings, using a system-level service like actkbd or using an X session tool, either provided by your Desktop environment, Window manager or a tool like xbindkeys.

Depending on the tools that work for controlling the backlight you will be able to choose one of those options.

  light xbacklight
System service Yes With hacks
X session Yes Yes

Follows, an example mapping for use with actkbd:

Note: This was verified to work with
  • NixOS 18.03 on a Lenovo T440 and
  • NixOS 19.09pre173166.373488e6f4c on a Lenovo X240
it may work on other models, but is unconfirmed. See actkbd for details on finding out the proper key bindings. Also check if the path to the light binary is correct.
  programs.light.enable = true;
  services.actkbd = {
    enable = true;
    bindings = [
      { keys = [ 224 ]; events = [ "key" ]; command = "/run/current-system/sw/bin/light -A 10"; }
      { keys = [ 225 ]; events = [ "key" ]; command = "/run/current-system/sw/bin/light -U 10"; }
    ];
  };

OLED Screens

OLED screens do not have a backlight, but their perceived brightness can be changed via xrandr:

  • xrandr --output <output> --brightness .5 - dim to 50%
  • xrandr --output <output> --brightness 1 - no dimming

See also