Giter VIP home page Giter VIP logo

monitorcontrol's People

Contributors

cppf0rev3r avatar dependabot[bot] avatar itsjfx avatar josephbrooksbank avatar klwlau avatar lurid-bogey avatar newam avatar rodinsevar avatar scottaxcell avatar tausackhn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

monitorcontrol's Issues

"--set-power-mode on" is not working (windows)

Hi,

I just stumbled upon this great project - unfortunately, some commands are not working.. (others work)

  • Monitor manufacturer and model number: LG 34GL750
  • Input source (HDMI, VGA, display port, etc.): display port (directly connected)
  • Output device (video card, discrete graphics, etc.): discrete nvidia graphics card (with latest driver - 528.02)
  • Operating system: Win11x64
  • Python version: python 3.10
  • monitorcontrol version (monitorcontrol --version): 3.0.2 (via pip)
  1. monitorcontrol --monitor 1 --set-power-mode off_soft
  • Result: Monitor powers off (no info in console)
  1. monitorcontrol --monitor 1 --set-power-mode on
  • Result: nothing happens (no info in console)

I have two questions:

  • is this a "known issue"?
  • are there any workarounds?

Thanks - Markus

MacOs Support ??

Hey , Great Package man , can we expect it to work in Macos in near future ??

4112 is not a valid InputSource when using Mini Displayport

OS: Win10 x64 20H2 (19042.867)
Python: 3.9.1
Package version: 2.4.0

When running get_input_source while using mini displayport, it throws an error of invalid InputSource

Code:

from monitorcontrol import get_monitors

monitors = get_monitors()
for monitor in monitors:
    with monitor:
        print(monitor.get_input_source())

Error

Traceback (most recent call last):
  File "c:\dev\lazymonitors\lazy_monitors.py", line 6, in <module>
    print(monitor.get_input_source())
  File "C:\dev\lazymonitors\.venv\lib\site-packages\monitorcontrol\monitorcontrol.py", line 361, in get_input_source
    return InputSource(value).name
  File "c:\users\cryocaustik\appdata\local\programs\python\python39\lib\enum.py", line 315, in __call__
    return cls.__new__(cls, value)
  File "c:\users\cryocaustik\appdata\local\programs\python\python39\lib\enum.py", line 611, in __new__
    raise ve_exc
ValueError: 4112 is not a valid InputSource

AttributeError: 'Monitor' object has no attribute 'get_constrast'

Running little test script on windows 10 python 3.8.2 and python 3.7

from monitorcontrol import get_monitors

for monitor in get_monitors():
    with monitor:
        print(monitor)
        print(monitor.get_constrast())
python monitor.py
<monitorcontrol.monitorcontrol.Monitor object at 0x000001AF0A315248>
Traceback (most recent call last):
  File "monitor.py", line 6, in <module>
    print(monitor.get_constrast())
AttributeError: 'Monitor' object has no attribute 'get_constrast

Second successive input source retrieve fails

  • Monitor manufacturer and model number: ASUS VG27A
  • Input source (HDMI, VGA, display port, ect.): DisplayPort / HDMI
  • Output device (video card, discrete graphics, ect.): discrete nvidia 3080
  • Operating system: Windows 11
  • Python version: 3.8.3
  • monitorcontrol version (monitorcontrol --version): 3.1.0

Steps to Reproduce

The following python code errors:

from monitorcontrol import get_monitors

try:
    with get_monitors()[1] as monitor: 
        inputsource = monitor.get_input_source()
        print(inputsource)

        inputsourceagain = monitor.get_input_source()
        print(inputsourceagain)
except Exception as e:
    print(f"An error occurred: {e}")

Output:

InputSource.HDMI2
An error occurred: failed to get VCP feature: An error occurred while transmitting data to the device on the I2C bus.

ValueError: 33 is not a valid InputSource

  • Monitor manufacturer and model number: MSI Optix MAG342CQRV
  • Input source (HDMI, VGA, display port, ect.): HDMI1
  • Output device (video card, discrete graphics, ect.): 6800XT
  • Operating system: Windows 10 21H1 19043.1466
  • Python version: 3.9.9
  • monitorcontrol version (monitorcontrol --version): 2.5.1

Steps to Reproduce

import monitorcontrol as mc
monitors = mc.get_monitors()
for monitor in monitors:
	with monitor:
		c = monitor.get_vcp_capabilities()

This code crashes with ValueError: 33 is not a valid InputSource and I don't get any return from that function.

