Ubuntu command line to change input source on a display monitor?
Solution 1:
The command you are looking for is ddccontrol
, available from the regular Ubuntu repository.
WARNING! ddccontrol
sends data over the i2c bus, which is inherently a dangerous thing to do. Most i2c devices are very low-level and very dumb, one misplaced command can be enough to brick them or at least freeze the computer. That said, DDC/CI is a somewhat standardized, quite established and quite old technology, so the risks is not too high.
For this reason, by default, i2c devices are only accessible to root. You will most likely need to prefix all commands below with sudo
. (I have voluntarily not done it to ensure you read the instructions and not blindly copy/paste them.)
Probing your monitor
The first thing to do is to probe the various i2c buses in your computer (mine has 11 such buses...), searching for the one that is actually on the graphics card, connected to the screen.
The ddccontrol -p
command does that, and shows what it found. Sample output from my computer:
Detected monitors :
- Device: dev:/dev/i2c-4
DDC/CI supported: Yes
Monitor Name: VESA standard monitor
Input type: Digital
(Automatically selected)
Reading EDID and initializing DDC/CI at bus dev:/dev/i2c-4...
I/O warning : failed to load external entity "/usr/share/ddccontrol-db/monitor/DELD070.xml"
Document not parsed successfully.
EDID readings:
Plug and Play ID: DELD070 [VESA standard monitor]
Input type: Digital
Note the I/O warning: it merely means that your monitor is unknown to ddccontrol
, so it does not know the description of all the non-standard commands and values it may support. This does not prevent you from issuing the commands, but this may be a trials and errors process.
Note also the detected bus name: dev:/dev/i2c-4
in my example.
Listing all commands
The ddccontrol -d dev:/dev/i2c-4
command reads all the possible controls (from 0x00 to 0xff) and shows the values it found. Of course, you should use the bus found when probing.
ddccontrol
also shows a description for the controls and values that are known to it; either standard ones, or ones described in XML files. In my example, there is no XML file for my monitor (see the I/O warning above).
Querying a value
The ddccontrol -r 0x10 dev:/dev/i2c-4
queries the current value of the 0x10 control. Example output:
Reading 0x10...
Control 0x10: +/21/100 C [Brightness]
The current value is the number in the middle, 21 in my example. The value after that is supposed to be the maximum, but this seem to only work for ranged values (such as brightness and contrast), not so much for list items.
Setting a value
The ddccontrol -r 0x10 -w 25 dev:/dev/i2c-4
sets the value of the 0x10 control. Example output:
Writing 0x10, 0x19(25)...
Control 0x10: +/25/100 C [Brightness]
Note that you can set values in hexadecimal or decimal formats. In my example, I used decimal.
Changing monitor input source
I found the command and values to use to switch my monitor inputs. It works well, by you will of course need to experiment to find the values for your monitor. Mine is a Dell UltraSharp U2515H.
Control 0x60 [Input Source Select]
- Value 15: DP
- Value 16: mDP
- Value 17: HDMI (MHL) 1
- Value 18: HDMI (MHL) 2
The values are in the same order as the Input Source menu in the monitor.
For example, switching to DP: ddccontrol -r 0x60 -w 15 dev:/dev/i2c-4
Solution 2:
In addition to Adrien Beau answer.
Changing monitor input source
Standard change input source command is 0x60. So you want to use such command:
ddccontrol -r 0x60 -w $some_value dev:/dev/i2c-X
Determining values to pass to monitor
But how do you know which values are responsible for which input source? I do not know if vendors provide such information, but I have found a way how you can know it without asking vendor.
Just read current value of 0x60 command (using sudo ddccontrol -r 0x60 dev:/dev/i2c-X
). It will return something like this:
Case when your monitor is in ddccontrol database
EDID readings:
Plug and Play ID: DELA0D7 [DELL P2217H (VGA)]
Input type: Analog
Reading 0x60...
Control 0x60: +/257/4626 C [Input Source Select]
Case when your monitor is not in ddccontrol database
EDID readings:
Plug and Play ID: DELA0D9 [VESA standard monitor]
Input type: Digital
=============================== WARNING ===============================
There is no support for your monitor in the database, but ddccontrol is
using a basic generic profile. Many controls will not be supported, and
some controls may not work as expected.
Please update ddccontrol-db, or, if you are already using the latest
version, please send the output of the following command to
[email protected]:
LANG= LC_ALL= ddccontrol -p -c -d
Thank you.
=============================== WARNING ===============================
Reading 0x60...
Control 0x60: +/4369/4626 C [Input Source Select]
Let's assume your monitor is not in ddccontrol database. Note this 4369 value. This is a value that you will use to switch monitor back to current state via cable you are currently speak to monitor. Note, that this value will be different when you use another transport cable (I mean port which you use to speak to monitor, for example via vga and via hdmi values will be different even for same input source).
Now, disable auto selecting input source using monitor's osd menu, because we do not want it for now. Now switch input source using your monitor's osd menu, and then read current value. For this example, I switched monitor to use vga source (source is coming from another computer), while still speaking to monitor via hdmi using first computer, and returned value is 4353. Do the same for all inputs which you are planning to use for switching.
Ok, so now you know values of monitor in different source states. Now you can switch input source for monitor using:
sudo ddccontrol -r 0x60 -w 4353 dev:/dev/i2c-X # switch to vga input using hdmi cable on Dell P2217H
sudo ddccontrol -r 0x60 -w 4369 dev:/dev/i2c-X # switch to hdmi input using hdmi cable on Dell P2217H
Values are presented in decimal, however you can use hexadecimal values like this:
sudo ddccontrol -r 0x60 -w 0x1101 dev:/dev/i2c-X # 0x1101 is 4353
sudo ddccontrol -r 0x60 -w 0x1111 dev:/dev/i2c-X # 0x1111 is 4369
Adding your monitor to ddccontrol database
Now you want your monitor to be in ddccontrol-db. You need to explore values for all functions of your monitor and which values are applied to which state. Then you should create xml file describing all these values. Note, there will be several xml files, due to different ports use different monitor Plug and Play id. For example, for my DELL P2217H monitor I will create two files: DELA0D7.xml (this id is used when connecting via vga) and DELA0D9.xml (this id is used when connecting via hdmi). Dell P2217H has one vga, one hdmi and one displayport. Because I have not got displayport devices, I cannot make explorations to create DELA0D8.xml (this id is used when connecting via displayport).
Some description of xml parameters could be found at Monitor Database Structure page (file:///usr/share/doc/ddccontrol/html/apes02.html).
Capabilities (caps) and Plug and Play ID could be recieved usingsudo ddccontrol -c dev:/dev/i2c-X
.
When you are ready, contribute to https://github.com/ddccontrol/ddccontrol-db repository.
Detect monitor by serial number
Let's assume you have connected several monitors of the same model to a single computer. Then you need to differentiate monitors somehow. For this purpose, I have created a script, which determines i2c bus number by monitor serial number.
I do it usingsudo get-edid -b $X 2>/dev/null | grep $TARGET_SERIAL
See my repository for more details: https://github.com/Ashark/Ashark-bin/blob/master/i2c-bus-by-monitor-serial
Final script for keyboard binding
Now, see this script: https://github.com/Ashark/Ashark-bin/blob/master/switch-monitor-source You can use it as following:
switch-monitor-source -s 0G2TG7360DXB -u # get and cache i2c-id number for monitor with specified s/n
switch-monitor-source -s 0G2TG7360DXB -v # switch that monitor to vga input
switch-monitor-source -s 0G2TG7360DXB -h # switch that monitor to hdmi input
Now you can bind two last commands to keyboard shortcut and use them for fast switching. Amazing!
Solution 3:
ddccontrol works fine, but it has been unsupported for over a decade (2006). Meaning every time you use it you get a big red flashing warning that your monitor is not in the database.
There is a newer utility ddcutil which works much better with newer monitors as it interrogates the monitor itself for its VCP feature codes. It also works on non-pci computers, like the Raspberry-Pi, with some caveats.
Here is a comparison: https://www.ddcutil.com/ddccontrol/
e.g. with ddcutil I now have created three shell aliases to switch my DELL monitor's inputs using these commands:
ddcutil -b 6 setvcp 0x60 0x1b
: usbc
ddcutil -b 6 setvcp 0x60 0x11
: hdmi
ddcutil -b 6 setvcp 0x60 0x0f
: display port