I am the happy owner of an Intel NUC dual booting Windows 8.1 and Ubuntu, hooked up to a great-looking Apple LED Cinema Display. The only problem is that the Apple display comes with no physical controls for brightness and Ubuntu doesn't seem to be able to adjust it either. Being a geek I was anything but content with this situation. I finally found a solution to control the brightness using keyboard shortcuts.

Updated December 2020: Using a maintained fork of the acdcontrol tool, removing the need to run acdcontrol with root privileges and a much simpler Bash script for the integration with the desktop environment, documented how to modify acdcontrol to support other monitors.

Step 1 - control the brightness from the command line

We need a way to control the brightness of the display. There's a handy tool called acdcontrol to do that.

Unfortunately, the original version has been unmaintained for over a decade and doesn't support my 27" Apple LED Cinema Display or anything newer than that. Luckily there's a a third party, currently maintained fork of acdcontrol with support for many more monitors. You can clone the repository locally and built this simple tool from source:

git clone https://github.com/yhaenggi/acdcontrol.git
cd acdcontrol
rm acdcontrol
make

After a second or so the acdcontrol binary will have been built.

This tool needs to communicate with the USB Human Interface Device your monitor creates. By default, this is only possible if you are root because the /dev/usb/hiddev* devices are owned by root and are only writeable by root. There are two ways around that. We can either tell our Linux system to change the ownership of the device or have acdcontrol always run as root.

The first alternative is the safest. 

First, run lsusb | grep "Apple" and you will see something like this:

$ lsusb | grep Apple 
Bus 001 Device 012: ID 05ac:9226 Apple, Inc. LED Cinema Display
Bus 001 Device 011: ID 05ac:8508 Apple, Inc. iSight in LED Cinema Display
Bus 001 Device 010: ID 05ac:1105 Apple, Inc. Audio in LED Cinema Display
Bus 001 Device 007: ID 05ac:9126 Apple, Inc. USB2.0 Hub

This line in bold is the main USB device that controls the Apple display. Note the ID has two four digit hexadecimal numbers separated by a colon. The first is the USB vendor ID, the second is the USB device ID. Note them down.

Now, create the file /etc/udev/rules.d/50-apple-display.rules with the following content:

KERNEL=="hiddev*", ATTRS{idVendor}=="05ac", ATTRS{idProduct}=="9226", GROUP="nicholas", OWNER="root", MODE="0660"

You need to replace three things here:

  • 05ac is the USB vendor ID of your Apple display that you got previously.
  • 9226 is the USB device ID of your Apple display that you got previously.
  • nicholas is your user group. Obviously this will be different for you. If you are not sure what this is run id -gn on your terminal.

Next up, we tell the kernel that our udev rules have changed:

sudo udevadm control --reload-rules
sudo udevadm trigger

Remember that you may also need to unplug your monitor's USB or Thunderbolt connector from your computer and then plug it right back in for these changes to take effect.

Now copy acdcontrol somewhere in your PATH, e.g. /usr/local/bin:

chmod +x acdcontrol
sudo cp acdcontrol /usr/local/bin

If you are on a multi-user system and your users don't belong in a common group the previous method won't work. In this case you need to use the alternative method, having acdcontrol always run as root:

sudo cp acdcontrol /usr/local/bin 
sudo chown root:users /usr/local/bin/acdcontrol 
sudo chmod 0755 /usr/local/bin/acdcontrol 
sudo chmod +s /usr/local/bin/acdcontrol

Either way, we can now test that acdcontrol works.

Make sure that your display's USB cord is plugged in to your computer. The brightness control, just like the iSight camera and audio input/output, is sent to your display over USB. If you have a Thunderbolt display make sure that it's plugged into a Thunderbolt port. If you have a Thunderbolt display plugged into a Mini DisplayPort only port you're out of luck, sorry. Now run the following:

acdcontrol --detect /dev/usb/hiddev*

It should reply with something like

