#!/usr/bin/env bash # rice-power - system stats and power actions for the eww panel and power menu. # # rice-power info JSON: CPU/GPU load and temperature, memory, uptime, profile # rice-power profile power-saver | balanced | performance # rice-power lock|suspend|logout|reboot|shutdown # logout, reboot and shutdown ask first set -uo pipefail run="${XDG_RUNTIME_DIR:-/tmp}/rice" mkdir -p "$run" # CPU load since the previous call (the panel polls every few seconds). cpu_load() { local now prev idle total pidle ptotal read -r _ user nice system idle iowait irq softirq steal _ < /proc/stat total=$((user + nice + system + idle + iowait + irq + softirq + steal)) idle=$((idle + iowait)) if [[ -f $run/cpu.prev ]]; then read -r pidle ptotal < "$run/cpu.prev" (( total > ptotal )) && echo $(( 100 * ((total - ptotal) - (idle - pidle)) / (total - ptotal) )) || echo 0 else echo 0 fi echo "$idle $total" > "$run/cpu.prev" } info() { local sensors gpu_dev profile profiles sensors=$(sensors -j 2>/dev/null || echo '{}') gpu_dev=$(ls -d /sys/class/drm/card*/device 2>/dev/null | while read -r d; do [[ -f $d/gpu_busy_percent ]] && echo "$d" && break; done) profile=$(powerprofilesctl get 2>/dev/null || echo "") profiles=$(powerprofilesctl list 2>/dev/null | sed -n 's/^[* ]*\([a-z-]*\):$/\1/p' | jq -R -s -c 'split("\n") | map(select(length > 0))') jq -cn \ --argjson sensors "$sensors" \ --argjson cpu "$(cpu_load)" \ --arg gpubusy "$( [[ -n $gpu_dev ]] && cat "$gpu_dev/gpu_busy_percent" 2>/dev/null)" \ --arg vramused "$( [[ -n $gpu_dev ]] && cat "$gpu_dev/mem_info_vram_used" 2>/dev/null)" \ --arg vramtotal "$( [[ -n $gpu_dev ]] && cat "$gpu_dev/mem_info_vram_total" 2>/dev/null)" \ --arg mem "$(free -b | awk '/^Mem:/ { print $3 " " $2 }')" \ --arg uptime "$(uptime -p | sed 's/^up //; s/ hours\?/h/; s/ minutes\?/m/; s/ days\?/d/; s/,//g')" \ --arg profile "$profile" --argjson profiles "${profiles:-[]}" ' def temp($pat): [$sensors | to_entries[] | select(.key | test($pat)) | .value | to_entries[] | select(.key | test("^(Tctl|Tdie|edge|Package id 0|temp1)$")) | .value | to_entries[] | select(.key | endswith("_input")) | .value] | first // null; def gib: (. / 1073741824 * 10 | round / 10 | tostring) + "G"; ($mem | split(" ") | map(tonumber)) as [$mused, $mtotal] | { cpu: {load: $cpu, temp: (temp("k10temp|coretemp|zenpower") | if . then round else null end)}, gpu: {load: ($gpubusy | tonumber? // null), temp: (temp("amdgpu|radeon|nouveau") | if . then round else null end), vram: (if $vramtotal != "" then (($vramused | tonumber | gib) + " / " + ($vramtotal | tonumber | gib)) else "" end)}, memory: {used: ($mused | gib), total: ($mtotal | gib), percent: ($mused * 100 / $mtotal | round)}, uptime: $uptime, profile: $profile, profiles: [ $profiles[] | {name: ., label: ({"power-saver": "saver", "balanced": "balanced", "performance": "performance"}[.] // .), active: (. == $profile)} ] }' } confirm() { local answer answer=$(printf '%s\nCancel\n' "$1" | rofi -dmenu -theme "$HOME/.config/rofi/menu.rasi" -p "$2" -mesg "Are you sure?") || return 1 [[ $answer == "$1" ]] } case "${1:-}" in info) info ;; profile) [[ ${2:-} =~ ^(power-saver|balanced|performance)$ ]] || { echo "rice-power: unknown profile '${2:-}'" >&2; exit 2; } powerprofilesctl set "$2" && rice-notify send "Power profile" "$2" -i power-profile-"$2"-symbolic ;; lock) rice-panel close; rice-lock ;; suspend) rice-panel close; systemctl suspend ;; logout) rice-panel close; confirm "󰍃 Log out" "Log out" && bspc quit ;; reboot) rice-panel close; confirm "󰜉 Reboot" "Reboot" && systemctl reboot ;; shutdown) rice-panel close; confirm "󰐥 Shut down" "Shut down" && systemctl poweroff ;; *) sed -n '2,8p' "$0" | sed 's/^# \{0,1\}//'; exit 2 ;; esac