For more information, on the problematic monitor, monitor.vcp.get_vcp_capabilities() returns

(prot(monitor)type(lcd)model(MAG342CQRV)cmds(01 02 03 07 0C E3 F3)vcp(02 04 05 08 0B 0C 10 12 14(04 05 08 0B) 16 18 1A 60(00 11 12 0F 21 22 2F 31) CC(02 03 04 05 07 08 09 0A 0C 0D 01 06 0B 0E 12 14 16 17 1A 1E 24) D6(01 04 05) DF FF)mswhql(1)asset_eep(40)mccs_ver(2.2))

And indeed in the input source section there is OFF,HDMI1,HDMI2,DP1 (as expected), then there is 21,22,2F,31 and these are not in the enum (and at least the first one crashes).

Are these not standard values?

File access won't be closed on /dev/i2c

  • Input source: HDMI
  • Output device: Raspberry Pi 4
  • Operating system: Raspberry OS
  • Python version: 3
  • monitorcontrol version: 3.0.2

Hi, I've got a problem with the python library.
Everytime I execute monitorcontrol.get_monitors() it accesses the file (in my case) /dev/i2c-21 with a new file descriptor.
I need to execute it every second and after a few hundred iterations my script crashes with [Errno 24] Too many open files. Because there is a limit of open files on the system (Yes, I could increase the limit, but it won't help) is it possible to dispose whatever the library does there? I need to somehow evade this problem.

Thanks for the help

set_input_source does not work for any of the codes listed in get_vcp_capabilities

Even though i have inputs': [<InputSource.DP1: 15>, <InputSource.DP2: 16>, <InputSource.HDMI1: 17>] shown when using get_vcp_capabilities the set_input_source does not work for any of the codes. Any assistance would be appreciated.

print(monitor.set_input_source("DP1") )
= to none

  • Monitor manufacturer and model number: LG 34WP65G
  • Input source (HDMI, VGA, display port, ect.): HDMI
  • Output device (video card, discrete graphics, ect.): dedicated graphics
  • Operating system: Windows 11
  • Python version: 3.11.0
  • monitorcontrol version (monitorcontrol --version): 3.0.2

Steps to Reproduce

Run
from monitorcontrol import get_monitors

for monitor in get_monitors():
with monitor:
print(monitor.get_vcp_capabilities())
print(monitor.set_input_source("DP1"))

image

Crash when monitor do not support input_source

My monitor do not retrun Input sources. I guess it is not supported. This cause crashe in monitor_obj.get_input_source() because code = vcp.VCPCode("input_select") return 0.
So in main.py extra if should be added
elif args.get_monitors:
for monitor_index, monitor_obj in enumerate(get_monitors(), 0):
with monitor_obj:
monitors_dict = monitor_obj.get_vcp_capabilities()
if (len(monitors_dict["inputs"])>0):
current_input = monitor_obj.get_input_source()
model = monitors_dict["model"]
inputs = monitors_dict["inputs"]
sys.stdout.write(f"Monitor {monitor_index + 1}: {model}" + "\n")
sys.stdout.write("Available Inputs:\n")
for i in inputs:
sys.stdout.write(f"\t{i}")
if i == current_input:
sys.stdout.write("*\n")
else:
sys.stdout.write("\n")

    return

Support for USB C

USB C listed as 27

monitorcontrol --set-input-source 27

is not working

Monitor 1: U3219Q
Available Inputs:
InputSource.DP1*
InputSource.HDMI1
27
Monitor 2:
Available Inputs:
Monitor 3: VG27AQ
Available Inputs:
InputSource.DP1*
InputSource.HDMI1
InputSource.HDMI2

ValueError: 27 is not a valid InputSource

Getting an error regarding an unrecognized InputSource value. Based on my monitor's inputs and reviewing the list on lines 28-46 of monitorcontrol.py, I'm guessing it may be for the USB-C input. I can try creating a fork and adding that as a possible value, but wanted to double check with you if there is some standard list of input codes I should be referencing.


  • Monitor manufacturer and model number: Dell U4924DW
  • Input source (HDMI, VGA, display port, ect.): USB-C
  • Output device (video card, discrete graphics, ect.):
  • Operating system: Windows 10
  • Python version: 3.11.1
  • monitorcontrol version (monitorcontrol --version): 3.0.3

Steps to Reproduce

monitorcontrol --get-monitors -vvvv

Traceback (most recent call last):
File "C:\Users\user\apps\WPy64-31110\python-3.11.1.amd64\Lib\site-packages\monitorcontrol\monitorcontrol.py", line 397, in get_input_source
return InputSource(value)
^^^^^^^^^^^^^^^^^^
File "C:\Users\user\apps\WPy64-31110\python-3.11.1.amd64\Lib\enum.py", line 715, in call
return cls.new(cls, value)
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\apps\WPy64-31110\python-3.11.1.amd64\Lib\enum.py", line 1131, in new
raise ve_exc
ValueError: 27 is not a valid InputSource

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "", line 198, in run_module_as_main
File "", line 88, in run_code
File "C:\Users\user\apps\WPy64-31110\python-3.11.1.amd64\Scripts\monitorcontrol.exe_main
.py", line 7, in
File "C:\Users\user\apps\WPy64-31110\python-3.11.1.amd64\Lib\site-packages\monitorcontrol_main
.py", line 158, in main
current_input = monitor_obj.get_input_source()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\user\apps\WPy64-31110\python-3.11.1.amd64\Lib\site-packages\monitorcontrol\monitorcontrol.py", line 399, in get_input_source
raise InputSourceValueError(
monitorcontrol.monitorcontrol.InputSourceValueError: 27 is not a valid InputSource

Severity of VCPIOError errors

Due to high level of errors severity it is impossible to use monitorcontrol (VCPIOError exception thrown) with monitors which do not follow the DDC/CI standard e.g. Philips 223V monitors returns corrupted data i.e. incorrect checksum and/or wrong length, despite that it is possible to control it.

Example output:
Reading 0x60...
Send: 51 82 01 60 dc | Q...
Recv: 6e | n
Invalid response, corrupted data - xor is 0x5e, length 0x08
6e 88 88 02 00 60 00 00 03 00 01 | n.........
Send: 51 82 01 60 dc | Q...
Recv: 6e | n
Invalid response, corrupted data - xor is 0x5e, length 0x08
6e 88 88 02 00 60 00 00 03 00 01 | n.........
Send: 51 82 01 60 dc | Q...
Recv: 6e | n
Invalid response, corrupted data - xor is 0x5e, length 0x08
6e 88 88 02 00 60 00 00 03 00 01 | n.........

If possible, it could be better to handle errors without throwing an exception and try to continue execution.

More information for each monitor

I want to distinguish each monitor according to the name or id, get_monitors() just returen a monitor list, but I can't distinguish which is my physical display. Another demand is get each monitor's resolution and starting point x/y.

After some look, found this repo: https://github.com/rr-/screeninfo

and this: https://github.com/dot-osk/monitor_ctrl (surpport for get monitor model)

So maybe get_monitors() could return more information after merge or reference this repo's code.

In addition, I want to confirm that the monitor list returned by module screeninfo and the monitor list returned by monitorcontrol correspond to one or one ?

USB-C InputMode not supported

Thanks a lot for this work, it is very handy!

I have a Dell U2720Q and when it is on the "USB-C" input, I get an error message trying to read the input mode:

ValueError: 27 is not a valid InputSource

Return 0 of get_luminance() in windows 10

Hello
I tried get_luminance() of monitocontrol package ver 3.0.1 in windows 10 but I've got return 0 in my Display Monitor

from monitorcontrol import get_monitors
for monitor in get_monitors():
with monitor:
print(monitor.get_contrast())
print(monitor.get_luminance())
print(monitor.get_vcp_capabilities())

0
0
{'prot': '', 'type': '', 'model': '', 'cmds': {}, 'vcp': {}, 'mswhql': '', 'asset_eep': '', 'mccs_ver': '', 'window': '', 'vcpname': '', 'inputs': ''}
EDID data is like that
ID Manufacture Name : ALX
ID Product Code : 0010
ID Serial Number : N/A
Week of Manufacture : 30
Year of Manufacture : 2017
and more
Do you have any idea why get_luminance() returns 0?

ValueError: invalid literal for int() with base 16: ')'

  • Monitor manufacturer and model number: LG 27GL83A-B and HP Z27n
  • Input source (HDMI, VGA, display port, ect.): DisplayPort
  • Output device (video card, discrete graphics, ect.): NVIDIA RTX 3070
  • Operating system: Debian sid (Linux 5.10.0-8-amd64)
  • Python version: 3.9.2
  • monitorcontrol version: 2.5.0

Steps to Reproduce

from monitorcontrol import get_monitors

for monitor in get_monitors():
    with monitor:
        print(monitor.get_vcp_capabilities())

or

$ monitorcontrol --get-monitors
(Pdb) caps_str
'02 04 05 08 10 12 14(05 08 0B ) 16 18 1A 52 60( 11 12 0F 10) AC AE B2 B6 C0 C6 C8 C9 D6(01 04) DF 62 8D F4 F5(00 01 02) F6(00 01 02) 4D 4E 4F 15(01 06 09 10 11 13 14 28 29 32  44 48) F7(00 01 02 03) F8(00 01) F9 EF FD(00 01) FE(00 01 02) FF'

(Pdb) caps_str[i]
' '

(Pdb) val
')'

...

(Pdb) val
') 16'

I believe the trailing spaces before the parenthesis ) 16 is throwing it off when _convert_to_dict() is called.

I patched this dirty workaround as proof of concept:
monitorcontrol.py

542:            if val == "" or val == ")":
543:                continue
544:            if val == ") 16":
545:                val = "16"
$ monitorcontrol --get-monitors
Monitor 1: 
Available Inputs:
        DP1
        DP2
        HDMI1
        HDMI2

And for some reason only one monitor is detected, more troubleshooting needed.

Thanks for the great lib!

Erratic ValueError raised in get_power_mode()

  • Monitor manufacturer and model number: Dell U2415
  • Input source (HDMI, VGA, display port, ect.): via passive DVI-D -> HDMI cable
  • Output device (video card, discrete graphics, ect.): Nvidia GTX 1050 Ti
  • Operating system: Windows 10 (build 19045.3448)
  • Python version: 3.11.6
  • monitorcontrol version (monitorcontrol --version): 3.0.3

Steps to Reproduce

  1. Start this snippet:
      import time
      
      from monitorcontrol import get_monitors
      
      if __name__ == '__main__':
          while True:
              for i, monitor in enumerate(get_monitors()):
                  with monitor:
                      print(f"Monitor #{i}: {monitor.get_power_mode()}")
                      time.sleep(3)
  2. Wait until the display goes into standby, the issue should pop up after some time. It seems nondeterministic.
  3. Here the self._get_vcp_feature(code) returns zero, then PowerMode(value) called with this 0 which raises {ValueError}0 is not a valid PowerMode

def get_power_mode(self) -> PowerMode:
"""
Get the monitor power mode.
Returns:
Value from the :py:class:`PowerMode` enumeration.
Example:
Basic Usage::
from monitorcontrol import get_monitors
for monitor in get_monitors():
with monitor:
print(monitor.get_power_mode())
Raises:
VCPError: Failed to get the power mode.
ValueError: Set power state outside of valid range.
KeyError: Set power mode string is invalid.
"""
code = vcp.VCPCode("display_power_mode")
value = self._get_vcp_feature(code)
return PowerMode(value)

Traceback (most recent call last):
  File "C:\Users\Username\AppData\Roaming\JetBrains\PyCharm2023.2\scratches\scratch_1.py", line 9, in <module>
    print(f"Monitor #{i}: {monitor.get_power_mode()}")
                           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "D:\Projects\monitor\venv\Lib\site-packages\monitorcontrol\monitorcontrol.py", line 324, in get_power_mode
    return PowerMode(value)
           ^^^^^^^^^^^^^^^^
  File "C:\Users\Username\AppData\Local\Programs\Python\Python311\Lib\enum.py", line 712, in __call__
    return cls.__new__(cls, value)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Username\AppData\Local\Programs\Python\Python311\Lib\enum.py", line 1135, in __new__
    raise ve_exc
ValueError: 0 is not a valid PowerMode

#288 Seems related.

Luminance function not working as intended

Docs says that it is getting the monitors back-light luminance, but is actually looking at the brightness and not the luminance (intensity of backlight of an LCD).
Can it be supported?

Error Running with Windows Task Scheduler

Info:

Manufacturer: Dell
Model: U2719D
Input Source: HDMI
Output Device: Nvidia card
OS: Windows 11
Python version: 3.9.0
Monitorcontrol version: 3.0.3

Steps to Reproduce

  1. Write a simple script and make sure it works when running normally with python. Make sure to output any errors to a file because you can't see stdout when running with the task scheduler. Here is a working example:
from monitorcontrol import get_monitors
import traceback

LOGFILE = "D:\Desktop\example.log"

def log(msg):
    """ log to a file """
    with open(LOGFILE, 'a') as f:
        f.write(msg+'\n')

try:
    monitors = get_monitors()
    log(f"Found {len(monitors)} monitors")
    for monitor in monitors:
        with monitor:  # <--- Error happens here
            info = monitor.get_vcp_capabilities()
except Exception as e:
    log(f"Error: {traceback.format_exc()}")

When this runs normally, you should see an output like Found 2 monitors in the output file.

  1. Open windows task scheduler and click "Create Basic Task" and provide a name and trigger interval, neither of which impact the bug.
  2. In the "Action" section, select "Start a program".
  3. In the "Program/script" field, enter the absolute path to your python executable (note that if the monitorcontrol package is in a virtual environment, the executable should be from that virtual environment). Example: D:\Desktop\myproject\venv\Scripts\python.exe
  4. In the "Add arguments" field, put the absolute path to the python script. Example: D:\Desktop\myproject\test.py
  5. Finish creating the task. You may need to specify your user password - note that it's your password and not your user PIN. (took me awhile to realize that).
  6. Select the task from the list
  7. On the right-hand side, click "Run" to run the task manually
  8. Now check the output file. Here is what I get:
Found 1 monitors
Error: Traceback (most recent call last):
  File "D:\Desktop\Repositories\Python\OSC-to-DDCCI\test2.py", line 16, in <module>
    with monitor:  # <--- Error happens here
  File "D:\Desktop\Repositories\Python\OSC-to-DDCCI\venv\lib\site-packages\monitorcontrol\monitorcontrol.py", line 84, in __enter__
    self.vcp.__enter__()
  File "D:\Desktop\Repositories\Python\OSC-to-DDCCI\venv\lib\site-packages\monitorcontrol\vcp\vcp_windows.py", line 50, in __enter__
    raise VCPError("no physical monitor found")
monitorcontrol.vcp.vcp_abc.VCPError: no physical monitor found

EDIT: added some missing steps to creating a task

How to identify monitors

How can we identify monitors?
If the order of monitors is guaranteed to be the same across reboots, we can just use its index in the get_monitors() list.
I'm not sure this is the case though. On Linux the i2c bus number could change across reboots (source). I think the same is the case with HMONITOR on Windows.
There is the EDID, which I believe can be parsed out into Manufacturer code, Model number and Serial number (ddcutil does this and you can use --mfg, --model and --sn flags resp. to target a specific monitor).
monitorcontrol could extract either the raw EDID or some other identifying information similar to how ddcutil does it. Simply being able to sort the output of get_monitors() on some stable key and use the index should be enough for many uses (rather than trying to replicate all the features of ddcutil).

Error in get_monitors() for SAMSUNG monitor

  • Monitor manufacturer and model number: SAMSUNG and LED Monitor (S24F354FH)
  • Input source (HDMI, VGA, display port, ect.): HDMI
  • Output device (video card, discrete graphics, ect.): discrete graphics
  • Operating system: window 10
  • Python version: 3.9.0
  • monitorcontrol version (monitorcontrol --version): 2.5.1

Steps to Reproduce

I wrote some test code as below. It works well for LG monitor.
However when I tried it with samsung monitor, I got error of InputSourceValueError(255).
I think it fails to get monitor information after software power off for samsung monitor.

I'd like to control monitor power for energy saving.
It would be great if you check it


for monitor in get_monitors():
    with monitor:
        monitorSrc = monitor.get_input_source()  
        if monitorSrc.value != 0:
            monitor.set_power_mode("off_soft")    # succeed to turn off the monitor

time.sleep(5.0)

for monitor in get_monitors():   
    with monitor:
        monitorSrc = monitor.get_input_source()    # raise InputSourceValueError: 255 is not a valid Input Source
        if monitorSrc.value != 0:
            monitor.set_power_mode("on")        

monitorcontrol is setting my monitor to DPS

My monitor has dynamic power saving as a option. Whenever I command the brightness to change or read the current brightness value, DPS gets turned back on. I can turn it off, but as soon as I send a command again DPS turns back on.

get_*()-commands return absurdly high values for luminance and contrast while monitor OSD is open

  • Monitor manufacturer and model number:
    HP Omen 27u
  • Input source (HDMI, VGA, display port, ect.):
    DP
  • Output device (video card, discrete graphics, ect.):
    Discrete Radeon 6800
  • Operating system:
    Win 10 Pro 64 bit
  • Python version:
    3.12.0
  • monitorcontrol version (monitorcontrol --version):
    3.1.0

Steps to Reproduce

Create a very basic Python script, which asks for monitor brightness and contrast:

import time
from monitorcontrol import get_monitors

# Check monitors
while True:
    for monitor in get_monitors():
        with monitor:
            try:
                brightness = monitor.get_luminance()
                contrast   = monitor.get_contrast()
                print(f'Brightness: {brightness}') 
                print(f'Contrast:   {contrast}')
            except:
                print('Error occured during get-command')

    time.sleep(0.25)

As discussed in #288, many get_*()-commands fail with an error, but that is not relevant for this bug. I kept the errors in the log, but they can be ignored. What is more interesting is the behaviour while interacting with the monitor OSD. Log looks like this:

= RESTART: C:\Users\MyName\Downloads\Monitor brightness\Test_Set brightness_monitorcontrol.py
Error occured during get-command

Error occured during get-command

Brightness: 0
Contrast:   80

Brightness: 0
Contrast:   80

Error occured during get-command

Error occured during get-command	<--- Around here I opened the OSD by pressing the control dial on the screen

Brightness: 43690
Contrast:   43690

Error occured during get-command

Error occured during get-command

Error occured during get-command	<--- OSD closed around here

Error occured during get-command

Error occured during get-command

Brightness: 0
Contrast:   80

The behaviour is repeatable and the value is always 43690 for both, get_luminance() and get_contrast(). I am not sure, where this problem originates - it might be specific to my display, but that's difficult for me to check right now.

That being said, those values should be far outside of the allowed value ranges for these parameters, right? If so, I feel like this should trigger an error regardless of the origin of the problem.

Not compatible with pyglet.window.Window

Great tool!

I discovered a bug that appears when using monitortool together with pyglet:

import monitorcontrol
from pyglet.window import Window

monitorcontrol.get_monitors()

# ArgumentError: argument 2: <class 'TypeError'>: expected LP_RECT instance instead of int
# TypeError: catching classes that do not inherit from BaseException is not allowed

image

Do you think there is any way to repair that?

  • Operating system: Win 10
  • Python version: 3.9.7
  • monitorcontrol version (monitorcontrol --version): 3.0.0 (dev)

Monitor randomly responds with 0 to get_*()-command and/or fails set_*()-command

  • Monitor manufacturer and model number:
    HP Omen 27u
  • Input source (HDMI, VGA, display port, ect.):
    DP (different cables and both DP ports on the GPU tested)
  • Output device (video card, discrete graphics, ect.):
    Discrete Radeon 6800 (at least two different driver versions tested)
  • Operating system:
    Win 10 Pro 64 bit
  • Python version:
    3.12.0 (also tested 3.11.3)
  • monitorcontrol version (monitorcontrol --version):
    3.0.3

Steps to Reproduce

Create a very basic Python script, which asks for monitor brightness and contrast and then tries to set the reported value for brightness (contrast ignored for now):

import time
from monitorcontrol import get_monitors

# Check monitors
while True:
    for monitor in get_monitors():
        with monitor:
            brightness = monitor.get_luminance()
            contrast   = monitor.get_contrast()
            print(f'Brightness: {brightness}') 
            print(f'Contrast:   {contrast}')

    time.sleep(1)

    # Set monitor backlight using monitorcontrol
    for monitor in get_monitors():
        with monitor:
            monitor.set_luminance(brightness)
            #monitor.set_contrast(contrast)
        
    time.sleep(1)

The script works erratically. Almost always, the first reported contrast value is 0, while the first reported brightness is correct. Sometimes, brightness is reported as 0 later on. If that is the case, the screen brightness is accordingly set to 0 in the following step, in case monitor.set_luminance() does not crash. If the script does crash, it is always at monitor.set_luminance() with the reported error that whatever brightness was defined is larger than the maximum allowed value of 0 (?).

Crashes occur with roughly 20% probability. A typical run of the script looks like this:

Python 3.12.0 (tags/v3.12.0:0fb18b0, Oct  2 2023, 13:03:39) [MSC v.1935 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license()" for more information.

= RESTART: C:\Users\MyName\Downloads\Monitor brightness\Test_Set brightness_monitorcontrol.py
Brightness: 16
Contrast:   0
Brightness: 16
Contrast:   80
Brightness: 16
Contrast:   80
Traceback (most recent call last):
  File "C:\Users\MyName\Downloads\Monitor brightness\Test_Set brightness_monitorcontrol.py", line 22, in <module>
    monitor.set_luminance(brightness)
  File "C:\Users\MyName\AppData\Local\Programs\Python\Python312\Lib\site-packages\monitorcontrol\monitorcontrol.py", line 254, in set_luminance
    self._set_vcp_feature(code, value)
  File "C:\Users\MyName\AppData\Local\Programs\Python\Python312\Lib\site-packages\monitorcontrol\monitorcontrol.py", line 149, in _set_vcp_feature
    raise ValueError(
ValueError: value of 16 exceeds code maximum of 0

Question regarding setting a code value

I am running on Windows and wanting to get and set the backlight of my monitor. It is using the legacy VCP code. How does one go about doing this?

the VCP code is 0x13

get
MH = color choice
ML = returned value

set
SH = color choice
SL = new value

color choices are
white = 0x00
red = 0x01
green = 0x02
blue = 0x03

The set should be pretty easy to do with some bit shifting.
The get on the other hand I am not sure how I would go about passing the color choice

any help would be appreciated.

KeyError: 0 when running `monitorcontrol --get-monitors`

I have a setup with 8 total monitors on Windows 10, Python 3.8, monitorcontrol==3.0.2. When I run:

monitorcontrol --get-monitors

I get:

Monitor 1: PA278QV
Available Inputs:
        InputSource.DVI1
        InputSource.DP1
        InputSource.DP2
        InputSource.HDMI1*
Monitor 2: P2422H
Available Inputs:
        InputSource.ANALOG1
        InputSource.DP1
        InputSource.HDMI1*
Monitor 3: P2422H
Available Inputs:
        InputSource.ANALOG1
        InputSource.DP1
        InputSource.HDMI1*
Monitor 4: PA278QV
Available Inputs:
        InputSource.DVI1
        InputSource.DP1
        InputSource.DP2
        InputSource.HDMI1*
Monitor 5: PA278QV
Available Inputs:
        InputSource.DVI1
        InputSource.DP1
        InputSource.DP2
        InputSource.HDMI1*
Monitor 6: P2419H
Available Inputs:
        InputSource.ANALOG1*
        InputSource.DP1
        InputSource.HDMI1
Monitor 7: P2419H
Available Inputs:
        InputSource.ANALOG1*
        InputSource.DP1
        InputSource.HDMI1
Traceback (most recent call last):
  File "c:\program files\python\python38\lib\runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "c:\program files\python\python38\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\Program Files\Python\Python38\Scripts\monitorcontrol.exe\__main__.py", line 7, in <module>
  File "c:\program files\python\python38\lib\site-packages\monitorcontrol\__main__.py", line 157, in main
    monitors_dict = monitor_obj.get_vcp_capabilities()
  File "c:\program files\python\python38\lib\site-packages\monitorcontrol\monitorcontrol.py", line 208, in get_vcp_capabilities
    res = _parse_capabilities(cap_str)
  File "c:\program files\python\python38\lib\site-packages\monitorcontrol\monitorcontrol.py", line 593, in _parse_capabilities
    caps_dict[key] = _convert_to_dict(_extract_a_cap(caps_str, key))
  File "c:\program files\python\python38\lib\site-packages\monitorcontrol\monitorcontrol.py", line 553, in _convert_to_dict
    result_dict[group].append(val)
KeyError: 0

It looks like it is failing when trying to retrieve information about monitor 8 (I assume, I'm just guessing). Monitor 8 is an HP monitor while all the other monitors are Dells and Asus monitors, in case that matters.

Any idea what to do here?

How to distinguish between different monitors of the same model type?

I have several monitors which are the same model; for example, two Dell P2422H monitors. When I print the VCP capabilities, I don't see any information that distinguishes them:

{'prot': 'monitor', 'type': 'lcd', 'model': 'P2422H', 'cmds': {1: [], 2: [], 3: [], 7: [], 12: [], 227: [], 243: []}, 'vcp': {2: [], 4: [], 5: [], 8: [], 16: [], 18: [], 20: [5, 8, 11, 12], 22: [], 24: [], 26: [], 82: [], 96: [1, 15, 17], 170: [1, 2, 4], 172: [], 174: [], 178: [], 182: [], 198: [], 200: [], 201: [], 204: [2, 3, 4, 6, 9, 10, 13, 14], 214: [1, 4, 5], 220: [0, 3, 5], 223: [], 224: [], 225: [], 226: [0, 2, 4, 14, 18, 20], 241: [], 242: [], 253: [], 254: []}, 'mswhql': '1', 'asset_eep': '', 'mccs_ver': '2.1', 'window': '', 'vcpname': '', 'inputs': [<InputSource.ANALOG1: 1>, <InputSource.DP1: 15>, <InputSource.HDMI1: 17>]}

I checked and this output is identical for both monitors. How can I distinguish them other than the index? For example, in another software "Nirsoft ControlMyMonitor" I get a serial number of some kind as well:

image

image

In Nirsoft ControlMyMonitor, I can address the monitor by the number in the red box directly, which makes it possible to distinguish them when controlling them.

It would make more sense to identify them this way since monitor indexes in Windows can change, especially as I add and remove other monitors. The indexes are not consistent in my experience.

I have a setup with 8 total monitors on Windows 10, Python 3.8, monitorcontrol==3.0.2.

monitorcontrol doesn't switch inputs

monitorcontrol does nothing when attempting to switch inputs

  • Monitor manufacturer and model number: Dell S3221QS
  • Input source (HDMI, VGA, display port, ect.): HDMI1 HDMI2
  • Output device (video card, discrete graphics, ect.): Nvidia gt1030
  • Operating system: Linux - Ubuntu 22.04
  • Python version: 3.10.4
  • monitorcontrol version (monitorcontrol --version): 3.0.0

Steps to Reproduce

Works:
ddccontrol -r 0x60 -w 18 dev:/dev/i2c-4
ddccontrol -r 0x60 -w 17 dev:/dev/i2c-4

Doesn't:
monitorcontrol --set-input-source HDMI1
monitorcontrol --set-input-source HDMI2

Set the contrast after setting the brightness will raise an error

Code:

for monitor in get_monitors():
    with monitor:
        monitor.set_luminance(0)
        monitor.set_contrast(5)

Error:

Traceback (most recent call last):
  File "D:/python/Lib/site-packages/MyUtils/RPA/monitor_control.py", line 221, in <module>
    monitor.set_contrast(5)
  File "D:\python\lib\site-packages\monitorcontrol\monitorcontrol.py", line 277, in set_contrast
    self._set_vcp_feature(code, value)
  File "D:\python\lib\site-packages\monitorcontrol\monitorcontrol.py", line 134, in _set_vcp_feature
    f"value of {value} exceeds code maximum of {maximum}"
ValueError: value of 5 exceeds code maximum of 0

Add time.sleep(0.05) between set_luminance and set_contrast method could avoid this error, either if you call set_contrast first.

Please check and try to fix it.

Checking input works for one monitor but not the other (both same model)

  • Monitor manufacturer and model number: See ddcutil info below for list
  • Input source (HDMI, VGA, display port, ect.): DP and DP via DP->HDMI active adapter
  • Output device (video card, discrete graphics, ect.): VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (rev e7)
  • Operating system: Arch linux
  • Python version: Python 3.9.7
  • monitorcontrol version (monitorcontrol --version):

Steps to Reproduce

Iterate through monitors checking which input is selected:

#!/bin/env python
import monitorcontrol

for monitor in monitorcontrol.get_monitors():
    with monitor:
        print(monitor.get_input_source())

InputSource.DP1
Traceback (most recent call last):
  File "switch_monitor_input.py", line 8, in <module>
    print(monitor.get_input_source())
  File "venv/lib/python3.9/site-packages/monitorcontrol/monitorcontrol.py", line 389, in get_input_source
    value = self._get_vcp_feature(code) & 0xFF
  File "venv/lib/python3.9/site-packages/monitorcontrol/monitorcontrol.py", line 175, in _get_vcp_feature
    current, maximum = self.vcp.get_vcp_feature(code.value)
  File "venv/lib/python3.9/site-packages/monitorcontrol/vcp/vcp_linux.py", line 180, in get_vcp_feature
    ) = struct.unpack(">BBBBHH", payload)
struct.error: unpack requires a buffer of 8 bytes

display info from ddcutil:

Display 1
   I2C bus:  /dev/i2c-11
   EDID synopsis:
      Mfg id:               ACR
      Model:                CB282K
      Product code:         1887
      Serial number:        
      Binary serial number: 1898...
      Manufacture year:     2020,  Week: 12
   VCP version:         2.1

Display 2 <-- this one
   I2C bus:  /dev/i2c-12
   EDID synopsis:
      Mfg id:               ACR
      Model:                CB282K
      Product code:         1887
      Serial number:        
      Binary serial number: 1898...
      Manufacture year:     2020,  Week: 12
   VCP version:         2.1

Display 3
   I2C bus:  /dev/i2c-13
   EDID synopsis:
      Mfg id:               ACR
      Model:                CB282K
      Product code:         1887
      Serial number:        
      Binary serial number: 18983...
      Manufacture year:     2020,  Week: 12
   VCP version:         2.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.