9

Sometimes I like to watch VLC media on my TV connected to the HDMI port on my laptop and I now have to:

  • Start VLC on the TV:
    • Positioned on the TV by CCSM.
    • The screen saver is being turned off by VLC.
  • Close the laptop
  • Turn off the monitor (If it's on)

because I like to sit in the dark while watching TV!

Has anyone solved the above already for themselves through a script?

The TV is always connected to HDMI and the monitor always to the VGA port if that makes things easier.

11

I've created a script that slowly dims two monitors after 5 minutes of keyboard or mouse inactivity while you watch a movie on a third monitor. When you move your mouse or use your keyboard the two dimmed monitors quickly brighten (but not suddenly to shock you).

Save the script below to a filename in your path such as /usr/local/bin/movie.sh or /home/your_user_name/bin/movie.sh and then use:

chmod a+x /path/to/script/movie.sh

Xorg's package xprintidle is required to track how long it's been since a mouse movement or keyboard activity:

sudo apt install xprintidle

Then to launch the script use:

movie.sh

To learn more about the script and how it works use:

movie.sh anyparameter

and debug / trace statements are displayed in your terminal.

Note: When testing, change TIME_TO_FADE from 310000 to 10000 so you only have to wait 10 seconds instead of 5 minutes for fading to start.

The script

#!/bin/bash

# NAME: movie.sh
# PATH: ~/eyesome
# DESC: Dim monitors 1 and 3 after 5 minutes of activity
# DATE: June 27, 2019. Modified June 30, 2019.
# PARM: Pass any parameter 1 to generate trace output
# NOTE: No notes.

# TODO: Increase limit of 3 with array with up to 9 monitor names, eg use:
#       XrandrNames=( "eDP-1-1" "" "DP-1-1" "HDMI-1-1" ) # Gives 4 monitors


: <<'END'
/* -----------------------------------------------------------------------------

CUSTOM NOTES
============
Put your own free form notes here for disabling third party auto-brightness
sunrise / sunset applications like nightlight, redshift, flux, eyesome, etc.

CONFIGURATION FILE LOCATION
===========================
$ ll /usr/local/bin/.eyesome-cfg
-rw-r--r-- 1 root root 610 Jun 27 18:31 /usr/local/bin/.eyesome-cfg

CONFIGURATION FILE RECORD LAYOUT
================================
$ cat /usr/local/bin/.eyesome-cfg
https://www.timeanddate.com/sun/canada/edmonton|70.000000|120.000000|90.000000|
1.000000|TRUE| | | | |1|Disabled|Hardware|Alien 17" Builtin DIsplay|
intel_backlight|eDP-1-1|3500.000000|1.000000|1.000000|1.000000|850.000000|
1.000000|0.780000|0.650000|3500|1.000000:1.000000:1.000000| | | | |2|Enabled|
Software|Sony 50" TV|xrandr|HDMI-0|1.000000|1.000000|1.000000|1.000000|0.750000|
1.000000|0.950000|0.850000|1.00|1.000000:1.000000:1.000000| | | | |3|Disabled|
Software|Toshibal 43" 4K TV|xrandr|DP-1-1|1.000000|1.000000|1.000000|1.000000|
0.650000|1.000000|0.880000|0.780000|1.00|1.000000:1.000000:1.000000| | | | 

----------------------------------------------------------------------------- */
END

# If sudo powers not needed, eg no 3rd party auto-brightening to disable,
# then comment out the next four lines:
if [[ $(id -u) != 0 ]]; then # root powers needed to call this script
    echo >&2 "$0 must be called with sudo powers"
    exit 1
fi

# To echo debug/trace statements to screen, pass any parameter to script
Debug=0
[[ $# -gt 0 ]] && Debug=1

# To get list of your monitors use: xrandr --verbose | grep " connected"
MON1="eDP-1-1"      # eDP-1-1 = Laptop display
MON2=""             # HDMI-0 = Sony TV
MON3="DP-1-1"       # DP-1-1 = Toshiba TV

# If you elect to turn backlight complete off and on you must use sudo
BACK="intel_backlight"  # Setting to blank means no backlight to turn off/on
BACK=""  # After xrandr dims backlight will stay on

# All seconds in millisconds, eg 1000 milliseconds = 1 second
TIME_TO_FADE=310000 # Keyboard/Mouse idle time before dim 300000 = 5 minutes
TIME_TO_WAKE=2000   # 2 second time or less to trigger brightening
FADE_SLEEP=.15      # When fading sleep seconds between monitor changes
WAKE_SLEEP=.025     # When waking sleep seconds between monitor changes

# Optional configuration file for 3rd party auto brightnes / color temperature
CFG_FILE=""
# if nothing else is automatically controlling monitors comment out next line
#CFG_FILE=/usr/local/bin/.eyesome-cfg

DisableAutoBright () {
    # Disable specific monitors from nightlight, redshift, flux, eyesome, ect.
    [[ $CFG_FILE == "" ]] && return # No third party apps
    [[ $MON1 != "" ]] && sed -i 's/1|Enabled/1|Disabled/g' "$CFG_FILE"
    [[ $MON2 != "" ]] && sed -i 's/2|Enabled/2|Disabled/g' "$CFG_FILE"
    [[ $MON3 != "" ]] && sed -i 's/3|Enabled/3|Disabled/g' "$CFG_FILE"
} # DisableAutoBright

EnableAutoBright () {
    # Renable specific monitors for nightlight, redshift, flux, eyesome, ect.
    [[ $CFG_FILE == "" ]] && return # No third party apps
    [[ $MON1 != "" ]] && sed -i 's/1|Disabled/1|Enabled/g' "$CFG_FILE"
    [[ $MON2 != "" ]] && sed -i 's/2|Disabled/2|Enabled/g' "$CFG_FILE"
    [[ $MON3 != "" ]] && sed -i 's/3|Disabled/3|Enabled/g' "$CFG_FILE"

    # Trigger 3rd party app to gradually set brightness based on sunrise/sunset
    /usr/local/bin/wake-eyesome.sh post eyesome-cfg.sh nosleep

} # EnableAutoBright

MonArr=()   # Index 0= Monitor # 1 to 3, 1=Xrandr Name, 2=Connected/Disconnected, 
            # 3=Save Bright "100"=1.0, 4=Current Bright "75"=0.75, 5=xprintidle cnt

SetBrightness () {

    # Parm 1: XrandrMonitor Name
    # Parm 2: Math Brigthness Value
    local MON CurrBright
    MON="$1"
    MathBright="$2"

    [[ "${MathBright:0:1}" == "-" ]] && MathBright=0    # Negative not allowed
    [[ "$MathBright" -gt 999  ]] && MathBright=999      # Can't go over 9.99

    if [[ "${#MathBright}" -eq 3 ]] ; then
        MathBright="$MathBright"000         # Pad with lots of zeros
        CurrBright="${MathBright:0:1}.${MathBright:1:2}"
    elif [[ "${#MathBright}" -eq 1 ]] ; then
        CurrBright=".0$MathBright"
    else
        MathBright="$MathBright"000         # Pad with lots of zeros
        CurrBright=".${MathBright:0:2}"
    fi

    # Even if brigthness hasn't changed we want to set it each time so
    # that `xrandr` will lag sleep cycle by 25 milliseconds
    if [[ $CurrBright == ".0" ]] ; then
        xrandr --output "$MON" --off
    else    
        xrandr --output "$MON" --brightness "$CurrBright"   # Set new brightness
    fi
}

GetCurrBright () {

    # Call this before starting to fade monitor. Parm1: Monitor Xrandr name
    # Setup for global variables failure
    MonMathBright="0"
    MonCurrBright="0.0"
    MonStatus="Disconnected"
    [[ $1 == "" ]] && return

    local CurrBright Left Right

    CurrBright=$( xrandr --verbose --current | \
                                      grep ^"$1 connected" -A5 | tail -n1 )
    [[ $CurrBright == "" ]] && { echo "$1 Monitor not found in xorg"; return; }

    MonStatus="Connected"
    MonCurrBright="${CurrBright##* }"  # Get brightness level with decimal place

    Left=${MonCurrBright%%"."*}        # Extract left of decimal point
    Right=${MonCurrBright#*"."}        # Extract right of decimal point

    [[ "$Left" != 0 ]] && MonMathBright="$Left"00          # 1.0 becomes "100"
    [[ "${#Right}" -eq 1 ]] && Right="$Right"0          # 0.5 becomes "50"
    MonMathBright=$(( MonMathBright + Right ))

} # GetCurrBright

BrightenMonitors () {
    # Turn monitor on and slowly raise brightness to saved setting
    [[ "$BACK" != "" ]] && echo 0 > "/sys/class/backlight/$BACK/bl_power"

    local i m LastPercent NewMathBright
    LastPercent=0
    for (( m = 0 ; m < MonArrCnt ; m=m+MON_COL_CNT )); do   #loop for each monitor
        GetByNdx "$m"
        [[ $MonStatus == Disconnected ]] && continue
        # If dimming interrupted, start from last percentage and not 0%
        [[ $MonPercent -gt "$LastPercent" ]] && LastPercent="$MonPercent"
    done
    ((Debug)) && echo Starting percentage: "$LastPercent"

    # Brighten by increments of 4% for quicker waking
    for (( i = LastPercent ; i <= 100 ; i=i+4 )); do    # loop from 0% to 100%
        [[ $i -ge 96 ]] && i=100 # If 96, next loop will be 100
        for (( m = 0 ; m < MonArrCnt ; m=m+MON_COL_CNT )); do   #loop for each monitor
            GetByNdx "$m"
            [[ $MonStatus == Disconnected ]] && continue
            [[ $MonMathBright -eq 0 ]] && MonMathBright=1
            NewMathBright=$(( MonMathBright * i / 100 ))
            SetBrightness "$MonName" "$NewMathBright"
            SetByNdx "$m"
            sleep "$WAKE_SLEEP"       # Very quick increase, so smaller sleep
        done
    done

} # BrightenMonitors

DimMonitors () {

    local i m NewMathBright Elapsed
    for (( m = 0 ; m < MonArrCnt ; m=m+MON_COL_CNT )); do   #loop for each monitor
        GetByNdx "$m"
        # Get starting full brightness level, blank monitor name returns zeros
        GetCurrBright "$MonName"
        ((Debug)) && echo "$MonName Starting brightness: $MonMathBright"
        SetByNdx "$m"
    done

    # Dim by increments of 1% for slow fading
    for (( i = 100 ; i >= 0 ; i-- )); do    # loop from 100% to 0% brightness
        for (( m = 0 ; m < MonArrCnt ; m=m+MON_COL_CNT )); do   #loop for each monitor
            GetByNdx "$m"
            [[ $MonStatus == Disconnected ]] && continue
            NewMathBright=$(( MonMathBright * i / 100 ))
            SetBrightness "$MonName" "$NewMathBright"
            MonPercent="$i"
            SetByNdx "$m"
        done
        Elapsed=$(xprintidle)
        [[ $Elapsed -lt 2000 ]] && break
        sleep "$FADE_SLEEP"         # slowly dim so longer sleep
        Elapsed=$(xprintidle)
        [[ $Elapsed -lt 2000 ]] && break
    done

    [[ "$BACK" != "" ]] && echo 4 > "/sys/class/backlight/$BACK/bl_power"

} # DimMonitors

GetByNdx () {
    # Parm1 = index number, 0 = first monitor array entry
    MonNumber="${MonArr[$1]}"       # 3rd party monitor number, eg "3"
    MonName="${MonArr[$1+1]}"       # Xrandr Monitor name, eg "DP-1-1"
    MonStatus="${MonArr[$1+2]}"     # Xrandr Connected/Disconnected
    MonCurrBright="${MonArr[$1+3]}" # Value when dimming first starts eg 1.00
    MonMathBright="${MonArr[$1+4]}" # Math implied decimal 100 = 1.00, 50 = .5
    MonPercent="${MonArr[$1+5]}"    # Last percentage brightness set
} # GetByNdx

SetByNdx () {
    # Parm1 = index number, 0 = first monitor array entry
    MonArr[$1]="$MonNumber"         # 3rd party monitor number, eg "3"
    MonArr[$1+1]="$MonName"         # Xrandr Monitor name, eg "DP-1-1"
    MonArr[$1+2]="$MonStatus"       # Xrandr Connected/Disconnected
    MonArr[$1+3]="$MonCurrBright"   # Value when dimming first starts eg 1.00
    MonArr[$1+4]="$MonMathBright"   # Implied decimal 100 = 1.00, 50 = .5
    MonArr[$1+5]="$MonPercent"      # Last percentage brightness set
}

InitializeMonArr () {

    # Initialize arrays with Xrandr name, status, curret bright, math bright, %
    MonArr=()
    MonArr+=( "1" "$MON1" "Cconnected" "1.0" "100" "0" )
    GetByNdx 0
    SetByNdx 0
    MonArr+=( "2" "$MON2" "Disconnected" ".0" "0" "0" )
    GetByNdx 1
    SetByNdx 1
    MonArr+=( "3" "$MON3" "Connected" "1.0" "100" "0" )
    GetByNdx 2
    SetByNdx 2

    MON_COL_CNT=6
    MonArrCnt="${#MonArr[@]}"

} # InitializeMonArr

Dimmed=false
InitializeMonArr
if ((Debug)) ; then
    echo "Starting movie.sh"
    echo "Monitor Array Dump: #, Name, Curr Bright, Math Bright, Last Percent"
    echo "${MonArr[*]}"
fi

# Loop until CTRL + C
while true ; do

    Elapsed=$(xprintidle)

    if [[ $Elapsed -lt "$TIME_TO_WAKE" ]] ; then
        if [[ $Dimmed == true ]] ; then
            ((Debug)) && echo -e $'\n'"Wake after: $Elapsed milliseconds"
            Dimmed=false
            BrightenMonitors
            EnableAutoBright
        fi
    elif [[ $Elapsed -gt "$TIME_TO_FADE" ]] ; then
        if [[ $Dimmed == false ]] ; then
            ((Debug)) && echo -e $'\n'"Fade after: $Elapsed milliseconds"
            Dimmed=true
            DisableAutoBright
            # TODO: THey jiggle mouse whilst dimming to stop
            DimMonitors
            continue    # Avoid first sleep incase mouse moved.
        fi
    fi

    sleep 1     # Wait a sec until next keyboard / mouse idle test

done
  • 2
    Impressive, that's far more readable and maintainable than I expected. – Mast Jul 1 at 9:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.