Brightness Sensor and External Screens

I use an external screen with my laptop. Mostly because it is larger, but also because it has a sufficient height to reduce neck strain. There is another problem that causes strain: suboptimal brightness settings. On the laptop, I have brightness keys handy and can quickly use them to adjust the brightness. My Android devices regulate the brightness automatically for me. But on the desktop, the brightness is always fixed.

My external screen (Dell P2314H) supports DDC/CI, that is Display Data Channel and Control Interface. This just means that I can change settings from the computer and do not have to use the OSD (On Screen Display) for that. Most screens have a hard to use OSD and I really do not feel like changing the brightness manually every couple minutes.

ddccontrol

Luckily there is ddccontrol for Linux which can control supported screens via DDC/CI. It works as follows:

ddccontrol -r 0x10 -w $brightness dev:/dev/i2c-$device

This sets the brightness of the screen to the given percentage. One first has to find which i2c device the current screen actually is. This works with ddccontrol -p, this gives me, among other things:

- Device: dev:/dev/i2c-7
  DDC/CI supported: Yes

My Dell screen therefore supports DDC/CI. With this screen, you have to enable DDC/CI in the OSC first, though. Now I know that the device is i2c-7. I wrote the above line of ddccontrol into a little shell script called brightness that accepts a percentage as the first argument.

In Awesome WM, my window manager, I defined a couple keyboard commands in order to regulate the brightness:

awful.key({ modkey, "Control" }, "F2",
          function () awful.util.spawn("brightness 3") end),

By pressing modifiers and F2, I would set the screen to a low setting. This works well, but you have to regulate it manually.

In case you are on Windows or a Mac, there might be other tools which help you set the brightness. Some display manufacturers supply their own tools which mostly run on Windows.

ColorHug ALS

All this was a great step forward. During the day, the screen was too dim. During the evening and nights, the screen was too bright. Now I could regulate the brightness if I felt that it did not quite match the ambient light.

I thought that automatically setting the brightness depending on the time of day would be sufficient. However, some days are bright, some days are cloudy. At worst one has clouds passing by and it changes every other minute. So this was not really an option.

That brought me to the ColorHug ALS device. It is an affordable (I paid like EUR 24) ambient light sensor which runs out of the box on Fedora. I ordered mine, payed with a SEPA bank payment and got it within a week or so. After installing the packages on Fedora from the official repository, I was able to get readings with it. There is a GObject API and a tool for GNOME which automatically changes the laptop brightness. As I do not use GNOME and want to regulate external screens, I decided to cook up my own.

There is a command line utility which can be used to obtain readings. I use it like this:

$ colorhug-cmd set-multiplier 20       # Enable device
$ colorhug-cmd set-color-select white  # Select white color
$ colorhug-cmd take-reading-raw        # Take reading
Impulse:                17408
$ colorhug-cmd set-multiplier 0        # Disable device

All it then took was a Python program which parses that output and calls ddccontrol with a converted value. I found that a simple exponential model does a good job:

$$B(x) = a \exp(b x) + c \,,\qquad a = 8.732 \,,\quad b = 5.691 \cdot 10^{-4} \,,\quad c = -9 \,.$$

The whole program is here: https://github.com/martin-ueding/external-screen-auto-brightness

Everything in action

Now I just added an entry into my crontab to run the script in automatic mode every minute:

* * * * * /home/mu/bin/brightness --auto > /dev/null 2> /dev/null

Alternatively one could just let the program run and have it sleep for a little while before performing the next brightness change.

There is a video and another one where you can see how this looks like. The camera in my phone adjust for the change in overall brightness, so the screen stays about the same apparent brightness. Sadly there is some flicker in the screen when it increases the brightness; it is totally worth the automatic brightness, though!