Giter Site home page Giter Site logo

digitaltrails / vdu_controls Goto Github PK

View Code? Open in Web Editor NEW
110.0 4.0 3.0 7.46 MB

VDU controls - a control panel for monitor brightness/contrast/...

License: GNU General Public License v3.0

Python 98.48% Shell 1.52%
ddc mccs linux python gui ddcutil bh1750 gy-30 qt5 gy-302

vdu_controls's Introduction

vdu_controls - a DDC control panel for monitors

A control panel for external monitors (Visual Display Units).

KDE 6 introduced energy saving brighness dimming after 5 minutes of idle time. This may interfere with changes made via vdu_controls, including scheduled-presets and ambient-light-control. The relevant KDE 6 options can be found under System Settings -> System -> Energy Saving.

vdu_controls version 2.0 adds manual ambient-light-level input. This allows all connected VDU's to be simultatiniously adjusted by moving one slider. This is an alternative to fully automatic control via hardware lux-metering. When the ambient-light-level is changed, each VDU us adjusted according to its own custom light-level/brighness profile defined under Settings->Light-Metering. This new option is enabled by default, but can be disabled by unchecking Settings->Lux options enabled.

Custom

The second major change in 2.0 is actually far more wide-reaching, but much less visibile. The internal DDC/VDU interface has been rewritten to optionally use the D-Bus ddcutil-service instead of the ddcutil command. The new ddcutil-service is a daemon I've written to interface with libddcutil, it's faster and more reponsive than the older command-based implementation. Should the ddcutil-service be unavailable, the DDC/VDU interface reverts to using the ddcutil command. Should you encounter any issues with using the service, Settings->D-Bus client enabled can be used to disable it and force the use of the command.

If you'd like to try the ddcutil-service, builds are available for OpenSUSE Tumbleweed and the Arch AUR:

OpenSUSE Tumbleweed RPM:

https://software.opensuse.org/package/ddcutil-service

AUR (Arch Linux User Repository):

https://aur.archlinux.org/packages/ddcutil-service

Otherwise it's written in C, so you'd need to build and install it. It's one C file. It will build against any libddcutil from 1.4 onward. It doesn't need to be installed as root, it can also be started manually from the command line or installed as a single user D-Bus daemon. For install/build details, see:

https://github.com/digitaltrails/ddcutil-service

The service can be installed for on demand access via the D-BUS daemon. It can also run manually from the command line. Once the service is running, any new instance of vdu_controls should automatically find and connect to the service. When using the service, the bottom line of vdu_controls About Dialog will list ddcutil-interface as 1.0.0 (QtDBus client). Use of the service can be manually toggled via vdu_controls->Settins->dbus client enabled.

The service may also be accessed from generic D-Bus clients such as d-feet dbus-send and busctl.

Description

vdu_controls is a virtual control panel for externally connected VDUs. The application detects DVI, DP, HDMI, or USB connected VDUs. It provides controls for settings such as brightness and contrast.

The application interacts with VDUs via the VESA Display Data Channel (DDC) Virtual Control Panel (VCP) commands set. DDC VCP interactions are mediated by the ddcutil command line utility. Ddcutil provides a robust interface that is tolerant of the vagaries of the many OEM DDC implementations.

By default vdu_controls offers a subset of controls including brightness, contrast and audio controls. Additional controls can be enabled via the Settings dialog.

vdu_controls may optionally run as an entry in the system tray of KDE, Deepin, GNOME, and Xfce (and possibly others). The UI attempts to adapt to the quirks of the different tray implementations.

