diff --git a/advanced/Scripts/chronometer.sh b/advanced/Scripts/chronometer.sh index 4bc090f2..046a98c4 100755 --- a/advanced/Scripts/chronometer.sh +++ b/advanced/Scripts/chronometer.sh @@ -12,540 +12,537 @@ LC_NUMERIC=C # Retrieve stats from FTL engine pihole-FTL() { - ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null) - if [[ -n "$ftl_port" ]]; then - # Open connection to FTL - exec 3<>"/dev/tcp/127.0.0.1/$ftl_port" + ftl_port=$(cat /var/run/pihole-FTL.port 2> /dev/null) + if [[ -n "$ftl_port" ]]; then + # Open connection to FTL + exec 3<>"/dev/tcp/127.0.0.1/$ftl_port" - # Test if connection is open - if { "true" >&3; } 2> /dev/null; then - # Send command to FTL - echo -e ">$1" >&3 + # Test if connection is open + if { "true" >&3; } 2> /dev/null; then + # Send command to FTL + echo -e ">$1" >&3 - # Read input - read -r -t 1 LINE <&3 - until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do - echo "$LINE" >&1 - read -r -t 1 LINE <&3 - done + # Read input + read -r -t 1 LINE <&3 + until [[ ! $? ]] || [[ "$LINE" == *"EOM"* ]]; do + echo "$LINE" >&1 + read -r -t 1 LINE <&3 + done - # Close connection - exec 3>&- - exec 3<&- - fi - else - echo "0" - fi + # Close connection + exec 3>&- + exec 3<&- + fi + else + echo "0" + fi } # Print spaces to align right-side additional text printFunc() { - local text_last + local text_last - title="$1" - title_len="${#title}" + title="$1" + title_len="${#title}" - text_main="$2" - text_main_nocol="$text_main" - if [[ "${text_main:0:1}" == "" ]]; then - text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main") - fi - text_main_len="${#text_main_nocol}" + text_main="$2" + text_main_nocol="$text_main" + if [[ "${text_main:0:1}" == "" ]]; then + text_main_nocol=$(sed 's/\[[0-9;]\{1,5\}m//g' <<< "$text_main") + fi + text_main_len="${#text_main_nocol}" - text_addn="$3" - if [[ "$text_addn" == "last" ]]; then - text_addn="" - text_last="true" - fi + text_addn="$3" + if [[ "$text_addn" == "last" ]]; then + text_addn="" + text_last="true" + fi - # If there is additional text, define max length of text_main - if [[ -n "$text_addn" ]]; then - case "$scr_cols" in - [0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";; - 4[5-9]) text_main_max_len="14";; - *) text_main_max_len="19";; - esac - fi + # If there is additional text, define max length of text_main + if [[ -n "$text_addn" ]]; then + case "$scr_cols" in + [0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-4]) text_main_max_len="9";; + 4[5-9]) text_main_max_len="14";; + *) text_main_max_len="19";; + esac + fi - [[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))" + [[ -z "$text_addn" ]] && text_main_max_len="$(( scr_cols - title_len ))" - # Remove excess characters from main text - if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then - # Trim text without colours - text_main_trim="${text_main_nocol:0:$text_main_max_len}" - # Replace with trimmed text - text_main="${text_main/$text_main_nocol/$text_main_trim}" - fi + # Remove excess characters from main text + if [[ "$text_main_len" -gt "$text_main_max_len" ]]; then + # Trim text without colours + text_main_trim="${text_main_nocol:0:$text_main_max_len}" + # Replace with trimmed text + text_main="${text_main/$text_main_nocol/$text_main_trim}" + fi - # Determine amount of spaces for each line - if [[ -n "$text_last" ]]; then - # Move cursor to end of screen - spc_num=$(( scr_cols - ( title_len + text_main_len ) )) - else - spc_num=$(( text_main_max_len - text_main_len )) - fi + # Determine amount of spaces for each line + if [[ -n "$text_last" ]]; then + # Move cursor to end of screen + spc_num=$(( scr_cols - ( title_len + text_main_len ) )) + else + spc_num=$(( text_main_max_len - text_main_len )) + fi - [[ "$spc_num" -le 0 ]] && spc_num="0" - spc=$(printf "%${spc_num}s") - #spc="${spc// /.}" # Debug: Visualise spaces + [[ "$spc_num" -le 0 ]] && spc_num="0" + spc=$(printf "%${spc_num}s") + #spc="${spc// /.}" # Debug: Visualise spaces - printf "%s%s$spc" "$title" "$text_main" + printf "%s%s$spc" "$title" "$text_main" - if [[ -n "$text_addn" ]]; then - printf "%s(%s)%s\\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC" - else - # Do not print trailing newline on final line - [[ -z "$text_last" ]] && printf "%s\\n" "$COL_NC" - fi + if [[ -n "$text_addn" ]]; then + printf "%s(%s)%s\\n" "$COL_NC$COL_DARK_GRAY" "$text_addn" "$COL_NC" + else + # Do not print trailing newline on final line + [[ -z "$text_last" ]] && printf "%s\\n" "$COL_NC" + fi } # Perform on first Chrono run (not for JSON formatted string) get_init_stats() { - calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; } + calcFunc(){ awk "BEGIN {print $*}" 2> /dev/null; } - # Convert bytes to human-readable format - hrBytes() { - awk '{ - num=$1; - if(num==0) { - print "0 B" - } else { - xxx=(num<0?-num:num) - sss=(num<0?-1:1) - split("B KB MB GB TB PB",type) - for(i=5;yyy < 1;i--) { - yyy=xxx / (2^(10*i)) - } - printf "%.0f " type[i+2], yyy*sss - } - }' <<< "$1"; - } + # Convert bytes to human-readable format + hrBytes() { + awk '{ + num=$1; + if(num==0) { + print "0 B" + } else { + xxx=(num<0?-num:num) + sss=(num<0?-1:1) + split("B KB MB GB TB PB",type) + for(i=5;yyy < 1;i--) { + yyy=xxx / (2^(10*i)) + } + printf "%.0f " type[i+2], yyy*sss + } + }' <<< "$1"; + } - # Convert seconds to human-readable format - hrSecs() { - day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 )) - mins=$(( ($1%3600)/60 )); secs=$(( $1%60 )) - [[ "$day" -ge "2" ]] && plu="s" - [[ "$day" -ge "1" ]] && days="$day day${plu}, " || days="" - printf "%s%02d:%02d:%02d\\n" "$days" "$hrs" "$mins" "$secs" - } + # Convert seconds to human-readable format + hrSecs() { + day=$(( $1/60/60/24 )); hrs=$(( $1/3600%24 )) + mins=$(( ($1%3600)/60 )); secs=$(( $1%60 )) + [[ "$day" -ge "2" ]] && plu="s" + [[ "$day" -ge "1" ]] && days="$day day${plu}, " || days="" + printf "%s%02d:%02d:%02d\\n" "$days" "$hrs" "$mins" "$secs" + } - # Set Colour Codes - coltable="/opt/pihole/COL_TABLE" - if [[ -f "${coltable}" ]]; then - source ${coltable} - else - COL_NC="" - COL_DARK_GRAY="" - COL_LIGHT_GREEN="" - COL_LIGHT_BLUE="" - COL_LIGHT_RED="" - COL_YELLOW="" - COL_LIGHT_RED="" - COL_URG_RED="" - fi - - # Get RPi throttle state (RPi 3B only) & model number, or OS distro info - if command -v vcgencmd &> /dev/null; then - local sys_throttle_raw - local sys_rev_raw - - sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}") - - # Active Throttle Notice: http://bit.ly/2gnunOo - if [[ "$sys_throttle_raw" != "0" ]]; then - case "$sys_throttle_raw" in - *0001) thr_type="${COL_YELLOW}Under Voltage";; - *0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";; - *0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";; - *0004) thr_type="${COL_LIGHT_RED}Throttled";; - *0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; - *0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; - *0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; - esac - [[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}" + # Set Colour Codes + coltable="/opt/pihole/COL_TABLE" + if [[ -f "${coltable}" ]]; then + source ${coltable} + else + COL_NC="" + COL_DARK_GRAY="" + COL_LIGHT_GREEN="" + COL_LIGHT_BLUE="" + COL_LIGHT_RED="" + COL_YELLOW="" + COL_LIGHT_RED="" + COL_URG_RED="" fi - sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo) - case "$sys_rev_raw" in - 000[2-6]) sys_model=" 1, Model B";; # 256MB - 000[7-9]) sys_model=" 1, Model A";; # 256MB - 000d|000e|000f) sys_model=" 1, Model B";; # 512MB - 0010|0013) sys_model=" 1, Model B+";; # 512MB - 0012|0015) sys_model=" 1, Model A+";; # 256MB - a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB - 900021) sys_model=" 1, Model A+";; # 512MB - 900032) sys_model=" 1, Model B+";; # 512MB - 90009[2-3]|920093) sys_model=" Zero";; # 512MB - 9000c1) sys_model=" Zero W";; # 512MB - a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB - a020d3) sys_model=" 3, Model B+";; # 1GB - *) sys_model="";; - esac - sys_type="Raspberry Pi$sys_model" - else - source "/etc/os-release" - CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}") - sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID" - fi + # Get RPi throttle state (RPi 3B only) & model number, or OS distro info + if command -v vcgencmd &> /dev/null; then + local sys_throttle_raw + local sys_rev_raw - # Get core count - sys_cores=$(grep -c "^processor" /proc/cpuinfo) + sys_throttle_raw=$(vgt=$(sudo vcgencmd get_throttled); echo "${vgt##*x}") - # Test existence of clock speed file for ARM CPU - if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then - scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" - fi + # Active Throttle Notice: http://bit.ly/2gnunOo + if [[ "$sys_throttle_raw" != "0" ]]; then + case "$sys_throttle_raw" in + *0001) thr_type="${COL_YELLOW}Under Voltage";; + *0002) thr_type="${COL_LIGHT_BLUE}Arm Freq Cap";; + *0003) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC";; + *0004) thr_type="${COL_LIGHT_RED}Throttled";; + *0005) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; + *0006) thr_type="${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; + *0007) thr_type="${COL_YELLOW}UV${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_BLUE}AFC${COL_DARK_GRAY},${COL_NC} ${COL_LIGHT_RED}TT";; + esac + [[ -n "$thr_type" ]] && sys_throttle="$thr_type${COL_DARK_GRAY}" + fi - # Test existence of temperature file - if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then - temp_file="/sys/class/thermal/thermal_zone0/temp" - elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then - temp_file="/sys/class/hwmon/hwmon0/temp1_input" - else - temp_file="" - fi + sys_rev_raw=$(awk '/Revision/ {print $3}' < /proc/cpuinfo) + case "$sys_rev_raw" in + 000[2-6]) sys_model=" 1, Model B";; # 256MB + 000[7-9]) sys_model=" 1, Model A";; # 256MB + 000d|000e|000f) sys_model=" 1, Model B";; # 512MB + 0010|0013) sys_model=" 1, Model B+";; # 512MB + 0012|0015) sys_model=" 1, Model A+";; # 256MB + a0104[0-1]|a21041|a22042) sys_model=" 2, Model B";; # 1GB + 900021) sys_model=" 1, Model A+";; # 512MB + 900032) sys_model=" 1, Model B+";; # 512MB + 90009[2-3]|920093) sys_model=" Zero";; # 512MB + 9000c1) sys_model=" Zero W";; # 512MB + a02082|a[2-3]2082) sys_model=" 3, Model B";; # 1GB + a020d3) sys_model=" 3, Model B+";; # 1GB + *) sys_model="";; + esac + sys_type="Raspberry Pi$sys_model" + else + source "/etc/os-release" + CODENAME=$(sed 's/[()]//g' <<< "${VERSION/* /}") + sys_type="${NAME/ */} ${CODENAME^} $VERSION_ID" + fi - # Test existence of setupVars config - if [[ -f "/etc/pihole/setupVars.conf" ]]; then - setupVars="/etc/pihole/setupVars.conf" - fi + # Get core count + sys_cores=$(grep -c "^processor" /proc/cpuinfo) + + # Test existence of clock speed file for ARM CPU + if [[ -f "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" ]]; then + scaling_freq_file="/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq" + fi + + # Test existence of temperature file + if [[ -f "/sys/class/thermal/thermal_zone0/temp" ]]; then + temp_file="/sys/class/thermal/thermal_zone0/temp" + elif [[ -f "/sys/class/hwmon/hwmon0/temp1_input" ]]; then + temp_file="/sys/class/hwmon/hwmon0/temp1_input" + else + temp_file="" + fi + + # Test existence of setupVars config + if [[ -f "/etc/pihole/setupVars.conf" ]]; then + setupVars="/etc/pihole/setupVars.conf" + fi } get_sys_stats() { - local ph_ver_raw - local cpu_raw - local ram_raw - local disk_raw + local ph_ver_raw + local cpu_raw + local ram_raw + local disk_raw - # Update every 12 refreshes (Def: every 60s) - count=$((count+1)) - if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then - # Do not source setupVars if file does not exist - [[ -n "$setupVars" ]] && source "$setupVars" + # Update every 12 refreshes (Def: every 60s) + count=$((count+1)) + if [[ "$count" == "1" ]] || (( "$count" % 12 == 0 )); then + # Do not source setupVars if file does not exist + [[ -n "$setupVars" ]] && source "$setupVars" - mapfile -t ph_ver_raw < <(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p') - if [[ -n "${ph_ver_raw[0]}" ]]; then - ph_core_ver="${ph_ver_raw[0]}" - ph_lte_ver="${ph_ver_raw[1]}" - ph_ftl_ver="${ph_ver_raw[2]}" - else - ph_core_ver="-1" + mapfile -t ph_ver_raw < <(pihole -v -c 2> /dev/null | sed -n 's/^.* v/v/p') + if [[ -n "${ph_ver_raw[0]}" ]]; then + ph_core_ver="${ph_ver_raw[0]}" + ph_lte_ver="${ph_ver_raw[1]}" + ph_ftl_ver="${ph_ver_raw[2]}" + else + ph_core_ver="-1" + fi + + sys_name=$(hostname) + + [[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c" + + # Get storage stats for partition mounted on / + read -r -a disk_raw <<< "$(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')" + disk_used="${disk_raw[0]}" + disk_total="${disk_raw[1]}" + disk_perc="${disk_raw[2]}" + + net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}') + + # Get DHCP stats, if feature is enabled + if [[ "$DHCP_ACTIVE" == "true" ]]; then + ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 )) + fi + + # Get DNS server count + dns_count="0" + [[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1)) + [[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+" fi - sys_name=$(hostname) + # Get screen size + read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)" + scr_lines="${scr_size[0]}" + scr_cols="${scr_size[1]}" - [[ -n "$TEMPERATUREUNIT" ]] && temp_unit="$TEMPERATUREUNIT" || temp_unit="c" + # Determine Chronometer size behaviour + if [[ "$scr_cols" -ge 58 ]]; then + chrono_width="large" + elif [[ "$scr_cols" -gt 40 ]]; then + chrono_width="medium" + else + chrono_width="small" + fi - # Get storage stats for partition mounted on / - read -r -a disk_raw <<< "$(df -B1 / 2> /dev/null | awk 'END{ print $3,$2,$5 }')" - disk_used="${disk_raw[0]}" - disk_total="${disk_raw[1]}" - disk_perc="${disk_raw[2]}" + # Determine max length of divider string + scr_line_len=$(( scr_cols - 2 )) + [[ "$scr_line_len" -ge 58 ]] && scr_line_len="58" + scr_line_str=$(printf "%${scr_line_len}s") + scr_line_str="${scr_line_str// /—}" - net_gateway=$(route -n | awk '$4 == "UG" {print $2;exit}') + sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)") + sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg) + + # Get CPU usage, only counting processes over 1% as active + # shellcheck disable=SC2009 + cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0") + cpu_tasks=$(wc -l <<< "$cpu_raw") + cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l) + cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw") + + # Get CPU clock speed + if [[ -n "$scaling_freq_file" ]]; then + cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 )) + else + cpu_mhz=$(lscpu | awk -F ":" '/MHz/ {print $2;exit}') + cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}") + fi + + # Determine whether to display CPU clock speed as MHz or GHz + if [[ -n "$cpu_mhz" ]]; then + [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(printf "%.1f" $(calcFunc "$cpu_mhz"/1000)) GHz" + [[ "${cpu_freq}" == *".0"* ]] && cpu_freq="${cpu_freq/.0/}" + fi + + # Determine colour for temperature + if [[ -n "$temp_file" ]]; then + if [[ "$temp_unit" == "C" ]]; then + cpu_temp=$(printf "%.0fc\\n" "$(calcFunc "$(< $temp_file) / 1000")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 4[0-9]) cpu_col="";; + 5[0-9]) cpu_col="$COL_YELLOW";; + 6[0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED + cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + elif [[ "$temp_unit" == "F" ]]; then + cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")") + + case "${cpu_temp::-1}" in + -*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";; + 1[0-1][0-9]) cpu_col="";; + 1[2-3][0-9]) cpu_col="$COL_YELLOW";; + 1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";; + *) cpu_col="$COL_URG_RED";; + esac + + cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" + + else + cpu_temp_str=$(printf " @ %.0fk\\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")") + fi + else + cpu_temp_str="" + fi + + read -r -a ram_raw <<< "$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)" + ram_perc="${ram_raw[0]}" + ram_used="${ram_raw[1]}" + ram_total="${ram_raw[2]}" + + if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then + ph_status="${COL_LIGHT_GREEN}Active" + else + ph_status="${COL_LIGHT_RED}Offline" + fi - # Get DHCP stats, if feature is enabled if [[ "$DHCP_ACTIVE" == "true" ]]; then - ph_dhcp_max=$(( ${DHCP_END##*.} - ${DHCP_START##*.} + 1 )) + local ph_dhcp_range + + ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}") + + # Count dynamic leases from available range, and not static leases + ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases") + ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max )) fi - - # Get DNS server count - dns_count="0" - [[ -n "${PIHOLE_DNS_1}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_2}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_3}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_4}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_5}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_6}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_7}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_8}" ]] && dns_count=$((dns_count+1)) - [[ -n "${PIHOLE_DNS_9}" ]] && dns_count="$dns_count+" - fi - - # Get screen size - read -r -a scr_size <<< "$(stty size 2>/dev/null || echo 24 80)" - scr_lines="${scr_size[0]}" - scr_cols="${scr_size[1]}" - - # Determine Chronometer size behaviour - if [[ "$scr_cols" -ge 58 ]]; then - chrono_width="large" - elif [[ "$scr_cols" -gt 40 ]]; then - chrono_width="medium" - else - chrono_width="small" - fi - - # Determine max length of divider string - scr_line_len=$(( scr_cols - 2 )) - [[ "$scr_line_len" -ge 58 ]] && scr_line_len="58" - scr_line_str=$(printf "%${scr_line_len}s") - scr_line_str="${scr_line_str// /—}" - - sys_uptime=$(hrSecs "$(cut -d. -f1 /proc/uptime)") - sys_loadavg=$(cut -d " " -f1,2,3 /proc/loadavg) - - # Get CPU usage, only counting processes over 1% as active - # shellcheck disable=SC2009 - cpu_raw=$(ps -eo pcpu,rss --no-headers | grep -E -v " 0") - cpu_tasks=$(wc -l <<< "$cpu_raw") - cpu_taskact=$(sed -r "/(^ 0.)/d" <<< "$cpu_raw" | wc -l) - cpu_perc=$(awk '{sum+=$1} END {printf "%.0f\n", sum/'"$sys_cores"'}' <<< "$cpu_raw") - - # Get CPU clock speed - if [[ -n "$scaling_freq_file" ]]; then - cpu_mhz=$(( $(< /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / 1000 )) - else - cpu_mhz=$(lscpu | awk -F ":" '/MHz/ {print $2;exit}') - cpu_mhz=$(printf "%.0f" "${cpu_mhz//[[:space:]]/}") - fi - - # Determine whether to display CPU clock speed as MHz or GHz - if [[ -n "$cpu_mhz" ]]; then - [[ "$cpu_mhz" -le "999" ]] && cpu_freq="$cpu_mhz MHz" || cpu_freq="$(printf "%.1f" $(calcFunc "$cpu_mhz"/1000)) GHz" - [[ "${cpu_freq}" == *".0"* ]] && cpu_freq="${cpu_freq/.0/}" - fi - - # Determine colour for temperature - if [[ -n "$temp_file" ]]; then - if [[ "$temp_unit" == "C" ]]; then - cpu_temp=$(printf "%.0fc\\n" "$(calcFunc "$(< $temp_file) / 1000")") - - case "${cpu_temp::-1}" in - -*|[0-9]|[1-3][0-9]) cpu_col="$COL_LIGHT_BLUE";; - 4[0-9]) cpu_col="";; - 5[0-9]) cpu_col="$COL_YELLOW";; - 6[0-9]) cpu_col="$COL_LIGHT_RED";; - *) cpu_col="$COL_URG_RED";; - esac - - # $COL_NC$COL_DARK_GRAY is needed for $COL_URG_RED - cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" - - elif [[ "$temp_unit" == "F" ]]; then - cpu_temp=$(printf "%.0ff\\n" "$(calcFunc "($(< $temp_file) / 1000) * 9 / 5 + 32")") - - case "${cpu_temp::-1}" in - -*|[0-9]|[0-9][0-9]) cpu_col="$COL_LIGHT_BLUE";; - 1[0-1][0-9]) cpu_col="";; - 1[2-3][0-9]) cpu_col="$COL_YELLOW";; - 1[4-5][0-9]) cpu_col="$COL_LIGHT_RED";; - *) cpu_col="$COL_URG_RED";; - esac - - cpu_temp_str=" @ $cpu_col$cpu_temp$COL_NC$COL_DARK_GRAY" - - else - cpu_temp_str=$(printf " @ %.0fk\\n" "$(calcFunc "($(< $temp_file) / 1000) + 273.15")") - fi - else - cpu_temp_str="" - fi - - read -r -a ram_raw <<< "$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.0f %.0f %.0f", (total-free-buffers-cached)*100/total, (total-free-buffers-cached)*1024, total*1024}' /proc/meminfo)" - ram_perc="${ram_raw[0]}" - ram_used="${ram_raw[1]}" - ram_total="${ram_raw[2]}" - - if [[ "$(pihole status web 2> /dev/null)" == "1" ]]; then - ph_status="${COL_LIGHT_GREEN}Active" - else - ph_status="${COL_LIGHT_RED}Offline" - fi - - if [[ "$DHCP_ACTIVE" == "true" ]]; then - local ph_dhcp_range - - ph_dhcp_range=$(seq -s "|" -f "${DHCP_START%.*}.%g" "${DHCP_START##*.}" "${DHCP_END##*.}") - - # Count dynamic leases from available range, and not static leases - ph_dhcp_num=$(grep -cE "$ph_dhcp_range" "/etc/pihole/dhcp.leases") - ph_dhcp_percent=$(( ph_dhcp_num * 100 / ph_dhcp_max )) - fi } get_ftl_stats() { - local stats_raw + local stats_raw - mapfile -t stats_raw < <(pihole-FTL "stats") - domains_being_blocked_raw="${stats_raw[0]#* }" - dns_queries_today_raw="${stats_raw[1]#* }" - ads_blocked_today_raw="${stats_raw[2]#* }" - ads_percentage_today_raw="${stats_raw[3]#* }" - queries_forwarded_raw="${stats_raw[5]#* }" - queries_cached_raw="${stats_raw[6]#* }" + mapfile -t stats_raw < <(pihole-FTL "stats") + domains_being_blocked_raw="${stats_raw[0]#* }" + dns_queries_today_raw="${stats_raw[1]#* }" + ads_blocked_today_raw="${stats_raw[2]#* }" + ads_percentage_today_raw="${stats_raw[3]#* }" + queries_forwarded_raw="${stats_raw[5]#* }" + queries_cached_raw="${stats_raw[6]#* }" - # Only retrieve these stats when not called from jsonFunc - if [[ -z "$1" ]]; then - local top_ad_raw - local top_domain_raw - local top_client_raw + # Only retrieve these stats when not called from jsonFunc + if [[ -z "$1" ]]; then + local top_ad_raw + local top_domain_raw + local top_client_raw - domains_being_blocked=$(printf "%.0f\\n" "${domains_being_blocked_raw}" 2> /dev/null) - dns_queries_today=$(printf "%.0f\\n" "${dns_queries_today_raw}") - ads_blocked_today=$(printf "%.0f\\n" "${ads_blocked_today_raw}") - ads_percentage_today=$(printf "%'.0f\\n" "${ads_percentage_today_raw}") - queries_cached_percentage=$(printf "%.0f\\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")") - recent_blocked=$(pihole-FTL recentBlocked) - read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")" - read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")" - read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")" + domains_being_blocked=$(printf "%.0f\\n" "${domains_being_blocked_raw}" 2> /dev/null) + dns_queries_today=$(printf "%.0f\\n" "${dns_queries_today_raw}") + ads_blocked_today=$(printf "%.0f\\n" "${ads_blocked_today_raw}") + ads_percentage_today=$(printf "%'.0f\\n" "${ads_percentage_today_raw}") + queries_cached_percentage=$(printf "%.0f\\n" "$(calcFunc "$queries_cached_raw * 100 / ( $queries_forwarded_raw + $queries_cached_raw )")") + recent_blocked=$(pihole-FTL recentBlocked) + read -r -a top_ad_raw <<< "$(pihole-FTL "top-ads (1)")" + read -r -a top_domain_raw <<< "$(pihole-FTL "top-domains (1)")" + read -r -a top_client_raw <<< "$(pihole-FTL "top-clients (1)")" - top_ad="${top_ad_raw[2]}" - top_domain="${top_domain_raw[2]}" - if [[ "${top_client_raw[3]}" ]]; then - top_client="${top_client_raw[3]}" - else - top_client="${top_client_raw[2]}" + top_ad="${top_ad_raw[2]}" + top_domain="${top_domain_raw[2]}" + if [[ "${top_client_raw[3]}" ]]; then + top_client="${top_client_raw[3]}" + else + top_client="${top_client_raw[2]}" + fi fi - fi } get_strings() { - # Expand or contract strings depending on screen size - if [[ "$chrono_width" == "large" ]]; then - phc_str=" ${COL_DARK_GRAY}Core" - lte_str=" ${COL_DARK_GRAY}Web" - ftl_str=" ${COL_DARK_GRAY}FTL" - api_str="${COL_LIGHT_RED}API Offline" + # Expand or contract strings depending on screen size + if [[ "$chrono_width" == "large" ]]; then + phc_str=" ${COL_DARK_GRAY}Core" + lte_str=" ${COL_DARK_GRAY}Web" + ftl_str=" ${COL_DARK_GRAY}FTL" + api_str="${COL_LIGHT_RED}API Offline" - host_info="$sys_type" - sys_info="$sys_throttle" - sys_info2="Active: $cpu_taskact of $cpu_tasks tasks" - used_str="Used: " - leased_str="Leased: " - domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked") - ads_blocked_today=$(printf "%'.0f" "$ads_blocked_today") - dns_queries_today=$(printf "%'.0f" "$dns_queries_today") - ph_info="Blocking: $domains_being_blocked sites" - total_str="Total: " - else - phc_str=" ${COL_DARK_GRAY}Core" - lte_str=" ${COL_DARK_GRAY}Web" - ftl_str=" ${COL_DARK_GRAY}FTL" - api_str="${COL_LIGHT_RED}API Down" - ph_info="$domains_being_blocked blocked" - fi + host_info="$sys_type" + sys_info="$sys_throttle" + sys_info2="Active: $cpu_taskact of $cpu_tasks tasks" + used_str="Used: " + leased_str="Leased: " + domains_being_blocked=$(printf "%'.0f" "$domains_being_blocked") + ads_blocked_today=$(printf "%'.0f" "$ads_blocked_today") + dns_queries_today=$(printf "%'.0f" "$dns_queries_today") + ph_info="Blocking: $domains_being_blocked sites" + total_str="Total: " + else + phc_str=" ${COL_DARK_GRAY}Core" + lte_str=" ${COL_DARK_GRAY}Web" + ftl_str=" ${COL_DARK_GRAY}FTL" + api_str="${COL_LIGHT_RED}API Down" + ph_info="$domains_being_blocked blocked" + fi - [[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x " - cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str" - ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")" - disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")" + [[ "$sys_cores" -ne 1 ]] && sys_cores_txt="${sys_cores}x " + cpu_info="$sys_cores_txt$cpu_freq$cpu_temp_str" + ram_info="$used_str$(hrBytes "$ram_used") of $(hrBytes "$ram_total")" + disk_info="$used_str$(hrBytes "$disk_used") of $(hrBytes "$disk_total")" - lan_info="Gateway: $net_gateway" - dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max" + lan_info="Gateway: $net_gateway" + dhcp_info="$leased_str$ph_dhcp_num of $ph_dhcp_max" - ads_info="$total_str$ads_blocked_today of $dns_queries_today" - dns_info="$dns_count DNS servers" + ads_info="$total_str$ads_blocked_today of $dns_queries_today" + dns_info="$dns_count DNS servers" - [[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}" + [[ "$recent_blocked" == "0" ]] && recent_blocked="${COL_LIGHT_RED}FTL offline${COL_NC}" } chronoFunc() { - get_init_stats + get_init_stats - for (( ; ; )); do - get_sys_stats - get_ftl_stats - get_strings + for (( ; ; )); do + get_sys_stats + get_ftl_stats + get_strings - # Strip excess development version numbers - if [[ "$ph_core_ver" != "-1" ]]; then - phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}" - lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}" - ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}" - else - phc_ver_str="$phc_str: $api_str${COL_NC}" - fi + # Strip excess development version numbers + if [[ "$ph_core_ver" != "-1" ]]; then + phc_ver_str="$phc_str: ${ph_core_ver%-*}${COL_NC}" + lte_ver_str="$lte_str: ${ph_lte_ver%-*}${COL_NC}" + ftl_ver_str="$ftl_str: ${ph_ftl_ver%-*}${COL_NC}" + else + phc_ver_str="$phc_str: $api_str${COL_NC}" + fi - # Get refresh number - if [[ "$*" == *"-r"* ]]; then - num="$*" - num="${num/*-r /}" - num="${num/ */}" - num_str="Refresh set for every $num seconds" - else - num_str="" - fi + # Get refresh number + if [[ "$*" == *"-r"* ]]; then + num="$*" + num="${num/*-r /}" + num="${num/ */}" + num_str="Refresh set for every $num seconds" + else + num_str="" + fi - clear + clear - # Remove exit message heading on third refresh - if [[ "$count" -le 2 ]] && [[ "$*" != *"-e"* ]]; then - echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC} - $num_str - ${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC} - ${COL_DARK_GRAY}$scr_line_str${COL_NC}" - else - echo -e "|¯¯¯(¯)_|¯|_ ___|¯|___$phc_ver_str -| ¯_/¯|_| ' \\/ _ \\ / -_)$lte_ver_str -|_| |_| |_||_\\___/_\\___|$ftl_ver_str - ${COL_DARK_GRAY}$scr_line_str${COL_NC}" - fi + # Remove exit message heading on third refresh + if [[ "$count" -le 2 ]] && [[ "$*" != *"-e"* ]]; then + echo -e " ${COL_LIGHT_GREEN}Pi-hole Chronometer${COL_NC} + $num_str + ${COL_LIGHT_RED}Press Ctrl-C to exit${COL_NC} + ${COL_DARK_GRAY}$scr_line_str${COL_NC}" + else + echo -e "|¯¯¯(¯)_|¯|_ ___|¯|___$phc_ver_str| ¯_/¯|_| ' \\/ _ \\ / -_)$lte_ver_str|_| |_| |_||_\\___/_\\___|$ftl_ver_str ${COL_DARK_GRAY}$scr_line_str${COL_NC}" + fi - printFunc " Hostname: " "$sys_name" "$host_info" - printFunc " Uptime: " "$sys_uptime" "$sys_info" - printFunc " Task Load: " "$sys_loadavg" "$sys_info2" - printFunc " CPU usage: " "$cpu_perc%" "$cpu_info" - printFunc " RAM usage: " "$ram_perc%" "$ram_info" - printFunc " HDD usage: " "$disk_perc" "$disk_info" + printFunc " Hostname: " "$sys_name" "$host_info" + printFunc " Uptime: " "$sys_uptime" "$sys_info" + printFunc " Task Load: " "$sys_loadavg" "$sys_info2" + printFunc " CPU usage: " "$cpu_perc%" "$cpu_info" + printFunc " RAM usage: " "$ram_perc%" "$ram_info" + printFunc " HDD usage: " "$disk_perc" "$disk_info" - if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then - printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info" - fi + if [[ "$scr_lines" -gt 17 ]] && [[ "$chrono_width" != "small" ]]; then + printFunc " LAN addr: " "${IPV4_ADDRESS/\/*/}" "$lan_info" + fi - if [[ "$DHCP_ACTIVE" == "true" ]]; then - printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info" - fi + if [[ "$DHCP_ACTIVE" == "true" ]]; then + printFunc "DHCP usage: " "$ph_dhcp_percent%" "$dhcp_info" + fi - printFunc " Pi-hole: " "$ph_status" "$ph_info" - printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info" - printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info" + printFunc " Pi-hole: " "$ph_status" "$ph_info" + printFunc " Ads Today: " "$ads_percentage_today%" "$ads_info" + printFunc "Local Qrys: " "$queries_cached_percentage%" "$dns_info" - printFunc " Blocked: " "$recent_blocked" - printFunc "Top Advert: " "$top_ad" + printFunc " Blocked: " "$recent_blocked" + printFunc "Top Advert: " "$top_ad" - # Provide more stats on screens with more lines - if [[ "$scr_lines" -eq 17 ]]; then - if [[ "$DHCP_ACTIVE" == "true" ]]; then - printFunc "Top Domain: " "$top_domain" "last" - else - print_client="true" - fi - else - print_client="true" - fi + # Provide more stats on screens with more lines + if [[ "$scr_lines" -eq 17 ]]; then + if [[ "$DHCP_ACTIVE" == "true" ]]; then + printFunc "Top Domain: " "$top_domain" "last" + else + print_client="true" + fi + else + print_client="true" + fi - if [[ -n "$print_client" ]]; then - printFunc "Top Domain: " "$top_domain" - printFunc "Top Client: " "$top_client" "last" - fi + if [[ -n "$print_client" ]]; then + printFunc "Top Domain: " "$top_domain" + printFunc "Top Client: " "$top_client" "last" + fi - # Handle exit/refresh options - if [[ "$*" == *"-e"* ]]; then - exit 0 - else - if [[ "$*" == *"-r"* ]]; then - sleep "$num" - else - sleep 5 - fi - fi + # Handle exit/refresh options + if [[ "$*" == *"-e"* ]]; then + exit 0 + else + if [[ "$*" == *"-r"* ]]; then + sleep "$num" + else + sleep 5 + fi + fi - done + done } jsonFunc() { - get_ftl_stats "json" - echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" + get_ftl_stats "json" + echo "{\"domains_being_blocked\":${domains_being_blocked_raw},\"dns_queries_today\":${dns_queries_today_raw},\"ads_blocked_today\":${ads_blocked_today_raw},\"ads_percentage_today\":${ads_percentage_today_raw}}" } helpFunc() { if [[ "$1" == "?" ]]; then - echo "Unknown option. Please view 'pihole -c --help' for more information" + echo "Unknown option. Please view 'pihole -c --help' for more information" else - echo "Usage: pihole -c [options] + echo "Usage: pihole -c [options] Example: 'pihole -c -j' Calculates stats and displays to an LCD @@ -560,15 +557,15 @@ Options: } if [[ $# = 0 ]]; then - chronoFunc + chronoFunc fi for var in "$@"; do - case "$var" in - "-j" | "--json" ) jsonFunc;; - "-h" | "--help" ) helpFunc;; - "-r" | "--refresh" ) chronoFunc "$@";; - "-e" | "--exit" ) chronoFunc "$@";; - * ) helpFunc "?";; - esac + case "$var" in + "-j" | "--json" ) jsonFunc;; + "-h" | "--help" ) helpFunc;; + "-r" | "--refresh" ) chronoFunc "$@";; + "-e" | "--exit" ) chronoFunc "$@";; + * ) helpFunc "?";; + esac done