Tips en Trucs 2020

Monitor via software instellen

Hoewel je met de knoppen op uw monitor deze naar wens kunt instellen, kan het handig zijn dit met software uit te voeren. Ddcutil is een programma om monitor instellingen aan te passen. Je kunt er de helderheid, kleur niveau's, ingangen, enz. mee regelen.

Ddcutil gebruikt DDC/CI (Display Data Channel Command Interface) om met de monitor te communiceren via I2C, een veel gebruikt systeem voor communicatie tussen hardwareonderdelen.

Ddcutil werkt niet met laptop schermen die een eigen speciaal systeem hebben en geen I2C gebruiken. Ddcutil werkt met alle grafische kaarten op voorwaarde dat je de open source stuurprogramma's gebruikt. Met AMD stuurprogramma's, moet je een speciaal geprepareerde versie van ddcutil gebruiken. Met NVidia stuurprogramma's moet je enkele extra instellingen aanpassen (zie verder).

Praktijkvoorbeeld

Sommige monitors bevatten een lichtsensor waarmee de helderheid van de monitor aangepast wordt als het omgevingslicht veranderd. Zo zal bij zonlicht de monitor helderder worden en bij donker weer de helderheid van de monitor lager worden ingesteld. Toevallig heb ik op een Raspberry Pi een lichtsensor die via HTTP in het netwerk kan uitgelezen worden. Een uitdaging om al mijn schermen automatisch te dimmen naargelang het omgevingslicht.

Voorbereiding

Waarschuwing: weet wat je doet en zorg dat je steeds het systeem kunt herstellen (bijvoorbeeld via een back-up), m.a.w. als je deze tip tot een goed einde wilt brengen, heb je toch wat ervaring nodig.

Stel de monitor in zodat deze DDC/CI opdrachten kan verwerken.

Mijn computers bevatten allemaal NVidia grafische kaarten en stuurprogramma's (geen open source). Om ddcutil te kunnen gebruiken, moet je het stuurprogramma daarvan op de hoogte brengen. Dit kan door opties mee te geven met de kernel module voor de NVidia grafische kaart. Maar eerst maken we daar een back-up van (je weet maar nooit):

dany@main:~> sudo cp /etc/modprobe.d/50-nvidia-default.conf .

Er staat nu een kopie in uw Persoonlijke map. Voeg als systeembeheerder de optie NVreg_RegistryDwords=RMUseSwI2c=0x01;RMI2cSpeed=100 aan de options regel toe. Dit wordt dan (in mijn geval):