Apple Cinema and Studio Display Control Program.
Please, use --about switch to learn more 
hiddev driver version is 1.0.4 
hiddev driver version is 1.0.4 
/dev/usb/hiddev1: USB Monitor - SUPPORTED. Vendor= 0x5ac (Apple), Product=0x9226[Apple Cinema HD Display 27"

See the part I put in bold type, /dev/usb/hiddev1? It may be different for you. If nothing is detected you will not be able to control the monitor brightness.

Part 2 - writing a script to step through the brightness

acdcontrol has a way of doing step changes to your brightness, essentially allowing you to increase and decrease the brightness. However, you need to always give it the hiddev device your monitor uses to talk to your computer which may change on each boot. We need a small script to fix that.

Put the following code into a new file /usr/local/bin/brightness

#!/bin/bash
HIDDEV=`acdcontrol --detect /dev/usb/hiddev* | grep -Po "/dev/usb/hiddev[0-9]"`
acdcontrol $HIDDEV -- $@ > /dev/null

Now let's make it executable:

$ sudo chmod +x /usr/local/bin/brightness

You can now step the brightness up and down using our script. Let's try it out:

$ brightness +500 
# It will make the monitor much brighter 
$ brightness -500 
# It will make the monitor much darker

Step 3 - keyboard shortcuts

Now for the final touch, adding keyboard controls. Assuming that you're using Unity, the default Ubuntu Desktop interface, you just need to open System Settings and click on the Keyboard icon. In there click on the Shortcuts tab.

At the bottom of the list there's a plus (+) button. Click on it. Set:

  • Name: Brightness up
  • Command: /usr/local/bin/brightness +50

Click on the plus icon a second time and add another entry with:

  • Name: Brightness down
  • Command: /usr/local/bin/brightness -50

Our custom actions appear under the "Custom..." category and have no keyboard shortcut assignments. Click on the Inactive label to the right of each shortcut and press the key combination you want to use. I use CTRL-SHIFT-ALT-plus and CTRL-SHIFT-ALT-minus for the brightness up and down command respectively. Now try using the shortcuts you specified a few times. You'll see that each time you use the shortcut there's a small brightness change in your display. That was it! Now your Ubuntu Desktop can control the brightness of your display easily through the keyboard.

What about Kubuntu?

You can set up custom shirtcuts from KDE logo, Application, Settings, System Settings, Shortcuts, Custom Shortcuts. You can create a new Command/URL global shortcut and assign the scripts mentioned above. As for the shortcuts, I found that META-F1 and META-F2 work best without causing conflicts. Why F1/F2? This is where brightness down/up can be found on a Mac keyboard :)

Supporting other monitors

As far as I can tell, acdcontrol should work with any monitor which implements the proprietary Apple HID for controlling its brightness (as opposed to using DDC which is what most other monitors do), such as LG UltraFine series of Mac-specific monitors. Please note that I do not have any of these monitors at hand so this section is half speculation, half information I extrapolated from discussions in support forums of other brightness control tools.

You may have to change the acdcontrol.cpp file in two places to add support for other monitors.

First you need to run lsusb to get the USB vendor and device ID of your monitor. Let's say it's vendor ID abcd and device ID 0123.

Edit acdcontrol.cpp and find the Supported vendors line. Add constants for your USB vendor and device ID. Changes in bold:

// Supported vendors 
const int APPLE                           = 0x05ac;
const int SAMSUNG                         = 0x0419;
const int MYVENDOR = 0xabcd;

// ... more lines here ...

const int CINEMA_DISPLAY_HD_27_2013       = 0x9227;
const int MY_MONITOR = 0x1234;

Then find the void init_device_database() in the code and add your monitor definition. Changes in bold:

