Display Backlight & Keyboard Illumination Bash Script
|Okay, so this might be a bit rough, it still has TODO’s in it, as I just threw this together to get the panel backlight and keyboard illumination to work together in a way I thought seemed really logical. That said, it may seem totally illogical for your own use-cases, but that’s what is great about scripts; they’re easy to hack on! It does fall back to xbacklight, which is for the display backlight only – so run it from the terminal first to make sure you have it configured correctly.
You might be happy using this from the terminal, but you’ll probably prefer to add it to your window manager configuration, mapped to some pair of hot-keys.
To use this you’ll probably have to change some (or all) of the USER CONFIG section, but if you have those correct the rest *should* just work. There are some other optional parameters throughout the file that you can tweak, and I tried to explain what they do as verbosely as possible.
If you have any ways to improve/streamline this script feel free to make suggestions! I’m certainly not a Bash guru and I’m always happy to learn something new!
#!/bin/bash # # Backlight Utility // bl-util.sh # Copyleft 2019, by Adam Gaskins <self@adamgaskins.com> # # Description: # Just a simple backlight control utility... # # If you need help finding the /sys path to your backlight device: # First try looking for a display backlight in: # /sys/class/backiight/ # If nothing is there try running: # find /sys/devices -type f -name 'brightness' # That should give you at least a handful of possible locations to where both # your display & keyboard backlight devices might be located (but also some # invalid ones too, so be careful). # # See the README for a painfully detailed explanation of the rationale behind # the way this script functions. # # Usage Example: # ./bl-util.sh + # ./bl-util.sh - # # TODO: # - If brightness to set is with x % near min or max just set the min or max. # It's annoying to see it set to to 98% and then the change to 100% is not # even perceptible, or worse it ends up at 1 or 2% and is basically at the # lowest brightness, but you have to press it again just to turn to off the # keyboard BL # - add option to attempt to auto find the display and keyboard backlight, # device and path and have all settings be optional. ############################## ######## USER CONFIG ######### ## Path to display's backlight control in /sys/... # Note: This is likely correct already SYS_DISPLAY_PATH='/sys/class/backlight' # NOTE: the above /sys/class path is preferable to the /sys/devices variant # (below), especially if your system has discreet video (i.e. Optimus) that # might use a different video card at times! Only list the device in the # specific manner shown below if you you have no other option. #SYS_DISPLAY_PATH='/sys/devices/pci0000:00/0000:00:02.0/drm/card0/card0-eDP-1' ## Name of display's backlight device in $SYS_DISPLAY_PATH # Note: If using Intel video this could be correct SYS_DISPLAY_DEVICE='intel_backlight' ## Path to the keyboard's backlight control in /sys/... (this may be correct) SYS_KEYBOARD_PATH='/sys/class/leds' ## Name of keyboard backlight device in $SYS_KEYBOARD_PATH (you will probably ## have to replace this) SYS_KEYBOARD_DEVICE='dell::kbd_backlight' ##### END OF USER CONFIG ##### ############################## n=/dev/null # reusable redirect abbreviation # Use notifications if possible, otherwise just echo # TODO: detect if run from terminal inside an X session and use echo if command -v notify-send >$n && echo $DISPLAY | grep '\:[0-9]' >$n; then notify="$(command -v notify-send) --urgency=low --app-name=$0 $0" # if available, use canberra to play a bell chime # if command -v canberra-gtk-play >$n; then # notify="$(command -v canberra-gtk-play) -i bell -d $0; ${notify}" # fi else notify="echo $0: " fi if [ ! -d ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE} ]; then ${notify} "Invalid display path ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}! Aborting." exit 1 fi if [ ! -r ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/actual_brightness ]; then ${notify} "Cannot read ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/actual_brightness! Aborting." exit 1 fi # Make sure the script is not already running (avoids launching lots of # instances when, for example, the brightness key is held down). processes=$(ps -x | grep $0 | grep -v grep | wc -l) if [ $processes -gt 3 ]; then echo $(ps -x | grep $0 | grep -v grep | wc -l) exit 1 fi # TODO: is there a better way? this is iffy... # Check that a command has been given if [[ $1 == '+' || $1 == '-' ]]; then direction=$1 else ${notify} "The script expects a '+' or '-' character as an argument!" exit 10 fi ### Display Settings ### ## Length of fade effect (in milliseconds) [integer] # Tip: If your keyboard backlight fades then it looks very nice to match that # time closely here. 200ms seems to be about right on my Inspiron 7573. fade_time_ms=200 # must be > 33 # CUSTOM_BL_CMD can be a user-defined string used to set brightness. This can be # any command that takes an integer value between the min & brightness values # (as defined in /sys/<path_to_device/). Just _remember_ to replace a real value # within the command with a '%s' (without the single quotes) so that this script # can insert the brightness values in to your command! You can, however, just # leave it empty and let the script try it's own methods. # Example: CUSTOM_BL_CMD='pkexec xfpm-power-backlight-helper --set-brightness %s' CUSTOM_BL_CMD='' # if provided, use CUSTOM_BL_CMD without question if [[ $CUSTOM_BL_CMD = *"%s"* ]]; then display_set_cmd=${CUSTOM_BL_CMD} # otherwise we try the echo method... elif [ -w ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/brightness ]; then display_set_cmd='echo %s > ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/brightness' # ...or fall back to xbacklight, if available elif command -v xbacklight >$n; then echo "Cannot write to ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/brightness, \ falling back to 'xbacklight' method. This likely means the keyboard backlight will \ not be set!" display_set_cmd='xbacklight -set $(( ( (%s * 10000 / 7500) + 99 ) / 100 ))' # if neither method works just abort else ${notify} "Cannot write to ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/brightness \ or find the 'xbacklight' utility on this system! Aborting." exit 1 fi # get display backlight values display_cur=$(cat ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/actual_brightness) display_max=$(cat ${SYS_DISPLAY_PATH}/${SYS_DISPLAY_DEVICE}/max_brightness) display_min=1 ## Base delta [integer] # Base delta effects brightness in a non-linear way so that we have smaller # changes at low brightness and larger changes at higher brightness. Since our # eyes tend to be more sensitive to changes at lower light levels, and less so # at higher brightness levels, this value can make the transitions at these # opposing extremes appear more consistent. display_delta_base=5 # values between 4 and 12 give reasonable results display_delta_applied=$(( ((${display_delta_base} * ${display_max}) + 50) / 100 )) # this might have rounding errors here, break this up... display_delta=$(( (${display_delta_applied} * ${display_cur}) / \ (($display_max + 1) / 2) + $display_delta_applied )) # calculate what the display brightness will end up being so we can set the # keyboard backlight accordingly. We only need to know this before hand because # some KB backlights have their own fade routine, so we need to set that before # we set the display brightness fade routine to have them both occur at the same # time. display_new=$((${display_cur} ${direction} $display_delta)) # calculate length of each step (steps_ms), number of stops needed (steps), and # how much to advance the brightness each step (brightness_step) fade_step_ms=$(( ((${fade_time_ms} * 3) + 50) / 100 )) # ensures ~30fps for fade fade_steps=$(( ( ${fade_time_ms} + (($fade_step_ms+1) / 2) ) / $fade_step_ms )) brightness_step=$(( ( $display_delta + (($fade_steps+1) / 2) ) / $fade_steps )) ### Keyboard Settings ### # Note: In the 'bl-util.readme', under the Keyboard Backlight Tips section, # there are some ideas to help in deciding how to configure the following three # variables! ## Enable/disable keyboard backlight control [bool] # Note: This just disables its control via this script, it does not enable or # disable the KB backlight itself! kb_control=true ## Turn backlight off if display brightness goes above percentage value [int] # Rationale: Turns off backlight when bright ambient light (i.e. bright room, or # sunlight) would render the backlight moot (see the README for details). This # is relative to display brightness, so a value of 60 would turn KB backlight # off when display brightness goes above 60%, and turns it back on if display # brightness drops just below this value. 100 effectively disables this feature! kb_cutoff=35 ## Turn off keyboard backlight when display brightness is at lowest value [bool] # Rationale: If you're running the display down to the absolute dimmest value # you might be trying to minimize the light you're emitting and there fore might # prefer not to have the keyboard lit up. Further more many keyboard backlights # cannot dim too much, so you may reach a point where the keyboard brightness is # much brighter than your display, which is both annoying and makes it difficult # for your eyes to adjust. kb_allow_zero=true ## This is the command used to set keyboard backlight brightness # This can be any command that takes an integer value. Simply replace a real # value within the command with a '%s'. kb_set_cmd='echo %s > ${SYS_KEYBOARD_PATH}/${SYS_KEYBOARD_DEVICE}/brightness' # get keyboard backlight values kb_cur=$(cat ${SYS_KEYBOARD_PATH}/${SYS_KEYBOARD_DEVICE}/brightness) kb_max=$(cat ${SYS_KEYBOARD_PATH}/${SYS_KEYBOARD_DEVICE}/max_brightness) # this is the display_max with kb_cutoff applied display_ceiling=$(( (${kb_cutoff} * ${display_max} + 50) / 100 )) # calculate the new keyboard brightness (+ 99 rounds up, + 50 rounds correctly, # remove it to round down) kb_new=$(( ((($display_new * 100 / $display_ceiling) * ${kb_max}) + 99 ) / 100 )) ### Apply Settings ### ## Set keyboard backlight if [ $kb_control -a \ -w ${SYS_KEYBOARD_PATH}/${SYS_KEYBOARD_DEVICE}/brightness -a \ $kb_new -ne ${kb_cur} ]; then if [ $kb_new -eq 0 ]; then # check for allow_zero option $kb_allow_zero && value=0 || value=1 cmd=$(printf "${kb_set_cmd}" $value) set -f; eval $cmd; set +f # allows us to eval multiplication (* char) test $value -eq 0 && ${notify} "Keyboard backlight has been turned off" test $value -eq 1 && ${notify} "Keyboard backlight brightness has been adjusted" elif [ ${display_new} -lt $display_ceiling ];then # adjust backlight cmd=$(printf "${kb_set_cmd}" $kb_new) set -f; eval $cmd; set +f ${notify} "Keyboard backlight brightness has been adjusted" else # display_cur is over cutoff value, turn kb backlight off cmd=$(printf "${kb_set_cmd}" 0) set -f; eval $cmd; set +f ${notify} "Keyboard backlight has been turned off" fi fi ## Set display brightness step=0 while [ $step -le $fade_steps ]; do sleep ${fade_step_ms}e-3 display_cur=$(( ${display_cur} ${direction} $brightness_step )) if [ ${display_cur} -ge ${display_max} ]; then cmd=$(printf "${display_set_cmd}" ${display_max}) set -f; eval $cmd; set +f ${notify} "The backlight is currently at the maximum brightness!" break; elif [ ${display_cur} -le ${display_min} ]; then cmd=$(printf "${display_set_cmd}" ${display_min}) set -f; eval $cmd; set +f ${notify} "The backlight has reached the minimum brightness!" break; fi cmd=$(printf "${display_set_cmd}" ${display_cur}) set -f; eval $cmd; set +f step=$(( $step + 1 )) done # make sure we can't get erroneous percent values in the notification if [ ${display_cur} -gt ${display_max} ]; then display_cur=$display_max elif [ ${display_cur} -lt ${display_min} ]; then display_cur=$display_min fi ${notify} "Current brightness set to $(( ${display_cur} * 100 / ${display_max} ))%"
This is just a hastily made README for the script. You probably don’t need it but I’ll include it here anyways.
==Keyboard Backlight Usage Tips== On my laptop the keyboard backlight uses nearly a whopping 1.5 watts of power at it's highest brightness, and almost one full watt at it's first and "lowest" brightness setting! This might not sound like much, but newer laptops are using less and less power, so this starts to seem like a pretty big piece of the battery pie chart considering this same laptop (Dell Inspiron Model: 7375) only uses about ~6 watts total power when idle! That translates in to nearly fifty minutes of battery life PER STEP! Aside from "off", there are just two steps (low or high) on this particular machine, but that still comes out to around ~1.7 hours of battery time that are lost when I use full backlight brightness! Now, keep in mind that this laptop gets nine hours of battery life under light load, so that isn't a huge percentage, but even if your battery life is only three hours, and assuming similar power consumption from the keyboard backlight (a big assumption, but...) that could still translate to roughly half an hour of battery time lost to just powering the keyboard backlight! If your watching a movie using hardware acceleration and left the keyboard backlight on then that could be the difference in seeing the ending, or not! So take a moment to consider your usage patterns and set the keyboard backlight variables appropriately! You might not want to disable the backlight at zero display brightness, but you probably don't need it on all the time and can still set the cutoff value to something conservative, say 60-80% (which would nix the kb backlight at display brightness above that percentage) so that you don't run it needlessly outside, or in bright rooms! ==bl-util Notes== Folks who haven't had to think much about display brightness often think that that brighter values in darker rooms & dimmer values in brighter rooms makes sense... the reality is quite the opposite. We want our screens brighter in bright rooms (or sunlight) because of the way our eyes adjust to deal with them relative to our surroundings. In a bright room or out in the sun our eyes dilate to let in less light. This is also why bright sunlight makes you squint, it's like our fall-back mechanism when pupil dilation isn't enough to compensate. So it turns out that we actually need brighter back-lighting in brighter settings. Likewise, in darker settings our eyes are trying to let in as much light as they can, so a bright screen can be very harsh to look at in a dark room where our eyes are trying to adjust to dim surroundings and deal with the bright screen at the same time - although we tend to deal with this scenarios better than a dim screen in bright sunlight, and I'm sure some of you reading this are old enough to remember phones and laptops that couldn't even been seen outside on a sunny day! In that case the light from our screen just wasn't enough to compete with the ambient light around us, so our dilated pupils just couldn't even see the light radiating from those old devices. I assure you, the light was indeed there... but as Einstein said, it's all relative - and relative to the sun a bright display isn't so bright. This line of reasoning is also what I'm using to deal with the screen & keyboard backlight settings in this script. Typically display backlights have a large range of values (anywhere from around a dozen levels to many thousands of levels of brightness) but keyboard backlights tend to simply have an on/off settings, or maybe some very small number of brightness levels. Even my brand new Inspiron only has only three settings: off/low/high! [Of course some fancy keyboards have many brightness levels, even RGB and other features/effects, but I'm mostly targeting laptops and their built-in keyboards here]. Despite all this, I'm certain there are some laptop keyboards that have a higher ranges of brightness values, similar to a display backlight, and this is why I'm doing some extra work here to make sure we can handle those sorts of keyboards properly, rather than just making them behave as if they just had two or three levels of brightness, like mine does. In my mind the KB backlight does have a slightly different ideal optimal behavior than the display backlight. I still believe it should be at its brightest when the display is brightest (with a caveat that I'll get to in a moment), and it should dim when the display is dimmed - generally speaking. However, with a display backlight you never really want to have the backlight turned off all together, as there's no real scenario in which it's even very readable that way, but with a keyboard the backlight can be off and you can still read the key's printed characters assuming there's enough ambient light. With this in mind it seems logical to turn off the backlight completely when there is an abundance of ambient light, and, short of using a light-sensor or web-cam to measure that, we can make assumptions on ambient light levels based on the users brightness setting. For example, if the screen backlight is set to 75% or higher, then it's safe to assume we have a lot of ambient light, either a very bright room or outdoors in the day-light, and so we can probably just turn off the KB backlight in this situation. This situation, where we kill the KB backlight in favor using ambient light to read the KB is a special case because the keyboard is still visible when we have adequate lighting. Having the ability to cut off the backlight when it is washed out by ambient light isn't that noticeable (after all, you can't really see that it's lit in bright light), however if your outside where this scenario is most likely then you will be more appreciative of the small but not completely insignificant power savings, since you are probably running on battery power in this situation! That said, there does come a point where we still have some ambient light but not enough to adequately illuminate the keys without some help. Now we will want the keyboard lit up to make our display and keys closer in brightness. Basically, this is where ambient light become inadequate to illuminate the keys sufficiently and our keyboard's backlight needs to be at its maximum brightness level. Remember, just like with the display, the more ambient light we have the brighter the backlight needs to be for it to be of benefit. It's just that there is this scenario where a bright room or sunlight are of more benefit than the backlight itself! It is only below this point where we begin to make the KB backlight behave much like the display backlight in that it should get dimmer as the ambient light gets lower. To sum it up, this is all to ensure that our screen, our keyboard and our environmental ambient light are all at similar levels so as to reduce eye strain and other issues caused by improper and highly contrasted light sources within our field of vision! I hope this all makes sense, as I am probably over-complicating it, but I think it's more likely that it's just not as simple as it seems to be at first glance. So let's say I'm working at a very minimal display brightness in a dark room - with this logic we would have our KB backlight on but set at (or near) it's lowest brightness value (we don't want the KB BL brighter than our screen, that would just be distracting and uncomfortable) and as we raise our screen brightness the KB backlight should also get brighter - but remember that we will get to a point where the screen brightness will need to continue rising and our keyboard backlight becomes useless in the brighter ambient light, so it gets cuts off as it becomes an unneeded waste of power ==Software Design Note== It would seemingly make sense to do the keyboard backlight changes within the same loop that changes the backlight display, however my KB backlight automatically does a fade effect lasting ~200ms, and since it has only two brightness levels this is obviously hard-coded and not something one can easily override (maybe even impossible from software). I might still move the KB control to the loop eventually, once I learn more about how other keyboard backlights work (not to mention the possibilities/complexities of having RGB keys, but that's a topic for another time). So right now I'm just going to stick with setting the keyboard backlight in one step before the display brightness (so the kb fade effect happens while our software display fade runs). If you have a keyboard backlight with more than a couple of brightness levels then please contact me and send me the the output of all the relevant /sys/... files, I'll certainly add the custom fade capability for KB BLs if I learn that systems out there can actually make use of it! That said, I am still implementing this in a way that will take advantage of such KB backlights, they just wont utilize the fade effect unless it is hard-coded to do so (like mine and likely many others indeed do). ==Final Thoughts== There is one other school of thought regarding brightness, an alternative to the logic of brighter backlight in a brighter environment, dimmer backlight in a darker environment. I'll call it the Graphic Designer's Profile. Now, I'm not implementing it in this script, as it would basically require the thing to do a full monitor calibration, and there's already tools out there for that (not to mention I'm not even sure my concept of gamma is 100% accurate!). Anyways, the differences are that graphic designers want optimal deep blacks and bright whites, and accuracy across the color spectrum - and for most displays there is an optimal brightness where these settings become as good they can possibly get for a particular display. Anyways, I'm not going to delve in to all of this too deeply (not that I understand it all too deeply anyhow), but suffice it to say that my script doesn't take this in to account. If this your concern you need software that helps you calibrate your display and then you need to leave this settings along. I have used some hardware devices that service this purpose, even one that supposedly calibrated for ambient lighting changes using a USB sensor - and none of these devices worked as good as the software calibration tools that rely on you picking the best options from a series of questions, just using your own eyes. They're similar to how an eye doctor prescribes glasses where they flip the lens back and forth and ask you which is best. So yeah, if your hard core in to graphics design you might want to go that route instead. You could still use my tool for adjustments and just be aware of what brightness level it is that you calibrated it, so you can make sure to return to that later. ==Ideas for the future== **USING SCREEN EVENTS TO CONTROL KEYBOARD BACKLIGHT** I know that an event is triggered when the keyboard is needed, such as when you click/touch inside a text-box that requires typing, and this would bring up an on-screen keyboard in the even that a convertible device is in tablet mode. I want to figure this out more and use those events to enable/disable the keyboard backlight. There would be other times it should be on, but this would be a great method to reduce it's power usage - and from the section Keyboard Backlight Usage Tips we do know that the kb backlight wastes a significant amount of power! **A BETTER DYNAMIC BRIGHTNESS CONTROL** I'd also like to take a stab at the concept of adjusting brightness based on screen content. For example, lets say you have your quad of dark terminals on one desktop, then you switch to your browser window and suddenly the screen is painfully bright and mostly white! We could average the screen values to adjust the brightness here, and many have already implemented this sort of thing - that said, I've yet to see it done well, or in a non-distracting sort of way. My Dell even has something like this build in, but it's horrible and everyone I've met with this feature hates it... and I met them because they were asking 'why?' how to disable it! It isn't the most intuitive thing to find in the BIOS. There's also some software, even available on Linux, to do this, but I also haven't had great luck there. I won't name names, but either the packages were just harder to setup and use than they needed to be (or I'm just dumb)... or, again, they just worked in a distracting and undesirable manner. So yeah, if anyone else things this sounds nice (assuming it was done well) or you have some ideas to do it well, then please let me know! **THAT'S IT...** ...but if you have ideas let me know! I'm not trying to compete with large projects, but rather I'm trying to make something that is small & simple to use, and has minimal dependencies, but I'd still like it to work intelligently and be feature rich! Speak up if you have ideas and if I see a pattern I'll implement them... or at least try to do so! ==Contact Info== My name is Adam Gaskins. I'm not a great Bash scripter, so if you have some tips then by all means let me know! My email is self@adamgaskins.com. I hope you find this tool useful!