Named Preset configurations can be saved for later recall. For example, a user could create presets for night, day, photography, movies, and so forth. Presets may be automatically triggered according to solar elevation, and can be further constrained by local weather conditions (as reported by https://wttr.in). Presets can be set to transition immediately or gradually. Presets may also be activated by UNIX signals.

From any application window, use F1 to access help, and F10 to access the context-menu. The context menu is also available via the right-mouse button in the main-window, the hamburger-menu item on the bottom right of the main window, and the right-mouse button on the system-tray icon. The context-menu provides ALT-key shortcuts for all menu items (subject to sufficient letters being available to support all user defined Presets).

Version 1.10 introduces options for using lux readings from a hardware lux meter (or in some cases a webcam). When lux metering is enabled, vdu_controls can vary brightness according to customisable lux/VDU-brightness profiles. See Lux Metering for more details.

The UI's look-and-feel dynamically adjusts to the desktop theme and desktop environment: light-theme, dark-theme, KDE, Deepin, GNOME, and others.

Default Custom Custom Custom Custom Custom

Getting Started

The long term affects of repeatably rewriting a VDUs setting are not well understood, but some concerns have been expressed. See below for further details.

To get started with vdu_controls, you only need to download the vdu_controls.py python script and check that the dependencies described below are in place. Alternatively, should you wish to install vdu_controls for all users, RPMs are available for OpenSUSE, Fedora, and there is an archlinux AUR package which also works in Manjaro. See the Install section below.

Development is trunk-based. It is my intention that the trunk should always be usable as a daily-driver. That being said, a download of trunk is likely to be less stable than downloading one of the formal releases or installing one of the packages that are available in various distros.

Dependencies

All the following runtime dependencies are likely to be pre-packaged on any modern Linux distribution (vdu_controls was originally developed on OpenSUSE Tumbleweed).

  • ddcutil >= 1.2, >= 1.4 recommended: the command line utility that interfaces to VDUs via DDC over i2c-dev or USB. (If anyone requires support for versions of ddcutil prior to v1.2 please contact me directly.)
  • i2c-dev: the i2c-dev kernel module normally shipped with all Linux distributions and required by ddcutil
  • python >=3.8: vdu_controls is written in python and may depend on some features present only in 3.8 onward.
  • python >=3.8 QtPy: the python GUI library used by vdu_controls.

It's best to confirm that ddcutil is functioning before using vdu_controls:

  • See https://www.ddcutil.com/config/ for instructions on configuring ddcutil (including some extra steps for Nvidia GPU users).
  • See https://www.ddcutil.com/i2c_permissions/ for instructions on setting and testing the required permissions.
  • Fo some VDUs, DDC/CI over Display-Port to Display-Port connections may work when others connections don't (mainly with some Nvidia GPUs).

As of ddcutil 1.4, installing a pre-packaged ddcutil will most likely set the correct udev rules to grant users access to the required devices. If you are using an earlier ddcutil, it may be necessary to follow all the steps detailed in the links above.

Installing

As previously stated, the vdu_vontrols.py script is only file required beyond the prerequisites. There are also OpenSUSE and Fedora RPMs available at: https://software.opensuse.org/package/vdu_controls and an archlinux (manjaro compatible) AUR package at: https://aur.archlinux.org/packages/vdu_controls

That makes three options for "installation":

  1. The script can be run without installation by using a python interpreter, for example:

    % python3 vdu_controls.py
    
  2. The script can be self installed as desktop application in the current user's desktop menu as Applications->Settings->VDU Controls by running:

     % python3 vdu_controls.py --install
    

    Depending on which desktop you're running menu changes may require logout before they become visible.

  3. A system-wide installation using a distribution's packaging system which will install all of:

    /usr/bin/vdu_controls
    /usr/share/applications/vdu_controls.desktop
    /usr/share/licenses/vdu_controls/LICENSE.md
    /usr/share/vdu_controls/icons/*
    /usr/share/vdu_controls/sample-scripts/*
    /usr/share/vdu_controls/translations/*
    /usr/share/man/man1/vdu_controls.1.gz
    

Please note the first two options only install vdu-controls for the current user. The script and desktop-file installed for a single user could be modified and copied into /usr or /usr/local hierarchies should you wish to do so. If using the first two options, you might want to follow up by manually downloading some of the other items such as the starter set of icons for use when creating Presets.

Executing the program

  • If installed from rpm, VDU Controls should be in everyone's application menu under Settings. The vdu_controls command will also be in everyone's PATH and will be able to be run from the command line, for example:
    % vdu_controls --show brightness --show contrast --show audio-volume
    
  • If installed by the current user via the --install option, VDU Controls should be in the current user's application menu under Settings. The vdu_controls command will be in $HOME/bin. If $HOME/bin is on the user's PATH, vdu_controls will be also able to be run from the command line in the same manner as above.
  • If the script has not been installed, it can still be run on the command line via the python interpreter, for example:
    % python3 vdu_controls.py --no-splash --system-tray --show brightness --show contrast

Help

Detailed help can be accessed by using the right mouse-button to bring up a context-menu. Access to the context-menu is available in the application-window and in the system-tray icon.

Both brief help and detailed help can also be accessed via the command line:

% python3 vdu_controls.py --help
% python3 vdu_controls.py --detailed-help
% python3 vdu_controls.py --detailed-help | pandoc --from markdown --to html > vdu_controls_help.html
# or if installed as an executable:
% vdu_controls --help
% vdu_controls --detailed-help
% vdu_controls --detailed-help | pandoc --from markdown --to html > vdu_controls_help.html

Whether run from the desktop application-menu or run from the command line, vdu-controls behaviour can be altered in a number of ways:

  • The Settings item in the context-menu.
  • Command line options.
  • Configurations files in $HOME/.config/vdu_controls/

See the context-menu or the man page for details.

VDU controls and optimisations can be specified in the global or VDU-specific config-files.

Does adjusting a VDU affect its lifespan or health?

There has been speculation that repeatably altering VDU settings might affect VDU lifespan. Possible reasons include the consumption of NVRAM write cycles, stressing the VDU power-supply, or increasing the LED panel burn-in.

That said, vdu_controls does include a number of features that can be used to reduce the overall frequency of adjustments, see Limitations in the man page for further details.

Other concerns

The power-supplies in some older VDUs may buzz/squeel audibly when the brightness is turned way down. This may not be a major issue because, in normal surroundings, older VDUs are often not usable below about 85-90% brightness.

Going beyond the standard DDC features by attempting to experiment with hidden or undocumented features or values has the potential to make irreversible changes.

Bugs and Suggestions

If you encounter a bug or issue, or wish to make a suggestion, you're most welcome to raise it on the issues page.

Development

I've set up the vdu_controls source as a typical Python development, but there is only one real source file, vdu_controls.py, so the file hierarchy is rather over the top. A standard python distributable can be built by issuing the following commands at the top of the project hierarchy:

% python3 -m pip install build
% python3 -m build
...
% ls -1 dist/
total 268
vdu_controls_digitaltrails-1.0.0-py3-none-any.whl
vdu_controls-digitaltrails-1.0.0.tar.gz

The source includes configuration files for the Sphinx Python Documentation Generator. The following commands will extract documentation from vdu_controls.py:

% cd docs
% make man
% make html

I prefer Pandoc's HTML generation. There is a util script that generates the Sphinx outputs and then pandoc for the html:

% ./util/make-man

My IDE for this project is PyCharm Community Edition.

Coverage testing is assisted by Coverage.py and Vulture. Type checking is assisted by Mypy.

My development Linux desktop is OpenSUSE Tumbleweed. The python3 interpreter and python3 libraries are from the standard Tumbleweed repositories.

Acknowledgements

Author

Michael Hamilton

Version History

  • 2.0.4

    • The About-Dialog now refreshes the ddcutil version info on each invocation.
    • Increased dbus timeout to 10 seconds (in case numerous VDUs or errors slow down VDU detection).
    • Dynamically enable a scroll-area when the main-panel exceeds the available screen height.
  • 2.0.3

    • Reduce the number of writes to VDU NVRAM by sliders, spinners, and ambient brightness adjustments.
      • Slider and spin-box controls now only update the VDU when adjustments become slow or stop (when the control value remains constant for 0.5 seconds).
      • Spin-Boxes now select the entire text on focus in (enables easier overtyping and decreases VDU updates).
      • Ambient lighting initiated changes in brightness of up to 20% are applied without any transitional steps (plus the existing code ignores updates of less than 10%).
      • Set the default ambient-light brightness adjustment-interval to 5 minutes.
    • React to DPMS awake signal from ddcutil-service by re-assessing ambient brightness.
    • Simplified locking and conformed to a locking hierarchy/protocol to avoid potential deadlocks.
  • 2.0.2

    • Added a refresh annotation suffix for use with VCP-codes which cause multiple changes.
    • Make manual adjustment of the ambient Light Level more accurate and responsive.
    • Updates are sent to the VDU as sliders are dragged (rather than only on release).
    • Fix exception on monitors that return invalid/unexpected combo-box VCP values.
    • Fix exception on monitors with blank VCP value descriptions.
    • When refresh is pressed, only auto adjust ambient brightness if auto-brightness is enabled.
    • Don't automatically refresh on error, eliminate popup dialog loops.
    • Eliminate deadlocks when exceptions occur.
    • Cleanup the initialisation of the ddcutil-service connection.
    • Add more caveats and limitations to the documentation.
    • Fix manual ambient light slider when light meter is uninitialized.
    • Promote Simple-Non-Continuous values whose metadata exceeds one-byte to two-byte Complex-NC.
  • 2.0.1

    • Fix D-Bus client code for python versions prior to 3.11.
    • Fix infinite-loop when altering an existing FIFO lux-meter in the Lux-Dialog.
    • Fix the refresh of the LuxDialog meter-readout/plot when changing to a new meter.
    • Apply context-aware defaults to the LuxDialog device file-chooser.
    • Improve/fix the handling of displays/laptop-displays that may be detected but lack proper DDC.
    • Force the file-picker to always show devices and FIFOs - it wasn't showing then on some desktops.
  • 2.0.0

    • Added an optional D-Bus interface to ddcutil for up to 10x faster response times.
    • Added an immediate-lighting-check button and corresponding context-menu item (when lux-metering is enabled).
    • Added an ambient-light-control for manual lux input, one slider to adjust brightness on all displays.
    • Added more preset icons.
  • 1.20.0

    • Added options monochrome-tray and mono-light-tray to enable a monochrome tray-icon (dark and light).
    • Optional $HOME/.config/vdu_controls/tray_icon.svg overrides the normal tray icon.
    • Improved the adjustment of icon/window dimensions by scaling them in respect to the user's default-font height.
    • Remove adjust-for-dpi in favour of the the above which automatically accounts for DPI.
    • When a Preset is transitioning slowly (i.e. not immediately), the UI controls can be used to stop the transition.
    • Considerable internal refactoring of option handling.
  • 1.12.0

    • Added an F10_key context menu shortcut to all application windows (KDE accessibility standard).
    • Set icon and pixmap sizes appropriately for Normal and High DPI (controlled by adjust-for-dpi) (issue #63).
    • Icon/device-chooser-dialog: init-time reduced from 30 to 5 seconds for users with large home folders (issue #61).
    • Improvements/Fixes to the vlux_meter.py sample-script and the related vdu_controls FIFO reader.
    • Improved visibility of the app-icon's preset-transitioning indicator and auto-lux indicator.
    • Increased contrast for generated text preset-abbreviation icons.
    • Encode translations in plain text rather than escaped XML (for easier editing).
  • 1.11.1

    • Fix Preset text size in tray icon.
    • Fix occasional concurrency lockup issue in lux_metering.
    • Update the Settings Dialog when a new VDU becomes available.
    • Light-metering: show both a lux-auto indicator (an orange "LED") AND the current preset (if any) in the app icon.
    • Fix first time use crash (issue #60).
    • Allow % in config files by turning off ConfigParser interpolation (issue #60).
  • 1.11.0

    • Made vdu_controls ddcutil-2.0-ready.
    • Added support for ddcutil versions earlier than 1.3 (issue #43, #53).
    • Main-Window: added a hide-on-focus-out option to minimize the main window on focus out (issue #57).
    • Main-Window: changed the layout to display brightness and contrast as the first two controls for each VDU.
    • Main-Window: added jump to clicked value to sliders (issue #59).
    • Main-Window: added a smart-main-window option to make main window placement and geometry preservation optional.
    • Main-Window: the main window can now be raised above the other sub-windows (gnome issue only).
    • Main-Window and Context Menu: added alt-key keyboard shortcuts (issue #13).
    • Context-Menu: added an indicator mark suffix to the currently active Preset (if any) (issue #55).
    • Context-Menu: made changes to Preset ordering propagate to the menu without requiring an application restart.
    • Tray-Icon: made the app icon un-themed so that overlaid active Preset text/icon is more visible (issue #55).
    • Settings-Dialog: added a Reset button to makes it possible to un-ignore a VDU (issue #51).
    • Settings-Dialog: added tool-tips to main config-settings, made them consistent with command line help (issue #52).
    • Preset-Dialog: combined the Activate and Edit buttons into one button (simpler and more intuitive).
    • Preset Dialog: made the dialog bold the text button of the currently active Preset (if any).
    • Preset Dialog: added code to detect and and warn of unsaved changes.
    • Preset Dialog: made the dialog lock out any scheduled or automatic VDU changes while a Preset is being edited.
    • Preset-Dialog: supplied a starter set of Prest icons - a selection of KDE breeze5-icons (issue #56).
    • Popup-Messages: made message box popups resizable for increased readability.
    • Command-line: made config-settings and command-line arguments consistent, command line has precedence (issue #52).
    • Command-line: fixed --sleep-multiplier so that it is actually applied (issue #54).
    • Prevented potential crashes in the event of utf-8 decoding errors for EDIDs and capabilities (issue #49).
    • Added logging of stack traces for some errors if debugging is set to on (issue #49).
    • Improved the handling of ddcutil not found (issue #48).
    • Refactored to improve maintainability and run-time efficiency (issue #52).
    • Added Deepin 23 pyqt library compatibility.
    • Numerous minor enhancements and fixes.
    • An alpha release of vlux_meter.py, a system-tray webcam lux-meter, has been included in the sample scripts folder.
  • 1.10.2

    • Fix Preset non-zero transition-step-seconds, so it works properly.
    • Changing log-to-syslog or log-debug-enabled no longer requires a restart.
    • Fix Lux Auto menu icon when starting with Auto disabled.
    • Use the progress bar area on the main panel for status messages.
    • Make auto brightness behave more predictably by removing unnecessary constraints on interpolation.
    • Improve auto-lux/preset tray icon interaction - better reflect actions and current state.
  • 1.10.1

    • Restore lux meter displayed-value when restoring LuxDialog window.
    • Minor fixes to reduce and improve displayed and logged messages.
    • Rollup release prior to downtime for ToTK
  • 1.10.0

    • Added hardware lux metering options (GY30/BH1750+Arduino, UNIX-fifo, or executable-script).
    • Added lux-to-brightness profiles per VDU.
    • Added sample scripts for using a webcam to produce approximate lux values.
    • Added an option to transition smoothly on UNIX signal.
    • Replaced the transition combo-box with a button+checkboxes.
    • Added drag-to-change, click-to-delete, to the elevation chart component.
    • Added a setting to quickly disable weather and another for elevation-scheduling.
    • Cleanup of thread handling - clarification of GUI/non-GUI thread operations.
    • Reduced logging and eliminated popup dialogs when monitors are suspended or powered off.
  • 1.9.2

    • Optional Smooth Transitions for presets:
      • The Presets Dialog now includes an option to set a Preset to Transition Smoothly.
      • The tray, main panel, and Preset Dialog indicate when a smooth transition is in progress.
      • Transitions are performed by a non-GUI thread, the GUI remains accessible during smooth transitions.
      • A smooth transition can be interrupted by moving the controls being transitioned or invoking a preset.
  • 1.9.1

    • The text input to right of slider controls has been replaced with a SpinBox with up/down arrows.
    • The main panel progress-bar spinner will now also display during preset-activation (in addition to displaying during refresh).
    • Refresh and preset controls now lock during refresh and preset-activation (to prevent conflicting actions).
    • The context menu and hamburger menu are now available during refresh (a subset of actions is available, such as help and about).
    • The VDU EDID 128/256 byte identifier is now used internally to ensure the controls operate on the correct monitor.
    • Build changes for submission to OpenSUSE Development and Factory by @malcolmlewis.
    • The thread handling and error handling has been cleaned up.
  • 1.9.0

    • Bug fixes and speedy performance improvements:
      • Speed up initialization and refresh by combining multiple ddcutil getvcp requests.
      • Stop executing a getvcp precheck before each setvcp.
      • Fix repeat-initialisation bug in Context-Menu Refresh.
      • Fix Settings Dialog text field validation, some errors were invisibly ignored.
      • Fix Settings Dialog Settings Enable VCP Codes, they had stopped working.
      • Fix the monitor specific sleep multipliers, they were not always being used.
      • Treat all monitor detection situations as needing time to stabilise (helps in disconnect situations).
      • Fix event handling so that tablet+pen input works on the main window.
      • Default to a sleep-multiplier of 1.0 to support a wider range of monitors out of the box.
    • V1.9.0 drops support for converting from v1.6.* config and preset files. To convert from v1.6.* and earlier versions, follow these steps to download and run v1.8.3:
       % wget https://github.com/digitaltrails/vdu_controls/blob/v1.8.3/vdu_controls.py
       % python3 vdu_controls.py
      
      Alternatively, start fresh by moving or removing the old configs from $HOME/.config/vdu_controls.
  • 1.8.3

    • Fix for a crash when the network is down and the weather site cannot be contacted.
  • 1.8.2

    • Solar elevation weather requirements.
    • Locale language support and sample AI generated translations.
  • 1.8.0

    • Presets can be scheduled to activate according to solar elevation at a given latitude and longitude.
  • 1.7.2

    • Better handle monitors being powered off: on set-value errors, check what's connected.
    • The display ordering of presets can now be manually altered in the Presets dialog.
    • Do not exit if no controllable monitor is found.
  • 1.7.1

    • Refactoring in 1.7 broke the signal handling - incorporate fix from Mark Lowne.
  • 1.7.0

    • Presets can now optionally have icons which display in the menu and overlay the tray icon.
    • The Preset-management dialog now includes an icon selection button.
  • 1.6.11

    • Display current preset in window and tray title and detect if a preset is in use at startup.
  • 1.6.10, 1.6.9

    • Cope better with invalid slider values caused by a monitor being too slow/busy when responding.
    • Wait for monitor detection to stabilise at session restoration (at login time).
  • 1.6.8

    • Fix preset restore/save bug introduced in 1.6.7
  • 1.6.7

    • Gnome system tray behaviour made consistent with gnome - when in gnome do as the gnomens do.
  • 1.6.5

    • Widen handling of pare exceptions for VDU capabilities - catch more exceptions.
  • 1.6.4

    • Wait for system tray to become available (for autostart Plasma Wayland).
    • Enable HiDPI icons (for the bottom toolbar) - fix blurred toolbar icons on up-scaled desktops.
  • 1.6.3

    • Added a hamburger menu as an obvious alternate path to the context menu.
    • Minor cosmetic UI changes.
  • 1.6.2

    • Added a Feature Values: min..max override to optionally restrict brightness and other sliders.
  • 1.6.1

    • Alterations for Wayland compatibility (cosmetic)
  • 1.6.0

    • Let other processes trigger vdu_controls preset changes and settings refreshes via UNIX/Linux signals.
  • 1.5.2

    • vdu-controls is now feature complete in respect to my own requirements.
    • Raise popup dialogs to the top (in case Qt renders them behind existing windows).
    • Documentation tweaks.
  • 1.5.1

    • New grey-scale reference chart for assistance with brightness and contrast adjustment.
    • About/help/settings/presets dialogs are now singletons, only one of each can be visible.
  • 1.5.0

    • New presets feature: easily switch between named presets such as Night, Day, Overcast, Sunny, Photography, and Video.
    • Presets context-menu item for access to the new preset management widget.
    • Context menu shortcuts for quickly accessing presets.
    • INI preset file format for ease of editing.
  • 1.4.2

    • Fix increasing indentation of multiline capabilities text on each config file save.
    • Prune the VDU settings-editor control-list to only show controls supported by the VDU.
    • Use grid layout in the settings editor.
  • 1.4.1

    • Internal code cleanups after switching to INI config files (no functional changes).
    • Updated the help.
  • 1.4.0

    • Added global and VDU-specific INI style configuration files in $HOME/.conf/vdu_controls/.
    • Added a GUI settings-editor as a settings menu-item in the context-menu.
  • 1.3.1

    • A minor enhancement to ease installation on Ubuntu, create $HOME/bin if it doesn't exist.
  • 1.3.0

    • Add a CUSTOM::Sleep_Multiplier VDU config-file option to allow VDU specific sleep multipliers. This can be used to prevent the slowest VDU from dragging down response time for all connected VDUs.
    • Added a main UI right-mouse action that makes the context menu available in the UI window.
    • Added a help option to context menu, it displays a formatted version of the --detailed-help text.
    • Added a --detailed-help command line option to extract the help from the script (in Markdown format).
  • 1.2.2

    • Generalise and simplify the error handling changes initiated in v1.2.1.
  • 1.2.1

    • Catch ddcutil error exit and offer to try a slower --sleep-multiplier
  • 1.2

    • Better handle out of range values.
    • Enable audio-mute,audio-treble,audio-bass,audio-mic-volume.
    • Allow ddcutil to be anywhere on the user's PATH.
    • Improve parsing to ignore laptop non-MCCS displays when present with external monitors.
    • Improve the documentation.
    • Add an --about command line option and an "about" tray option.
  • 1.0

    • Initial Release

License

This project is licensed under the GNU General Public License Version 3 - see the LICENSE.md file for details

vdu_controls Copyright (C) 2021 Michael Hamilton

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 3.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.

vdu_controls's People

Contributors

apsun avatar crashmatt avatar denilsonsa avatar digitaltrails avatar extent421 avatar lowne avatar usr3 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

vdu_controls's Issues

Dependency issues for Fedora

Updating vdu controls on fedora is now impossible due to two missing dependencies: noto-sans-math-fonts and noto-sans-symbols2-fonts . As far as I can tell, these packages are provided by the google-noto-sans-math-fonts package on fedora.

Unknown combo box values cause failure to show or app to close

My monitor changes color preset to an undefined value when display mode is changed. This either prevents the color preset from being shown or stops the monitor from being shown.

Simple fix is to add an "unknown:val" to the combo box instead of throwing an error. This allows the user to continue and fix it later if required.

By skipping the ValueError it fails to notify the user of the potential fix. Some more work required.

image

Fails on first run due to missing config file

Checks for existing monitor config here:

if os.path.isfile(config_path) and os.access(config_path, os.R_OK):

When running first time it doesn't find a config so it doesn't set self,config:

self.config = config

Then this line throws an error

self.config.restrict_to_actual_capabilities(self.capabilities)

which reports

Error: AttributeError: 'NoneType' object has no attribute 'restrict_to_actual_capabilities'
Is --sleep-multiplier set too low?

Probably need to move line 943 below line 948 and make it conditional on the test for self.config is None

Can't debug further since I now get the No controllable monitors found error

Main window cannot be interacted with a pen input

I have a Wacom tablet. If I try to use it to interact with the main window, absolutely nothing happens. I'm forced to either use a mouse or press ↹ Tab for keyboard navigation.

However, the settings dialog works perfectly fine with the stylus pen. I've tried a couple other tools using PyQt5 (qtqr and ckb-next), and both also work fine. So, there is something special about the vdu_controls main window. Something might be filtering the events or something.

I have not tested with touch input, because none of my displays support it. (Well, I can try testing touch input on Steam Deck, but I'm not sure if I have all the dependencies to run vdu_controls on that system; so don't count on it.)

If you have some additional debugging code that you want me try, just tell me. :)


In summary:

Input method Main window Settings window
Keyboard
Mouse
Stylus pen ✗ ☹
Touch-screen untested untested

Create laptop backlight control by wrapping ddcutil

Support some laptop backlight adjustment by wrapping ddcutil with a wrapper that accepts DDC/CI commands on behalf of the laptop and translates them into whatever really needs to be done. It must implement:

  • The DDC detect should return values for the laptop display (as well as any other displays).
  • Get and set vcp 10 brightness (and perhaps contrast).
  • Possibly the capabilities command, but that's not strictly necessary (vdu_controls already has an option to just hard wire the capabilities to brightness and contrast).

That all appears pretty easy, except I don't own a laptop. If anyone with a laptop would like to explore this, I'd be happy to try and create ddcutil wrapper script according for them to experiment with.

Suggestion: Color preset widget (VCP code 14)

Some displays may have a color preset (such as mine). It can be worth having it as a drop-down widget.

Feature: 14 (Select color preset)
   Values:
      01: sRGB
      05: 6500 K
      06: 7500 K
      08: 9300 K
      0b: User 1

full capabilities
Model: Q27P1
MCCS version: 2.1
Commands:
   Op Code: 01 (VCP Request)
   Op Code: 02 (VCP Response)
   Op Code: 03 (VCP Set)
   Op Code: 07 (Timing Request)
   Op Code: 0C (Save Settings)
   Op Code: F3 (Capabilities Request)
VCP Features:
   Feature: 02 (New control value)
   Feature: 04 (Restore factory defaults)
   Feature: 05 (Restore factory brightness/contrast defaults)
   Feature: 08 (Restore color defaults)
   Feature: 10 (Brightness)
   Feature: 12 (Contrast)
   Feature: 14 (Select color preset)
      Values:
         01: sRGB
         05: 6500 K
         06: 7500 K
         08: 9300 K
         0b: User 1
   Feature: 16 (Video gain: Red)
   Feature: 18 (Video gain: Green)
   Feature: 1A (Video gain: Blue)
   Feature: 60 (Input Source)
      Values:
         01: VGA-1
         03: DVI-1
   Feature: 62 (Audio speaker volume)
   Feature: 6C (Video black level: Red)
   Feature: 6E (Video black level: Green)
   Feature: 70 (Video black level: Blue)
   Feature: C8 (Display controller type)
   Feature: C9 (Display firmware level)
   Feature: B0 (Settings)
   Feature: B6 (Display technology type)
   Feature: D6 (Power mode)
   Feature: DF (VCP Version)
   Feature: F8 (Manufacturer specific feature)

VCP ValueError

INFO: checking for config file '/x/.config/vdu_controls/U32R59x_H1AK500000.conf'
INFO: checking for config file '/x/.config/vdu_controls/U32R59x.conf'
ERROR:
Traceback (most recent call last):
File "/usr/local/bin/vdu_controls", line 1181, in
main()
File "/usr/local/bin/vdu_controls", line 998, in main
main_window = DdcMainWidget(enabled_vcp_codes, args.warnings, args.debug, args.sleep_multiplier, detect_vdu_hook)
File "/usr/local/bin/vdu_controls", line 748, in init
vdu_widget = DdcVduWidget(vdu, enabled_vcp_codes, warnings)
File "/usr/local/bin/vdu_controls", line 699, in init
control = DdcComboBox(vdu, capability)
File "/usr/local/bin/vdu_controls", line 654, in init
raise ValueError('VCP_CODE {} value {} is not in allowed list: {}'.format(
ValueError: VCP_CODE 60 value 06 is not in allowed list: ['12', '0f']

ddcutil detect
Invalid display
I2C bus: /dev/i2c-4
EDID synopsis:
Mfg id: LGD
Model:
Serial number:
Manufacture year: 2018
EDID version: 1.4
DDC communication failed
This is an eDP laptop display. Laptop displays do not support DDC/CI.

Display 1
I2C bus: /dev/i2c-10
EDID synopsis:
Mfg id: SAM
Model: U32R59x
Serial number: H1AK500000
Manufacture year: 2018
EDID version: 1.3
VCP version: 2.0

Can't install on Ubuntu/Pop_OS?

Hi,

This is what I'm getting when trying to install:

lucasr@pop-os:~/src/vdu_controls$ sudo python3 vdu_controls.py --install
[sudo] password for lucasr:
ERROR: No desktop directory is present:/root/.local/share/applications Cannot proceed - is this a non-standard desktop?

The command ddcutil only works when run as sudo. The same applies for vdu_controls.py

I would like to install the script to my user. What is the equivalent in this distro?

Thank you!

[Feature Request] Add option to open main interface from tray icon

As it stands, the application loads to tray by default without using the --system-tray option. I used to be able to double-click the tray icon to open it, now nothing happens after updating to GNOME 42.

Another issue: Choosing About or Help then closing those dialogs exits the application completely.

Refactor for increased maintainability

Vdu_controls started as a script, but is now too large to be considered a script. It could benefit from refactoring into sub-components. That said, a modern IDE that shows structure can be used to successfully navigate the source, so it's less of an issue than one might think.

At this point it's functionally relatively complete (within the limits of what's possible) and relatively stable. The main incentive for refactoring is to improve the developers perspective. But I don't think there is a major developer held back by its current state :-)

Now the general requirements are known, a totally new effort with a more appropriate underlying structure would be desirable. The original code was not intended to support multiple independent threads, such as a GUI, a scheduler, and a light-meter, all making changes to the same hardware controls.

The original unit of abstraction was heavily oriented around sets of VDU slider-controls and dropdown-controls. Now that there are multiple independent threads in action, it would be better if VDU hardware, current values, and available commands was abstracted into a separately threaded hardware layer. A GUI thread, scheduling threads, and light-metering could then be provided better coordinated access to the same underlying hardware.

The other avenue to explore is whether a QML based UI could support a similar dynamically configured interface with a significant reduction in the amount of code required.

I feel cross desktop support (system tray, etc) is of major importance, that may place some restrictions on what technologies can be employed.

All of the above is something to consider because the code base has become a limitation for any future major enhancements (but I'm not anticipating anything at this time).

Smooth value transitions

As suggested by @Jakeler in issue #28 switching between presets should use a smooth transitions, applying small steps to reach to target set in the profile. This might possibly be optional.

QObject: Cannot create children for a parent that is in a different thread.

How to reproduce:

  1. Start vdu_controls, and hope ddcutil works.
  2. The main window shows up, everything fine so far.
  3. Press refresh. Or do anything that will trigger an automatic refresh.
  4. Hope that ddcutil breaks this time.

What happens:

ddcutil fails, returning non-zero. That causes vdu_controls to start some error-handling code, which shows some error message dialog, but also prints a lot of error output in the console:

Display not found
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ad40), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ad40), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)
QObject::installEventFilter(): Cannot filter events for objects in a different thread.
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ad40), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ad40), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ad40), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ad40), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ebd0), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)
QObject: Cannot create children for a parent that is in a different thread.
(Parent is Breeze::WidgetStateEngine(0x56030c37ebd0), parent's thread is QThread(0x56030bf6edf0), current thread is RefreshVduDataTask(0x56030c6890a0)

The first line is the output of ddcutil, failing. The rest is the Qt error message, while this dialog is open:

Error dialog

After clicking OK, this gets printed and the program closes:

zsh: segmentation fault (core dumped)  ./vdu_controls.py

How to reproduce yourself: edit ddcutil_simulator.py to add a random chance it will print "Display not found" while returning 1 as the exit code. Having the simulator randomly barf is a good way to simulate the real world scenario.

Automatic preset activation should be subject to weather.

Presets scheduled by solar elevation should optionally be subject to weather constraints. For example, a preset called Sunny might only activate if the weather WWO codes (World Weather Online) matches a list of codes found in a weather definition file called Good.weather. The file Good.weather might contain something like:

113, Sunny
116, Partly Cloudy
119, Cloudy

The UI will look as follows:

Screenshot_20221114_215235

By default vdu_controls will create a good.weather and bad.weather file. But users can create their own.

I've looked at the possibility of using cloud cover as a metric, but it's not that useful, as 100% cloud cover might still be quite bright.

I'm not 100% sure this will be a useful feature, I'll code it and use it for a while, and see whether it's worth keeping.

Issues with debug or syslog enabled

With no config files, v1.6.9 starts up fine. However, after enabling debug and/or syslog, it complains sleep-multiplier might be set too low. It's set to the default 0.5.

If debug-enabled is yes:

INFO checking for config file '/home/yochanan/.config/vdu_controls/vdu_controls.conf'
INFO using config file '/home/yochanan/.config/vdu_controls/vdu_controls.conf'
INFO application style is adwaita-dark
INFO using system tray.
ERROR 
Traceback (most recent call last):
  File "/usr/bin/vdu_controls", line 2870, in <module>
    main()
  File "/usr/bin/vdu_controls", line 2708, in main
    main_window = MainWindow(main_config, app, session_startup=is_logging_in())
  File "/usr/bin/vdu_controls", line 2541, in __init__
    self.main_control_panel = VduControlsMainPanel(main_config, detect_vdu_hook, app_context_menu, session_startup)
  File "/usr/bin/vdu_controls", line 1832, in __init__
    self.detected_vdus = self.ddcutil.detect_monitors()
  File "/usr/bin/vdu_controls", line 629, in detect_monitors
    result = self.__run__('detect', '--terse')
  File "/usr/bin/vdu_controls", line 617, in __run__
    log_debug("subprocess run    - ", DDCUTIL, args)
TypeError: log_debug() takes 1 positional argument but 3 were given

if debug-enabled and syslog-enabled are both yes:

INFO checking for config file '/home/yochanan/.config/vdu_controls/vdu_controls.conf'
INFO using config file '/home/yochanan/.config/vdu_controls/vdu_controls.conf'
INFO application style is adwaita-dark
INFO using system tray.
ERROR 
Traceback (most recent call last):
  File "/usr/bin/vdu_controls", line 2870, in <module>
    main()
  File "/usr/bin/vdu_controls", line 2708, in main
    main_window = MainWindow(main_config, app, session_startup=is_logging_in())
  File "/usr/bin/vdu_controls", line 2541, in __init__
    self.main_control_panel = VduControlsMainPanel(main_config, detect_vdu_hook, app_context_menu, session_startup)
  File "/usr/bin/vdu_controls", line 1832, in __init__
    self.detected_vdus = self.ddcutil.detect_monitors()
  File "/usr/bin/vdu_controls", line 629, in detect_monitors
    result = self.__run__('detect', '--terse')
  File "/usr/bin/vdu_controls", line 617, in __run__
    log_debug("subprocess run    - ", DDCUTIL, args)
TypeError: log_debug() takes 1 positional argument but 3 were given

Error in sys.excepthook:
Traceback (most recent call last):
  File "/usr/bin/vdu_controls", line 2267, in exception_handler
    log_error("\n" + ''.join(traceback.format_exception(e_type, e_value, e_traceback)))
  File "/usr/bin/vdu_controls", line 567, in log_error
    syslog.syslog(syslog.LOG_ERROR, str) if log_to_syslog else None
AttributeError: module 'syslog' has no attribute 'LOG_ERROR'. Did you mean: 'LOG_PERROR'?

Original exception was:
Traceback (most recent call last):
  File "/usr/bin/vdu_controls", line 2870, in <module>
    main()
  File "/usr/bin/vdu_controls", line 2708, in main
    main_window = MainWindow(main_config, app, session_startup=is_logging_in())
  File "/usr/bin/vdu_controls", line 2541, in __init__
    self.main_control_panel = VduControlsMainPanel(main_config, detect_vdu_hook, app_context_menu, session_startup)
  File "/usr/bin/vdu_controls", line 1832, in __init__
    self.detected_vdus = self.ddcutil.detect_monitors()
  File "/usr/bin/vdu_controls", line 629, in detect_monitors
    result = self.__run__('detect', '--terse')
  File "/usr/bin/vdu_controls", line 617, in __run__
    log_debug("subprocess run    - ", DDCUTIL, args)
TypeError: log_debug() takes 1 positional argument but 3 were given

Unable to get capabilities for monitor

I just added an MSI G27C4 monitor to the mix, it seems VDU Controls doesn't like it?

The error dialog shows the last line in the output below as well as:

Is --sleep-multiplier set too low?

I removed ~/.config/vdu_controls/* to no avail.

vdu-controls 1.5.7-1 (AUR package)
ddcutil 1.2.2-1
i2c-tools 4.3-3

❯ vdu_controls
INFO: checking for config file '/home/yochanan/.config/vdu_controls/vdu_controls.conf'
INFO: using config file '/home/yochanan/.config/vdu_controls/vdu_controls.conf'
INFO: application style is adwaita-dark
INFO: checking Display 1
   I2C bus:  /dev/i2c-2
   Monitor:             MSI:MSI G27C4:
INFO: checking Display 2
   I2C bus:  /dev/i2c-3
   Monitor:             HPN:HP X24ih:1CR1261L9W
WARNING: ignoring Invalid display
   I2C bus:  /dev/i2c-4
   Monitor:             NCP::
INFO: checking Display 3
   I2C bus:  /dev/i2c-5
   Monitor:             HPN:HP X24ih:1CR1060B95
INFO: checking for config file '/home/yochanan/.config/vdu_controls/MSI_G27C4_Display1.conf'
INFO: checking for config file '/home/yochanan/.config/vdu_controls/MSI_G27C4.conf'
Unable to get capabilities for monitor on Display_Handle[i2c: fd=3, busno=2 @0x55bb8667e590].  Maximum DDC retries exceeded.
ERROR:
 Traceback (most recent call last):
  File "/usr/bin/vdu_controls", line 2414, in <module>
    main()
  File "/usr/bin/vdu_controls", line 2252, in main
    main_window = MainWindow(main_config, app)
  File "/usr/bin/vdu_controls", line 2160, in __init__
    self.main_control_panel = VduControlsMainPanel(main_config, detect_vdu_hook, app_context_menu)
  File "/usr/bin/vdu_controls", line 1616, in __init__
    controller = VduController(vdu_id, vdu_model_name, vdu_serial, manufacturer, default_config, self.ddcutil)
  File "/usr/bin/vdu_controls", line 973, in __init__
    self.capabilities_text = ddcutil.query_capabilities(vdu_id)
  File "/usr/bin/vdu_controls", line 525, in query_capabilities
    result = self.__run__('--display', vdu_id, 'capabilities')
  File "/usr/bin/vdu_controls", line 495, in __run__
    result = subprocess.run(
  File "/usr/lib/python3.10/subprocess.py", line 524, in run
    raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command '['ddcutil', '--sleep-multiplier', '0.5', '--display', '1', 'capabilities']' returned non-zero exit status 1.

No reliable display ID

When issuing ddcutil commands, vdu_controls addresses each monitor by it's DDC display number (which is 1..M). If the current display-1 is turned off, the current display-2 (if any) is reassigned to be display-1. There is no event generated when this happens, vdu_controls remains unaware of the switch and it's controls for will now be altering display-2. When faced with this issue the user can press the refresh-button which will sort things out.

I have considered using other ID's, such as the EDID, but not even the EDID can be guaranteed to be unique (see https://www.ddcutil.com/release_notes/#multiple-monitors-having-the-same-edid).

So pending some fast (non-polling) what to detect monitors being powered on/off I'm not sure this issue can be addressed.

Idea: alternative widget using multiple buttons instead of a drop-down

I got this idea from qddcswitch, please take a look at the screenshots over there.

The idea is to have an alternative implementation of non-continuous values. Instead of a drop-down selection box (that requires two clicks, and some precision), we could have multiple buttons side-by-side (requiring just one click). So, instead of this:

┌──────────────────┐   ┌──────────────────┐
│ VGA-1          ▼ │ → │ VGA-1          ▼ │
└──────────────────┘   └┬────────────────┬┘
                        │VGA-1           │
                        │DVI-1           │
                        │HDMI-1          │
                        └────────────────┘

We could have this:

┌────────┬────────┬────────┐
│ VGA-1  │ DVI-1  │ HDMI-1 │
└────────┴────────┴────────┘

This of course doesn't make sense if the amount of options is too high.

Undefined value 05 for Input Source

When enabling the "input source" control widget, vdu_controls is complaining about my AOC displays:

Error message screenshot

Display 1 Q27P1B:GNXJ7HA015309 feature 60 '(Input Source)' has an undefined value '05'. Valid values are ['01', '03', '05'].

If you want to extend the set of permitted values, you can edit the metadata for Q27P1B:GNXJ7HA015309 in the settings panel. For more details see the man page concerning VDU/VDU-model config files.

Then the "Input Source" drop-down shows UNKNOWN-05 as one of the options.

Screenshot of the drop-down options

These monitors have four input ports: D-SUB (VGA), DVI, HDMI, DP

Using vdu_controls version 1.8.3 on Manjaro Linux. Both monitors are connected through DisplayPort.


What's the bug, then?

  1. It's weird it claims 05 is invalid while still listing 05 as one of the valid values.
  2. It should display 4 inputs instead of only 3. But I'm not sure if you can do anything about it.

Do you need any debugging output from ddcutil?

Changes to the sleep modifier aren't detected as changed

How to reproduce:

  1. vdu_controls version 1.8.3 on Manjaro Linux.
  2. Open the settings dialog.
  3. You can reproduce this either on the main vdu_controls tab, or in each of the displays tabs.
  4. Edit the value of sleep modifier. Let's say, from 0.5 to 0.25.
  5. Click Save.

What happens:

Screenshot of the error message

Application fails to restore on login if running at logout/shutdown.

The application needs to call QApplication(sys.argv) to apply and remove the Qt/X11 session restoration arguments before it attempts to do any of its own argument parsing.

# Restore Qt state (if any), arguments passed will include -session ID and -name app_name (?)
app = QApplication(sys.argv)
...
# Remaining args can now be processed by the VDU_control argument parser.
args = default_config.parse_args()

Will also refactor main/main-window area to potentially support Qt state and geometry restoration.

Do not exit if no controllable monitor is found

I configured VDU Controls to autostart (being hidden in the systray) because from time to time I plug my laptop to an external monitor. Then all I need to do when I need it is to access VDU Controls in the systray.

However, VDU Controls does not allow to start when no monitors are plugged, so autostart won't work unless I start my session with the external monitor, which is not always the case:

image

Would it be possible to allow VDU Controls to remain open even if not monitor is present at startup? Thanks!

Min and max brightness vals for quirky monitors (custom mapping)

Is it possible to only allow a set range of values for quirky monitors.

For whatever reason my monitor has 59 as min brightness, 84 as max brightness. 58 and 85 put the monitor into a state where it cannot accept any input, the OSD is disabled, and can only be rescued by sending a valid brightness value.

So ideally I would like the values sent to only go from 59-84. And even better if this could be mapped to show 0-100 in the GUI slider.

I also know of other monitors with different value ranges, so this should be helpful for other users.

It would be good to suspend activity if the session is locked or in screensaver mode.

It would be good to suspend activity if the session is locked or in screensaver mode. Currently vdu_controls periodically re-tries talking to the screen.

The screen saver status can be queried via DBUS. The command line query is:

% dbus-send --session --dest=org.freedesktop.ScreenSaver --type=method_call --print-reply /org/freedesktop/ScreenSaver org.freedesktop.ScreenSaver.GetActive

It would seem likely this would work on KDE/Gnome and X11/Wayland, but that needs to be verified.

In python we might use a dbus monitoring option (which would require another dependency).

Something to think about.

Side note: this thought was prompted by trying to find what was bringing my monitors out of suspension. The cause was pipewire. A script played a sound when mail arrives - it seems like pipewire is the cause, it didn't happen prior to pipewire.

vdu_controls crashes if ddcutil not found

If vdu_controls does not detect ddcutil, it can crash in various ways. You probably want to put up a message that ddcutil must be in the users path and exit immediately after the message is read.

configparser crashes on ddcutil capabilities output

I did install vducontrols on Tumbleweed and see it is crashing parsing the ddcutil capabilities output for my monitor, see below for the details.

I had a look at the ddcutil capabilities output and thought the problem was this piece of the output

   Feature: 70 (Video black level: Blue)
   Feature: 72 (Gamma)
      Specific presets of absolute adjustment supported (0xfb)
      Absolute tolerance: +/- 5% (=0x05)
      Native gamma: 2.20 (0x78)
      Specific presets:  1.80 (0x50), 2.00 (0x64), 2.20 (0x78), 2.40 (0x8c), 2.60 (0xa0)
   Feature: 86 (Display Scaling)

The third line does not have a ':' in it, so I tried with that line removed:

!self.capabilities_text = re.sub('\n[^:\n]+\n', self.capabilities_text)

but that did not resolve the problem, the error changed only into "....at position 1541" and it is not immediately clear to me why.

I know I can create a config file myself and will likely do that but it looks to me the parser could use a bit more robustness.

Error running with changes:

> /usr/bin/vdu_controls
INFO: checking for config file '~/.config/vdu_controls/vdu_controls.conf'
INFO: application style is breeze
INFO: checking Display 1
   I2C bus:             /dev/i2c-4
   Monitor:             PHL:Philips 272C4:AU41322000155
INFO: checking for config file '~/.config/vdu_controls/Philips_272C4_AU41322000155.conf'
INFO: checking for config file '~/.config/vdu_controls/Philips_272C4.conf'
ERROR:
 Traceback (most recent call last):
  File "/usr/bin/vdu_controls", line 2413, in <module>
    main()
  File "/usr/bin/vdu_controls", line 2251, in main
    main_window = MainWindow(main_config, app)
  File "/usr/bin/vdu_controls", line 2159, in __init__
    self.main_control_panel = VduControlsMainPanel(main_config, detect_vdu_hook, app_context_menu)
  File "/usr/bin/vdu_controls", line 1616, in __init__
    controller = VduController(vdu_id, vdu_model_name, vdu_serial, manufacturer, default_config, self.ddcutil)
  File "/usr/bin/vdu_controls", line 979, in __init__
    self.config.set_capabilities_alt_text(self.capabilities_text)
  File "/usr/bin/vdu_controls", line 774, in set_capabilities_alt_text
    self.ini_content['ddcutil-capabilities']['capabilities-override'] = alt_text
  File "/usr/lib64/python3.8/configparser.py", line 1259, in __setitem__
    return self._parser.set(self._name, key, value)
  File "/usr/lib64/python3.8/configparser.py", line 1201, in set
    super().set(section, option, value)
  File "/usr/lib64/python3.8/configparser.py", line 894, in set
    value = self._interpolation.before_set(self, section, option,
  File "/usr/lib64/python3.8/configparser.py", line 402, in before_set
    raise ValueError("invalid interpolation syntax in %r at "
ValueError: invalid interpolation syntax in 'Model: 272C4QPJK\nMCCS version: 2.2\nCommands:\n   Command: 01 (VCP Request)\n   Command: 02 (VCP Response)\n   Command: 03 (VCP Set)\n   Command: 07 (Timing Request)\n   Command: 0c (Save Settings)\n   Command: e3 (Capabilities Reply)\n   Command: f3 (Capabilities Request)\nVCP Features:\n   Feature: 02 (New control value)\n   Feature: 04 (Restore factory defaults)\n   Feature: 05 (Restore factory brightness/contrast defaults)\n   Feature: 08 (Restore color defaults)\n   Feature: 0B (Color temperature increment)\n   Feature: 0C (Color temperature request)\n   Feature: 10 (Brightness)\n   Feature: 12 (Contrast)\n   Feature: 14 (Select color preset)\n      Values:\n         01: sRGB\n         04: 5000 K\n         05: 6500 K\n         06: 7500 K\n         07: 8200 K\n         08: 9300 K\n         0a: 11500 K\n         0b: User 1\n   Feature: 16 (Video gain: Red)\n   Feature: 18 (Video gain: Green)\n   Feature: 1A (Video gain: Blue)\n   Feature: 52 (Active control)\n   Feature: 54 (Performance Preservation)\n      Values: 00 01 (interpretation unavailable)\n   Feature: 60 (Input Source)\n      Values:\n         00: Unrecognized value\n         03: DVI-1\n         11: HDMI-1\n         12: HDMI-2\n         0f: DisplayPort-1\n         21: Unrecognized value\n         22: Unrecognized value\n         23: Unrecognized value\n         2f: Unrecognized value\n   Feature: 62 (Audio speaker volume)\n   Feature: 6C (Video black level: Red)\n   Feature: 6E (Video black level: Green)\n   Feature: 70 (Video black level: Blue)\n   Feature: 72 (Gamma)\n      Specific presets of absolute adjustment supported (0xfb)\n      Absolute tolerance: +/- 5% (=0x05)\n      Native gamma: 2.20 (0x78)\n      Specific presets:  1.80 (0x50), 2.00 (0x64), 2.20 (0x78), 2.40 (0x8c), 2.60 (0xa0)\n   Feature: 86 (Display Scaling)\n      Values:\n         01: No scaling\n         02: Max image, no aspect ration distortion\n         08: Linear expansion (compression) on h and v axes\n   Feature: 8D (Audio mute/Screen blank)\n      Values: 01 02 (interpretation unavailable)\n   Feature: 95 (Window Position(TL_X))\n   Feature: 96 (Window Position(TL_Y))\n   Feature: 97 (Window Position(BR_X))\n   Feature: 98 (Window Position(BR_Y))\n   Feature: A4 (Window mask control)\n   Feature: A5 (Change the selected window)\n   Feature: AC (Horizontal frequency)\n   Feature: AE (Vertical frequency)\n   Feature: B6 (Display technology type)\n   Feature: C0 (Display usage time)\n   Feature: C6 (Application enable key)\n   Feature: C8 (Display controller type)\n   Feature: C9 (Display firmware level)\n   Feature: CA (OSD/Button Control)\n      Values:\n         01: OSD disabled, button events enabled\n         02: OSD enabled, button events enabled\n   Feature: CC (OSD Language)\n      Values:\n         02: English\n         03: French\n         04: German\n         05: Italian\n         08: Portuguese (Portugal)\n         09: Russian\n         0a: Spanish\n         0c: Turkish\n         0d: Chinese (simplified / Kantai)\n   Feature: D6 (Power mode)\n      Values:\n         01: DPM: On,  DPMS: Off\n         04: DPM: Off, DPMS: Off\n         05: Write only value to turn off display\n   Feature: DC (Display Mode)\n      Values:\n         00: Standard/Default mode\n         01: Productivity\n         02: Mixed\n         03: Movie\n         04: User defined\n         05: Games\n         08: Standard/Default mode with intermediate power consumption\n   Feature: DF (VCP Version)\n   Feature: E4 (manufacturer specific feature)\n      Values: 00 01 (interpretation unavailable)\n   Feature: E5 (manufacturer specific feature)\n      Values: 00 01 (interpretation unavailable)\n   Feature: E8 (manufacturer specific feature)\n      Values: 00 01 (interpretation unavailable)\n   Feature: E9 (manufacturer specific feature)\n      Values: 00 02 (interpretation unavailable)\n   Feature: EA (manufacturer specific feature)\n   Feature: EB (manufacturer specific feature)\n      Values: 00 01 02 03 (interpretation unavailable)\n   Feature: EC (manufacturer specific feature)\n      Values: 00 01 02 03 04 (interpretation unavailable)\n   Feature: F0 (manufacturer specific feature)\n      Values: 00 01 (interpretation unavailable)\n   Feature: F6 (manufacturer specific feature)\n      Values: 01 02 (interpretation unavailable)\n   Feature: F7 (manufacturer specific feature)\n      Values: 00 01 (interpretation unavailable)\n   Feature: F9 (manufacturer specific feature)\n      Values: 00 01 02 03 04 (interpretation unavailable)\n   Feature: FA (manufacturer specific feature)\n      Values: 00 01 02 (interpretation unavailable)\n   Feature: FB (manufacturer specific feature)\n   Feature: FC (manufacturer specific feature)\n   Feature: FD (manufacturer specific feature)\n   Feature: FE (manufacturer specific feature)\n      Values: 00 01 02 04 (interpretation unavailable)\n   Feature: FF (manufacturer specific feature)\n' at position 1604

Reduce message logging by tracking errors against individual VDU's

Reduce the number of logged messages by attributing errors to individual VDU's. At the moment we can get into a situation where one VDU is working and another is not, which leads to a sequence such as:

LuxAutoWorker: Brightness error on XYZ, will sleep and try again.
LuxAutoWorker: DDC command succeeded after 1 consecutive errors.
LuxAutoWorker: Brightness error on XYZ, will sleep and try again.
LuxAutoWorker: DDC command succeeded after 1 consecutive errors.
...

It would be good if this use-case behaved more like the situation where all ddcutil commands were failing and only report back when progress has been made:

LuxAutoWorker: multiple errors count=2, sleeping and retrying.
LuxAutoWorker: DDC command succeeded after 15 consecutive errors.

At the same time some consideration should be given to what errors should be counted, such as getvcp/getvcp, and what info should be logged, such as what DDC command succeeded.

Whatever is done, simplicity should be preferred, this is not a big deal.

Fail to set color preset above 9 - Hex format problem?

When setting the colour preset to 0x0b it fails. I suspect it is using the text value. ddcutil needs the value in explicit hex "0xXX". I get this error when setting values above 9.

Screenshot from 2021-11-09 09-38-42

MCCS version: 2.1
Commands:
Command: 01 (VCP Request)
Command: 02 (VCP Response)
Command: 03 (VCP Set)
Command: 07 (Timing Request)
Command: 0c (Save Settings)
Command: e3 (Capabilities Reply)
Command: f3 (Capabilities Request)
VCP Features:
Feature: 02 (New control value)
Feature: 04 (Restore factory defaults)
Feature: 05 (Restore factory brightness/contrast defaults)
Feature: 08 (Restore color defaults)
Feature: 10 (Brightness)
Feature: 12 (Contrast)
Feature: 14 (Select color preset)
Values:
04: 5000 K
05: 6500 K
06: 7500 K
08: 9300 K
09: 10000 K
0b: User 1
0c: User 2

GY30/BH1750 + Arduino Lux metering potential options

A simple light meter can be build using an Arduino and a GY30/BH1750 sensor. [Removed reference to dead link]

This raises some possibilities for vdu_controls to initiate transitions depending on metered light levels.

Today I built a meter using an Arduino Nano - image of wiring:
20230304_171125b

A simple Sketch using Christopher Laws' BH1750 library can be uploaded to the Arduino to retrieve a feed of Lux values:

#include <BH1750.h>
#include <Wire.h>

BH1750 lightMeter;

void setup() {
…  // Serial.println(F("BH1750 Lux values stream..."));
}

void loop() {
  float lux = lightMeter.readLightLevel();
  Serial.println(lux);
  delay(1000);
}

The feed of Lux values can be read from the USB tty on a Linux host. This feed can be used to trigger presets by issuing Linux signals (an existing capability of vdu_controls):

import os
import time

import serial
from serial import SerialException
import psutil


class Level:

    def __init__(self, min_level, max_level, signal) -> None:
        super().__init__()
        self.min = min_level
        self.max = max_level
        self.signal = signal


# (Min light level, max light level, UNIX signal number for Preset)
LEVELS = [Level(100, 200, 40), 
          Level(201, 300, 41),
          Level(300, 900, 42)]


def signal_vdu_controls(signal: int) -> bool:
    for proc in psutil.process_iter():
        if 'vdu_controls' in proc.name():
            pid = proc.pid
            os.kill(pid, signal)
            return True
    return False


try:
    current_level = None
    with serial.Serial('/dev/ttyUSB0') as gy30:
        while True:
            try:
                buffer = gy30.readline()
                value = float(buffer.decode('utf-8').replace("\r\n", ''))
                print(f"lux={value:6.2f}")
                for level in LEVELS:
                    if level != current_level:
                        if level.min <= value <= level.max:
                            print("signal")
                            if signal_vdu_controls(level.signal):
                                current_level = level
                            time.sleep(120)
            except ValueError as ve:
                print(ve, buffer)
except SerialException as se:
    print(se)

The above works and triggers presets according to the specified levels.

The issue is, how best to integrate this:

  • Built into vdu_controls.
  • A separate system tray utility for Lux that can be used by anything.
  • Just trigger Presets.
  • Directly drive changes in brightness/contrast (how?).
  • Does a UI need to help with a response curve (how do our eyes respond to changes in Lux).

Parking all of the above, pending time to properly investigate it.

Recover better when monitors are offline and Presets trigger

Use case: a user has setup multiple Preset elevation triggers, at some they power off or suspend their monitors (but not their PC) and go away for hours or days, or longer. The current situation is that if several of these triggers fire, they may all raise "can't talk to monitor - retry?" dialogs. On return the user will have to dismiss many similar dialogs and it's not clear which Preset will be the last to be restored (plus all the intermediate restores are unnecessary) .

Proposed behaviour: later scheduled activation triggers should override earlier ones:

  1. The most-recent activation trigger should dismiss previous retry-dialogs leaving only the latest dialog on display (call QMessageBox done()).
  2. When the user dismisses the dialog, the most-recent activation trigger should be the one that is applied.

Related to this is that a preset may restore several settings on several monitors. There needs to be a transactional wrapper around a preset activation, and the more recent transactions should cause previous ones to cease making changes and terminate. This can probably be achieved by having a transaction check if most-recent-transaction-date > my-transaction-date and terminating if it is.

This is not a locking situation. We don't want the first transaction to lock out further overlapping ones. We want the last-transaction (most recently relevant trigger) to override any past transactions that have not yet completed.

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 31: invalid start byte

I am using Arch Linux and installed via AUR. Launching vdu_controls cause this error message:

INFO: checking for config file '/home/username/.config/vdu_controls/vdu_controls.conf'
INFO: application style is fusion
INFO: checking Display 1
   I2C bus:  /dev/i2c-13
   Monitor:             GSM:IPS226       :SerialNumber
INFO: checking for config file '/home/username/.config/vdu_controls/IPS226_SerialNumber.conf'
INFO: checking for config file '/home/username/.config/vdu_controls/IPS226.conf'
ERROR:
 Traceback (most recent call last):
  File "/usr/bin/vdu_controls", line 2752, in <module>
    main()
  File "/usr/bin/vdu_controls", line 2590, in main
    main_window = MainWindow(main_config, app)
  File "/usr/bin/vdu_controls", line 2427, in __init__
    self.main_control_panel = VduControlsMainPanel(main_config, detect_vdu_hook, app_context_menu)
  File "/usr/bin/vdu_controls", line 1765, in __init__
    controller = VduController(vdu_id, vdu_model_name, vdu_serial, manufacturer, default_config,
  File "/usr/bin/vdu_controls", line 1058, in __init__
    self.capabilities_text = ddcutil.query_capabilities(vdu_id)
  File "/usr/bin/vdu_controls", line 615, in query_capabilities
    capability_text = result.stdout.decode('utf-8')
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 31: invalid start byte

I tried to debug by adding print(result.stdout) before line 615. This is what it prints out:

b"Unparsed capabilities string: O\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[U\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[{\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[\x01\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02['\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[\xcd\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[\xd3\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[\xf9\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[\x9f\xff\xff\x02\x01hX\xba\x1b\x01\xfd\x93\xb3\x83/7j`\x81\xcc\xc9\xe3\xe8C\x02[\xa5\xff\xff\x02\nErrors parsing capabilities string:\n   Nothing follows segment name at offset 238\nModel: Not specified\nMCCS version: Not specified\nVCP Features:\n"

It seems like running ddcutil --sleep-multiplier 0.5 detect --terse is working, but ddcutil --sleep-multiplier 0.5 --display 1 capabilities cause error

I was able to adjust brightness by Twinkle Tray in Windows, which is also an application that make use of DDC.

I am reporting this to ddcutil repo (rockowitz/ddcutil#259). In the meantime, is it possible to warn user about this while allowing the option to procede and try to adjust brightness anyway? Or even better, being able to parse the capabilities string?

[feature] Automatic adjustments based on sunrise/sunset

The idea is automatically switch profiles based on the natural background brightness.
Ideally with smooth transitions, so small steps to reach to target set in the profile.

Sunrise+sunset times can be calculated from the location for example with the astral module.
Location in lat:long coordinates could be either set manually or obtained via a location service that checks the IP etc.

A toggle switch for the automatic/manual selection in the tray menu would be useful.

Example from KDE:
grafik
It does not allow to change the brightness, but is otherwise very well made.
Also adjusted color temperature might be possible via ddc:

VCP code 0C: Color temperature request
   Specifies a color temperature (degrees Kelvin)
   MCCS versions: 2.0, 2.1, 3.0, 2.2
   ddcutil feature subsets: COLOR
   Attributes: Read Write, Continuous (complex)

Should produce a better result than the software filters (which reduce color depth).
Most important is the brightness I think though.

Zombie VDU's

Some monitors that have been powered down continue to report their settings. Any attempt to change a zombie's settings will cause an error. The zombie errors are similar to the errors that occur if --sleep-multiplier is set too low. Error handling needs to be revisited to encompass both of these types of errors (and probably other kinds of errors as well). Checking if a monitor is on before applying a setting is likely going to be too slow, so I probably won't take that approach.

At the moment attempting to change zombie setting will result in the --sleep-multiplier dialog popping up. That leaves the user with all paths leading to the program exiting. What should probably happen is that a dialog should popup and when the dialog is dismissed the program should carry on, but with the setting left as it was.

TypeError: must be real number, not NoneType

Hi guys, i am trying run this, python3 vdu_controls.py --no-splash --system-tray --show brightness --show contrast
but i get this error. what should i do?
i have XCFE4 and Python 3.10.10

/vdu_controls$ python3 vdu_controls.py --no-splash --system-tray --show brightness --show contrast
08:26:43 INFO: Python locale ('es_CO', 'UTF-8')
08:26:43 INFO: Looking for config file '/home/noe/.config/vdu_controls/vdu_controls.conf'
08:26:43 INFO: Logging to stdout
08:26:43 INFO: Using system tray.
08:26:43 INFO: Configuring application...
08:26:43 INFO: Use_edid=True (to disable it: export VDU_CONTROLS_USE_EDID=no)
08:26:43 INFO: ddcutil version info: ddcutil 1.2.2 [1, 2, 2]
08:26:43 INFO: Prefer dynamic sleep = False
08:26:46 INFO: Number of detected monitors is stable at 1 (loop=2)
08:26:46 INFO: Initializing controls for vdu_id='1' vdu_model_name='PA248QV' self.vdu_stable_id='PA248QV_M4LMQS006956'
08:26:46 INFO: Splash DDC ID 1
PA248QV:M4LMQS006956
08:26:46 ERROR: 
Traceback (most recent call last):
  File "/home/noe/vdu_controls/vdu_controls.py", line 7622, in <module>
    main()
  File "/home/noe/vdu_controls/vdu_controls.py", line 7451, in main
    main_window = VduAppWindow(main_config, app)
  File "/home/noe/vdu_controls/vdu_controls.py", line 6582, in __init__
    self.configure_application()
  File "/home/noe/vdu_controls/vdu_controls.py", line 6754, in configure_application
    self.create_main_control_panel()
  File "/home/noe/vdu_controls/vdu_controls.py", line 6797, in create_main_control_panel
    self.main_panel.initialise_control_panels(self.app_context_menu, self.main_config, self.vdu_controllers,
  File "/home/noe/vdu_controls/vdu_controls.py", line 3232, in initialise_control_panels
    vdu_control_panel = VduControlPanel(controller, warnings_enabled, self.display_vdu_exception)
  File "/home/noe/vdu_controls/vdu_controls.py", line 2797, in __init__
    self.refresh_data()
  File "/home/noe/vdu_controls/vdu_controls.py", line 2807, in refresh_data
    values = self.controller.get_attributes([control.vcp_capability.vcp_code for control in self.vcp_controls])
  File "/home/noe/vdu_controls/vdu_controls.py", line 1995, in get_attributes
    return self.ddcutil.get_attributes(self.vdu_id, attributes, sleep_multiplier=self.sleep_multiplier)
  File "/home/noe/vdu_controls/vdu_controls.py", line 1417, in get_attributes
    if not math.isclose(sleep_multiplier, 0.0) and not self.prefer_dynamic_sleep:
TypeError: must be real number, not NoneType

thank u very much !!

Multiple monitors with differing requirements

  • Currently there is only one --sleep-multiplier for all monitors. This means we communicate only as fast as the slowest monitor.
  • Currently --show/--hide applies to all monitors. It might be useful to the sets of controls independently for each monitor.

Addressing these issues might require some kind of config file or config UI. I'm not sure this is worth the extra effort, but if we go into another Covid-19 Delta lockdown, it might be something to consider.

How to unignore a VDU or refresh a VDU's capabilities?

Once a VDU is ignored the only way to unignore it is to manually enter it's capabilities in the Settings Dialog (or delete the VDU's config files and restart).

Perhaps there should be a way to refresh/reinitialise capabilities in the settings panel.

Internationalisation

Version 1.8.2, includes code for localised language translations. While a localisation capability now exists, I lack any properly proofed translations. Please contact me If you'd be interested in a localised version and would like to assist by proofreading a language file (I can generate a starter file by using sites such as google translate).

Here is a screenshot of vdu_controls localised by using scripts to bulk update Qt .ts files from text generated by deepl.com and google-translate.

Screenshot_20221113_da_DK

Scaling issue on HiDPI with Wayland

on my 4K display with 200% scaling vdu appears double the size it should be in wayland. it is also blurry but i guess that is a global xwayland issue.

can the scaling be fixed?

Building with PEP 517 standards fails

Running python -m build --wheel --no-isolation has failed since 1.8.2. It was working previously.

* Getting build dependencies for wheel...
error: Multiple top-level packages discovered in a flat-layout: ['translations', 'ddcutil_simulator_data'].

To avoid accidental inclusion of unwanted files or directories,
setuptools will not proceed with this build.

If you are trying to create a single distribution with multiple packages
on purpose, you should not rely on automatic discovery.
Instead, consider the following options:

1. set up custom discovery (`find` directive with `include` or `exclude`)
2. use a `src-layout`
3. explicitly set `py_modules` or `packages` with a list of names

To find more information, look for "package discovery" on setuptools docs.

ERROR Backend subprocess exited when trying to invoke get_requires_for_build_wheel

presets sorting

not sure how presets end up being sorted but it would be good to have a way to sort them manually (or alternatively according to e.g., brightness)

Coupling/Cohesion VduAppWindow and VduMainPanel

Creeping featuritis has destroyed the distribution of responsibilities between VduAppWindow and VduMainPanel. Refactor both of these in light of new task threading.

Move more of the non-GUI aspects out of VduMainPanel and into VduAppWindow.

Also try to sort out "most recent preset" issue - may require some persistence storage of the value.

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.