#! /bin/bash set -e BIN=$HOME/bin STATUS_DIR=$HOME/var/run/status STATUS_FILE__WIFI=$STATUS_DIR/wifi STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF=$STATUS_DIR/notified_energy_bellow_half while getopts ":b:d:s:i:w:" opt do case "$opt" in b) SCREEN_BRIGHTNESS_DEVICE_NAME="$OPTARG" ;; d) DISK_IO_DEVICE="$OPTARG" ;; s) DISK_SPACE_DEVICE="$OPTARG" ;; i) PREFIXES_OF_INTERFACES_TO_SHOW="$OPTARG" ;; w) WEATHER_STATION_ID="$OPTARG" ;; \?) echo "Unknown option: $OPTARG" >&2 exit 1 ;; :) echo "Missing argument for option: $OPTARG" >&2 exit 1 ;; esac done if [ "$SCREEN_BRIGHTNESS_DEVICE_NAME" == '' ]; then echo 'Missing -b' >&2; exit 1; fi if [ "$DISK_IO_DEVICE" == '' ]; then echo 'Missing -d' >&2; exit 1; fi if [ "$DISK_SPACE_DEVICE" == '' ]; then echo 'Missing -s' >&2; exit 1; fi if [ "$WEATHER_STATION_ID" == '' ]; then echo 'Missing -w' >&2; exit 1; fi SCREEN_BRIGHTNESS_DEVICE_PATH="/sys/class/backlight/$SCREEN_BRIGHTNESS_DEVICE_NAME" load=$(awk '{printf("%4.2f", $1)}' /proc/loadavg) fan=$(awk '/^speed:/ {printf "%4d", $2}' /proc/acpi/ibm/fan) #cpu=$($BIN/khatus_cpu_usage_from_proc_since_last_check) memory=$( free \ | awk ' function round(n) {return int(n + 0.5)} $1 == "Mem:" { total=$2; used=$3; cache=$6; prev_file = ENVIRON["HOME"] "/var/run/status/memory_used_percentage"; curr = round(used / total * 100); getline prev < prev_file; print curr > prev_file; if (curr > prev) { direction = ">"; } else if (curr < prev) { direction = "<"; } else { direction = "="; } printf("%s%d%%", direction, curr); }') temp=$(awk 'NR == 1 {print $1 / 1000}' /sys/class/thermal/thermal_zone0/temp) disk_io=$( awk ' { bytes_per_sector = 512 bytes_per_unit = 1024 * 1024 curr_sectors_read = $3 curr_sectors_write = $7 prev_file_prefix = ENVIRON["HOME"] "/var/run/status/disk_io" prev_sectors_read_file = prev_file_prefix "_sectors_read" prev_sectors_write_file = prev_file_prefix "_sectors_write" getline prev_sectors_read < prev_sectors_read_file getline prev_sectors_write < prev_sectors_write_file diff_read_sectors = (curr_sectors_read - prev_sectors_read) diff_write_sectors = (curr_sectors_write - prev_sectors_write) diff_read_bytes = diff_read_sectors * bytes_per_sector diff_write_bytes = diff_write_sectors * bytes_per_sector diff_read = diff_read_bytes / bytes_per_unit diff_write = diff_write_bytes / bytes_per_unit print curr_sectors_read > prev_sectors_read_file print curr_sectors_write > prev_sectors_write_file printf("%0.3f▲ %0.3f▼\n", diff_write, diff_read); } ' "/sys/block/$DISK_IO_DEVICE/stat" ) disk=$( df \ | awk \ -v disk_io="$disk_io" \ -v device="$DISK_SPACE_DEVICE" \ ' function round(n) {return int(n + 0.5)} $1 == device { curr_perc = $5; sub("%$", "", curr_perc); prev_perc_file = ENVIRON["HOME"] "/var/run/status/disk_space_used"; getline prev_perc < prev_perc_file; print curr_perc > prev_perc_file; if (curr_perc > prev_perc) { direction = ">"; } else if (curr_perc < prev_perc) { direction = "<"; } else { direction = "="; } printf("%s[%d%% %s]", direction, curr_perc, disk_io); }') # TODO: Wi-Fi status file should be a file per-wifi-device network=$( ip -s addr \ | awk \ -v wifi_conn="$(cat $STATUS_FILE__WIFI)" \ -v prefixes_of_interfaces_to_show="$PREFIXES_OF_INTERFACES_TO_SHOW" \ ' BEGIN { bytes_per_unit = 1024 * 1024 } /^[0-9]+:/ { sub(":$", "", $1) sub(":$", "", $2) sequence = $1 interface = $2 interfaces[sequence] = interface } /^ +inet [0-9]/ { sub("/[0-9]+", "", $2) addr = $2 addrs[interface] = addr } /^ +RX: / {transfer_direction = "r"} /^ +TX: / {transfer_direction = "w"} /^ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ +[0-9]+ *$/ { io[interface, transfer_direction] = $1; } END { for (seq=1; seq<=sequence; seq++) { interface = interfaces[seq] label = substr(interface, 1, 1) if (addrs[interface]) { curr_read = io[interface, "r"] curr_write = io[interface, "w"] prefix = ENVIRON["HOME"] "/var/run/status/io_net_" interface prev_read_file = prefix "_read" prev_write_file = prefix "_write" getline prev_read < prev_read_file getline prev_write < prev_write_file diff_read = (curr_read - prev_read ) / bytes_per_unit diff_written = (curr_write - prev_write) / bytes_per_unit print curr_read > prev_read_file print curr_write > prev_write_file io_stat = sprintf("%0.3f▲ %0.3f▼", diff_written, diff_read) if (interface ~ "^w") { label = label ":" wifi_conn } } else { io_stat = "--" } number_of_interfaces_to_show = \ split(\ prefixes_of_interfaces_to_show,\ array_of_prefixes_of_interfaces_to_show,\ " +"\ ) for (n = 1; n <= number_of_interfaces_to_show; n++) { prefix = array_of_prefixes_of_interfaces_to_show[n] if (interface ~ ("^" prefix)) { if (++count_printed > 1) { sep = " " } else { sep = "" } printf("%s%s:%s", sep, label, io_stat) } } } }' ) energy=$( upower -e \ | grep battery \ | xargs upower -i \ | awk ' /^ +percentage: +/ {percentage=$2} /^ +state: +/ {state=$2} END { if (state == "discharging") { direction_of_change = "<" } else if (state == "charging") { direction_of_change = ">" } else { direction_of_change = "=" }; printf("%s%s", direction_of_change, percentage) }') datetime=$(date +'%a %b %d %H:%M:%S') #datetime=$( # date +'%a %u %b %d %H:%M:%S' \ # | awk ' # { # wday_name = $1 # wday_seq = $2 # month = $3 # mday = $4 # time = $5 # # week = "" # for (i=1; i<=7; i++) { # if (i == 6 || i == 4) { # sep = " " # } else { # sep = "" # } # # if (i == wday_seq) { # #symbol = substr(wday_name, 1, 1) # symbol = "/" # } else if (i < wday_seq){ # symbol = "X" # } else { # symbol = "_" # } # week = week sep symbol # } # # print "["week"]", month, mday, time; # } # ' #) #volume_amixer=$( # amixer get Master \ # | tail -1 \ # | awk ' # { # level = $4; # sub("^\\[", "", level); # sub("\\]$", "", level); # print level; # }' \ # ) #volume_amixer=$( # amixer get Master \ # | tail -n 1 \ # | awk '{print $4}' \ # | tr -d '[]' #) volume_pactl=$( pactl list sinks \ | awk ' /^\tMute:/ { printf("%s,", $0); } /^\tVolume:/ { for (i=2; i<=NF; i++) printf(" %s", $i); }' \ | awk -v RS=',' ' /^[ \t]*Mute:/ {mute = $2} /^[ \t]*front-left:/ {left = $4} /^[ \t]*front-right:/ {right = $4} END { if (mute == "yes") { printf("x") } else { printf("%s %s", left, right) } } ' ) volume="($volume_pactl)" screen_brightness=$( echo -n $(( $(cat $SCREEN_BRIGHTNESS_DEVICE_PATH/brightness) / $(cat $SCREEN_BRIGHTNESS_DEVICE_PATH/max_brightness) * 100 )) ) #bluetooth_status=$( # grep '^status:' /proc/acpi/ibm/bluetooth \ # | awk ' # $2 == "disabled" {printf "off"} # $2 == "enabled" {printf "on"} # ' #) bluetooth_power=$( echo -e 'show \n quit' \ | bluetoothctl \ | awk ' /^Controller / { controller = $2; controllers[++ctrl_count] = controller; } /^\t[A-Z][A-Za-z]+:/ { key = $1; sub(":$", "", key); val = $2; for (i=3; i<=NF; i++) { val = val " " $i}; data[controller, key] = val; } END { # Using the 1st seen controller. Should we select specific instead? power_status = data[controllers[1], "Powered"]; if (ctrl_count > 0) { if (power_status == "no") { power_status = "off" } else if (power_status == "yes") { power_status = "on" } else { printf("Unexpected bluetooth power status: %s\n", power_status)\ > "/dev/stderr"; power_status = "ERROR" } } else { power_status = "off" # TODO: Perhaps use differentiated marker? } printf("%s", power_status); }' ) #touchpad_status=$( # xinput list-props 12 \ # | awk ' # /^\tDevice Enabled \([0-9]+\):/ { # status = $4; # printf("%s", status); # }' #) #color_off='\033[0m' #color_on_bg_gray='\033[m\033[40m' energy_direction=$(echo "$energy" | cut -b 1) energy_percentage=$(echo "$energy" | tr -d '<>=%') if [[ "$energy_direction" = '<' ]] then if [[ $energy_percentage -le 5 ]] then DISPLAY=:0.0 notify-send \ -u critical \ "Energy CRITICALLY low: $energy" \ 'CHARGE NOW!!! GO GO GO!!!' elif [[ $energy_percentage -le 10 ]] then DISPLAY=:0.0 notify-send \ -u critical \ "Energy VERY low: $energy" \ 'Plug it in ASAP.' elif [[ $energy_percentage -le 15 ]] then DISPLAY=:0.0 notify-send \ -u critical \ "Energy low: $energy" \ 'Get the charger.' elif [[ $energy_percentage -le 50 ]] then if [[ ! -a "$STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF" ]] then DISPLAY=:0.0 notify-send \ -u normal \ "Energy bellow half: $energy" \ 'Where is the charger?' touch "$STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF" fi fi else rm -f "$STATUS_FILE__ENERGY_NOTIFIED_BELLOW_HALF" fi weather=$( awk \ 'NR == 1 {printf("%s°F", $1)}' \ "$HOME/var/run/metar-${WEATHER_STATION_ID}-decoded-temp-fahrenheit" ) #signal_last_msg_age=$( # ls -lt --time-style=+%s $HOME/var/lib/signal/latest_message.json \ # | awk -v now_seconds=$(date +%s) \ # '{ # mtime_seconds = $6; # seconds = now_seconds - mtime_seconds; # minutes = seconds / 60; # hours = minutes / 60; # days = hours / 24; # weeks = days / 7; # months = days / 30; # #fmt = "%.1f"; # fmt = "%d"; # printf(fmt " s\n", seconds); # printf(fmt " m\n", minutes); # printf(fmt " h\n", hours); # printf(fmt " d\n", days); # printf(fmt " w\n", weeks); # printf(fmt " mo\n", months); # }' \ # | awk '$1 >= 1' \ # | sort -n -k 1 \ # | head -1 \ # | tr -d ' ' #) mpd_currentsong=$( echo 'currentsong' \ | nc 127.0.0.1 6600 \ | awk -v max_chars=10 ' /^OK/ { next } { key = $1 val = $2 for (i=3; i<=NF; i++) {val = val " " $i} data[key] = val } END { name = data["Name:"] title = data["Title:"] file = data["file:"] if (name) { out = name } else if (title) { out = title } else if (file) { last = split(file, parts, "/") out = parts[last] } else { out = "" } printf("%s", substr(out, 1, max_chars)) } ' ) mpd_state=$( echo 'status' \ | nc 127.0.0.1 6600 \ | awk \ -v current_song="$mpd_currentsong" \ ' { status[$1] = $2 } /^time: +[0-9]+:[0-9]+$/ { split($2, time, ":") seconds_current = time[1] seconds_total = time[2] hours = int(seconds_current / 60 / 60); secs_beyond_hours = seconds_current - (hours * 60 * 60); mins = int(secs_beyond_hours / 60); secs = secs_beyond_hours - (mins * 60); if (hours > 0) { current_time = sprintf("%d:%.2d:%.2d", hours, mins, secs) } else { current_time = sprintf("%.2d:%.2d", mins, secs) } if (seconds_total > 0) { time_percentage = (seconds_current / seconds_total) * 100 current_percentage = sprintf("%d%%", time_percentage) } else { current_percentage = "~" } } function print_known_state(symbol) { printf(\ "%s %s %s %s", symbol, current_time, current_percentage, current_song \ ) } function print_unknown_state(symbol) { printf("%s", symbol) } END { state = status["state:"] if (state == "play") { print_known_state("▶") } else if (state == "pause") { print_known_state("❚❚") } else if (state == "stop") { print_known_state("⬛") } else { print_unknown_state("--") } } ' ) #graphics_card=$( #nvidia-smi \ #--format=csv,noheader,nounits \ #--query-gpu=memory.total,memory.used,temperature.gpu \ #| awk -F ',' ' #{ #mem_total = $1; #mem_used = $2; #temp = $3; #mem_used_percent = (100 * mem_used) / mem_total; #printf("[%d%% %dC]", mem_used_percent, temp); #} #' #) echo \ "\ E$energy\ \ M$memory\ \ C=[$load ${temp}°C ${fan}rpm]\ \ D$disk\ \ N:[$network]\ \ B:$bluetooth_power\ \ *$screen_brightness%\ \ $volume\ \ [$mpd_state]\ \ $weather\ \ $datetime \ "