From: Siraaj Khandkar Date: Mon, 30 Jul 2018 15:25:38 +0000 (-0400) Subject: Merge branch 'parallelize_and_reduce_disk_io' X-Git-Url: https://git.xandkar.net/?a=commitdiff_plain;h=b9678adeefe210353d05b4993d845e271246cec6;hp=929e2a024846e8620f0a3daea9bfd44c31c4496f;p=khatus.git Merge branch 'parallelize_and_reduce_disk_io' --- diff --git a/bin/khatus b/bin/khatus new file mode 100755 index 0000000..51bc2b2 --- /dev/null +++ b/bin/khatus @@ -0,0 +1,791 @@ +#! /bin/bash + +set -e + +produce_energy() { + upower -e \ + | grep battery \ + | xargs upower -i \ + | awk ' + /^ +percentage: +/ { percentage=$2 } + /^ +state: +/ { state=$2 } + END { print(state, percentage) } + ' +} + + +produce_memory() { + free | awk '$1 == "Mem:" {print $2, $3}' +} + +produce_fan() { + fan_path="$1" + cat "$fan_path" +} + +produce_temperature() { + thermal_zone="$1" + cat "/sys/class/thermal/thermal_zone${thermal_zone}/temp" +} + +produce_loadavg() { + cat /proc/loadavg +} + +produce_disk_io() { + disk_io_device="$1" + awk ' + { + r = $3 + w = $7 + print w, r + } + ' "/sys/block/$disk_io_device/stat" +} + +produce_disk_space() { + disk_space_device="$1" + df --output=pcent "$disk_space_device" | awk 'NR == 2 {print $1}' +} + +produce_net_addr_io() { + ip -s addr \ + | awk ' + 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"] + print(interface, addrs[interface], curr_write, curr_read) + } else { + print(interface) + } + } + }' +} + +produce_net_wifi_status() { + nmcli \ + -f ACTIVE,SSID,SIGNAL \ + -t \ + d wifi \ + | awk \ + -F ':' \ + ' + BEGIN {wifi_status = "--"} + $1 == "yes" {wifi_status = $2 ":" $3 "%"} + END {print wifi_status} + ' +} + +produce_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\n", power_status); + }' +} + +produce_screen_brightness() { + screen_brightness_device_path="$1" + echo "\ + $(cat $screen_brightness_device_path/max_brightness) \ + $(cat $screen_brightness_device_path/brightness)\ + " +} + +produce_volume() { + 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") { + print("x") + } else { + print("%s %s\n", left, right) + } + } + ' +} + +produce_mpd_state() { + echo 'status' \ + | nc 127.0.0.1 6600 \ + | awk ' + { + 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 = "~" + } + } + + END { + state = status["state:"] + + if (state == "play") { + symbol = "▶" + } else if (state == "pause") { + symbol = "❚❚" + } else if (state == "stop") { + symbol = "⬛" + } else { + symbol = "--" + } + + printf(\ + "%s %s %s\n", + status["state:"], current_time, current_percentage\ + ) + } + ' +} + +produce_mpd_song() { + echo 'currentsong' \ + | nc 127.0.0.1 6600 \ + | awk ' + /^OK/ { + next + } + + { + key = $1 + sub("^" key " +", "") + val = $0 + 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 = "" + } + print out + } + ' +} + +produce_weather() { + weather_station_id="$1" + metar -d "$weather_station_id" 2>&1 \ + | awk ' + /METAR pattern not found in NOAA data/ { + failures++ + } + + /^Temperature/ { + celsius = $3; + fahrenheit = (celsius * (9 / 5)) + 32; + temperature = fahrenheit + } + + END { + if (failures > 0) { + temperature = "--" + } + print temperature "°F" + }' +} + +produce_datetime() { + date +'%a %b %d %H:%M:%S' +} + +consume() { + pipe="$1" + debug="$2" + prefixes_of_net_interfaces_to_show="$3" + tail -f "$pipe" \ + | stdbuf -o L awk \ + -v opt_debug="$debug" \ + -v opt_mpd_song_max_chars=10 \ + -v opt_prefixes_of_net_interfaces_to_show="$prefixes_of_net_interfaces_to_show" \ + ' + /^in:ENERGY/\ + { + split_msg_parts() + db["energy_state"] = $1 + db["energy_percentage"] = $2 + } + + /^in:MEMORY/\ + { + split_msg_parts() + db["memory_total"] = $1 + db["memory_used"] = $2 + } + + /^in:FAN +status:/\ + { + split_msg_parts() + db["fan_status"] = $2 + } + + /^in:FAN +speed:/\ + { + split_msg_parts() + db["fan_speed"] = $2 + } + + /^in:FAN +level:/\ + { + split_msg_parts() + db["fan_level"] = $2 + } + + /^in:TEMPERATURE/\ + { + split_msg_parts() + db["temperature"] = $1 + } + + /^in:LOAD_AVG/\ + { + split_msg_parts() + set_load_avg() + } + + /^in:DISK_IO/\ + { + split_msg_parts() + set_disk_io() + } + + /^in:DISK_SPACE/\ + { + split_msg_parts() + db["disk_space_used"] = msg_body + } + + /^in:NET_ADDR_IO/\ + { + split_msg_parts() + set_net_addr_io() + } + + /^in:NET_WIFI_STATUS/\ + { + split_msg_parts() + db["net_wifi_status"] = msg_body + } + + /^in:BLUETOOTH_POWER/\ + { + split_msg_parts() + db["bluetooth_power"] = msg_body + } + + /^in:SCREEN_BRIGHTNESS/\ + { + split_msg_parts() + set_screen_brightness() + } + + /^in:VOLUME/\ + { + split_msg_parts() + db["volume"] = msg_body + } + + /^in:MPD_STATE/\ + { + split_msg_parts() + db["mpd_state"] = $1 + db["mpd_curr_song_time"] = $2 + db["mpd_curr_song_percent"] = $3 + } + + /^in:MPD_SONG/\ + { + split_msg_parts() + db["mpd_curr_song_name"] = msg_body + } + + /^in:WEATHER/\ + { + split_msg_parts() + db["weather_temperature"] = msg_body + } + + /^in:DATE_TIME/\ + { + split_msg_parts() + db["datetime"] = msg_body + } + + /^out:BAR/\ + { + split_msg_parts() + print make_bar() + } + + function set_load_avg( sched) { + split($4, sched, "/") + db["load_avg_1min"] = $1 + db["load_avg_5min"] = $2 + db["load_avg_15min"] = $3 + db["kern_sched_queue_runnable"] = sched[1] + db["kern_sched_queue_total"] = sched[2] + db["kern_sched_latest_pid"] = $5 + } + + function set_disk_io( curr_w, curr_r, prev_w, prev_r) { + curr_w = $1 + curr_r = $2 + prev_w = db["disk_io_curr_w"] + prev_r = db["disk_io_curr_r"] + db["disk_io_curr_w"] = curr_w + db["disk_io_curr_r"] = curr_r + db["disk_io_diff_w"] = curr_w - prev_w + db["disk_io_diff_r"] = curr_r - prev_r + } + + function set_net_addr_io( \ + interface, address, io_curr_w, io_curr_r, io_prev_w, io_prev_r\ + ) { + interface = $1 + address = $2 + io_curr_w = $3 + io_curr_r = $4 + if (interface) { + if (address && io_curr_w && io_curr_r) { + # recalculate + io_prev_w = net_io_curr_w[interface] + io_prev_r = net_io_curr_r[interface] + + net_addr[interface] = address + net_io_curr_w[interface] = io_curr_w + net_io_curr_r[interface] = io_curr_r + net_io_diff_w[interface] = io_curr_w - io_prev_w + net_io_diff_r[interface] = io_curr_r - io_prev_r + } else { + # clear + net_addr[interface] = "" + net_io_curr_w[interface] = 0 + net_io_curr_r[interface] = 0 + net_io_diff_w[interface] = 0 + net_io_diff_r[interface] = 0 + } + } + } + + function set_screen_brightness( max, cur) { + max = $1 + cur = $2 + db["screen_brightness"] = (cur / max) * 100 + } + + function split_msg_parts() { + msg_head = $1 + sub("^" msg_head " +", "") + msg_body = $0 + debug(msg_head, msg_body) + } + + function make_bar( position, bar, sep, i, j) { + position[++i] = make_status_energy() + position[++i] = make_status_mem() + position[++i] = make_status_cpu() + position[++i] = make_status_disk() + position[++i] = make_status_net() + position[++i] = sprintf("B=%s", db["bluetooth_power"]) + position[++i] = sprintf("*%d%%", db["screen_brightness"]) + position[++i] = sprintf("(%s)", db["volume"]) + position[++i] = make_status_mpd() + position[++i] = db["weather_temperature"] + position[++i] = db["datetime"] + bar = "" + sep = "" + for (j = 1; j <= i; j++) { + bar = bar sep position[j] + sep = " " + } + return bar + } + + function make_status_energy( state, direction_of_change) { + state = db["energy_state"] + if (state == "discharging") { + direction_of_change = "<" + } else if (state == "charging") { + direction_of_change = ">" + } else { + direction_of_change = "=" + }; + printf("E%s%s", direction_of_change, db["energy_percentage"]) + } + + function make_status_mem( total, used, percent, status) { + total = db["memory_total"] + used = db["memory_used"] + # To avoid division by zero when data is missing + if (total && used) { + percent = round((used / total) * 100) + status = sprintf("%d%%", percent) + } else { + status = "__" + } + return sprintf("M=%s", status) + } + + function make_status_cpu( load, temp, fan) { + load = db["load_avg_1min"] + temp = db["temperature"] / 1000 + fan = db["fan_speed"] + return sprintf("C=[%4.2f %d°C %4drpm]", load, temp, fan) + } + + function make_status_disk( bytes_per_sector, bytes_per_mb, w, r) { + bytes_per_sector = 512 + bytes_per_mb = 1024 * 1024 + w = (db["disk_io_diff_w"] * bytes_per_sector) / bytes_per_mb + r = (db["disk_io_diff_r"] * bytes_per_sector) / bytes_per_mb + return \ + sprintf("D=[%s %0.3f▲ %0.3f▼]", db["disk_space_used"], w, r) + } + + function make_status_net( \ + out, + number_of_interfaces_to_show, + n, + array_of_prefixes_of_interfaces_to_show, + prefix, + interface, + label, + count_printed, + sep, + io_stat, + dw, dr, + bytes_per_unit\ + ) { + out = "" + number_of_interfaces_to_show = \ + split(\ + opt_prefixes_of_net_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] + for (interface in net_addr) { + if (interface ~ ("^" prefix)) { + label = substr(interface, 1, 1) + if (net_addr[interface]) { + bytes_per_mb = 1024 * 1024 # TODO: option + dw = net_io_diff_w[interface] / bytes_per_mb + dr = net_io_diff_r[interface] / bytes_per_mb + io_stat = sprintf("%0.3f▲ %0.3f▼", dw, dr) + } else { + io_stat = "--" + } + if (interface ~ "^w") { + label = label ":" db["net_wifi_status"] + } + if (++count_printed > 1) { + sep = " " + } else { + sep = "" + } + out = out sep label ":" io_stat + } + } + } + return sprintf("N[%s]", out) + } + + function make_status_mpd( state, status) { + state = db["mpd_state"] + + if (state == "play") { + status = make_status_mpd_state_known("▶") + } else if (state == "pause") { + status = make_status_mpd_state_known("❚❚") + } else if (state == "stop") { + status = make_status_mpd_state_known("⬛") + } else { + status = make_status_mpd_state_unknown("--") + } + + return sprintf("[%s]", status) + } + + function make_status_mpd_state_known(symbol) { + return sprintf(\ + "%s %s %s %s", + symbol, + db["mpd_curr_song_time"], + db["mpd_curr_song_percent"], + substr(db["mpd_curr_song_name"], 1, opt_mpd_song_max_chars)\ + ) + } + + function make_status_mpd_state_unknown(symbol) { + return sprintf("%s", symbol) + } + + function round(n) { + return int(n + 0.5) + } + + function debug(location, msg) { + if (opt_debug) { + print_error(location, msg) + } + } + + function print_error(location, msg) { + print(location " ==> " msg) > "/dev/stderr" + } + ' +} + +produce_bar_req() { + echo '' +} + +spawn() { + cmd="$1" + pipe="$2" + msg_head="$3" + interval="$4" + while true; do + $cmd | while read line; do + echo "${msg_head} $line" > "$pipe" + done + sleep "$interval" + done & +} + +main() { + # Defaults + debug=0 + dir_data=$(mktemp -d) + weather_station_id='KJFK' + screen_brightness_device_name='acpi_video0' + prefixes_of_net_interfaces_to_show='w' # comma-separated + disk_space_device='/' + disk_io_device='sda' + thermal_zone=0 + fan_path='/proc/acpi/ibm/fan' + + # User-overrides + long_options='' + long_options+='debug' + long_options+=',data_dir:' + long_options+=',weather_station:' + long_options+=',screen_device:' + long_options+=',prefixes_of_net_interfaces_to_show:' + long_options+=',disk_space_device:' + long_options+=',disk_io_device:' + long_options+=',thermal_zone:' + long_options+=',fan_path:' + OPTS=$( + getopt \ + -o 'd' \ + -l $long_options \ + -- "$@" + ) + eval set -- "$OPTS" + while true + do + case "$1" in + -d|--debug) + debug=1 + shift + ;; + --data_dir) + dir_data="$2" + shift 2 + ;; + --weather_station) + weather_station_id="$2" + shift 2 + ;; + --screen_device) + screen_brightness_device_name="$2" + shift 2 + ;; + --prefixes_of_net_interfaces_to_show) + prefixes_of_net_interfaces_to_show="$2" + shift 2 + ;; + --disk_space_device) + disk_space_device="$2" + shift 2 + ;; + --disk_io_device) + disk_io_device="$2" + shift 2 + ;; + --thermal_zone) + thermal_zone="$2" + shift 2 + ;; + --fan_path) + fan_path="$2" + shift 2 + ;; + --) + shift + break + ;; + esac + done + + pipe="$dir_data/khatus_data_pipe" + screen_brightness_device_path='/sys/class/backlight' + screen_brightness_device_path+="/$screen_brightness_device_name" + + ( echo "Khatus starting with the following parameters:" + ( echo " debug|= $debug" + echo " dir_data|= $dir_data" + echo " pipe|= $pipe" + echo " screen_brightness_device_name|= $screen_brightness_device_name" + echo " screen_brightness_device_path|= $screen_brightness_device_path" + echo " weather_station_id|= $weather_station_id" + echo " prefixes_of_net_interfaces_to_show|= $prefixes_of_net_interfaces_to_show" + echo " disk_space_device|= $disk_space_device" + echo " disk_io_device|= $disk_io_device" + echo " thermal_zone|= $thermal_zone" + echo " fan_path|= $fan_path" + ) | column -ts\| + echo '' + ) >&2 + + mkdir -p "$dir_data" + rm -f "$pipe" + mkfifo "$pipe" + + cmd_produce_screen_brightness='produce_screen_brightness' + cmd_produce_screen_brightness+=" $screen_brightness_device_path" + + cmd_produce_weather="produce_weather $weather_station_id" + + cmd_produce_disk_space="produce_disk_space $disk_space_device" + + cmd_produce_disk_io="produce_disk_io $disk_io_device" + + cmd_produce_temperature="produce_temperature $thermal_zone" + + cmd_produce_fan="produce_fan $fan_path" + + # TODO: Redirect each worker's stderr to a dedicated log file + spawn produce_datetime "$pipe" 'in:DATE_TIME' 1 + spawn "$cmd_produce_screen_brightness" "$pipe" 'in:SCREEN_BRIGHTNESS' 1 + spawn "$cmd_produce_weather" "$pipe" 'in:WEATHER' $(( 30 * 60 )) + spawn produce_mpd_state "$pipe" 'in:MPD_STATE' 1 + spawn produce_mpd_song "$pipe" 'in:MPD_SONG' 1 + spawn produce_volume "$pipe" 'in:VOLUME' 1 + spawn produce_bluetooth_power "$pipe" 'in:BLUETOOTH_POWER' 5 + spawn produce_net_wifi_status "$pipe" 'in:NET_WIFI_STATUS' 5 + spawn produce_net_addr_io "$pipe" 'in:NET_ADDR_IO' 1 + spawn "$cmd_produce_disk_space" "$pipe" 'in:DISK_SPACE' 1 + spawn "$cmd_produce_disk_io" "$pipe" 'in:DISK_IO' 1 + spawn produce_loadavg "$pipe" 'in:LOAD_AVG' 1 + spawn "$cmd_produce_temperature" "$pipe" 'in:TEMPERATURE' 1 + spawn "$cmd_produce_fan" "$pipe" 'in:FAN' 1 + spawn produce_memory "$pipe" 'in:MEMORY' 1 + spawn produce_energy "$pipe" 'in:ENERGY' 1 + spawn produce_bar_req "$pipe" 'out:BAR' 1 + + consume \ + "$pipe" \ + "$debug" \ + "$prefixes_of_net_interfaces_to_show" +} + +main $@ diff --git a/bin/khatus_cpu_usage_from_proc_since_last_check b/bin/khatus_cpu_usage_from_proc_since_last_check deleted file mode 100755 index e76d21d..0000000 --- a/bin/khatus_cpu_usage_from_proc_since_last_check +++ /dev/null @@ -1,99 +0,0 @@ -#! /bin/sh - -proc_stat_parse() { - proc_stat="$1" - n='[0-9]\+' - echo "$proc_stat" \ - | grep "^cpu$n $n $n $n $n $n $n $n $n $n $n$" \ - | awk ' - { - cpu = $1; - user = $2; - sys = $4; - idle = $5; - - total = user + sys + idle; - busy = user + sys; - - if (NR > 1) {printf " "}; - - out = sprintf("%s %d %d", cpu, total, busy); - #print out >> "cpu_usage_debug.txt"; - printf "%s", out; - } - END { - #print "" >> "cpu_usage_debug.txt"; - print ""; - } - ' -} - -calc_delta() { - for proc_stat in "$1" "$2"; do - proc_stat_parse "$proc_stat" - done \ - | awk ' - { - t = NR; - for (i = 1; i <= (NF - 2); i += 3) { - cpu_count[t]++; - cpu_id = $i; # For occasional debugging - total = $(i + 1); - busy = $(i + 2); - cpu[cpu_count[t], "total", t] = total; - cpu[cpu_count[t], "busy" , t] = busy; - } - } - - END { - for (c=1; c<=cpu_count[2]; c++) { - total_1 = cpu[c, "total", 1]; - total_2 = cpu[c, "total", 2]; - busy_1 = cpu[c, "busy" , 1]; - busy_2 = cpu[c, "busy" , 2]; - total_d = total_2 - total_1; - busy_d = busy_2 - busy_1; - percent_busy = (busy_d / total_d) * 100; - - #printf(\ - # "c: %d, total_1: %f total_2: %f, total_d: %f\n", - # c, total_1, total_2, total_d \ - #) >> "cpu_usage_debug.txt"; - #printf(\ - # "c: %d, busy_1: %f busy_2: %f, busy_d: %f\n", - # c, busy_1, busy_2, busy_d \ - #) >> "cpu_usage_debug.txt"; - #printf(\ - # "c: %d, percent_busy: %f\n", - # c, percent_busy \ - #) >> "cpu_usage_debug.txt"; - - if (c > 1) {printf " "}; - out = sprintf("%3.0f%%", percent_busy) - #printf "c: %d, out: %s\n", c, out >> "cpu_usage_debug.txt"; - printf "%s", out; - } - #print "" >> "cpu_usage_debug.txt"; - print ""; - } - ' -} - -main() { - last_proc_stat="$HOME/var/run/cpu_usage_from_proc_since_last_check/last_proc_stat" - - if [ ! -f "$last_proc_stat" ] - then - mkdir -p `dirname "$last_proc_stat"` - cat /proc/stat > "$last_proc_stat" - sleep 0.1 - fi - - previous=`cat $last_proc_stat`; - cat /proc/stat > "$last_proc_stat" - current=`cat $last_proc_stat`; - - calc_delta "$previous" "$current" -} - -main $@ diff --git a/bin/khatus_show b/bin/khatus_show deleted file mode 100755 index 5170492..0000000 --- a/bin/khatus_show +++ /dev/null @@ -1,577 +0,0 @@ -#! /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 \ -" diff --git a/bin/khatus_update_network b/bin/khatus_update_network deleted file mode 100755 index f3b562f..0000000 --- a/bin/khatus_update_network +++ /dev/null @@ -1,37 +0,0 @@ -#! /bin/bash - -set -e - -#TERM=xterm-256color # To keep unicode charcters from BARS - -STATUS_DIR=$HOME/var/run/status -STATUS_FILE_WIFI=$STATUS_DIR/wifi -STATUS_FILE_ETH=$STATUS_DIR/eth - -mkdir -p $STATUS_DIR - -# nmcli d \ -# | awk \ -# -v file_wifi="$STATUS_FILE_WIFI" \ -# -v file_eth="$STATUS_FILE_ETH" \ -# ' -# $2 == "wifi" {wifi = $4} -# $2 == "ethernet" {eth=$4} -# END { -# print(wifi) > file_wifi; -# print(eth) > file_eth; -# } -# ' - -nmcli \ - -f ACTIVE,SSID,SIGNAL \ - -t \ - d wifi \ -| awk \ - -F ':' \ - -v file_wifi="$STATUS_FILE_WIFI" \ - ' - BEGIN {wifi_status = "--"} - $1 == "yes" {wifi_status = $2 ":" $3 "%"} - END {print wifi_status > file_wifi} - ' diff --git a/bin/khatus_update_weather b/bin/khatus_update_weather deleted file mode 100755 index 665ae07..0000000 --- a/bin/khatus_update_weather +++ /dev/null @@ -1,35 +0,0 @@ -#! /bin/bash - -set -e - -STATION_ID="$1" # ICAO designator. e.g. KJFK, KBOS - -FILE_METAR_DECODED="$HOME/var/run/metar-${STATION_ID}-decoded" -FILE_TEMP_FAHRENHEIT="${FILE_METAR_DECODED}-temp-fahrenheit" -FILE_TEMP_CELSIUS="${FILE_METAR_DECODED}-temp-celsius" - -(metar -d "$STATION_ID" 2>&1) > $FILE_METAR_DECODED # TODO: Better error handling - -awk \ - -v file_fahrenheit="$FILE_TEMP_FAHRENHEIT" \ - -v file_celsius="$FILE_TEMP_CELSIUS" \ - ' - /METAR pattern not found in NOAA data/ { - failures++ - } - - /^Temperature/ { - celsius = $3; - fahrenheit = (celsius * (9 / 5)) + 32; - } - - END { - if (failures > 0) { - print "--" > file_fahrenheit - print "--" > file_celsius - } else { - print fahrenheit > file_fahrenheit - print celsius > file_celsius - } - }' \ - $FILE_METAR_DECODED diff --git a/install b/install index 44fa3fe..ca12cc4 100755 --- a/install +++ b/install @@ -11,5 +11,5 @@ cd bin for filename in * do - ln -s "`pwd`/$filename" "$PREFIX/$filename" + cp -p "`pwd`/$filename" "$PREFIX/$filename" done diff --git a/screenshot.jpg b/screenshot.jpg index e2dec88..6f9f660 100644 Binary files a/screenshot.jpg and b/screenshot.jpg differ