options nvidia NVreg_DeviceFileUID=0 NVreg_DeviceFileGID=484 NVreg_DeviceFileMode=0660 NVreg_RegistryDwords=RMUseSwI2c=0x01;RMI2cSpeed=100
install nvidia PATH=$PATH:/bin:/usr/bin; if /sbin/modprobe --ignore-install nvidia; then   if /sbin/modprobe nvidia_uvm; then     if [ ! -c /dev/nvidia-uvm ]; then       mknod -m 660 /dev/nvidia-uvm c $(cat /proc/devices | while read major device; do if [ "$device" == "nvidia-uvm" ]; then echo $major; break; fi ; done) 0;        chown :video /dev/nvidia-uvm;     fi;   fi;   if [ ! -c /dev/nvidiactl ]; then     mknod -m 660 /dev/nvidiactl c 195 255;     chown :video /dev/nvidiactl;   fi;   devid=-1;   for dev in $(ls -d /sys/bus/pci/devices/*); do      vendorid=$(cat $dev/vendor);     if [ "$vendorid" == "0x10de" ]; then       class=$(cat $dev/class);       classid=${class%%00};       if [ "$classid" == "0x0300" -o "$classid" == "0x0302" ]; then          devid=$((devid+1));         if [ ! -c /dev/nvidia${devid} ]; then            mknod -m 660 /dev/nvidia${devid} c 195 ${devid};            chown :video /dev/nvidia${devid};         fi;       fi;     fi;   done;   /sbin/modprobe nvidia_drm;   if [ ! -c /dev/nvidia-modeset ]; then     mknod -m 660 /dev/nvidia-modeset c 195 254;     chown :video /dev/nvidia-modeset;   fi; fi

Herstart de computer om de aanpassing te testen met:

dany@main:~> grep RegistryDwords /proc/driver/nvidia/params
RegistryDwords: "RMUseSwI2c=0x01;RMI2cSpeed=100"
RegistryDwordsPerDevice: ""

Op één computer gaf deze test foutieve parameters weer, daar werd het duidelijk in het logboek:

dany@pindabackup:~> cat /var/log/Xorg.0.log | grep RegistryDwords
[    12.915] (**) NVIDIA(0): Option "RegistryDwords" "RMUseSwI2c=0x01; RMI2cSpeed=100"

Aangezien ddcutil werkt met I2C, moeten we ook I2C via een kernel module activeren:

dany@pindabackup:~> echo "i2c_dev" | sudo tee /etc/modules-load.d/i2c-dev.conf
i2c_dev

Herstart de computer om de I2C kernel module te laden.

Uiteindelijk kunnen we ddcutil installeren:

dany@pindabackup:~> sudo zypper install ddcutil
Gegevens van opslagruimte laden...
Lezen van geïnstalleerde pakketten...
Pakketafhankelijkheden oplossen...

Het volgende NIEUWE pakket zal worden geïnstalleerd:
  ddcutil

1 nieuw te installeren pakket.
Totale downloadgrootte: 199,9 KiB. Reeds in de cache: 0 B. Na de bewerking zal aanvullend 537,3 KiB worden gebruikt.
Doorgaan? [j/n/v/...? alle opties tonen] (j): 
pakket ddcutil-0.8.5-lp151.2.3.x86_64 wordt opgehaald                               (1/1), 199,9 KiB (537,3 KiB uitgepakt)
Ophalen: ddcutil-0.8.5-lp151.2.3.x86_64.rpm ......................................................................[gereed]

Controleren op conflicten tussen bestanden: ......................................................................[gereed]
(1/1) Installeren van: ddcutil-0.8.5-lp151.2.3.x86_64 ............................................................[gereed]

Een volledig overzicht van DDC/CI mogelijkheden van uw hardware, kan je opvragen met sudo ddcutil interrogate. Bijvoorbeeld om het type grafische kaart te achterhalen:

dany@pindabackup:~> sudo ddcutil interrogate | grep Device
   Device class:        x030000    VGA compatible controller
   Device:              x13c0      GM204 [GeForce GTX 980]
      ModifyDeviceFiles: 1
      DeviceFileUID: 0
      DeviceFileGID: 484
      DeviceFileMode: 432
      RegistryDwordsPerDevice: ""
      Device Minor:      0
   Device /dev/i2c-0 is a SMBus or other ignorable device.  Skipping i2cdetect.
   ***One Device ***
   Device Node Path: /dev/i2c-1
   ***One Device ***
   Device Node Path: /dev/i2c-2
   ***One Device ***
   Device Node Path: /dev/i2c-3
   ***One Device ***
   Device Node Path: /dev/i2c-4
   ***One Device ***
   Device Node Path: /dev/i2c-5
   ***One Device ***
   Device Node Path: /dev/i2c-6
   ***One Device ***
   Device Node Path: /dev/i2c-7
   ***One Device ***
   Device Node Path: /dev/i2c-0
      options nvidia NVreg_DeviceFileUID=0 NVreg_DeviceFileGID=484 NVreg_DeviceFileMode=0660 NVreg_RegistryDwords=RMUseSwI2c=0x01;RMI2cSpeed=100
      Device information:
Device Identifier Cross Reference Report

Of je ddcutil kunt gebruiken, kan je testen met:

dany@pindabackup:~> ddcutil environment
The following tests probe the runtime environment using multiple overlapping methods.

*** Basic System Information ***

ddcutil version: 0.8.5

/proc/version:
   Linux version 4.12.14-lp151.28.40-default (geeko@buildhost) (gcc version 7.5.0 (SUSE Linux) ) #1 SMP Fri Mar 6 13:48:15 UTC 2020 (f0f1262)

Architecture:     x86_64
Distributor id:   sh: lsb_release: opdracht niet gevonden
Release:          sh: lsb_release: opdracht niet gevonden
Found a known architecture

/proc/cmdline:
   BOOT_IMAGE=/boot/vmlinuz-4.12.14-lp151.28.40-default root=UUID=3cb308c2-0508-4646-9e44-10efd013f7b2 splash=silent resume=/dev/disk/by-id/ata-OCZ-AGILITY3_OCZ-2SUN85O88IZYD6JY-part1 quiet mitigations=auto

*** Primary Check 1: Identify video card and driver ***

Obtaining card and driver information from /sys...
Primary video controller at PCI address 0000:01:00.0 (boot_vga flag is set)
   Device class:        x030000    VGA compatible controller
   Vendor:              x10de      NVIDIA Corporation
   Device:              x13c0      GM204 [GeForce GTX 980]
   Subvendor/Subdevice: 103c/2b49  Hewlett-Packard Company
   Driver name:         nvidia
   Driver version:      390.132
   I2C device:          i2c-3      name: NVIDIA i2c adapter 2 at 1:00.0
   I2C device:          i2c-1      name: NVIDIA i2c adapter 0 at 1:00.0
   I2C device:          i2c-6      name: NVIDIA i2c adapter 8 at 1:00.0
   I2C device:          i2c-4      name: NVIDIA i2c adapter 6 at 1:00.0
   I2C device:          i2c-2      name: NVIDIA i2c adapter 1 at 1:00.0
   I2C device:          i2c-7      name: NVIDIA i2c adapter 9 at 1:00.0
   I2C device:          i2c-5      name: NVIDIA i2c adapter 7 at 1:00.0

*** Primary Check 2: Check that /dev/i2c-* exist and writable ***

Current user: dany (1000)

Checking /dev/i2c-* devices...

Unless the system is using the AMD proprietary driver fglrx, devices /dev/i2c-*
must exist and the logged on user must have read/write permission for those
devices (or at least those devices associated with monitors).

Typically, this access is enabled by:
  - setting the group for /dev/i2c-* to i2c
  - setting group RW permissions for /dev/i2c-*
  - making the current user a member of group i2c

Alternatively, this can be enabled by just giving everyone RW permission
The following tests probe for these conditions.

Checking for /dev/i2c-* devices...
   crw-rw---- 1 root i2c 89, 0 20 mrt 14:40 /dev/i2c-0
   crw-rw---- 1 root i2c 89, 1 20 mrt 14:40 /dev/i2c-1
   crw-rw---- 1 root i2c 89, 2 20 mrt 14:40 /dev/i2c-2
   crw-rw---- 1 root i2c 89, 3 20 mrt 14:40 /dev/i2c-3
   crw-rw---- 1 root i2c 89, 4 20 mrt 14:40 /dev/i2c-4
   crw-rw---- 1 root i2c 89, 5 20 mrt 14:40 /dev/i2c-5
   crw-rw---- 1 root i2c 89, 6 20 mrt 14:40 /dev/i2c-6
   crw-rw---- 1 root i2c 89, 7 20 mrt 14:40 /dev/i2c-7

Current user (dany) has RW access to all /dev/i2c-* devices.

*** Primary Check 3: Check that module i2c_dev is loaded ***

Checking for module i2c_dev...
   Module i2c_dev is NOT built into kernel

Using only proprietary nvidia or fglrx driver. Module i2c_dev not required.

*** Primary Check 4: Driver specific checks ***

Performing driver specific checks...

Checking for special settings for proprietary Nvidia driver 
(Needed for some newer Nvidia cards).
   grep: /etc/X11/xorg.conf: Bestand of map bestaat niet
   /etc/X11/xorg.conf.d/90-nvidia_i2c.conf:   Option     "RegistryDwords"  "RMUseSwI2c=0x01; RMI2cSpeed=100"
   /etc/X11/xorg.conf.d/90-nvidia_i2c.conf:   # solves problem of i2c errors with nvidia driver
   /etc/X11/xorg.conf.d/90-nvidia_i2c.conf:   # per https://devtalk.nvidia.com/default/topic/572292/-solved-does-gddccontrol-work-for-anyone-here-nvidia-i2c-monitor-display-ddc/#4309293

*** Additional probes ***

Scanning /proc/modules for driver environment...
   Found other loaded module:      videobuf2_vmalloc
   Found other loaded module:      videobuf2_memops
   Found other loaded module:      videobuf2_v4l2
   Found other loaded module:      videobuf2_core
   Found other loaded module:      videodev
   Found other loaded module:      i2c_i801
   Found other loaded module:      i2c_dev
   Found video driver module:      nvidia
   Found other loaded module:      drm_kms_helper
   Loaded drm module depends on:   nvidia_drm,drm_kms_helper,
   Found other loaded module:      drm_panel_orientation_quirks
   Loaded video module depends on: -

Testing if modules are loaded using /sys...
   Module amdgpu           is NOT loaded
   Module fbdev            is NOT loaded
   Module fglrx            is NOT loaded
   Module fturbo           is NOT loaded
   Module i915             is NOT loaded
   Module mgag200          is NOT loaded
   Module nvidia           is loaded
   Module nouveau          is NOT loaded
   Module radeon           is NOT loaded
   Module vboxvideo        is NOT loaded
   Module vc4              is NOT loaded
   Module drm              is loaded
   Module i2c_algo_bit     is NOT loaded
   Module i2c_dev          is loaded
   Module i2c_piix4        is NOT loaded

Examining /sys/bus/i2c/devices...
   /sys/bus/i2c/devices/i2c-3/name:   NVIDIA i2c adapter 2 at 1:00.0
   /sys/bus/i2c/devices/i2c-1/name:   NVIDIA i2c adapter 0 at 1:00.0
   /sys/bus/i2c/devices/i2c-6/name:   NVIDIA i2c adapter 8 at 1:00.0
   /sys/bus/i2c/devices/i2c-4/name:   NVIDIA i2c adapter 6 at 1:00.0
   /sys/bus/i2c/devices/i2c-2/name:   NVIDIA i2c adapter 1 at 1:00.0
   /sys/bus/i2c/devices/i2c-0/name:   SMBus I801 adapter at f000
   /sys/bus/i2c/devices/i2c-7/name:   NVIDIA i2c adapter 9 at 1:00.0
   /sys/bus/i2c/devices/i2c-5/name:   NVIDIA i2c adapter 7 at 1:00.0

Env_Accumulator:
   architecture:                  x86_64
   distributor_id                 sh: lsb_release: opdracht niet gevonden
   /dev/i2c device numbers:       0 1 2 3 4 5 6 7
   Drivers detected:              nvidia
   sysfs_i2c_devices_exist:       true
   /sys/bus/i2c device numbers:   0 1 2 3 4 5 6 7
   dev_i2c_devices_required:      true
   group_i2c_checked:             true
   group_i2c_exists:              true
   dev_i2c_common_group_name:     i2c
   cur_uname:                     dany
   cur_uid:                       1000
   cur_user_in_group_i2c:         true
   cur_user_any_devi2c_rw:        true
   cur_user_all_devi2c_rw:        true
   module_i2c_dev_needed:         false
   module_i2c_dev_loaded:         false
   all_dev_i2c_has_group_i2c:     true
   any_dev_i2c_has_group_i2c:     true
   all_dev_i2c_is_group_rw:       true
   any_dev_i2c_is_group_rw:       true

Configuration suggestions:
   Current user has RW access to all /dev/i2c-N devices.
   Skipping further group and permission checks.

Hou de geladen kernel modules in het oog. Deze opdracht toont op het einde configuratie suggesties. Bovenstaande uitvoer is van op een reeds geconfigureerd en werkend systeem. Bij jullie staan er waarschijnlijk opmerkingen over de group i2c en zijn gebruikers en apparaatrechten. De groep i2c maak je aan met:

dany@pindabackup:~> sudo groupadd --system i2c

Waarna je de gebruiker (hier dany) aan de i2c groep toevoegt:

dany@pindabackup:~> sudo usermod -G i2c -a dany

Met de volgende stap zorg je dat het I2C apparaat (toegang tot het gebruik van I2C) mogelijk wordt voor leden van de i2c groep. Dit zit in het ddcutil softwarepakket en moet je enkel kopiëren naar de juiste map om het te activeren:

dany@pindabackup:~> sudo cp /usr/share/ddcutil/data/45-ddcutil-i2c.rules /etc/udev/rules.d/

Na een herstart moet alles werken. De gebruiker moet lid zijn van de i2c groep:

dany@pindabackup:~> groups dany
dany : users i2c

En de I2C apparaten (devices) moeten toegankelijk zijn voor leden van de i2c groep:

dany@pindabackup:~> ls -l /dev/i2c-*
crw-rw---- 1 root i2c 89, 0 20 mrt 14:40 /dev/i2c-0
crw-rw---- 1 root i2c 89, 1 20 mrt 14:40 /dev/i2c-1
crw-rw---- 1 root i2c 89, 2 20 mrt 14:40 /dev/i2c-2
crw-rw---- 1 root i2c 89, 3 20 mrt 14:40 /dev/i2c-3
crw-rw---- 1 root i2c 89, 4 20 mrt 14:40 /dev/i2c-4
crw-rw---- 1 root i2c 89, 5 20 mrt 14:40 /dev/i2c-5
crw-rw---- 1 root i2c 89, 6 20 mrt 14:40 /dev/i2c-6
crw-rw---- 1 root i2c 89, 7 20 mrt 14:40 /dev/i2c-7

Ddcutil

Om de instelmogelijkheden van uw monitor via ddcutil op te vragen, gebruik je de volgende opdracht:

dany@pindabackup:~> ddcutil getvcp known
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 2 sleep and retry for DDC Null Response
VCP code 0x02 (New control value             ): One or more new control values have been saved (0x02)
VCP code 0x0b (Color temperature increment   ): 1000 degree(s) Kelvin
VCP code 0x0c (Color temperature request     ): 3000 + 4 * (feature 0B color temp increment) degree(s) Kelvin
VCP code 0x0e (Clock                         ): current value =    60, max value =   120
VCP code 0x10 (Brightness                    ): current value =    37, max value =   100
VCP code 0x12 (Contrast                      ): current value =    50, max value =   100
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0x14 (Select color preset           ): 6500 K (sl=0x05)
VCP code 0x16 (Video gain: Red               ): current value =   255, max value =   255
VCP code 0x18 (Video gain: Green             ): current value =   255, max value =   255
VCP code 0x1a (Video gain: Blue              ): current value =   255, max value =   255
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0x1e (Auto setup                    ): Auto setup not active (sl=0x00)
VCP code 0x1f (Auto color setup              ): Auto setup not active (sl=0x00)
VCP code 0x20 (Horizontal Position (Phase)   ): current value =     0, max value =   100
VCP code 0x30 (Vertical Position (Phase)     ): current value =    50, max value =   100
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0x3e (Clock phase                   ): current value =     0, max value =    60
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0x52 (Active control                ): Value: 0x10
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0x60 (Input Source                  ): DVI-2 (sl=0x04)
VCP code 0x62 (Audio speaker volume          ): current value =     0, max value =   100
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0x6c (Video black level: Red        ): current value =     0, max value =   255
VCP code 0x6e (Video black level: Green      ): current value =     0, max value =   255
VCP code 0x70 (Video black level: Blue       ): current value =     0, max value =   255
VCP code 0x73 (LUT Size                      ): Maximum retries exceeded
VCP code 0x74 (Single point LUT operation    ): Maximum retries exceeded
VCP code 0x75 (Block LUT operation           ): Maximum retries exceeded
VCP code 0x78 (EDID operation                ): Maximum retries exceeded
VCP code 0x8a (Color Saturation              ): current value =     0, max value = 65535
VCP code 0x8c (TV Sharpness                  ): current value =     0, max value = 65535
VCP code 0x8d (Audio Mute                    ): Unmute the audio (sl=0x02)
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0x9b (6 axis hue control: Red       ): current value =     0, max value = 65535
VCP code 0x9c (6 axis hue control: Yellow    ): current value =     0, max value = 65535
VCP code 0x9d (6 axis hue control: Green     ): current value =     0, max value = 65535
VCP code 0x9e (6 axis hue control: Cyan      ): current value =     0, max value = 65535
VCP code 0x9f (6 axis hue control: Blue      ): current value =     0, max value = 65535
VCP code 0xa0 (6 axis hue control: Magenta   ): current value =     0, max value = 65535
VCP code 0xac (Horizontal frequency          ): 58370 hz
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0xae (Vertical frequency            ): 59.90 hz
VCP code 0xb2 (Flat panel sub-pixel layout   ): Red/Green/Blue vertical stripe (sl=0x01)
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0xb6 (Display technology type       ): LCD (active matrix) (sl=0x03)
(ddc_write_read_with_retry) Display_Handle[i2c: fh=3, busno=4], ddc_write_read() succeeded after 1 sleep and retry for DDC Null Response
VCP code 0xc0 (Display usage time            ): Usage time (hours) = 22511 (0x0057ef) mh=0xff, ml=0xff, sh=0x57, sl=0xef
VCP code 0xc3 (Transmit display descriptor   ): Maximum retries exceeded
VCP code 0xc6 (Application enable key        ): 0x005a
VCP code 0xc8 (Display controller type       ): Mfg: Genesis (sl=0x02), controller number: mh=0x00, ml=0x4a, sh=0x00
VCP code 0xc9 (Display firmware level        ): 1.6
VCP code 0xca (OSD                           ): OSD Enabled (sl=0x02)
VCP code 0xcc (OSD Language                  ): Danish (sl=0x13)
VCP code 0xd2 (Asset Tag                     ): Maximum retries exceeded
VCP code 0xd6 (Power mode                    ): DPM: On,  DPMS: Off (sl=0x01)
VCP code 0xdc (Display Mode                  ): Standard/Default mode (sl=0x00)
VCP code 0xdf (VCP Version                   ): 2.1

Uit deze informatie blijkt dat we de helderheid (Brightness) kunnen regelen van 0 tot en met 100, en deze nu is ingesteld op 37. Wil je één bepaalde instelling opvragen, bijvoorbeeld de helderheid:

dany@pindabackup:~> ddcutil getvcp 10
VCP code 0x10 (Brightness                    ): current value =    37, max value =   100

De code voor Brightness is 10, die je kunt achterhalen met de vorige opdracht. Op een gelijkaardige manier pas je een monitor instelling aan:

dany@pindabackup:~> ddcutil setvcp 10 60

Deze opdracht stelt de helderheid (10) van de monitor in op 60. Wil je alle mogelijkheden van ddcutil ontdekken, raadpleeg dan de manual (man ddcutil) en/of de help van ddcutil.

ddcutil help

Automatiseren

Met behulp van een lichtsensor en een script dat bij het aanmelden automatisch gestart wordt, kan je de helderheid van jouw monitor automatisch aanpassen aan het omgevingslicht. Mijn lichtsensor is aan een Raspberry Pi bevestigd en kan via HTTP door elk systeem op het netwerk uitgelezen worden.

Bash

Bash is bij velen de eerste keuze om scripts te schrijven. Met het volgend bash script lukt dit:

#!/bin/bash
# brightness.sh

# https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
correction=(65535 65508 65479 65451 65422 65394 65365 65337
    65308 65280 65251 65223 65195 65166 65138 65109
    65081 65052 65024 64995 64967 64938 64909 64878
    64847 64815 64781 64747 64711 64675 64637 64599
    64559 64518 64476 64433 64389 64344 64297 64249
    64200 64150 64099 64046 63992 63937 63880 63822
    63763 63702 63640 63577 63512 63446 63379 63310
    63239 63167 63094 63019 62943 62865 62785 62704
    62621 62537 62451 62364 62275 62184 62092 61998
    61902 61804 61705 61604 61501 61397 61290 61182
    61072 60961 60847 60732 60614 60495 60374 60251
    60126 59999 59870 59739 59606 59471 59334 59195
    59053 58910 58765 58618 58468 58316 58163 58007
    57848 57688 57525 57361 57194 57024 56853 56679
    56503 56324 56143 55960 55774 55586 55396 55203
    55008 54810 54610 54408 54203 53995 53785 53572
    53357 53140 52919 52696 52471 52243 52012 51778
    51542 51304 51062 50818 50571 50321 50069 49813
    49555 49295 49031 48764 48495 48223 47948 47670
    47389 47105 46818 46529 46236 45940 45641 45340
    45035 44727 44416 44102 43785 43465 43142 42815
    42486 42153 41817 41478 41135 40790 40441 40089
    39733 39375 39013 38647 38279 37907 37531 37153
    36770 36385 35996 35603 35207 34808 34405 33999
    33589 33175 32758 32338 31913 31486 31054 30619
    30181 29738 29292 28843 28389 27932 27471 27007
    26539 26066 25590 25111 24627 24140 23649 23153
    22654 22152 21645 21134 20619 20101 19578 19051
    18521 17986 17447 16905 16358 15807 15252 14693
    14129 13562 12990 12415 11835 11251 10662 10070
    9473 8872 8266 7657 7043 6424 5802 5175
    4543 3908 3267 2623 1974 1320 662 0)

while :
do
    # Haal het omgevingslicht op
    lux=$(curl -k https://rpipindanet/data/luxtls)
    if [ $? = 0 ]; then # Ophalen van meting gelukt en kan dus verwerkt worden
        echo "Omgevingslicht: $lux"
        maxlux=$(curl -k https://rpipindanet/data/luxmaxtls)
        minlux=$(curl -k https://rpipindanet/data/luxmintls)
        echo Maximaal gemeten omgevingslicht: $maxlux
        echo Minimaal gemeten omgevingslicht: $minlux
        rangelux=$(awk "BEGIN {printf \"%.2f\", $maxlux - $minlux}")
        echo Bereik gemeten omgevingslicht: $rangelux
        rellux=$(awk "BEGIN {printf \"%.2f\", ($lux - $minlux) / $rangelux}")
        
        echo Niet gecorrigeerde Relatief omgevingslicht: $rellux

        echo SQRT Relatief omgevingslicht: $(awk "BEGIN {printf sqrt($rellux)}")
        # rellux=$(awk "BEGIN {printf sqrt($rellux)}")

        correctionTableIndex=$(awk "BEGIN {printf \"%.0f\", 255 - ($rellux * 255)}")
        correctionTableValue=${correction[$correctionTableIndex]}
        correctionTableBrightness=$(awk "BEGIN {printf $correctionTableValue / ${correction[0]}}")
        echo CorrectionTable Relatief omgevingslicht: $correctionTableBrightness
        rellux=$correctionTableBrightness

        echo Relatief omgevingslicht: $rellux
        helderheid=$(awk "BEGIN {printf \"%.0f\", 5 + $rellux * 60}") # 0.6, 0.40

        # Huidige helderheid
        huidige=$(ddcutil getvcp 10 | sed -r 's/([^0-9]*([0-9]*)){3}.*/\2/')

        # Helderheid geleidelijk aanpassen
        echo "Helderheid aanpassen van $huidige naar $helderheid"
        if [ ${huidige%.*} -eq ${helderheid%.*} ] && [ ${huidige#*.} \< ${helderheid#*.} ] || [ ${huidige%.*} -lt ${helderheid%.*} ]; then
            for i in $( LANG=en_US seq $huidige 1 $helderheid ); do
                echo verhogen: $i
                ddcutil setvcp 10 $i
                sleep 1
            done
        else
            for i in $( LANG=en_US seq $huidige -1 $helderheid ); do
                echo verlagen: $i
                ddcutil setvcp 10 $i
                sleep 1
            done
        fi
    fi

    # Wacht 1 minuut
    sleep 60
done

Daarbij kan je gebruik maken van allerlei correctieberekeningen waardoor de helderheid van de monitor beter de ooggevoeligheid volgt. Onze ogen zijn namelijk veel gevoeliger bij donker en veel minder gevoelig bij fel licht (gelukkig maar).

Hetzelfde kan je bereiken met een PHP script. Bash is OK, maar minder portable naar andere systemen.

#!/usr/bin/php
<?php
$maxHelderheid = 70;
$minHelderheid = 5;
# https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/
$correction = array(65535,    65508,    65479,    65451,    65422,    65394,    65365,    65337,
      65308,    65280,    65251,    65223,    65195,    65166,    65138,    65109,
      65081,    65052,    65024,    64995,    64967,    64938,    64909,    64878,
      64847,    64815,    64781,    64747,    64711,    64675,    64637,    64599,
      64559,    64518,    64476,    64433,    64389,    64344,    64297,    64249,
      64200,    64150,    64099,    64046,    63992,    63937,    63880,    63822,
      63763,    63702,    63640,    63577,    63512,    63446,    63379,    63310,
      63239,    63167,    63094,    63019,    62943,    62865,    62785,    62704,
      62621,    62537,    62451,    62364,    62275,    62184,    62092,    61998,
      61902,    61804,    61705,    61604,    61501,    61397,    61290,    61182,
      61072,    60961,    60847,    60732,    60614,    60495,    60374,    60251,
      60126,    59999,    59870,    59739,    59606,    59471,    59334,    59195,
      59053,    58910,    58765,    58618,    58468,    58316,    58163,    58007,
      57848,    57688,    57525,    57361,    57194,    57024,    56853,    56679,
      56503,    56324,    56143,    55960,    55774,    55586,    55396,    55203,
      55008,    54810,    54610,    54408,    54203,    53995,    53785,    53572,
      53357,    53140,    52919,    52696,    52471,    52243,    52012,    51778,
      51542,    51304,    51062,    50818,    50571,    50321,    50069,    49813,
      49555,    49295,    49031,    48764,    48495,    48223,    47948,    47670,
      47389,    47105,    46818,    46529,    46236,    45940,    45641,    45340,
      45035,    44727,    44416,    44102,    43785,    43465,    43142,    42815,
      42486,    42153,    41817,    41478,    41135,    40790,    40441,    40089,
      39733,    39375,    39013,    38647,    38279,    37907,    37531,    37153,
      36770,    36385,    35996,    35603,    35207,    34808,    34405,    33999,
      33589,    33175,    32758,    32338,    31913,    31486,    31054,    30619,
      30181,    29738,    29292,    28843,    28389,    27932,    27471,    27007,
      26539,    26066,    25590,    25111,    24627,    24140,    23649,    23153,
      22654,    22152,    21645,    21134,    20619,    20101,    19578,    19051,
      18521,    17986,    17447,    16905,    16358,    15807,    15252,    14693,
      14129,    13562,    12990,    12415,    11835,    11251,    10662,    10070,
      9473,    8872,    8266,    7657,    7043,    6424,    5802,    5175,
      4543,    3908,    3267,    2623,    1974,    1320,    662,    0);
function cURLdownload($url)
{
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $result = curl_exec($ch);
    curl_close($ch);
    return $result;
}
while (1){
    $lux = cURLdownload("http://rpipindanet/data/luxtls");
    if (! $lux === FALSE)
    {
        echo "Omgevingslicht: $lux";
        $maxlux = cURLdownload("http://rpipindanet/data/luxmaxtls");
        echo "Maximaal gemeten omgevingslicht: $maxlux";
        $minlux = cURLdownload("http://rpipindanet/data/luxmintls");
        echo "Minimaal gemeten omgevingslicht: $minlux";
        $rangelux = (float) $maxlux - (float) $minlux;
        echo "Bereik gemeten omgevingslicht: $rangelux\n";
        $rellux = ((float) $lux - (float) $minlux) / $rangelux;
        echo "Niet gecorrigeerde Relatief omgevingslicht: $rellux\n";
        echo "SQRT Relatief omgevingslicht: " . sqrt($rellux) . "\n";
        $correctionTableIndex = 255 - (int) ($rellux * 255);
        $correctionTableValue = $correction[$correctionTableIndex];
        $correctionTableBrightness = $correctionTableValue / $correction[0];
        echo "CorrectionTable Relatief omgevingslicht: $correctionTableBrightness\n";
        $rellux = $correctionTableBrightness;
        echo "Relatief omgevingslicht: $rellux\n";
        $helderheid = (int) ($minHelderheid + $rellux * ($maxHelderheid - $minHelderheid));
        unset($output);
        exec("ddcutil getvcp 10", $output, $return);
        preg_match_all('!\d+!',$output[0],$matches);
#        var_dump($matches);
        $huidige = (int) $matches[0][2];
        echo "Helderheid aanpassen van $huidige naar $helderheid\n";
        if ($huidige < $helderheid)
        {
            for ($i = $huidige + 1; $i <= $helderheid; $i++) {
                echo "Verhogen: $i\n";
                exec("ddcutil setvcp 10 $i");
                sleep (1);
            }
        } else {
            for ($i = $huidige - 1; $i >= $helderheid; $i--) {
                echo "Verlagen: $i\n";
                exec("ddcutil setvcp 10 $i");
                sleep (1);
            }
        }
    }
    sleep(60);
}
?>