void init_device_database() { 
 supportedVendors.insert( VendorDesc( SAMSUNG, "Samsung Electronics" ) );
 supportedVendors.insert( VendorDesc( APPLE, "Apple" ) );
supportedVendors.insert( VendorDesc( MYVENDOR, "My Vendor's Name" ) ); 

  supportedDevices.insert( DeviceId( MYVENDOR, MY_MONITOR,
                                    "My Monitor's Name" ));
 supportedDevices.insert( DeviceId( APPLE, STUDIO_DISPLAY_15,
                                    "Apple Studio Display 15\"" ));

Delete the acdcontrol file and run make again. The recompiled binary will now have support for the device you added.

Pitfalls

The acdcontrol utility has the supported USB vendor and device ID list hard-coded into it. I only have one Apple display to test with. It is possible that different generations of Apple displays may use a different USB device ID. In this case you'll need to modify the source code of the utility yourself as described above.

Brightness control requires a USB connection between your computer and display, obviously. With older Apple displays this is as simple as connecting the USB cord of your display to your computer. With the Thunderbolt display you only have one Thurderbolt cable which transfers both the video signal and the USB data. If your computer has a Thunderbolt port and you connect it there it will work. If your computer has a Mini DisplayPort you will get video output normally but all USB-related features, including brightness control, iSight camera and audio, will not work. There's no workaround for that.

Ubuntu Desktop has brightness controls and options under the Displays section of the system configuration. These will still not work. Ubuntu is not aware of the need to use acdcontrol for Apple displays. That's why we had to go through these steps to get brightness controls working in the first place.

19 comments

  • Hey man! This is really awesome because you found the right balance between showing a solution and having the user work through it - so he can actually learn from it!

    I use two 24" displays on my Shuttle barebone PC where I run Lubuntu 16.04.

    Now, I have two things to say. Firstly, in
    $ sudo chmod 0755 usr/local/bin/acdcontrol
    and the following line, there is a root
    /
    missing.

    Secondly, my devices show up, BUT are unsupported. The message I get after
    acdcontrol --detect /dev/usb/hiddev*
    is

    Apple Cinema and Studio Display Control Program. Please, use --about switch to learn more

    hiddev driver version is 1.0.4

    /dev/usb/hiddev0: USB Monitor - UNSUPPORTED. Vendor= 0x5ac (Apple), Product=0x9236

    hiddev driver version is 1.0.4

    /dev/usb/hiddev1: USB Monitor - UNSUPPORTED. Vendor= 0x5ac (Apple), Product=0x9236

  • Hey, I found the solution. I deleted
    /usr/local/bin/acdcontrol
    and installed this one (probably unpatched and fine with my 24" monitors: https://github.com/warvariuc/acdcontrol. You said your skript was usefull because the original acdcontrol had false values in its code. This does not seem to be the case for the fork I downloaded, thus I now use
    acdcontrol /dev/usb/hiddev0 200
    to adjust. Be aware that the github manual is missing the
    /usb
    -part of the directory. Thank you very much, again! I use this setup for two years now and was never able to really set the brightness right.

    • Thanks for the heads up on the typo. I have fixed it now :)

      The 24" monitors seem to have been older than the codebase I was using. Likewise my 27" was too new. To be fair, that code was abandoned years ago. My fork only addressed the one missing monitor I own. I'm glad you found a version with your monitor. I had to go through the C code without knowing enough C :D
  • I am using a 24in Apple display, but it doesn't automatically turn off on my Ubuntu 16.04.3 even I have set up energy saving options. Any idea?
  • I have a Apple Cinema HD Display 27" 2013. This worked for me on Kubuntu 16.04:

    git clone https://github.com/warvariuc/acdcontrol
    cd acdcontrol
    sudo python3 acdcontrol.py /dev/usb/hiddev1 65000

    hiddev driver version is 1.0.4
    Found supported product 9227 (Apple Cinema HD Display 27" 2013) of vendor 05ac (Apple).

    I didn't use any bash wrappers or c code (directly), it uses Python 3, which can be apt-get installed as python3 or similar.
  • Thank you man! Worked like a charm for my 27" Cinema Display, minidisplay port version. And thanks for walking us through. Cheers from sunny south of France!
    • That's great news! I knew about ddcutil but didn't have a monitor that supports the protocol. My only monitor with real brightness control is the Apple Cinema Display. I'm glad that you are trying to get a patch into ddcutil, it will help a lot having native control of the display instead of going through an external tool and scripts every time :)

      • It would be definitely awesome to have some desktop integration for these brightness controls one day, but it looks like the USB HID protocols are not well documented and differ from model to model and sometimes even change with firmware updates (at least on LG), which is somewhat annoying. At this point I'm happy about any brightness control, because the monitor came with its backlight set so low that it was hard to read. (And it has no control buttons on it, not even a switch.)