Last active
May 28, 2022 06:33
-
-
Save giuliomagnifico/fdce5bb3108fd34913aa84711663e839 to your computer and use it in GitHub Desktop.
PADD for Pi-Hole 3.7.1 custom for 800x480px screen. More info: https://giuliomagnifico.blog/networking/2022/05/24/PADD-3.7.0-custom-hyperpixel.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
#!/usr/bin/env bash | |
# shellcheck disable=SC1091 | |
# PADD | |
# A more advanced version of the chronometer provided with Pihole | |
# SETS LOCALE | |
# Issue 5: https://github.com/jpmck/PADD/issues/5 | |
# Updated to en_US to support | |
# export LC_ALL=en_US.UTF-8 > /dev/null 2>&1 || export LC_ALL=en_GB.UTF-8 > /dev/null 2>&1 || export LC_ALL=C.UTF-8 > /dev/null 2>&1 | |
LC_ALL=C | |
LC_NUMERIC=C | |
# creates a new local temp directory /tmp/padd_uid | |
tmpdir=$(dirname "$(mktemp -u)") | |
mkdir -p "$tmpdir/padd_$(id -u)/" | |
# change into the newly created directory | |
oldpath=$(pwd) | |
cd "$tmpdir/padd_$(id -u)/" > /dev/null || { | |
EC=$? | |
echo >&2 "Could not chdir to the temp directory (exit code $EC)" | |
exit $EC | |
} | |
######################### VARIABLES FOR 800X480 DISPLAY, TERMINUS FONT 15PT SIZE #################### | |
version=$(tail -1 /proc/cpuinfo | awk 'NR==1{print $5$7, $8, $9}') | |
SoC=$(grep -a "Hardware" /proc/cpuinfo) | awk 'NR==1{print $NF}' | |
disk_used=$(df -Th | awk 'NR==2{gsub(/[^0-9. ]/,"");print $3}') #disk_used=$(df -Th | awk 'NR==2{print $4}') | |
disk_total=$(df -Th | awk 'NR==2{gsub(/[^0-9. ]/,"");print $2}') | |
disk_perc=$(df -Th | awk 'NR==2{print $6}') | |
installed_packages=$(dpkg --get-selections | wc -l) | |
run_process=$(echo $(( $(pstree -Ta | wc -l) - 3 ))) | |
boot_time=$(sudo systemd-analyze | mawk 'NR==1{gsub(/[^0-9. ]/,"");print $NF}') | |
log_size=$(df -Th | awk 'NR==8{print $4}') | |
log_perc=$(df -Th | awk 'NR==8{print $6}') | |
unbound=$(sudo unbound-control status | awk 'NR==1{print $NF}') | |
#sys_cores=$(grep -c "^processor" /proc/cpuinfo) | |
cpu_freq=$(lscpu | awk '/CPU max MHz/{if($NF+0>1000)printf "%0.2f GHz\n",$NF/1000; else printf "%.3f MHz\n",$NF}') | |
ram_total=$(awk '/MemTotal/ {printf( "%.f\n", $2 / 1024 / 1024 )}' /proc/meminfo) | |
ram_free=$(free -th | mawk '/^Total:/{print $4}') | |
ram_used=$(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) #(free -m | awk 'NR==2{printf "%s",$3 }') | |
############################################ VARIABLES ############################################# | |
# VERSION | |
padd_version="v3.7.1" | |
# DATE | |
today=$(date +%Y%m%d) | |
# CORES | |
core_count=1 | |
core_count=$(cat /sys/devices/system/cpu/kernel_max 2> /dev/null)+1 | |
# Get Config variables | |
. /etc/pihole/setupVars.conf | |
piHoleVersion_file="./piHoleVersion" | |
# COLORS | |
#black_text=$(tput setaf 0) # Black | |
#red_text=$(tput setaf 1) # Red | |
#green_text=$(tput setaf 2) # Green | |
#yellow_text=$(tput setaf 3) # Yellow | |
#blue_text=$(tput setaf 4) # Blue | |
#magenta_text=$(tput setaf 5) # Magenta | |
#cyan_text=$(tput setaf 6) # Cyan | |
#white_text=$(tput setaf 7) # White | |
#reset_text=$(tput sgr0) # Reset to default color | |
CSI="$(printf '\033')[" | |
red_text="${CSI}91m" # Red | |
green_text="${CSI}92m" # Green | |
yellow_text="${CSI}93m" # Yellow | |
blue_text="${CSI}94m" # Blue | |
magenta_text="${CSI}95m" # Magenta | |
cyan_text="${CSI}96m" # Cyan | |
reset_text="${CSI}0m" # Reset to default | |
# STYLES | |
#bold_text=$(tput bold) | |
#blinking_text=$(tput blink) | |
#dim_text=$(tput dim) | |
bold_text="${CSI}1m" | |
blinking_text="${CSI}5m" | |
dim_text="${CSI}2m" | |
# CHECK BOXES | |
check_box_good="[${green_text}✓${reset_text}]" # Good | |
check_box_bad="[${red_text}✗${reset_text}]" # Bad | |
check_box_question="[${yellow_text}?${reset_text}]" # Question / ? | |
check_box_info="[${yellow_text}i${reset_text}]" # Info / i | |
# PICO STATUSES | |
pico_status_ok="${check_box_good} Sys. OK" | |
pico_status_update="${check_box_info} Update" | |
pico_status_hot="${check_box_bad} Sys. Hot!" | |
pico_status_off="${check_box_bad} Offline" | |
pico_status_ftl_down="${check_box_info} FTL Down" | |
pico_status_dns_down="${check_box_bad} DNS Down" | |
pico_status_unknown="${check_box_question} Stat. Unk." | |
# MINI STATUS | |
mini_status_ok="${check_box_good} System OK" | |
mini_status_update="${check_box_info} Update avail." | |
mini_status_hot="${check_box_bad} System is hot!" | |
mini_status_off="${check_box_bad} Pi-hole off!" | |
mini_status_ftl_down="${check_box_info} FTL down!" | |
mini_status_dns_down="${check_box_bad} DNS off!" | |
mini_status_unknown="${check_box_question} Status unknown" | |
# REGULAR STATUS | |
full_status_ok="${check_box_good} System is healthy." | |
full_status_update="${check_box_info} Updates are available." | |
full_status_hot="${check_box_bad} System is hot!" | |
full_status_off="${check_box_bad} Pi-hole is offline" | |
full_status_ftl_down="${check_box_info} FTL is down!" | |
full_status_dns_down="${check_box_bad} DNS is off!" | |
full_status_unknown="${check_box_question} Status unknown!" | |
# MEGA STATUS | |
mega_status_ok="${check_box_good} Your system is healthy." | |
mega_status_update="${check_box_info} Updates are available." | |
mega_status_hot="${check_box_bad} Your system is hot!" | |
mega_status_off="${check_box_bad} Pi-hole is offline." | |
mega_status_ftl_down="${check_box_info} FTLDNS service is not running." | |
mega_status_dns_down="${check_box_bad} Pi-hole's DNS server is off!" | |
mega_status_unknown="${check_box_question} Pi-hole status unknown!" #Unable to determine Pi-hole status." | |
# TINY STATUS | |
tiny_status_ok="${check_box_good} System is healthy." | |
tiny_status_update="${check_box_info} Updates are available." | |
tiny_status_off="${check_box_bad} Pi-hole is offline" | |
tiny_status_ftl_down="${check_box_info} FTL is down!" | |
tiny_status_dns_down="${check_box_bad} DNS is off!" | |
tiny_status_unknown="${check_box_question} Status unknown!" | |
# Text only "logos" | |
padd_text="${green_text}${bold_text}PADD${reset_text}" | |
padd_text_retro="${bold_text}${red_text}P${yellow_text}A${green_text}D${blue_text}D${reset_text}${reset_text}" | |
mini_text_retro="${dim_text}${cyan_text}m${magenta_text}i${red_text}n${yellow_text}i${reset_text}" | |
# PADD logos - regular and retro | |
padd_text="${green_text}${bold_text}PADD${reset_text}" | |
padd_text_retro="${bold_text}${red_text}P${yellow_text}A${green_text}D${blue_text}D${reset_text}${reset_text}" | |
mini_text_retro="${dim_text}${cyan_text}m${magenta_text}i${red_text}n${yellow_text}i${reset_text}" | |
# PADD logos - regular and retro | |
padd_logo_1="${bold_text}${green_text}|¯¯¯(¯)_|¯|_ ___|¯|___ ${reset_text}" | |
padd_logo_2="${bold_text}${green_text}| ¯_/¯|_| ' \/ _ \ / -_) ${reset_text}" | |
padd_logo_3="${bold_text}${green_text}|_| |_| |_||_\___/_\___| ${reset_text}" | |
padd_logo_retro_1="${bold_text}|¯¯¯(¯)_|¯|_ ___|¯|___ ${reset_text}" | |
padd_logo_retro_2="${bold_text}| ¯_/¯|_| ' \/ _ \ / -_) ${reset_text}" | |
padd_logo_retro_3="${bold_text}|_| |_| |_||_\___/_\___| ${reset_text}" | |
#Logo retro colorful | |
#padd_logo_retro_1="${bold_text}${red_text}|¯${white_text}¯${blue_text}¯(¯${cyan_text})${green_text}_${magenta_text}|${magenta_text}¯${magenta_text}|_ ${blue_text}__${cyan_text}_|${red_text}¯${green_text}|${magenta_text}__${red_text}_ ${reset_text}" | |
#padd_logo_retro_2="${bold_text}${white_text}| ¯${blue_text}_${cyan_text}/¯${green_text}|${green_text}_| ${white_text}' ${blue_text}\/ ${cyan_text}_ ${green_text}\ ${magenta_text}/ ${red_text}-${white_text}_) ${reset_text}" | |
#padd_logo_retro_3="${bold_text}${blue_text}|_${cyan_text}| ${green_text}|_${magenta_text}| ${white_text}|_${blue_text}||${cyan_text}_\_${green_text}_${magenta_text}_/${red_text}_\_${white_text}_${blue_text}_| ${reset_text}" | |
# old script Pi-hole logos - regular and retro | |
pihole_logo_script_1="${bold_text}${green_text}.-.. . . ${reset_text}" | |
pihole_logo_script_2="${bold_text}${green_text}|-'. - |-. .-.| .-, ${reset_text}" | |
pihole_logo_script_3="${bold_text}${green_text}' ' ' '-\`-''-\`'- ${reset_text}" | |
pihole_logo_script_retro_1="${red_text}.${yellow_text}-${green_text}.${blue_text}. ${green_text}. ${magenta_text}. ${reset_text}" | |
pihole_logo_script_retro_2="${yellow_text}|${green_text}-${blue_text}'${magenta_text}. ${yellow_text}- ${blue_text}|${magenta_text}-${red_text}. ${green_text}.${blue_text}-${magenta_text}.${red_text}| ${green_text}.${blue_text}-${magenta_text}, ${reset_text}" | |
pihole_logo_script_retro_3="${green_text}' ${red_text}' ${magenta_text}' ${yellow_text}'${green_text}-${blue_text}\`${magenta_text}-${red_text}'${yellow_text}'${green_text}-${blue_text}\`${magenta_text}'${red_text}- ${reset_text}" | |
############################################# GETTERS ############################################## | |
GetFTLData() { | |
ftl_port=$(cat /run/pihole-FTL.port 2> /dev/null) | |
if [ -n "$ftl_port" ]; then | |
# Send command to FTL and ask to quit when finished | |
echo ">$1 >quit" | nc 127.0.0.1 "${ftl_port}" | |
else | |
echo "0" | |
fi | |
} | |
GetSummaryInformation() { | |
summary=$(GetFTLData "stats") | |
cache_info=$(GetFTLData "cacheinfo") | |
clients=$(echo "${summary}" | grep "unique_clients" | grep -Eo "[0-9]+$") | |
blocking_status=$(echo "${summary}" | grep "status" | grep -Eo "enabled|disabled|unknown" ) | |
domains_being_blocked_raw=$(echo "${summary}" | grep "domains_being_blocked" | grep -Eo "[0-9]+$") | |
domains_being_blocked=$(printf "%.f" "${domains_being_blocked_raw}") | |
dns_queries_today_raw=$(echo "$summary" | grep "dns_queries_today" | grep -Eo "[0-9]+$") | |
dns_queries_today=$(printf "%.f" "${dns_queries_today_raw}") | |
ads_blocked_today_raw=$(echo "$summary" | grep "ads_blocked_today" | grep -Eo "[0-9]+$") | |
ads_blocked_today=$(printf "%.f" "${ads_blocked_today_raw}") | |
ads_percentage_today_raw=$(echo "$summary" | grep "ads_percentage_today" | grep -Eo "[0-9.]+$") | |
ads_percentage_today=$(printf "%.1f" "${ads_percentage_today_raw}") | |
cache_size=$(echo "$cache_info" | grep "cache-size" | grep -Eo "[0-9.]+$") | |
cache_deletes=$(echo "$cache_info" | grep "cache-live-freed" | grep -Eo "[0-9.]+$") | |
cache_inserts=$(echo "$cache_info"| grep "cache-inserted" | grep -Eo "[0-9.]+$") | |
latest_blocked=$(GetFTLData recentBlocked) | |
top_blocked=$(GetFTLData "top-ads (1)" | awk '{print $3}') | |
top_domain=$(GetFTLData "top-domains (1)" | awk '{print $3}') | |
top_client_raw=$(GetFTLData "top-clients (1)" | awk '{print $4}') | |
if [ -z "${top_client_raw}" ]; then | |
top_client=$(GetFTLData "top-clients (1)" | awk '{print $3}') | |
else | |
top_client="${top_client_raw}" | |
fi | |
if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then | |
ads_blocked_bar=$(BarGenerator "$ads_percentage_today" 10 "color") | |
elif [ "$1" = "mini" ]; then | |
ads_blocked_bar=$(BarGenerator "$ads_percentage_today" 20 "color") | |
if [ ${#latest_blocked} -gt 30 ]; then | |
latest_blocked=$(echo "$latest_blocked" | cut -c1-27)"..." | |
fi | |
if [ ${#top_blocked} -gt 30 ]; then | |
top_blocked=$(echo "$top_blocked" | cut -c1-27)"..." | |
fi | |
elif [ "$1" = "tiny" ]; then | |
ads_blocked_bar=$(BarGenerator "$ads_percentage_today" 30 "color") | |
if [ ${#latest_blocked} -gt 38 ]; then | |
latest_blocked=$(echo "$latest_blocked" | cut -c1-38)"..." | |
fi | |
if [ ${#top_blocked} -gt 38 ]; then | |
top_blocked=$(echo "$top_blocked" | cut -c1-38)"..." | |
fi | |
if [ ${#top_domain} -gt 38 ]; then | |
top_domain=$(echo "$top_domain" | cut -c1-38)"..." | |
fi | |
if [ ${#top_client} -gt 38 ]; then | |
top_client=$(echo "$top_client" | cut -c1-38)"..." | |
fi | |
elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then | |
ads_blocked_bar=$(BarGenerator "$ads_percentage_today" 40 "color") | |
else | |
ads_blocked_bar=$(BarGenerator "$ads_percentage_today" 30 "color") | |
fi | |
} | |
GetSystemInformation() { | |
# System uptime | |
if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then | |
system_uptime=$(uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours"}') | |
else | |
system_uptime=$(uptime | awk -F'( |,|:)+' '{if ($7=="min") m=$6; else {if ($7~/^day/){if ($9=="min") {d=$6;m=$8} else {d=$6;h=$8;m=$9}} else {h=$6;m=$7}}} {print d+0,"days,",h+0,"hours,",m+0,"minutes"}') | |
fi | |
# CPU temperature | |
if [ -f /sys/class/thermal/thermal_zone0/temp ]; then | |
cpu=$(cat /sys/class/thermal/thermal_zone0/temp) | |
elif [ -f /sys/class/hwmon/hwmon0/temp1_input ]; then | |
cpu=$(cat /sys/class/hwmon/hwmon0/temp1_input) | |
else | |
cpu=0 | |
fi | |
# Convert CPU temperature to correct unit | |
if [ "${TEMPERATUREUNIT}" = "F" ]; then | |
temperature="$(printf %.1f "$(echo "${cpu}" | awk '{print $1 * 9 / 5000 + 32}')")°F" | |
elif [ "${TEMPERATUREUNIT}" = "K" ]; then | |
temperature="$(printf %.1f "$(echo "${cpu}" | awk '{print $1 / 1000 + 273.15}')")°K" | |
# Addresses Issue 1: https://github.com/jpmck/PAD/issues/1 | |
else | |
temperature="$(printf %.1f "$(echo "${cpu}" | awk '{print $1 / 1000}')")°C" | |
fi | |
# CPU load, heatmap | |
cpu_load_1=$(awk '{print $1}' < /proc/loadavg) | |
cpu_load_5=$(awk '{print $2}' < /proc/loadavg) | |
cpu_load_15=$(awk '{print $3}' < /proc/loadavg) | |
cpu_load_1_heatmap=$(HeatmapGenerator "${cpu_load_1}" "${core_count}") | |
cpu_load_5_heatmap=$(HeatmapGenerator "${cpu_load_5}" "${core_count}") | |
cpu_load_15_heatmap=$(HeatmapGenerator "${cpu_load_15}" "${core_count}") | |
cpu_percent=$(printf %.1f "$(echo "${cpu_load_1} ${core_count}" | awk '{print ($1 / $2) * 100}')") | |
# CPU temperature heatmap | |
# If we're getting close to 85°C... (https://www.raspberrypi.org/blog/introducing-turbo-mode-up-to-50-more-performance-for-free/) | |
if [ ${cpu} -gt 80000 ]; then | |
temp_heatmap=${blinking_text}${red_text} | |
pico_status="${pico_status_hot}" | |
mini_status_="${mini_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" | |
full_status_="${full_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" | |
mega_status="${mega_status_hot} ${blinking_text}${red_text}${temperature}${reset_text}" | |
elif [ ${cpu} -gt 70000 ]; then | |
temp_heatmap=${magenta_text} | |
elif [ ${cpu} -gt 60000 ]; then | |
temp_heatmap=${blue_text} | |
else | |
temp_heatmap=${cyan_text} | |
fi | |
# Memory use, heatmap and bar | |
memory_percent=$(awk '/MemTotal:/{total=$2} /MemFree:/{free=$2} /Buffers:/{buffers=$2} /^Cached:/{cached=$2} END {printf "%.1f", (total-free-buffers-cached)*100/total}' '/proc/meminfo') | |
memory_heatmap=$(HeatmapGenerator "${memory_percent}") | |
# Bar generations | |
if [ "$1" = "mini" ]; then | |
cpu_bar=$(BarGenerator "${cpu_percent}" 20) | |
memory_bar=$(BarGenerator "${memory_percent}" 20) | |
elif [ "$1" = "tiny" ]; then | |
cpu_bar=$(BarGenerator "${cpu_percent}" 7) | |
memory_bar=$(BarGenerator "${memory_percent}" 7) | |
else | |
cpu_bar=$(BarGenerator "${cpu_percent}" 10) | |
memory_bar=$(BarGenerator "${memory_percent}" 10) | |
fi | |
} | |
GetNetworkInformation() { | |
# Get pi IPv4 address | |
pi_ip4_addrs="$(ip addr | grep 'inet ' | grep -v '127.0.0.1/8' | awk '{print $2}' | cut -f1 -d'/' |wc -l)" | |
if [ "${pi_ip4_addrs}" -eq 0 ]; then | |
# No IPv4 address available | |
pi_ip4_addr="N/A" | |
elif [ "${pi_ip4_addrs}" -eq 1 ]; then | |
# One IPv4 address available | |
pi_ip4_addr="$(ip addr | grep 'inet ' | grep -v '127.0.0.1/8' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)" | |
else | |
# More than one IPv4 address available | |
pi_ip4_addr="$(ip addr | grep 'inet ' | grep -v '127.0.0.1/8' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)+" | |
fi | |
# Get pi IPv6 address | |
pi_ip6_addrs="$(ip addr | grep 'inet6 ' | grep -v '::1/128' | awk '{print $2}' | cut -f1 -d'/' | wc -l)" | |
if [ "${pi_ip6_addrs}" -eq 0 ]; then | |
# No IPv6 address available | |
pi_ip6_addr="N/A" | |
elif [ "${pi_ip6_addrs}" -eq 1 ]; then | |
# One IPv6 address available | |
pi_ip6_addr="$(ip addr | grep 'inet6 ' | grep -v '::1/128' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)" | |
else | |
# More than one IPv6 address available | |
pi_ip6_addr="$(ip addr | grep 'inet6 ' | grep -v '::1/128' | awk '{print $2}' | cut -f1 -d'/' | head -n 1)+" | |
fi | |
# Get hostname and gateway | |
pi_hostname=$(hostname) | |
pi_gateway=$(ip r | grep 'default' | awk '{print $3}') | |
full_hostname=${pi_hostname} | |
# does the Pi-hole have a domain set? | |
if [ -n "${PIHOLE_DOMAIN+x}" ]; then | |
# is Pi-hole acting as DHCP server? | |
if [ "${DHCP_ACTIVE}" = "true" ]; then | |
count=${pi_hostname}"."${PIHOLE_DOMAIN} | |
count=${#count} | |
if [ "${count}" -lt "18" ]; then | |
full_hostname=${pi_hostname}"."${PIHOLE_DOMAIN} | |
fi | |
fi | |
fi | |
# Get the DNS count (from pihole -c) | |
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+1)) | |
# if there's only one DNS server | |
if [ ${dns_count} -eq 1 ]; then | |
if [ "${PIHOLE_DNS_1}" = "127.0.0.1#5053" ]; then | |
dns_information="1 server (Cloudflared)" | |
elif [ "${PIHOLE_DNS_1}" = "${pi_gateway}#53" ]; then | |
dns_information="1 server (gateway)" | |
else | |
dns_information="1 server" | |
fi | |
elif [ ${dns_count} -gt 8 ]; then | |
dns_information="8+ servers" | |
else | |
dns_information="${dns_count} servers" | |
fi | |
# Is Pi-Hole acting as the DHCP server? | |
if [ "${DHCP_ACTIVE}" = "true" ]; then | |
dhcp_status="Enabled" | |
dhcp_info=" Range: ${DHCP_START} - ${DHCP_END}" | |
dhcp_heatmap=${green_text} | |
dhcp_check_box=${check_box_good} | |
# Is DHCP handling IPv6? | |
# DHCP_IPv6 is set in setupVars.conf | |
# shellcheck disable=SC2154 | |
if [ "${DHCP_IPv6}" = "true" ]; then | |
dhcp_ipv6_status="Enabled" | |
dhcp_ipv6_heatmap=${green_text} | |
dhcp_ipv6_check_box=${check_box_good} | |
else | |
dhcp_ipv6_status="Disabled" | |
dhcp_ipv6_heatmap=${red_text} | |
dhcp_ipv6_check_box=${check_box_bad} | |
fi | |
else | |
dhcp_status="Disabled" | |
dhcp_heatmap=${red_text} | |
dhcp_check_box=${check_box_bad} | |
# if the DHCP Router variable isn't set | |
# Issue 3: https://github.com/jpmck/PADD/issues/3 | |
if [ -z ${DHCP_ROUTER+x} ]; then | |
DHCP_ROUTER=$(/sbin/ip route | awk '/default/ { printf "%s\t", $3 }') | |
fi | |
dhcp_info="Router: ${DHCP_ROUTER}" | |
dhcp_heatmap=${red_text} | |
dhcp_check_box=${check_box_bad} | |
dhcp_ipv6_status="N/A" | |
dhcp_ipv6_heatmap=${yellow_text} | |
dhcp_ipv6_check_box=${check_box_question} | |
fi | |
# DNSSEC | |
if [ "${DNSSEC}" = "true" ]; then | |
dnssec_status="Enabled" | |
dnssec_heatmap=${green_text} | |
else | |
dnssec_status="Disabled" | |
dnssec_heatmap=${red_text} | |
fi | |
# Conditional forwarding | |
if [ "${CONDITIONAL_FORWARDING}" = "true" ] || [ "${REV_SERVER}" = "true" ]; then | |
conditional_forwarding_status="Enabled" | |
conditional_forwarding_heatmap=${green_text} | |
else | |
conditional_forwarding_status="Disabled" | |
conditional_forwarding_heatmap=${red_text} | |
fi | |
} | |
GetPiholeInformation() { | |
# Get FTL status | |
ftlPID=$(pidof pihole-FTL) | |
if [ -z ${ftlPID+x} ]; then | |
ftl_status="Not running" | |
ftl_heatmap=${yellow_text} | |
ftl_check_box=${check_box_info} | |
pico_status=${pico_status_ftl_down} | |
mini_status_=${mini_status_ftl_down} | |
tiny_status_=${tiny_status_ftl_down} | |
full_status_=${full_status_ftl_down} | |
mega_status=${mega_status_ftl_down} | |
else | |
ftl_status="Running" | |
ftl_heatmap=${green_text} | |
ftl_check_box=${check_box_good} | |
ftl_cpu="$(ps -p "${ftlPID}" -o %cpu | tail -n1 | tr -d '[:space:]')" | |
ftl_mem_percentage="$(ps -p "${ftlPID}" -o %mem | tail -n1 | tr -d '[:space:]')" | |
fi | |
# Get Pi-hole (blocking) status | |
ftl_dns_port=$(GetFTLData "dns-port") | |
# ${ftl_dns_port} == 0 DNS server part of dnsmasq disabled, ${ftl_status} == "Not running" no ftlPID found | |
if [ "${ftl_dns_port}" = 0 ] || [ "${ftl_status}" = "Not running" ]; then | |
pihole_status="DNS Offline" | |
pihole_heatmap=${red_text} | |
pihole_check_box=${check_box_bad} | |
pico_status=${pico_status_dns_down} | |
mini_status_=${mini_status_dns_down} | |
tiny_status_=${tiny_status_dns_down} | |
full_status_=${full_status_dns_down} | |
mega_status=${mega_status_dns_down} | |
else | |
if [ "${blocking_status}" = "enabled" ]; then | |
pihole_status="Active" | |
pihole_heatmap=${green_text} | |
pihole_check_box=${check_box_good} | |
fi | |
if [ "${blocking_status}" = "disabled" ]; then | |
pihole_status="Blocking disabled" | |
pihole_heatmap=${red_text} | |
pihole_check_box=${check_box_bad} | |
pico_status=${pico_status_off} | |
mini_status_=${mini_status_off} | |
tiny_status_=${tiny_status_off} | |
full_status_=${full_status_off} | |
mega_status=${mega_status_off} | |
fi | |
if [ "${blocking_status}" = "unknown" ]; then | |
pihole_status="Unknown" | |
pihole_heatmap=${yellow_text} | |
pihole_check_box=${check_box_question} | |
pico_status=${pico_status_unknown} | |
mini_status_=${mini_status_unknown} | |
tiny_status_=${tiny_status_unknown} | |
full_status_=${full_status_unknown} | |
mega_status=${mega_status_unknown} | |
fi | |
fi | |
} | |
GetVersionInformation() { | |
# Check if version status has been saved | |
if [ -f "$piHoleVersion_file" ]; then # the file exists... | |
# the file exits, use it | |
# shellcheck source=./piHoleVersion | |
. "$piHoleVersion_file" | |
# Today is | |
today=$(date +%Y%m%d) | |
# was the last check today? | |
# last_check is read from ./piHoleVersion | |
# shellcheck disable=SC2154 | |
if [ "${today}" != "${last_check}" ]; then # no, it wasn't today | |
# Remove the Pi-hole version file... | |
rm -f "$piHoleVersion_file" | |
fi | |
else # the file doesn't exist, create it... | |
# Gather core version information... | |
core_version=$(pihole -v -p | awk '{print $4}' | tr -d '[:alpha:]') | |
core_version_latest=$(pihole -v -p | awk '{print $6}' | tr -d ')') | |
if [ "${core_version_latest}" = "ERROR" ]; then | |
core_version_heatmap=${yellow_text} | |
else | |
core_version_latest=$(echo "${core_version_latest}" | tr -d '\r\n[:alpha:]') | |
# is core up-to-date? | |
if [ "${core_version}" != "${core_version_latest}" ]; then | |
out_of_date_flag="true" | |
core_version_heatmap=${red_text} | |
else | |
core_version_heatmap=${green_text} | |
fi | |
fi | |
# Gather web version information... | |
if [ "$INSTALL_WEB_INTERFACE" = true ]; then | |
web_version=$(pihole -v -a | awk '{print $4}' | tr -d '[:alpha:]') | |
web_version_latest=$(pihole -v -a | awk '{print $6}' | tr -d ')') | |
if [ "${web_version_latest}" = "ERROR" ]; then | |
web_version_heatmap=${yellow_text} | |
else | |
web_version_latest=$(echo "${web_version_latest}" | tr -d '\r\n[:alpha:]') | |
# is web up-to-date? | |
if [ "${web_version}" != "${web_version_latest}" ]; then | |
out_of_date_flag="true" | |
web_version_heatmap=${red_text} | |
else | |
web_version_heatmap=${green_text} | |
fi | |
fi | |
else | |
# Web interface not installed | |
web_version_heatmap=${red_text} | |
web_version="$(printf '\x08')" # Hex 0x08 is for backspace, to delete the leading 'v' | |
web_version="${web_version}N/A" # N/A = Not Available | |
fi | |
# Gather FTL version information... | |
ftl_version=$(pihole -v -f | awk '{print $4}' | tr -d '[:alpha:]') | |
ftl_version_latest=$(pihole -v -f | awk '{print $6}' | tr -d ')') | |
if [ "${ftl_version_latest}" = "ERROR" ]; then | |
ftl_version_heatmap=${yellow_text} | |
else | |
ftl_version_latest=$(echo "${ftl_version_latest}" | tr -d '\r\n[:alpha:]') | |
# is ftl up-to-date? | |
if [ "${ftl_version}" != "${ftl_version_latest}" ]; then | |
out_of_date_flag="true" | |
ftl_version_heatmap=${red_text} | |
else | |
ftl_version_heatmap=${green_text} | |
fi | |
fi | |
# PADD version information... | |
padd_version_latest="$(curl --silent https://api.github.com/repos/pi-hole/PADD/releases/latest | grep '"tag_name":' | awk -F \" '{print $4}')" | |
# is PADD up-to-date? | |
if [ "${padd_version_latest}" = "" ]; then | |
padd_version_heatmap=${yellow_text} | |
else | |
if [ "${padd_version}" != "${padd_version_latest}" ]; then | |
padd_out_of_date_flag="true" | |
padd_version_heatmap=${red_text} | |
else | |
padd_version_heatmap=${green_text} | |
fi | |
fi | |
# was any portion of Pi-hole out-of-date? | |
# yes, pi-hole is out of date | |
if [ "${out_of_date_flag}" = "true" ]; then | |
version_status="Pi-hole is out-of-date!" | |
version_heatmap=${red_text} | |
version_check_box=${check_box_bad} | |
pico_status=${pico_status_update} | |
mini_status_=${mini_status_update} | |
tiny_status_=${tiny_status_update} | |
full_status_=${full_status_update} | |
mega_status=${mega_status_update} | |
else | |
# but is PADD out-of-date? | |
if [ "${padd_out_of_date_flag}" = "true" ]; then | |
version_status="PADD is out-of-date!" | |
version_heatmap=${red_text} | |
version_check_box=${check_box_bad} | |
pico_status=${pico_status_update} | |
mini_status_=${mini_status_update} | |
tiny_status_=${tiny_status_update} | |
full_status_=${full_status_update} | |
mega_status=${mega_status_update} | |
# else, everything is good! | |
else | |
version_status="Pi-hole is up-to-date!" | |
version_heatmap=${green_text} | |
version_check_box=${check_box_good} | |
pico_status=${pico_status_ok} | |
mini_status_=${mini_status_ok} | |
tiny_status_=${tiny_status_ok} | |
full_status_=${full_status_ok} | |
mega_status=${mega_status_ok} | |
fi | |
fi | |
# write it all to the file | |
echo "last_check=${today}" > "$piHoleVersion_file" | |
{ | |
echo "core_version=$core_version" | |
echo "core_version_latest=$core_version_latest" | |
echo "core_version_heatmap=$core_version_heatmap" | |
echo "web_version=$web_version" | |
echo "web_version_latest=$web_version_latest" | |
echo "web_version_heatmap=$web_version_heatmap" | |
echo "ftl_version=$ftl_version" | |
echo "ftl_version_latest=$ftl_version_latest" | |
echo "ftl_version_heatmap=$ftl_version_heatmap" | |
echo "padd_version=$padd_version" | |
echo "padd_version_latest=$padd_version_latest" | |
echo "padd_version_heatmap=$padd_version_heatmap" | |
echo "version_status=\"$version_status\"" | |
echo "version_heatmap=$version_heatmap" | |
echo "version_check_box=\"$version_check_box\"" | |
echo "pico_status=\"$pico_status\"" | |
echo "mini_status_=\"$mini_status_\"" | |
echo "tiny_status_=\"$tiny_status_\"" | |
echo "full_status_=\"$full_status_\"" | |
echo "mega_status=\"$mega_status\"" | |
} >> "$piHoleVersion_file" | |
# there's a file now | |
fi | |
} | |
############################################# PRINTERS ############################################# | |
# terminfo clr_eol (clears to end of line to erase artifacts after resizing smaller) | |
ceol=$(tput el) | |
# wrapper - echo with a clear eol afterwards to wipe any artifacts remaining from last print | |
CleanEcho() { | |
echo "${ceol}$1" | |
} | |
# wrapper - printf | |
CleanPrintf() { | |
# tput el | |
# disabling shellcheck here because we pass formatting instructions within `"${@}"` | |
# shellcheck disable=SC2059 | |
printf "$@" | |
} | |
PrintLogo() { | |
# Screen size checks | |
if [ "$1" = "pico" ]; then | |
CleanEcho "p${padd_text} ${pico_status}" | |
elif [ "$1" = "nano" ]; then | |
CleanEcho "n${padd_text} ${mini_status_}" | |
elif [ "$1" = "micro" ]; then | |
CleanEcho "µ${padd_text} ${mini_status_}" | |
CleanEcho "" | |
elif [ "$1" = "mini" ]; then | |
CleanEcho "${padd_text}${dim_text}mini${reset_text} ${mini_status_}" | |
CleanEcho "" | |
elif [ "$1" = "tiny" ]; then | |
CleanEcho "${padd_text}${dim_text}tiny${reset_text} Pi-hole® ${core_version_heatmap}v${core_version}${reset_text}, Web ${web_version_heatmap}v${web_version}${reset_text}, FTL ${ftl_version_heatmap}v${ftl_version}${reset_text}" | |
CleanPrintf " PADD ${padd_version_heatmap}${padd_version}${reset_text} ${tiny_status_}${reset_text}\e[0K\\n" | |
elif [ "$1" = "slim" ]; then | |
CleanEcho "${padd_text}${dim_text}slim${reset_text} ${full_status_}" | |
CleanEcho "" | |
# For the next two, use printf to make sure spaces aren't collapsed | |
elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then | |
CleanPrintf "${padd_logo_1}\e[0K\\n" | |
CleanPrintf "${padd_logo_2}Pi-hole® ${core_version_heatmap}v${core_version}${reset_text}, Web ${web_version_heatmap}v${web_version}${reset_text}, FTL ${ftl_version_heatmap}v${ftl_version}${reset_text}\e[0K\\n" | |
CleanPrintf "${padd_logo_3}PADD ${padd_version_heatmap}${padd_version}${reset_text} ${full_status_}${reset_text}\e[0K\\n" | |
CleanEcho "" | |
# normal or not defined | |
else | |
CleanPrintf "${padd_logo_retro_1}\e[0K\\n" | |
CleanPrintf "${padd_logo_retro_2} Pi-hole® ${core_version_heatmap}v${core_version}${reset_text}, Web ${web_version_heatmap}v${web_version}${reset_text}, FTL ${ftl_version_heatmap}v${ftl_version}${reset_text}, PADD ${padd_version_heatmap}${padd_version}${reset_text}, Unbound ${green_text}v${unbound}${reset_text}\e[0K\\n" | |
CleanPrintf "${padd_logo_retro_3} ${pihole_check_box} Core ${ftl_check_box} FTL ${mega_status} ${check_box_info} "$(date +%d/%m/%y)", "$(date +%R)" ${reset_text}\e[0K\\n" | |
CleanEcho "" | |
fi | |
} | |
PrintNetworkInformation() { | |
if [ "$1" = "pico" ]; then | |
CleanEcho "${bold_text}NETWORK ============${reset_text}" | |
CleanEcho " Hst: ${pi_hostname}" | |
CleanEcho " IP: ${pi_ip4_addr}" | |
CleanEcho " DHCP ${dhcp_check_box} IPv6 ${dhcp_ipv6_check_box}" | |
elif [ "$1" = "nano" ]; then | |
CleanEcho "${bold_text}NETWORK ================${reset_text}" | |
CleanEcho " Host: ${pi_hostname}" | |
CleanEcho " IP: ${pi_ip4_addr}" | |
CleanEcho " DHCP: ${dhcp_check_box} IPv6: ${dhcp_ipv6_check_box}" | |
elif [ "$1" = "micro" ]; then | |
CleanEcho "${bold_text}NETWORK ======================${reset_text}" | |
CleanEcho " Host: ${full_hostname}" | |
CleanEcho " IP: ${pi_ip4_addr}" | |
CleanEcho " DHCP: ${dhcp_check_box} IPv6: ${dhcp_ipv6_check_box}" | |
elif [ "$1" = "mini" ]; then | |
CleanEcho "${bold_text}NETWORK ================================${reset_text}" | |
CleanPrintf " %-9s%-19s\e[0K\\n" "Host:" "${full_hostname}" | |
CleanPrintf " %-9s%-19s\e[0K\\n" "IP:" "${pi_ip4_addr}" | |
CleanPrintf " %-9s%-10s\e[0K\\n" "DNS:" "${dns_information}" | |
if [ "${DHCP_ACTIVE}" = "true" ]; then | |
CleanPrintf " %-9s${dhcp_heatmap}%-10s${reset_text} %-9s${dhcp_ipv6_heatmap}%-10s${reset_text}\e[0K\\n" "DHCP:" "${dhcp_status}" "IPv6:" ${dhcp_ipv6_status} | |
fi | |
elif [ "$1" = "tiny" ]; then | |
CleanEcho "${bold_text}NETWORK ============================================${reset_text}" | |
CleanPrintf " %-10s%-16s %-8s%-16s\e[0K\\n" "Hostname:" "${full_hostname}" "IP: " "${pi_ip4_addr}" | |
CleanPrintf " %-6s%-39s\e[0K\\n" "IPv6:" "${pi_ip6_addr}" | |
CleanPrintf " %-10s%-16s %-8s%-16s\e[0K\\n" "DNS:" "${dns_information}" "DNSSEC:" "${dnssec_heatmap}${dnssec_status}${reset_text}" | |
if [ "${DHCP_ACTIVE}" = "true" ]; then | |
CleanPrintf " %-10s${dhcp_heatmap}%-16s${reset_text} %-8s${dhcp_ipv6_heatmap}%-10s${reset_text}\e[0K\\n" "DHCP:" "${dhcp_status}" "IPv6:" ${dhcp_ipv6_status} | |
CleanPrintf "%s\e[0K\\n" "${dhcp_info}" | |
fi | |
elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then | |
CleanEcho "${bold_text}NETWORK ===================================================${reset_text}" | |
CleanPrintf " %-10s%-19s %-10s%-19s\e[0K\\n" "Hostname:" "${full_hostname}" "IP:" "${pi_ip4_addr}" | |
CleanPrintf " %-6s%-19s\e[0K\\n" "IPv6:" "${pi_ip6_addr}" | |
CleanPrintf " %-10s%-19s %-10s%-19s\e[0K\\n" "DNS:" "${dns_information}" "DNSSEC:" "${dnssec_heatmap}${dnssec_status}${reset_text}" | |
if [ "${DHCP_ACTIVE}" = "true" ]; then | |
CleanPrintf " %-10s${dhcp_heatmap}%-19s${reset_text} %-10s${dhcp_ipv6_heatmap}%-19s${reset_text}\e[0K\\n" "DHCP:" "${dhcp_status}" "IPv6:" ${dhcp_ipv6_status} | |
CleanPrintf "%s\e[0K\\n" "${dhcp_info}" | |
fi | |
else | |
CleanEcho "${bold_text}NETWORK ============================================================================================${reset_text}" | |
CleanPrintf " %-10s%-19s %-10s%-29s\e[0K\\n" "FQDN:" "${full_hostname}" #"Date:" "$(date +%d/%m/%y)" #"PID": "${paddPID}" | |
CleanPrintf " %-10s%-19s %-6s%-29s\e[0K\\n" "IPv4:" "${pi_ip4_addr}" "IPv6:" "${pi_ip6_addr}"${reset_text} #${dhcp_ipv6_status} | |
CleanEcho "UNBOUND ============================================================================================" | |
CleanPrintf " %-10s%-19s%-10s%-9s\e[0K\\n" "Total: " "$(sudo unbound-control stats_noreset | awk -F '=' '/total.num.queries=/ {printf $NF}') queries" " Reply:" " $(sudo unbound-control stats_noreset | awk -F '=' '/total.recursion.time.avg/ {printf "%.3f\n", $NF}') seconds" | |
CleanPrintf " %-10s%-19s%-10s%-9s\e[0K\\n" "Cached:" "$(sudo unbound-control stats_noreset | awk -F '=' '$1 == "total.num.queries" {queries=$NF} $1 == "total.num.cachehits" {hits=$NF}END{printf "%d, %.2f\n", hits, hits/queries*100"%"}')% " " Updted: " " $(cat /var/lib/unbound/root.hints | awk '/last update/ {printf ($4" "$5" "$6)}') " | |
#CleanPrintf " %-10s%-19s%-10s%-9s\e[0K\\n" "Missed: " "$(sudo unbound-control stats_noreset | awk -F '=' '/total.num.cachemiss=/ {printf $NF}') queries" " Cached:" " $(sudo unbound-control stats_noreset | awk -F '=' '/total.num.cachehits/ {printf $NF}') queries" | |
#CleanPrintf " %-10s${dnssec_heatmap}%-19s${reset_text} %-20s${conditional_forwarding_heatmap}%-9s${reset_text}\e[0K\\n" "DNSSEC:" "${dnssec_status}" "Conditional Fwding:" "${conditional_forwarding_status}" | |
CleanEcho "DHCP ===============================================================================================" | |
#CleanPrintf " %-10s${dhcp_status}%-19s${reset_text} %-20s%-20s\e[0K\\n" "DHCP:" "${dhcp_info}" | |
CleanPrintf " %-10s${dhcp_heatmap}%-19s${reset_text} %-30s${dhcp_ipv6_heatmap}%-9s${reset_text}\e[0K\\n" "DHCP:" "${dhcp_status}" "${dhcp_info}" | |
CleanPrintf " %-10s${dnssec_heatmap}%-19s${reset_text} %-10s${conditional_forwarding_heatmap}%-9s${reset_text}\e[0K\\n" "DNSSEC:" "${dnssec_status}" "Fwding:" "${conditional_forwarding_status}" | |
#CleanPrintf "%-10s%-19s %-10s%-29s\e[0K\\n" "${dhcp_info}" "DNSSEC:" "${dnssec_heatmap}${dnssec_status}"${reset_text} | |
fi | |
} | |
PrintPiholeInformation() { | |
# size checks | |
if [ "$1" = "pico" ]; then | |
: | |
elif [ "$1" = "nano" ]; then | |
CleanEcho "${bold_text}PI-HOLE ================${reset_text}" | |
CleanEcho " Up: ${pihole_check_box} FTL: ${ftl_check_box}" | |
elif [ "$1" = "micro" ]; then | |
CleanEcho "${bold_text}PI-HOLE ======================${reset_text}" | |
CleanEcho " Status: ${pihole_check_box} FTL: ${ftl_check_box}" | |
elif [ "$1" = "mini" ]; then | |
CleanEcho "${bold_text}PI-HOLE ================================${reset_text}" | |
CleanPrintf " %-9s${pihole_heatmap}%-10s${reset_text} %-9s${ftl_heatmap}%-10s${reset_text}\e[0K\\n" "Status:" "${pihole_status}" "FTL:" "${ftl_status}" | |
elif [ "$1" = "tiny" ]; then | |
CleanEcho "${bold_text}PI-HOLE ============================================${reset_text}" | |
CleanPrintf " %-10s${pihole_heatmap}%-16s${reset_text} %-8s${ftl_heatmap}%-10s${reset_text}\e[0K\\n" "Status:" "${pihole_status}" "FTL:" "${ftl_status}" | |
elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then | |
CleanEcho "${bold_text}PI-HOLE ===================================================${reset_text}" | |
CleanPrintf " %-10s${pihole_heatmap}%-19s${reset_text} %-10s${ftl_heatmap}%-19s${reset_text}\e[0K\\n" "Status:" "${pihole_status}" "FTL:" "${ftl_status}" | |
else | |
return | |
fi | |
} | |
PrintPiholeStats() { | |
# are we on a reduced screen size? | |
if [ "$1" = "pico" ]; then | |
CleanEcho "${bold_text}PI-HOLE ============${reset_text}" | |
CleanEcho " [${ads_blocked_bar}] ${ads_percentage_today}%" | |
CleanEcho " ${ads_blocked_today} / ${dns_queries_today}" | |
elif [ "$1" = "nano" ]; then | |
CleanEcho " Blk: [${ads_blocked_bar}] ${ads_percentage_today}%" | |
CleanEcho " Blk: ${ads_blocked_today} / ${dns_queries_today}" | |
elif [ "$1" = "micro" ]; then | |
CleanEcho "${bold_text}STATS ========================${reset_text}" | |
CleanEcho " Blckng: ${domains_being_blocked} domains" | |
CleanEcho " Piholed: [${ads_blocked_bar}] ${ads_percentage_today}%" | |
CleanEcho " Piholed: ${ads_blocked_today} / ${dns_queries_today}" | |
elif [ "$1" = "mini" ]; then | |
CleanEcho "${bold_text}STATS ==================================${reset_text}" | |
CleanPrintf " %-9s%-29s\e[0K\\n" "Blckng:" "${domains_being_blocked} domains" | |
CleanPrintf " %-9s[%-20s] %-5s\e[0K\\n" "Piholed:" "${ads_blocked_bar}" "${ads_percentage_today}%" | |
CleanPrintf " %-9s%-29s\e[0K\\n" "Piholed:" "${ads_blocked_today} out of ${dns_queries_today}" | |
CleanPrintf " %-9s%-29s\e[0K\\n" "Latest:" "${latest_blocked}" | |
if [ "${DHCP_ACTIVE}" != "true" ]; then | |
CleanPrintf " %-9s%-29s\\n" "Top Ad:" "${top_blocked}" | |
fi | |
elif [ "$1" = "tiny" ]; then | |
CleanEcho "${bold_text}STATS ==============================================${reset_text}" | |
CleanPrintf " %-10s%-29s\e[0K\\n" "Blocking:" "${domains_being_blocked} domains" | |
CleanPrintf " %-10s[%-30s] %-5s\e[0K\\n" "Pi-holed:" "${ads_blocked_bar}" "${ads_percentage_today}%" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Pi-holed:" "${ads_blocked_today} out of ${dns_queries_today}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Latest:" "${latest_blocked}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Ad:" "${top_blocked}" | |
if [ "${DHCP_ACTIVE}" != "true" ]; then | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Dmn:" "${top_domain}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Clnt:" "${top_client}" | |
fi | |
elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then | |
CleanEcho "${bold_text}STATS =====================================================${reset_text}" | |
CleanPrintf " %-10s%-49s\e[0K\\n" "Blocking:" "${domains_being_blocked} domains" | |
CleanPrintf " %-10s[%-40s] %-5s\e[0K\\n" "Pi-holed:" "${ads_blocked_bar}" "${ads_percentage_today}%" | |
CleanPrintf " %-10s%-49s\e[0K\\n" "Pi-holed:" "${ads_blocked_today} out of ${dns_queries_today} queries" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Latest:" "${latest_blocked}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Ad:" "${top_blocked}" | |
if [ "${DHCP_ACTIVE}" != "true" ]; then | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Dmn:" "${top_domain}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Clnt:" "${top_client}" | |
fi | |
else | |
CleanEcho "${bold_text}STATS ==============================================================================================${reset_text}" | |
CleanPrintf " %-10s%-29s %-10s[%-40s] %-5s\e[0K\\n" "Blocking:" "${domains_being_blocked} domains" "PiHoled:" "${ads_blocked_bar}" "${ads_percentage_today}%" | |
CleanPrintf " %-10s%-40s%-29s\e[0K\\n" "Clients:" "${clients}" " ${ads_blocked_today} out of ${dns_queries_today} queries" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Latest:" "${latest_blocked}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Ad:" "${top_blocked}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Dmn:" "${top_domain}" | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Top Clnt:" "${top_client}" | |
CleanEcho "FTL ================================================================================================" | |
CleanPrintf " %-10s%-9s %-5s%-9s %-6s%-9s %-5s%-9s\e[0K\\n" "PID:" "${ftlPID}" "CPU:" "${ftl_cpu}%" "RAM:" "${ftl_mem_percentage}%" "Size: $(du -h /etc/pihole/pihole-FTL.db | awk '{ print $1}')" | |
CleanPrintf " %-10s%-69s\e[0K\\n" "DNSCache:" "${cache_inserts} insertions, ${cache_deletes} deletions, ${cache_size} total entries" | |
fi | |
} | |
PrintSystemInformation() { | |
if [ "$1" = "pico" ]; then | |
CleanEcho "${bold_text}CPU ================${reset_text}" | |
printf "%b" "${ceol} [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" | |
elif [ "$1" = "nano" ]; then | |
CleanEcho "${ceol}${bold_text}SYSTEM =================${reset_text}" | |
CleanEcho " Up: ${system_uptime}" | |
printf "%b" "${ceol} CPU: [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" | |
elif [ "$1" = "micro" ]; then | |
CleanEcho "${bold_text}SYSTEM =======================${reset_text}" | |
CleanEcho " Uptime: ${system_uptime}" | |
CleanEcho " Load: [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" | |
printf "%b" "${ceol} Memory: [${memory_heatmap}${memory_bar}${reset_text}] ${memory_percent}%" | |
elif [ "$1" = "mini" ]; then | |
CleanEcho "${bold_text}SYSTEM =================================${reset_text}" | |
CleanPrintf " %-9s%-29s\\n" "Uptime:" "${system_uptime}" | |
CleanEcho " Load: [${cpu_load_1_heatmap}${cpu_bar}${reset_text}] ${cpu_percent}%" | |
printf "%b" "${ceol} Memory: [${memory_heatmap}${memory_bar}${reset_text}] ${memory_percent}%" | |
elif [ "$1" = "tiny" ]; then | |
CleanEcho "${bold_text}SYSTEM =============================================${reset_text}" | |
CleanPrintf " %-10s%-29s\e[0K\\n" "Uptime:" "${system_uptime}" | |
CleanPrintf " %-10s${temp_heatmap}%-17s${reset_text} %-8s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}\e[0K\\n" "CPU Temp:" "${temperature}" "Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" | |
# Memory and CPU bar | |
CleanPrintf " %-10s[${memory_heatmap}%-7s${reset_text}] %-6s %-8s[${cpu_load_1_heatmap}%-7s${reset_text}] %-5s" "Memory:" "${memory_bar}" "${memory_percent}%" "CPU:" "${cpu_bar}" "${cpu_percent}%" | |
# else we're not | |
elif [ "$1" = "regular" ] || [ "$1" = "slim" ]; then | |
CleanEcho "${bold_text}SYSTEM ====================================================${reset_text}" | |
# Uptime | |
CleanPrintf " %-10s%-39s\e[0K\\n" "Uptime:" "${system_uptime}" | |
# Temp and Loads | |
CleanPrintf " %-10s${temp_heatmap}%-20s${reset_text}" "CPU Temp:" "${temperature}" | |
CleanPrintf " %-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-4s${reset_text}\e[0K\\n" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" | |
# Memory and CPU bar | |
CleanPrintf " %-10s[${memory_heatmap}%-10s${reset_text}] %-6s %-10s[${cpu_load_1_heatmap}%-10s${reset_text}] %-5s" "Memory:" "${memory_bar}" "${memory_percent}%" "CPU Load:" "${cpu_bar}" "${cpu_percent}%" | |
else | |
CleanEcho "${bold_text}INFO ===============================================================================================${reset_text}" | |
# Boot and log | |
CleanPrintf " %-10s%-19s%-6s%-9s\e[0K\\n" "Boot: " "${boot_time} seconds" " Log:" " ${log_size}B (${log_perc})" | |
# Disk Usage | |
CleanPrintf " %-10s%-19s%-6s%-9s\e[0K\\n" "Disk: " "${disk_total}GB" " Used:" " ${disk_used}GB (${disk_perc})" | |
# Processes and installed packages -comment the below 2 lines if you want to use 16pt font: Uni2-Fixed16 | |
CleanPrintf " %-10s%-19s%-10s%-9s\e[0K\\n" "Packages: " "${installed_packages}" " Processes:" " ${run_process}" | |
CleanPrintf " %-10s%-19s%-6s%-4s\e[0K\\n" "Model: " "${version}" " RAM:" "${ram_total} GB" | |
CleanEcho "SYSTEM ============================================================================================" | |
# Uptime and memory | |
CleanPrintf " %-10s%-39s %-10s[${memory_heatmap}%-10s${reset_text}] %-6s\\n" "Uptime:" "${system_uptime}" "RAM use $(free -m | awk 'NR==2{printf "%s", $3 }') MB of ${ram_total} GB: " "${memory_bar}" "${memory_percent}% "${reset_text} | |
# CPU temp, load, percentage | |
CleanPrintf " %-10s${temp_heatmap}%-10s${reset_text} %-10s${cpu_load_1_heatmap}%-4s${reset_text}, ${cpu_load_5_heatmap}%-4s${reset_text}, ${cpu_load_15_heatmap}%-7s${reset_text} %-10s[${memory_heatmap}%-10s${reset_text}] %-6s" "CPU Temp:" "${temperature}" "CPU Load:" "${cpu_load_1}" "${cpu_load_5}" "${cpu_load_15}" "CPU $(awk 'length==6{printf("%.0f MHz\n", $0/10^3); next} length==7{printf("%.1f GHz\n", $0/10^6)}' /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq) / ${cpu_freq}: "$(printf '%s')" " "${cpu_bar}" "${cpu_percent}%" | |
CleanEcho "" | |
CleanPrintf "" | |
fi | |
} | |
############################################# HELPERS ############################################## | |
# Provides a color based on a provided percentage | |
# takes in one or two parameters | |
HeatmapGenerator () { | |
# if one number is provided, just use that percentage to figure out the colors | |
if [ -z "$2" ]; then | |
load=$(printf "%.0f" "$1") | |
# if two numbers are provided, do some math to make a percentage to figure out the colors | |
else | |
load=$(printf "%.0f" "$(echo "$1 $2" | awk '{print ($1 / $2) * 100}')") | |
fi | |
# Color logic | |
# |<- green ->| yellow | red -> | |
# 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 | |
if [ "${load}" -lt 75 ]; then | |
out=${green_text} | |
elif [ "${load}" -lt 90 ]; then | |
out=${yellow_text} | |
else | |
out=${red_text} | |
fi | |
echo "$out" | |
} | |
# Provides a "bar graph" | |
# takes in two or three parameters | |
# $1: percentage filled | |
# $2: max length of the bar | |
# $3: colored flag, if "color" backfill with color | |
BarGenerator() { | |
# number of filled in cells in the bar | |
barNumber=$(printf %.f "$(echo "$1 $2" | awk '{print ($1 / 100) * $2}')") | |
frontFill=$(for i in $(seq "$barNumber"); do printf "%b" "■"; done) | |
# remaining "unfilled" cells in the bar | |
backfillNumber=$(($2-barNumber)) | |
# if the filled in cells is less than the max length of the bar, fill it | |
if [ "$barNumber" -lt "$2" ]; then | |
# if the bar should be colored | |
if [ "$3" = "color" ]; then | |
# fill the rest in color | |
backFill=$(for i in $(seq $backfillNumber); do printf "%b" "■"; done) | |
out="${red_text}${frontFill}${green_text}${backFill}${reset_text}" | |
# else, it shouldn't be colored in | |
else | |
# fill the rest with "space" | |
backFill=$(for i in $(seq $backfillNumber); do printf "%b" "·"; done) | |
out="${frontFill}${reset_text}${backFill}" | |
fi | |
# else, fill it all the way | |
else | |
out=$(for i in $(seq "$2"); do printf "%b" "■"; done) | |
fi | |
echo "$out" | |
} | |
# Checks the size of the screen and sets the value of padd_size | |
SizeChecker(){ | |
# Below Pico. Gives you nothing... | |
if [ "$console_width" -lt "20" ] || [ "$console_height" -lt "10" ]; then | |
# Nothing is this small, sorry | |
clear | |
printf "%b" "${check_box_bad} Error!\\n PADD isn't\\n for ants!\n" | |
exit 1 | |
# Below Nano. Gives you Pico. | |
elif [ "$console_width" -lt "24" ] || [ "$console_height" -lt "12" ]; then | |
padd_size="pico" | |
# Below Micro, Gives you Nano. | |
elif [ "$console_width" -lt "30" ] || [ "$console_height" -lt "16" ]; then | |
padd_size="nano" | |
# Below Mini. Gives you Micro. | |
elif [ "$console_width" -lt "40" ] || [ "$console_height" -lt "18" ]; then | |
padd_size="micro" | |
# Below Tiny. Gives you Mini. | |
elif [ "$console_width" -lt "53" ] || [ "$console_height" -lt "20" ]; then | |
padd_size="mini" | |
# Below Slim. Gives you Tiny. | |
elif [ "$console_width" -lt "60" ] || [ "$console_height" -lt "21" ]; then | |
padd_size="tiny" | |
# Below Regular. Gives you Slim. | |
elif [ "$console_width" -lt "80" ] || [ "$console_height" -lt "26" ]; then | |
if [ "$console_height" -lt "22" ]; then | |
padd_size="slim" | |
else | |
padd_size="regular" | |
fi | |
# Mega | |
else | |
padd_size="mega" | |
fi | |
} | |
CheckConnectivity() { | |
connectivity="false" | |
connection_attempts=1 | |
wait_timer=1 | |
while [ $connection_attempts -lt 9 ]; do | |
if nc -zw1 google.com 443 2>/dev/null; then | |
if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then | |
echo "Attempt #${connection_attempts} passed..." | |
elif [ "$1" = "mini" ]; then | |
echo "Attempt ${connection_attempts} passed." | |
else | |
echo " - Attempt ${connection_attempts} passed... " | |
fi | |
connectivity="true" | |
connection_attempts=11 | |
else | |
connection_attempts=$((connection_attempts+1)) | |
inner_wait_timer=$((wait_timer*1)) | |
# echo "$wait_timer = $inner_wait_timer" | |
while [ $inner_wait_timer -gt 0 ]; do | |
if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then | |
printf "%b" "Attempt #${connection_attempts} failed...\\r" | |
elif [ "$1" = "mini" ] || [ "$1" = "tiny" ]; then | |
printf "%b" "- Attempt ${connection_attempts} failed, wait ${inner_wait_timer} \\r" | |
else | |
printf "%b" " - Attempt ${connection_attempts} failed... waiting ${inner_wait_timer} seconds... \\r" | |
fi | |
sleep 1 | |
inner_wait_timer=$((inner_wait_timer-1)) | |
done | |
# echo -ne "Attempt $connection_attempts failed... waiting $wait_timer seconds...\\r" | |
# sleep $wait_timer | |
wait_timer=$((wait_timer*2)) | |
fi | |
done | |
if [ "$connectivity" = "false" ]; then | |
if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then | |
echo "Check failed..." | |
elif [ "$1" = "mini" ] || [ "$1" = "tiny" ]; then | |
echo "- Connectivity check failed." | |
else | |
echo " - Connectivity check failed..." | |
fi | |
else | |
if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then | |
echo "Check passed..." | |
elif [ "$1" = "mini" ] || [ "$1" = "tiny" ]; then | |
echo "- Connectivity check passed." | |
else | |
echo " - Connectivity check passed..." | |
fi | |
fi | |
} | |
########################################## MAIN FUNCTIONS ########################################## | |
OutputJSON() { | |
GetSummaryInformation | |
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},\"clients\": ${clients}}" | |
cd "$oldpath" > /dev/null || exit | |
} | |
StartupRoutine(){ | |
if [ "$1" = "pico" ] || [ "$1" = "nano" ] || [ "$1" = "micro" ]; then | |
PrintLogo "$1" | |
printf "%b" "START-UP ===========\n" | |
printf "%b" "Checking connection.\n" | |
CheckConnectivity "$1" | |
printf "%b" "Starting PADD...\n" | |
printf "%b" " [■·········] 10%\\r" | |
# Check for updates | |
printf "%b" " [■■········] 20%\\r" | |
if [ -f "$piHoleVersion_file" ]; then | |
rm -f "$piHoleVersion_file" | |
printf "%b" " [■■■·······] 30%\\r" | |
else | |
printf "%b" " [■■■·······] 30%\\r" | |
fi | |
# Get our information for the first time | |
printf "%b" " [■■■■······] 40%\\r" | |
GetSystemInformation "$1" | |
printf "%b" " [■■■■■·····] 50%\\r" | |
GetSummaryInformation "$1" | |
printf "%b" " [■■■■■■····] 60%\\r" | |
GetPiholeInformation "$1" | |
printf "%b" " [■■■■■■■···] 70%\\r" | |
GetNetworkInformation "$1" | |
printf "%b" " [■■■■■■■■··] 80%\\r" | |
GetVersionInformation "$1" | |
printf "%b" " [■■■■■■■■■·] 90%\\r" | |
printf "%b" " [■■■■■■■■■■] 100%\\n" | |
elif [ "$1" = "mini" ]; then | |
PrintLogo "$1" | |
echo "START UP =====================" | |
echo "Checking connectivity." | |
CheckConnectivity "$1" | |
echo "Starting PADD." | |
# Check for updates | |
echo "- Checking for version file." | |
if [ -f "$piHoleVersion_file" ]; then | |
echo " - Found and deleted." | |
rm -f "$piHoleVersion_file" | |
else | |
echo " - Not found." | |
fi | |
# Get our information for the first time | |
echo "- Gathering system info." | |
GetSystemInformation "mini" | |
echo "- Gathering Pi-hole info." | |
GetSummaryInformation "mini" | |
echo "- Gathering network info." | |
GetNetworkInformation "mini" | |
echo "- Gathering version info." | |
GetVersionInformation "mini" | |
echo " - Core v$core_version, Web v$web_version" | |
echo " - FTL v$ftl_version, PADD $padd_version" | |
echo " - $version_status" | |
else | |
printf "%b" "${padd_logo_retro_1}\n" | |
printf "%b" "${padd_logo_retro_2}Pi-hole® Ad Detection Display\n" | |
printf "%b" "${padd_logo_retro_3}A client for Pi-hole\n\n" | |
if [ "$1" = "tiny" ]; then | |
echo "START UP ============================================" | |
else | |
echo "START UP ===================================================" | |
fi | |
printf "%b" "- Checking internet connection...\n" | |
CheckConnectivity "$1" | |
# Check for updates | |
echo "- Checking for PADD version file..." | |
if [ -f "$piHoleVersion_file" ]; then | |
echo " - PADD version file found... deleting." | |
rm -f "$piHoleVersion_file" | |
else | |
echo " - PADD version file not found." | |
fi | |
# Get our information for the first time | |
echo "- Gathering system information..." | |
GetSystemInformation "$1" | |
echo "- Gathering Pi-hole information..." | |
GetSummaryInformation "$1" | |
GetPiholeInformation "$1" | |
echo "- Gathering network information..." | |
GetNetworkInformation "$1" | |
echo "- Gathering version information..." | |
GetVersionInformation "$1" | |
echo " - Pi-hole Core v$core_version" | |
echo " - Web Admin v$web_version" | |
echo " - FTL v$ftl_version" | |
echo " - PADD $padd_version" | |
echo " - $version_status" | |
fi | |
printf "%s" "- Starting in " | |
for i in 3 2 1 | |
do | |
printf "%s..." "$i" | |
sleep 1 | |
done | |
} | |
NormalPADD() { | |
while true; do | |
console_width=$(tput cols) | |
console_height=$(tput lines) | |
# Sizing Checks | |
SizeChecker | |
# Move the cursor to top left of console to redraw | |
tput cup 0 0 | |
# Output everything to the screen | |
PrintLogo ${padd_size} | |
PrintPiholeInformation ${padd_size} | |
PrintPiholeStats ${padd_size} | |
PrintNetworkInformation ${padd_size} | |
PrintSystemInformation ${padd_size} | |
# Clear to end of screen (below the drawn dashboard) | |
tput ed | |
pico_status=${pico_status_ok} | |
mini_status_=${mini_status_ok} | |
tiny_status_=${tiny_status_ok} | |
# Start getting our information | |
GetVersionInformation ${padd_size} | |
GetSummaryInformation ${padd_size} | |
GetPiholeInformation ${padd_size} | |
GetNetworkInformation ${padd_size} | |
GetSystemInformation ${padd_size} | |
# Sleep for 5 seconds | |
sleep 5 | |
done | |
} | |
DisplayHelp() { | |
cat << EOM | |
::: PADD displays stats about your piHole! | |
::: | |
::: Note: If no option is passed, then stats are displayed on screen, updated every 5 seconds | |
::: | |
::: Options: | |
::: -j, --json output stats as JSON formatted string | |
::: -h, --help display this help text | |
EOM | |
exit 0 | |
} | |
if [ $# = 0 ]; then | |
# Turns off the cursor | |
# (From Pull request #8 https://github.com/jpmck/PADD/pull/8) | |
setterm -cursor off | |
trap "{ setterm -cursor on ; echo "" ; exit 0 ; }" INT TERM EXIT | |
clear | |
console_width=$(tput cols) | |
console_height=$(tput lines) | |
SizeChecker | |
StartupRoutine ${padd_size} | |
# Run PADD | |
clear | |
NormalPADD | |
cd "$oldpath" > /dev/null || exit | |
fi | |
for var in "$@"; do | |
case "$var" in | |
"-j" | "--json" ) OutputJSON;; | |
"-h" | "--help" ) DisplayHelp;; | |
* ) exit 1;; | |
esac | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment