Thought this was a cool one to share, it’s been a while since I posted something on here!

At home I have 4 27″ HP G27 monitors, one is a G2 and the other three are G1’s

Layout is like this:

 

With the whole COVID thing going on, I was using my home PC to work, however I figured I may as well pop to the office and grab my work desktop, saves dealing with laptop docks and such. I brought it home, nuked it and installed Ubuntu 20 on there as my install was a fair way out of date and rather bloated after a couple of years of use. I hooked up my work PC into my 4 screens on the HDMI inputs and my personal PC into them on the DisplayPort inputs.

This was working quite well, I have a keyboard and mouse for my work PC and one for my home pc and I just swap them over on my desk then change the input sources on my monitors. However – I was getting pretty bored of pressing the buttons and submenus on the monitors each time I wanted to switch.

I remember seeing a feature on my TV, called HDMI CEC which allows a device plugged into the TV, to control input sources, volume, brightness etc, and it got me thinking. A bit of googling around later, I discovered you can indeed control monitors via DisplayPort or HDMI

I believe the standard for this is called the MCCS 2.0 standard, and it’s called Display Data Channel / i2c

This then lead me onto finding a really neat utility called ddccontrol. Here is how I made it all work:

  1. Install the ddccontrol package
    sudo apt-get install ddccontrol
  2. Determine the i2c devices representing the DDC interfaces:
    ddccontrol -p

    Output like so:

    Detected monitors :
    - Device: dev:/dev/i2c-16
    DDC/CI supported: Yes
    Monitor Name: VESA standard monitor
    Input type: Digital
    (Automatically selected)
    - Device: dev:/dev/i2c-14
    DDC/CI supported: Yes
    Monitor Name: VESA standard monitor
    Input type: Digital
    - Device: dev:/dev/i2c-12
    DDC/CI supported: Yes
    Monitor Name: VESA standard monitor
    Input type: Digital
    - Device: dev:/dev/i2c-10
    DDC/CI supported: Yes
    Monitor Name: VESA standard monitor
    Input type: Digital

    Here we can see that I have 4 monitors connected, and their device addresses (dev:/dev/i2c-10)
    Make note of these addresses, they will come in useful later on.

  3. Now you have your i2c devices, you need to do some reverse engineering. You need to find the address values for the input switching. it should be a standard value, however some manufacturers like to use none standard values! The common value for input is 0x60 – so lets use ddccontrol to query that:
    sudo ddccontrol -r 0x60 dev:/dev/i2c-16
    
    Reading 0x60...
    Control 0x60: +/17/17 C [Input Source Select (Main)]

    So you can see the response confirms that the address of 0x60 is indeed the input source selection. Most values will be named, so you can just hunt through the various addresses until you find the one you want, don’t forget you can use this to change things like brightness, contrast etc though I won’t be covering that here.

  4.  Now we want to work out the value to set on that address to change the screen to the input source we desire. Again this is one of those things that most people follow the standard, but there are some bad eggs that do their own thing. HP follow the standard and it matches between the G1 and G2 versions.
    To send a new value, use the following command:

    sudo ddccontrol -r 0x60 -w 16 dev:/dev/i2c-16
  5. you should now see your monitor has changed to the mini displayport input type. A handy list of values for my screens are:
    15 = DisplayPort 1
    16 = DisplayPort 2
    17 – HDMI Input
  6. Now – lets wrap it all up in a handy bash script:
    OS=$1
    
    if [ $OS == "windows" ]
    then
    echo "Changing screens to windows PC"
    sudo ddccontrol -r 0x60 -w 16 dev:/dev/i2c-16 # top right to mini DP
    sudo ddccontrol -r 0x60 -w 15 dev:/dev/i2c-10 # far left to displayPort
    sudo ddccontrol -r 0x60 -w 15 dev:/dev/i2c-12 # main screen to displayPort
    sudo ddccontrol -r 0x60 -w 15 dev:/dev/i2c-14 # far right to displayPort
    fi
    
    if [ $OS = "linux" ]
    then
    echo "Changing screens to ubuntu PC"
    sudo ddccontrol -r 0x60 -w 17 dev:/dev/i2c-16 # top right to HDMI
    sudo ddccontrol -r 0x60 -w 17 dev:/dev/i2c-10 # far left to HDMI
    sudo ddccontrol -r 0x60 -w 17 dev:/dev/i2c-12 # main screen to HDMI
    sudo ddccontrol -r 0x60 -w 17 dev:/dev/i2c-14 # far right to HDMI
    fi
  7. And finally – add it as a keyboard shortcut in Ubuntu:

 

And Voila! you can now change your screens input sources with a keyboard shortcut or over SSH.