Setting monitors brightness on desktop: ddcutil

Recently I had to work both in the evening, whent it’s dark outside, and daytime, when the sun shines in through the window. It got very annoying to adjust the brightness level in the menus of the 2 monitors…
Let me share my finding, ddcutil:smiley:
I have 2 pieces of BenQ GW2255 attached to a GTX 1060.

For it to work, I need the module i2c-dev loaded. I want it to be loaded automatically on boot, the easiest way seems to be create a file called /etc/modules-load.d/i2c-dev.conf (its name could be anything, just end with .conf), and put into it:
i2c-dev
Of course I needed to install the ddcutil
apt install ddcutil

Right, ddcutil was succesfully installed, but
ddcutil detect
reported no display.
I checked, both my monitors have the option DDC/CI turned on.
I read, that nvidia cards may need additional settings. I discovered, that adding
options nvidia NVreg_RegistryDwords=RMUseSwI2c=0x01;RMI2cSpeed=100
to
/etc/modprobe.d/nvidia-kernel-common.conf solves my problem.
After reboot, ddcutil nicely list my monitors:

#ddcutil detect
Display 1
   I2C bus:             /dev/i2c-8
   EDID synopsis:
      Mfg id:           BNQ
      Model:            BenQ GW2255
      Serial number:    T5D03192019
      Manufacture year: 2013
      EDID version:     1.3
   VCP version:         2.1

Display 2
   I2C bus:             /dev/i2c-10
   EDID synopsis:
      Mfg id:           BNQ
      Model:            BenQ GW2255
      Serial number:    T5D03200019
      Manufacture year: 2013
      EDID version:     1.3
   VCP version:         2.1

Using my regular user account still doesn’t work, I need to add my user to i2c group:

usermod <my_username> -aG i2c

Log out, then back in, and everything is fine…

I’ve put 2 scripts in /opt/, one brgihtens, the other darkens:

/opt/brightnessup:

#!/bin/sh
if [ ! -f /tmp/brgght ]; then
touch /tmp/brgght
ddcutil -d 1 setvcp 10 + 10 
ddcutil -d 2 setvcp 10 + 10 
rm /tmp/brgght
fi

/opt/brightnessdown:

#!/bin/sh
if [ ! -f /tmp/brgght ]; then
touch /tmp/brgght
ddcutil -d 1 setvcp 10 - 10 
ddcutil -d 2 setvcp 10 - 10 
rm /tmp/brgght
fi

Of course I’ve set both to be executable.
After that I choosed 2 key combinations, which I 'll use for adjusting monitors brightness:
Fn-F8, Fn-F6
these were originally multimedia keys (next track/previous track) on my keyboard, which I never used.
Using MATE’s shortcut manager I added these keys, so that when I press it, the according script will be executed. Now I can adjust the brightness of my 2 monitors (both at the same time with only one keypress!!!) just like I could do it with a laptops display.
It’s just slower, monitor #1 actually changes brightness 1 sec. after the keypress, monitor #2 2 secs. after the keypress. So it’s slow, yes, but waaaay much faster and even more comfortable than setting that in the monitors menu system…
I spent an hour this morning to implement this, I did not regret :smiley:
I like it so, it’s just another proof of flexibility of Linux.

3 Likes

Its great.
You could use cron to automate it at set times… like redshift.

1 Like

The capabilities responds:


laco@Nagygep:~$ ddcutil capabilities
Model: GW2255
MCCS version: 2.1
Commands:
   Command: 01 (VCP Request)
   Command: 02 (VCP Response)
   Command: 03 (VCP Set)
   Command: 07 (Timing Request)
   Command: 0c (Save Settings)
   Command: 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: 0B (Color temperature increment)
   Feature: 0C (Color temperature request)
   Feature: 10 (Brightness)
   Feature: 12 (Contrast)
   Feature: 14 (Select color preset)
      Values:
         04: 5000 K
         05: 6500 K
         08: 9300 K
         0b: User 1
   Feature: 16 (Video gain: Red)
   Feature: 18 (Video gain: Green)
   Feature: 1A (Video gain: Blue)
   Feature: 52 (Active control)
   Feature: 60 (Input Source)
      Values:
         01: VGA-1
         03: DVI-1
   Feature: AC (Horizontal frequency)
   Feature: AE (Vertical frequency)
   Feature: B2 (Flat panel sub-pixel layout)
   Feature: B6 (Display technology type)
   Feature: C0 (Display usage time)
   Feature: C6 (Application enable key)
   Feature: C8 (Display controller type)
   Feature: C9 (Display firmware level)
   Feature: CA (OSD)
      Values:
         01: OSD Disabled
         02: OSD Enabled
   Feature: CC (OSD Language)
      Values:
         01: Chinese (traditional, Hantai)
         02: English
         03: French
         04: German
         05: Italian
         06: Japanese
         09: Russian
         0a: Spanish
         0b: Swedish
         0d: Chinese (simplified / Kantai)
         0e: Portuguese (Brazil)
         12: Czech
         14: Dutch
         1a: Hungarian
         1e: Polish
         1f: Romanian 
         20: Serbian
   Feature: D6 (Power mode)
      Values:
         01: DPM: On,  DPMS: Off
         05: Write only value to turn off display
   Feature: DF (VCP Version)

That suggests, Feature: 14 (Select color preset) could be used for something similar to what redshift does, so set it to 6500K for daytime, and set it to 5000K (or user setting) to night-time. However, I won’t do it. I want my monitors to have the same contrast/color all the time. Just change brightness on my prompt demand. :slight_smile:

1 Like

That looks like the color temperature of the light source, so yes a lower value should make the appearance less blue.

1 Like

I made it way much faster.
First, I merged into one script, then made to work with a stored value, instead of querying the monitor all the time…
Then made 2 monitors setting simultaneous.
Also made sure, that ddcutil setvcp succeeds, so the monitors brightness keep in sync, they change really always together.

#!/bin/sh

setvcp() {
rep=true
while $rep 
do
ddcutil -d $1 setvcp 10 $2 --sleep-multiplier .4
if [ $? -eq 0 ]; then 
  rep=false
  echo "set OK"
fi
done
}

# check if not a repeated call
if [ ! -f /tmp/brgght ]; then
touch /tmp/brgght

#check, if there's a stored value, if not, create one
if [ ! -f /tmp/curbrght ]; then
 curbrght=$(ddcutil getvcp 10 | awk '{ print $9 }' | tr ',' '\n');
else
 curbrght=$(head -n 1 /tmp/curbrght)
fi

#check if brightness up or down...

case $1 in
u) if [ $curbrght -lt 90 ] ; then 
        curbrght=$((curbrght + 10))
   else 
        curbrght=100;
   fi ;;
d) if [ $curbrght -gt 9 ] ; then 
       curbrght=$((curbrght - 10))
   else 
      curbrght=0;
   fi ;;
esac

#store the new value
echo $curbrght > /tmp/curbrght

#for display 1 it just runs, for display 2 it is done in the background

setvcp 1 $curbrght & setvcp 2 $curbrght

# I'm not sure how to properly wait for background functions exit?
# 1 seconds seems to OK anytime.

sleep 1

# remove the flag that this script is running
rm /tmp/brgght
fi

Now, the 2 monitors change brightnes about 0.8…1 second after my keypress, and they do it in a random order, but the difference is always less than 0.5 seconds.

To call this script the argument is “u” for brightness up, and “d” for brightness down.
Something like:
/opt/brightness u

I changed the shortcut keys actions accordingly.