169 lines
4.1 KiB
Bash
Executable File
169 lines
4.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# blob:summary=Show or adjust DDC/CI display brightness for a Hyprland monitor.
|
|
# blob:args=<monitor> [+N%|N%-|N%]
|
|
# blob:examples=blob-brightness-ddc DP-1 | blob-brightness-ddc DP-1 50%
|
|
|
|
monitor="${1:-}"
|
|
step="${2:-}"
|
|
|
|
[[ -n $monitor ]] || exit 1
|
|
|
|
cache_dir="${XDG_RUNTIME_DIR:-/tmp}/blob-brightness-ddc"
|
|
cache_name="${monitor//[^[:alnum:]_.-]/_}"
|
|
cache_file="$cache_dir/$cache_name.bus"
|
|
unavailable_cache_seconds=60
|
|
range_cache_seconds=10
|
|
|
|
cache_unavailable() {
|
|
mkdir -p "$cache_dir" 2>/dev/null || true
|
|
printf 'unavailable %s\n' "$(date +%s)" >"$cache_file" 2>/dev/null || true
|
|
}
|
|
|
|
detect_bus() {
|
|
ddcutil --skip-ddc-checks detect --brief 2>/dev/null | awk -v monitor="$monitor" '
|
|
/I2C bus:/ {
|
|
bus = $NF
|
|
sub(/^.*\/i2c-/, "", bus)
|
|
}
|
|
|
|
/DRM connector:/ {
|
|
connector = $NF
|
|
sub(/^card[0-9]+-/, "", connector)
|
|
if (connector == monitor && bus != "") {
|
|
print bus
|
|
exit
|
|
}
|
|
bus = ""
|
|
}
|
|
'
|
|
}
|
|
|
|
find_bus() {
|
|
local bus=""
|
|
local cached_value=""
|
|
local now=0
|
|
|
|
if [[ -r $cache_file ]]; then
|
|
read -r bus cached_value <"$cache_file" || true
|
|
fi
|
|
|
|
if [[ $bus == "unavailable" ]]; then
|
|
now=$(date +%s)
|
|
if [[ $cached_value =~ ^[0-9]+$ ]] && (( now - cached_value < unavailable_cache_seconds )); then
|
|
return 1
|
|
fi
|
|
bus=""
|
|
rm -f "$cache_file"
|
|
fi
|
|
|
|
if [[ -z $bus ]]; then
|
|
bus="$(detect_bus)" || return 1
|
|
if [[ ! $bus =~ ^[0-9]+$ ]]; then
|
|
cache_unavailable
|
|
return 1
|
|
fi
|
|
mkdir -p "$cache_dir" 2>/dev/null || true
|
|
printf '%s\n' "$bus" >"$cache_file" 2>/dev/null || true
|
|
fi
|
|
|
|
printf '%s\n' "$bus"
|
|
}
|
|
|
|
read_vcp() {
|
|
local bus="$1"
|
|
|
|
ddcutil --bus "$bus" --skip-ddc-checks getvcp 10 --brief 2>/dev/null | awk '
|
|
$1 == "VCP" && toupper($2) == "10" && $3 == "C" && $4 ~ /^[0-9]+$/ && $5 ~ /^[0-9]+$/ && $5 > 0 {
|
|
print $4, $5
|
|
found = 1
|
|
exit
|
|
}
|
|
|
|
END { exit !found }
|
|
'
|
|
}
|
|
|
|
read_brightness() {
|
|
local bus=""
|
|
local now=0
|
|
local values=""
|
|
|
|
bus="$(find_bus)" || return 1
|
|
values="$(read_vcp "$bus")" || {
|
|
rm -f "$cache_file"
|
|
return 1
|
|
}
|
|
|
|
now=$(date +%s)
|
|
mkdir -p "$cache_dir" 2>/dev/null || true
|
|
printf '%s %s %s\n' "$bus" "${values##* }" "$now" >"$cache_file" 2>/dev/null || true
|
|
printf '%s %s\n' "$bus" "$values"
|
|
}
|
|
|
|
bus=""
|
|
current=""
|
|
maximum=""
|
|
percent=""
|
|
range_cached_at=""
|
|
|
|
if [[ -z $step ]]; then
|
|
read -r bus current maximum < <(read_brightness) || exit 1
|
|
[[ -n ${bus:-} && -n ${current:-} && -n ${maximum:-} ]] || exit 1
|
|
(( percent = (current * 100 + maximum / 2) / maximum ))
|
|
printf '%s\n' "$percent"
|
|
exit 0
|
|
fi
|
|
|
|
if [[ $step =~ ^([0-9]+)%$ ]]; then
|
|
target="${BASH_REMATCH[1]}"
|
|
range_cache_fresh=0
|
|
if [[ -r $cache_file ]]; then
|
|
read -r bus maximum range_cached_at <"$cache_file" || true
|
|
fi
|
|
|
|
if [[ $bus =~ ^[0-9]+$ && $maximum =~ ^[0-9]+$ && $range_cached_at =~ ^[0-9]+$ ]] && (( maximum > 0 )); then
|
|
now=$(date +%s)
|
|
if (( range_cached_at <= now && now - range_cached_at < range_cache_seconds )); then
|
|
range_cache_fresh=1
|
|
fi
|
|
fi
|
|
|
|
if (( ! range_cache_fresh )); then
|
|
read -r bus current maximum < <(read_brightness) || exit 1
|
|
fi
|
|
elif [[ $step =~ ^\+([0-9]+)%$ ]]; then
|
|
read -r bus current maximum < <(read_brightness) || exit 1
|
|
[[ -n ${bus:-} && -n ${current:-} && -n ${maximum:-} ]] || exit 1
|
|
(( percent = (current * 100 + maximum / 2) / maximum ))
|
|
amount="${BASH_REMATCH[1]}"
|
|
if (( amount == 5 && percent < 5 )); then
|
|
(( target = percent + 1 ))
|
|
else
|
|
(( target = percent + amount ))
|
|
fi
|
|
elif [[ $step =~ ^([0-9]+)%-$ ]]; then
|
|
read -r bus current maximum < <(read_brightness) || exit 1
|
|
[[ -n ${bus:-} && -n ${current:-} && -n ${maximum:-} ]] || exit 1
|
|
(( percent = (current * 100 + maximum / 2) / maximum ))
|
|
amount="${BASH_REMATCH[1]}"
|
|
if (( amount == 5 && percent <= 5 )); then
|
|
(( target = percent - 1 ))
|
|
else
|
|
(( target = percent - amount ))
|
|
fi
|
|
else
|
|
exit 1
|
|
fi
|
|
|
|
(( target < 1 )) && target=1
|
|
(( target > 100 )) && target=100
|
|
(( raw_target = (target * maximum + 50) / 100 ))
|
|
|
|
if ! ddcutil --bus "$bus" --skip-ddc-checks --noverify setvcp 10 "$raw_target" >/dev/null 2>&1; then
|
|
rm -f "$cache_file"
|
|
exit 1
|
|
fi
|
|
|
|
printf '%s\n' "$target"
|