The Life of a Programmer

Search

Keeping my monitor brightness after power save and switch

Upgrading to Ubuntu 22.04 brought along a frustrating bug: every time I switch monitors on my KVM, or when the system comes out of power saving, my monitor brightness settings are lost. I have a script I run to reset the values, but it’s too annoying. Something has to be done.

But why?

A normal person might think, why don’t you just turn down the brightness on your monitor? Alas, my monitor is beholden to the vanity of its HDR range, and 0% brightness is more like 50%. I need to turn it down more.

Plus, I don’t like the gamma colour balance.

I want this setting, persisted, forever, only changing if I decide so:

xrandr --output HDMI-0 --brightness 0.5 --gamma “0.9:0.9:0.75”

xrandr

xrandr is the lifeblood of monitor configuration in Linux. From activating monitors, changing orientation, and, of course, to setting the brightness, it does everything. Well, not quite, especially since Ubuntu 22.04 overwrites the settings — bad Ubuntu.

Asking at “Ask Ubuntu” got me the less than helpful response that I shouldn’t expect the system to honour settings not done via the settings console. I might accept that position if brightness and gamma were adjustable in the settings, but alas, they are not. I’m using Kubuntu desktop, and there’s no brightness setting. There’s gamma, but for who knows what reason, brightness is absent.

I use an nvidia card, so tried their settings tool as well. The “permanent” nvidia settings are also overwritten. This further confirms a regression in the operating system.

A Solution

After many headaches and searching, the below is the best I could come up with it. It watches for udev changes, which should trigger anytime the monitor is disconnected, or powered on/off. As you see however, there’s nonsense.

#!/bin/bash
log_file=/tmp/watch_monitor.txt
echo "Watching" > $log_file

udevadm monitor --subsystem-match=drm --udev |
while read line
do
	date >> $log_file
	echo $line >> $log_file
	status=$(cat /sys/class/drm/card0-HDMI-A-1/status)
	if [ "$status" = "connected" ];
	then
		echo "CONNECTED"  >> $log_file
		for i in {1..10}; do
			xrandr --output HDMI-0 --brightness 0.5 --gamma "0.9:0.9:0.75" &>> $log_file 
			brightness=$(xrandr --verbose | grep Brightness | cut -d ' ' -f 2)
			if [ "${brightness}" = "0.50" ]; then
				break
			fi
			echo "Try Again..."  >> $log_file
			sleep 0.5s
		done
	fi
done
udevadm

udevadm is a high-level interface to the udev system. I’m using it to read events about the hardware. I appear unable to watch for events for a particular connection, so I’m listening to all “drm” events — which is the display subsystem. The events look like this:

UDEV [1483.203365] change /devices/pci0000:64/0000:64:00.0/0000:65:00.0/drm/card0 (drm)

There’s no clean way to map this device path to the monitor of interest, at least not one that I’ve found. I don’t know from the event whether my monitor has changed, or what its status is, only that something display related has changed. Indeed, each time I do a KVM switch, I get several events for the same device. I’m unsure why.

Thus I read /sys/class/drm/card0-HDMI-A-1/status to check if the video output is actually connected.

Mystery of xrandr and /sys/class/drm names

Hold on though, what is this “card0-HDMI-A-1” name? In xrandr my output is HDMI-0. I could not find any way that would link the two names together, so I manually tried all the cards in sys/class/drm until I found the right one.

Does anybody know how to determine link the two names together?

Curiously, if I want information about this device I can type udevadm info -q all -a /dev/dri/card0, which is yet another name for it. From that output I could, if I wanted, get the full device path to filter in my script. But so few events show up it felt unnecessary.

An undesired sleep

And what about the sleep 0.5s? I determined that until the status file reported “connected” I couldn’t do any operations on the monitor. However, even after it connects, the first operation would still sometimes fail, with the message xrandr: Need crtc to set gamma on.

I’ve not found any explanation for this message, nor have I found any solution other than a sleep statement. Even then, it sometimes fails, thus I created a loop that checks for my desired brightness and retries until it can be set.

Surely there must be someway to figure out the “true” status of the connection?

It works

Despite the nonsense, this script has been working for a few weeks now. When I switch devices via the KVM, power the monitor on/off, or wake it up from sleep, I always get my brightness and gamma settings restored. Despite the sleep and loops, this also always happens prior to me visually seeing anything on the monitor. Thus I’m saved from the blinding flash of full brightness.

Please join me on Discord to discuss, or ping me on Mastadon.

Keeping my monitor brightness after power save and switch

I wrote a script restoring my monitor's brightness and gamma, after power savings and dynamic switches, in Ubuntu 22.04 with udev and xrandr.

A Harmony of People. Code That Runs the World. And the Individual Behind the Keyboard.

Mailing List

Signup to my mailing list to get notified of each article I publish.

Recent Posts

Search