├── README.md ├── LICENSE ├── get_CLN_data.sh ├── get_LND_data.sh └── raspibolt-pulse-switch.sh /README.md: -------------------------------------------------------------------------------- 1 | # RaspiBolt Pulse 2 | 3 | A bash script to monitor a RaspiBolt node health and activity at a glance. 4 | 5 | ## Installation 6 | ```sh 7 | $ cd /tmp 8 | $ git clone https://github.com/raspibolt/raspibolt-pulse 9 | $ sudo cp raspibolt-pulse/*.sh /usr/local/bin/ 10 | $ sudo mv /usr/local/bin/raspibolt-pulse-switch.sh /usr/local/bin/raspibolt 11 | ``` 12 | 13 | To use this script, follow the following RaspiBolt [bonus guide](https://raspibolt.org/guide/bonus/raspberry-pi/system-overview.html). 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 raspibolt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /get_CLN_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | chain=$1 3 | color_green=$2 4 | color_red=$3 5 | ln_git_version=$4 6 | 7 | 8 | echo -ne '\r### Loading CoreLN data \r' 9 | 10 | ln_running=$(systemctl is-active cln 2>&1) 11 | coreln_color="${color_green}" 12 | if [ -z "${ln_running##*inactive*}" ]; then 13 | ln_running="down" 14 | coreln_color="${color_red}\e[7m" 15 | else 16 | if [ -z "${ln_running##*failed*}" ]; then 17 | ln_running="down" 18 | coreln_color="${color_red}\e[7m" 19 | else 20 | ln_running="up" 21 | fi 22 | fi 23 | lncli="/home/lightningd/lightning/cli/lightning-cli" 24 | 25 | printf "%0.s#" {1..63} 26 | echo -ne '\r### Loading CoreLN data \r' 27 | 28 | 29 | alias_color="${color_grey}" 30 | ln_alias="$(${lncli} getinfo | jq -r '.alias')" 2>/dev/null 31 | 32 | # Reduce number of calls to LND by doing once and caching 33 | lncli_getinfo=$(${lncli} getinfo 2>&1) 34 | lncli_listfunds=$(${lncli} listfunds 2>&1) 35 | 36 | ln_walletbalance=0 37 | #check if len(outputs) == 0 --> empty wallet 38 | amount_of_wallet_transactions=$(echo ${lncli_listfunds} | jq -r '.outputs | length') 39 | if [ $amount_of_wallet_transactions -gt 0 ];then 40 | ln_walletbalance=$(echo ${lncli_listfunds} | jq -r '.outputs[0].value | tonumber') 41 | fi 42 | 43 | ## Show channel balance 44 | ln_channelbalance=0 45 | #check if len(channels) == 0 --> no channels 46 | amount_of_channels=$(echo ${lncli_listfunds} | jq -r '.channels | length') 47 | if [ $amount_of_channels -gt 0 ];then 48 | ln_channelbalance=$(echo ${lncli_listfunds} | jq -r '[.channels[].channel_sat] | add') 49 | fi 50 | printf "%0.s#" {1..66} 51 | 52 | echo -ne '\r### Loading CoreLN data \r' 53 | 54 | ln_channels_online=$(echo ${lncli_getinfo} | jq -r '.num_active_channels | tonumber') 2>/dev/null 55 | ln_channels_pending=$(echo ${lncli_getinfo} | jq -r '.num_pending_channels | tonumber') 2>/dev/null 56 | ln_channels_inactive=$(echo ${lncli_getinfo} | jq -r '.num_inactive_channels | tonumber') 2>/dev/null 57 | ln_channels_total=$((ln_channels_online + ln_channels_pending + ln_channels_inactive)) 58 | node_id=$(echo ${lncli_getinfo} | jq -r '.id') 2>/dev/null 59 | node_address=$(echo ${lncli_getinfo} | jq -r '.address[0].address') 2>/dev/null 60 | node_port=$(echo ${lncli_getinfo} | jq -r '.address[0].port') 2>/dev/null 61 | ln_connect_addr="$node_id"@"$node_address":"$node_port" 2>/dev/null 62 | ln_connect_guidance="lightning-cli connect ${ln_connect_addr}" 63 | if [ -z "${node_addr##*onion*}" ]; then 64 | ln_external="Using TOR Address" 65 | else 66 | ln_external="Using Clearnet" 67 | fi 68 | 69 | printf "%0.s#" {1..70} 70 | # echo -ne '\r### Loading LND data \r' 71 | 72 | # ln_pendingopen=$(echo ${lncli_pendingchannels} | jq '.pending_open_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}') 73 | # if [ -z "${ln_pendingopen}" ]; then 74 | # ln_pendingopen=0 75 | # fi 76 | 77 | # ln_pendingforce=$(echo ${lncli_pendingchannels} | jq '.pending_force_closing_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}') 78 | # if [ -z "${ln_pendingforce}" ]; then 79 | # ln_pendingforce=0 80 | # fi 81 | 82 | # ln_waitingclose=$(echo ${lncli_pendingchannels} | jq '.waiting_close_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}') 83 | # if [ -z "${ln_waitingclose}" ]; then 84 | # ln_waitingclose=0 85 | # fi 86 | 87 | # echo -ne '\r### Loading LND data \r' 88 | 89 | # ln_pendinglocal=$((ln_pendingopen + ln_pendingforce + ln_waitingclose)) 90 | ln_pendinglocal=0 91 | 92 | ln_sum_balance=0 93 | if [ -n "${ln_channelbalance}" ]; then 94 | ln_sum_balance=$((ln_channelbalance + ln_sum_balance )) 95 | fi 96 | if [ -n "${ln_walletbalance}" ]; then 97 | ln_sum_balance=$((ln_walletbalance + ln_sum_balance )) 98 | fi 99 | if [ -n "$ln_pendinglocal" ]; then 100 | ln_sum_balance=$((ln_sum_balance + ln_pendinglocal )) 101 | fi 102 | 103 | 104 | #create variable ln_version 105 | lndpi=$(echo ${lncli_getinfo} | jq -r '.version') 2>/dev/null 106 | if [ "${lndpi}" = "${ln_git_version}" ]; then 107 | ln_version="${lndpi}" 108 | ln_version_color="${color_green}" 109 | else 110 | ln_version="${lndpi}"" Update!" 111 | ln_version_color="${color_red}" 112 | fi 113 | 114 | #create variables for ln_sync 115 | ln_sync_warning_bitcoind=$(echo ${lncli_getinfo} | jq -r '.warning_bitcoind_sync') 2>/dev/null 116 | ln_sync_warning_lightningd=$(echo ${lncli_getinfo} | jq -r '.warning_lightningd_sync') 2>/dev/null 117 | ln_sync_note2_color="${color_red}" 118 | ln_sync_note2="" 119 | if [ "${ln_sync_warning_bitcoind}" = "null" ]; then 120 | if [ "${ln_sync_warning_lightningd}" = "null" ]; then 121 | ln_sync_note1_color="${color_green}" 122 | ln_sync_note1="chain:OK" 123 | else 124 | ln_sync_note1_color="${color_red}" 125 | ln_sync_note1="chain:No" 126 | fi 127 | else 128 | ln_sync_note1_color="${color_red}" 129 | ln_sync_note1="chain:No" 130 | fi 131 | 132 | #get channel.db size 133 | coreln_dir="/data/lightningd" 134 | ln_channel_db_size=$(du -h ${coreln_dir}/bitcoin/lightningd.sqlite3 | awk '{print $1}') 135 | 136 | # Write to JSON file 137 | lnd_infofile="${HOME}/.raspibolt.lndata.json" 138 | ln_color=$(echo $coreln_color | sed 's/\\/\\\\/g') 139 | lnversion_color=$(echo $lndversion_color | sed 's/\\/\\\\/g') 140 | alias_color=$(echo $alias_color| sed 's/\\/\\\\/g') 141 | ln_sync_note1_color=$(echo $ln_sync_note1_color | sed 's/\\/\\\\/g') 142 | ln_sync_note2_color=$(echo $ln_sync_note2_color | sed 's/\\/\\\\/g') 143 | printf '{"ln_running":"%s","ln_version":"%s","ln_walletbalance":"%s","ln_channelbalance":"%s","ln_pendinglocal":"%s","ln_sum_balance":"%s","ln_channels_online":"%s","ln_channels_total":"%s","ln_channel_db_size":"%s","ln_color":"%s","ln_version_color":"%s","alias_color":"%s","ln_alias":"%s","ln_connect_guidance":"%s","ln_sync_note1":"%s","ln_sync_note1_color":"%s","ln_sync_note2":"%s","ln_sync_note2_color":"%s"}' "\ 144 | $ln_running" "$ln_version" "$ln_walletbalance" "$ln_channelbalance" "$ln_pendinglocal" "$ln_sum_balance" "$ln_channels_online" "$ln_channels_total" "$ln_channel_db_size" "$ln_color" "$lnversion_color" "$alias_color" "$ln_alias" "$ln_connect_guidance" "$ln_sync_note1" "$ln_sync_note1_color" "$ln_sync_note2" "$ln_sync_note2_color" > $lnd_infofile 145 | -------------------------------------------------------------------------------- /get_LND_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | chain=$1 3 | color_green=$2 4 | color_red=$3 5 | ln_git_version=$4 6 | 7 | echo -ne '\r### Loading LND data \r' 8 | 9 | # set datadir 10 | lnd_dir="/mnt/ext/lnd" # Raspibolt 1.x, 2.x 11 | if [ -d "/data/lnd" ]; then 12 | lnd_dir="/data/lnd" # Raspibolt 3.x 13 | fi 14 | 15 | if [ "${chain}" = "test" ]; then 16 | macaroon_path="${lnd_dir}/data/chain/bitcoin/testnet/readonly.macaroon" 17 | else 18 | macaroon_path="${lnd_dir}/data/chain/bitcoin/mainnet/readonly.macaroon" 19 | fi 20 | lnd_running=$(systemctl is-active lnd 2>&1) 21 | lnd_color="${color_green}" 22 | if [ -z "${lnd_running##*inactive*}" ]; then 23 | lnd_running="down" 24 | lnd_color="${color_red}\e[7m" 25 | else 26 | if [ -z "${lnd_running##*failed*}" ]; then 27 | lnd_running="down" 28 | lnd_color="${color_red}\e[7m" 29 | else 30 | lnd_running="up" 31 | fi 32 | fi 33 | if [ -z "${lnd_running##*up*}" ] ; then 34 | lncli="/usr/local/bin/lncli --macaroonpath=${macaroon_path} --tlscertpath=${lnd_dir}/tls.cert" 35 | $lncli getinfo 2>&1 | grep "Please unlock" >/dev/null 36 | wallet_unlocked=$? 37 | else 38 | wallet_unlocked=0 39 | fi 40 | printf "%0.s#" {1..40} 41 | echo -ne '\r### Loading LND data \r' 42 | 43 | if [ "$wallet_unlocked" -eq "0" ] ; then 44 | alias_color="${color_red}" 45 | ln_alias="Wallet Locked" 46 | ln_walletbalance="?" 47 | ln_channelbalance="?" 48 | ln_sync_chain="false" 49 | ln_sync_graph="false" 50 | ln_channels_online="?" 51 | ln_channels_total="?" 52 | ln_connect_addr="" 53 | ln_external="" 54 | ln_pendingopen="?" 55 | ln_pendingforce="?" 56 | ln_waitingclose="?" 57 | ln_pendinglocal="?" 58 | ln_sum_balance="?" 59 | if [ $lnd_running = "up" ]; then 60 | ln_connect_guidance="You must first unlock your wallet: lncli unlock" 61 | else 62 | ln_connect_guidance="The LND service is down. Start the service: sudo systemctl start lnd" 63 | fi 64 | else 65 | # Reduce number of calls to LND by doing once and caching 66 | lncli_channelbalance=$(${lncli} channelbalance) 67 | lncli_getinfo=$(${lncli} getinfo) 68 | lncli_listchannels=$(${lncli} listchannels) 69 | lncli_pendingchannels=$(${lncli} pendingchannels) 70 | lncli_walletbalance=$(${lncli} walletbalance) 71 | 72 | alias_color="${color_grey}" 73 | ln_alias="$(echo ${lncli_getinfo} | jq -r '.alias')" 2>/dev/null 74 | ln_walletbalance="$(echo ${lncli_walletbalance} | jq -r '.confirmed_balance')" 2>/dev/null 75 | ln_channelbalance="$(echo ${lncli_channelbalance} | jq -r '.balance')" 2>/dev/null 76 | 77 | ln_sync_chain="$(echo ${lncli_getinfo} | jq -r '.synced_to_chain')" 2>/dev/null 78 | ln_sync_graph="$(echo ${lncli_getinfo} | jq -r '.synced_to_graph')" 2>/dev/null 79 | 80 | printf "%0.s#" {1..46} 81 | 82 | echo -ne '\r### Loading LND data - connect info \r' 83 | 84 | ln_channels_online="$(echo ${lncli_getinfo} | jq -r '.num_active_channels')" 2>/dev/null 85 | ln_channels_total="$(echo ${lncli_listchannels} | jq '.[] | length')" 2>/dev/null 86 | ln_connect_addr="$(echo ${lncli_getinfo} | jq -r '.uris[0]')" 2>/dev/null 87 | ln_connect_guidance="lncli connect ${ln_connect_addr}" 88 | if [ -z "${ln_connect_addr##*onion*}" ]; then 89 | ln_external="Using TOR Address" 90 | else 91 | ln_external="Using Clearnet" 92 | fi 93 | 94 | printf "%0.s#" {1..52} 95 | echo -ne '\r### Loading LND data - pending channels \r' 96 | 97 | ln_pendingopen=$(echo ${lncli_pendingchannels} | jq '.pending_open_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}') 98 | if [ -z "${ln_pendingopen}" ]; then 99 | ln_pendingopen=0 100 | fi 101 | 102 | ln_pendingforce=$(echo ${lncli_pendingchannels} | jq '.pending_force_closing_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}') 103 | if [ -z "${ln_pendingforce}" ]; then 104 | ln_pendingforce=0 105 | fi 106 | 107 | ln_waitingclose=$(echo ${lncli_pendingchannels} | jq '.waiting_close_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}') 108 | if [ -z "${ln_waitingclose}" ]; then 109 | ln_waitingclose=0 110 | fi 111 | 112 | printf "%0.s#" {1..58} 113 | echo -ne '\r### Loading LND data - summary \r' 114 | 115 | ln_pendinglocal=$((ln_pendingopen + ln_pendingforce + ln_waitingclose)) 116 | 117 | ln_sum_balance=0 118 | if [ -n "${ln_channelbalance}" ]; then 119 | ln_sum_balance=$((ln_channelbalance + ln_sum_balance )) 120 | fi 121 | if [ -n "${ln_walletbalance}" ]; then 122 | ln_sum_balance=$((ln_walletbalance + ln_sum_balance )) 123 | fi 124 | if [ -n "$ln_pendinglocal" ]; then 125 | ln_sum_balance=$((ln_sum_balance + ln_pendinglocal )) 126 | fi 127 | 128 | printf "%0.s#" {1..64} 129 | echo -ne '\r### Determining version \r' 130 | 131 | #create variable lndversion 132 | lndpi="$(echo ${lncli_getinfo} | jq -r '.version | split("=") | .[1]')" 2>/dev/null 133 | if [ "${lndpi}" = "${ln_git_version}" ]; then 134 | lndversion="${lndpi}" 135 | lndversion_color="${color_green}" 136 | else 137 | lndversion="${lndpi}"" Update!" 138 | lndversion_color="${color_red}" 139 | fi 140 | fi 141 | 142 | 143 | #create variables for ln_sync 144 | if [ "${ln_sync_chain}" = "true" ]; then 145 | ln_sync_note1_color="${color_green}" 146 | ln_sync_note1="chain:OK" 147 | else 148 | ln_sync_note1_color="${color_red}" 149 | ln_sync_note1="chain:No" 150 | fi 151 | if [ "${ln_sync_graph}" = "true" ]; then 152 | ln_sync_note2_color="${color_green}" 153 | ln_sync_note2="graph:OK" 154 | else 155 | ln_sync_note2_color="${color_red}" 156 | ln_sync_note2="graph:No" 157 | fi 158 | 159 | 160 | printf "%0.s#" {1..70} 161 | echo -ne '\r### Determining channel db size \r' 162 | 163 | #get channel.db size 164 | ln_channel_db_size=$(du -h ${lnd_dir}/data/graph/mainnet/channel.db | awk '{print $1}') 165 | 166 | printf "%0.s#" {1..76} 167 | echo -ne '\r### Saving \r' 168 | 169 | # Write to JSON file 170 | lnd_infofile="${HOME}/.raspibolt.lndata.json" 171 | lnd_color=$(echo $lnd_color | sed 's/\\/\\\\/g') 172 | lndversion_color=$(echo $lndversion_color | sed 's/\\/\\\\/g') 173 | alias_color=$(echo $alias_color| sed 's/\\/\\\\/g') 174 | ln_sync_note1_color=$(echo $ln_sync_note1_color | sed 's/\\/\\\\/g') 175 | ln_sync_note2_color=$(echo $ln_sync_note2_color | sed 's/\\/\\\\/g') 176 | printf '{"ln_running":"%s","ln_version":"%s","ln_version_available":"%s","ln_walletbalance":"%s","ln_channelbalance":"%s","ln_pendinglocal":"%s","ln_sum_balance":"%s","ln_channels_online":"%s","ln_channels_total":"%s","ln_channel_db_size":"%s","ln_color":"%s","ln_version_color":"%s","alias_color":"%s","ln_alias":"%s","ln_connect_guidance":"%s","ln_sync_note1":"%s","ln_sync_note1_color":"%s","ln_sync_note2":"%s","ln_sync_note2_color":"%s"}' "\ 177 | $lnd_running" "$lndversion" "$ln_git_version" "$ln_walletbalance" "$ln_channelbalance" "$ln_pendinglocal" "$ln_sum_balance" "$ln_channels_online" "$ln_channels_total" "$ln_channel_db_size" "$lnd_color" "$lndversion_color" "$alias_color" "$ln_alias" "$ln_connect_guidance" "$ln_sync_note1" "$ln_sync_note1_color" "$ln_sync_note2" "$ln_sync_note2_color" > $lnd_infofile 178 | -------------------------------------------------------------------------------- /raspibolt-pulse-switch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # /etc/systemd/system/raspibolt-pulse.sh 3 | set -u 4 | 5 | # make executable and copy script to /etc/update-motd.d/ 6 | # user must be able to execute bitcoin-cli and lncli 7 | 8 | # Script configuration 9 | # ------------------------------------------------------------------------------ 10 | 11 | # set datadir 12 | bitcoin_dir="/mnt/ext/bitcoin" # Raspibolt 1.x, 2.x 13 | if [ -d "/data/bitcoin" ]; then 14 | bitcoin_dir="/data/bitcoin" # Raspibolt 3.x 15 | fi 16 | 17 | # determine second drive info 18 | drivecount=$(lsblk --output MOUNTPOINT | grep / | grep -v /boot | sort | wc -l) 19 | if [ $drivecount -gt 1 ]; then 20 | ext_storage2nd=$(lsblk --output MOUNTPOINT | grep / | grep -v /boot | sort | sed -n 2p) 21 | else 22 | ext_storage2nd="" 23 | fi 24 | 25 | # expected service names... common alternate values supported 26 | sn_bitcoin="bitcoind" 27 | sn_lnd="lnd" 28 | sn_cln="lightningd" # cln, lightningd 29 | sn_btcrpcexplorer="btcrpcexplorer" 30 | sn_electrs="electrs" 31 | sn_fulcrum="fulcrum" 32 | sn_rtl="rtl" # rtl, ridethelightning 33 | sn_thunderhub="thunderhub" 34 | 35 | # Helper functionality 36 | # ------------------------------------------------------------------------------ 37 | 38 | # set colors 39 | color_red='\033[0;31m' 40 | color_green='\033[0;32m' 41 | color_yellow='\033[0;33m' 42 | color_grey='\033[0;37m' 43 | color_orange='\033[38;5;208m' 44 | color_magenta='\033[0;35m' 45 | 46 | # controlled abort on Ctrl-C 47 | trap_ctrlC() { 48 | echo -e "\r" 49 | printf "%0.s " {1..80} 50 | printf "\n" 51 | exit 52 | } 53 | 54 | trap trap_ctrlC SIGINT SIGTERM 55 | 56 | # print usage information for script 57 | usage() { 58 | echo "RaspiBolt Welcome: system status overview 59 | usage: $(basename "$0") [--help] [--mock] 60 | 61 | This script can be run on startup: make it executable and 62 | copy the script to /etc/update-motd.d/ 63 | " 64 | } 65 | 66 | # check script arguments 67 | mockmode=0 68 | if [[ ${#} -gt 0 ]]; then 69 | if [[ "${1}" == "-m" ]] || [[ "${1}" == "--mock" ]]; then 70 | mockmode=1 71 | else 72 | usage 73 | exit 0 74 | fi 75 | fi 76 | 77 | 78 | # Print first welcome message 79 | # ------------------------------------------------------------------------------ 80 | printf " 81 | ${color_yellow}RaspiBolt %s:${color_grey} Sovereign \033[1m"₿"\033[22mitcoin full node 82 | ${color_yellow}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 83 | " "3" 84 | 85 | # Gather system data 86 | # ------------------------------------------------------------------------------ 87 | printf "%0.s#" {1..40} 88 | echo -ne '\r### Loading System data \r' 89 | 90 | # get uptime & load 91 | load=$(w|head -1|sed -E 's/.*load average: (.*)/\1/') 92 | uptime=$(w|head -1|sed -E 's/.*up (.*),.*user.*/\1/'|sed -E 's/([0-9]* days).*/\1/') 93 | 94 | # get highest reported temperature 95 | temp="N/A" 96 | color_temp="${color_grey}" 97 | hitemp=$(grep . /sys/class/hwmon/*/* /sys/class/thermal/*/* 2>/dev/null | grep "temp" | grep "input" | awk '{split($0,a,":"); print a[2]}' | sort -r | head -n 1) 98 | if (( hitemp > 0 )); then 99 | temp=$((hitemp/1000)) 100 | if [ ${temp} -gt 68 ]; then 101 | color_temp="${color_red}\e[7m" 102 | elif [ ${temp} -gt 55 ]; then 103 | color_temp="${color_yellow}" 104 | else 105 | color_temp="${color_green}" 106 | fi 107 | temp="${temp}""°C" 108 | fi 109 | 110 | # get memory 111 | ram_avail=$(free --mebi | grep Mem | awk '{ print $7 }') 112 | 113 | if [ "${ram_avail}" -lt 100 ]; then 114 | color_ram="${color_red}\e[7m" 115 | else 116 | color_ram=${color_green} 117 | fi 118 | 119 | # get storage 120 | storage_free_ratio=$(printf "%.0f" "$(df | grep "/$" | awk '{ print $4/$2*100 }')") 2>/dev/null 121 | storage=$(printf "%s" "$(df -h|grep '/$'|awk '{print $4}')") 2>/dev/null 122 | 123 | if [ "${storage_free_ratio}" -lt 10 ]; then 124 | color_storage="${color_red}\e[7m" 125 | else 126 | color_storage=${color_green} 127 | fi 128 | 129 | storage2nd_free_ratio=$(printf "%.0f" "$(df | grep ${ext_storage2nd} | awk '{ print $4/$2*100 }')") 2>/dev/null 130 | storage2nd=$(printf "%s" "$(df -h|grep ${ext_storage2nd}|awk '{print $4}')") 2>/dev/null 131 | 132 | if [ -z "${storage2nd}" ]; then 133 | storage2nd="none" 134 | color_storage2nd=${color_grey} 135 | else 136 | storage2nd="${storage2nd} free" 137 | if [ "${storage2nd_free_ratio}" -lt 10 ]; then 138 | color_storage2nd="${color_red}\e[7m" 139 | else 140 | color_storage2nd=${color_green} 141 | fi 142 | fi 143 | 144 | # get network traffic (sums from all devices but excludes the loopback named 'lo') 145 | network_rx=$(ip -j -s link show | jq '.[] | [(select(.ifname!="lo") | .stats64.rx.bytes)//0] | add' | awk -v OFMT='%.0f' '{sum+=$0} END{print sum}' | numfmt --to=iec) 146 | network_tx=$(ip -j -s link show | jq '.[] | [(select(.ifname!="lo") | .stats64.tx.bytes)//0] | add' | awk -v OFMT='%.0f' '{sum+=$0} END{print sum}' | numfmt --to=iec) 147 | 148 | # Gather application versions 149 | # ------------------------------------------------------------------------------ 150 | gitstatusfile="${HOME}/.raspibolt.versions.json" 151 | 152 | save_raspibolt_versions() { 153 | # write to json file 154 | cat >${gitstatusfile} <&1) 282 | bitcoind_color="${color_green}" 283 | if [ -z "${bitcoind_running##*inactive*}" ]; then 284 | bitcoind_running="down" 285 | bitcoind_color="${color_red}\e[7m" 286 | else 287 | bitcoind_running="up" 288 | fi 289 | btc_path=$(command -v bitcoin-cli) 290 | if [ -n "${btc_path}" ]; then 291 | 292 | # Reduce number of calls to bitcoin by doing once and caching 293 | bitcoincli_getblockchaininfo=$(bitcoin-cli -datadir=${bitcoin_dir} getblockchaininfo 2>&1) 294 | bitcoincli_getmempoolinfo=$(bitcoin-cli -datadir=${bitcoin_dir} getmempoolinfo 2>&1) 295 | bitcoincli_getnetworkinfo=$(bitcoin-cli -datadir=${bitcoin_dir} getnetworkinfo 2>&1) 296 | bitcoincli_getpeerinfo=$(bitcoin-cli -datadir=${bitcoin_dir} getpeerinfo 2>&1) 297 | 298 | chain="$(echo ${bitcoincli_getblockchaininfo} | jq -r '.chain')" 299 | btc_title="itcoin" 300 | btc_title="${btc_title} (${chain}net)" 301 | 302 | # create variable btcversion 303 | btcpi=$(bitcoin-cli -version |sed -n 's/^.*version //p') 304 | case "${btcpi}" in 305 | *"${btcgit}"*) 306 | btcversion="$btcpi" 307 | btcversion_color="${color_green}" 308 | ;; 309 | *) 310 | btcversion="$btcpi"" Update!" 311 | btcversion_color="${color_red}" 312 | ;; 313 | esac 314 | 315 | # get sync status 316 | block_chain="$(echo ${bitcoincli_getblockchaininfo} | jq -r '.headers')" 317 | block_verified="$(echo ${bitcoincli_getblockchaininfo} | jq -r '.blocks')" 318 | if [ -n "${block_chain}" ]; then 319 | block_diff=$(("${block_chain}" - "${block_verified}")) 320 | else 321 | block_diff=999999 322 | fi 323 | 324 | progress="$(echo ${bitcoincli_getblockchaininfo} | jq -r '.verificationprogress')" 325 | sync_percentage=$(printf "%.2f%%" "$(echo "${progress}" | awk '{print 100 * $1}')") 326 | 327 | if [ "${block_diff}" -eq 0 ]; then # fully synced 328 | sync="OK" 329 | sync_color="${color_green}" 330 | sync_behind="[#${block_chain}]" 331 | elif [ "${block_diff}" -eq 1 ]; then # fully synced 332 | sync="OK" 333 | sync_color="${color_green}" 334 | sync_behind="-1 block" 335 | elif [ "${block_diff}" -le 10 ]; then # <= 10 blocks behind 336 | sync="Behind" 337 | sync_color="${color_red}" 338 | sync_behind="-${block_diff} blocks" 339 | else 340 | sync="In progress" 341 | sync_color="${color_red}" 342 | sync_behind="${sync_percentage}" 343 | fi 344 | 345 | # get mem pool transactions 346 | mempool=$(echo ${bitcoincli_getmempoolinfo} | jq -r '.size') 347 | 348 | # get connection info 349 | connections=$(echo ${bitcoincli_getnetworkinfo} | jq -r '.connections') 350 | inbound=$(echo ${bitcoincli_getpeerinfo} | jq '.[] | select(.inbound == true)' | jq -s 'length') 351 | outbound=$(echo ${bitcoincli_getpeerinfo} | jq '.[] | select(.inbound == false)' | jq -s 'length') 352 | 353 | # create variable btcversion 354 | btcpi=$(bitcoin-cli -version |sed -n 's/^.*version //p') 355 | case "${btcpi}" in 356 | *"${btcgit}"*) 357 | btcversion="$btcpi" 358 | btcversion_color="${color_green}" 359 | ;; 360 | *) 361 | btcversion="$btcpi"" Update!" 362 | btcversion_color="${color_red}" 363 | ;; 364 | esac 365 | else 366 | # bitcoin-cli was not found 367 | btc_title="Bitcoin not active" 368 | btcversion="Is Bitcoin installed?" 369 | btcversion_color="${color_red}" 370 | connections="0" 371 | inbound="0" 372 | mempool="0" 373 | outbound="0" 374 | sync="Not synching" 375 | sync_color="${color_red}" 376 | sync_behind="" 377 | fi 378 | 379 | # Gather LN data based on preferred implementation 380 | # ------------------------------------------------------------------------------ 381 | printf "%0.s#" {1..60} 382 | 383 | load_lightning_data() { 384 | lnd_infofile="${HOME}/.raspibolt.lndata.json" 385 | ln_file_content=$(cat $lnd_infofile) 386 | ln_color="$(echo $ln_file_content | jq -r '.ln_color')" 387 | ln_version_color="$(echo $ln_file_content | jq -r '.ln_version_color')" 388 | alias_color="$(echo $ln_file_content | jq -r '.alias_color')" 389 | ln_running="$(echo $ln_file_content | jq -r '.ln_running')" 390 | ln_version="$(echo $ln_file_content | jq -r '.ln_version')" 391 | ln_walletbalance="$(echo $ln_file_content | jq -r '.ln_walletbalance')" 392 | ln_channelbalance="$(echo $ln_file_content | jq -r '.ln_channelbalance')" 393 | ln_pendinglocal="$(echo $ln_file_content | jq -r '.ln_pendinglocal')" 394 | ln_sum_balance="$(echo $ln_file_content | jq -r '.ln_sum_balance')" 395 | ln_channels_online="$(echo $ln_file_content | jq -r '.ln_channels_online')" 396 | ln_channels_total="$(echo $ln_file_content | jq -r '.ln_channels_total')" 397 | ln_channel_db_size="$(echo $ln_file_content | jq -r '.ln_channel_db_size')" 398 | ln_connect_guidance="$(echo $ln_file_content | jq -r '.ln_connect_guidance')" 399 | ln_alias="$(echo $ln_file_content | jq -r '.ln_alias')" 400 | ln_sync_note1="$(echo $ln_file_content | jq -r '.ln_sync_note1')" 401 | ln_sync_note1_color="$(echo $ln_file_content | jq -r '.ln_sync_note1_color')" 402 | ln_sync_note2="$(echo $ln_file_content | jq -r '.ln_sync_note2')" 403 | ln_sync_note2_color="$(echo $ln_file_content | jq -r '.ln_sync_note2_color')" 404 | } 405 | 406 | # Prepare Lightning output data (name, version, data lines) 407 | # ------------------------------------------------------------------------------ 408 | echo -ne '\r### Loading Lightning data \r' 409 | lserver_found=0 410 | lserver_label="No Lightning Server" 411 | lserver_running="" 412 | lserver_color="${color_red}\e[7m" 413 | lserver_version="" 414 | lserver_version_color="${color_red}" 415 | lserver_dataline_1="${color_grey}" 416 | lserver_dataline_2="${color_grey}" 417 | lserver_dataline_3="${color_grey}" 418 | lserver_dataline_4="${color_grey}" 419 | lserver_dataline_5="${color_grey}" 420 | lserver_dataline_6="${color_grey}" 421 | lserver_dataline_7="${color_grey}" 422 | ln_footer="" 423 | lnd_status=$(systemctl is-enabled $sn_lnd 2>&1) 424 | cln_status=$(systemctl is-enabled $sn_cln 2>&1) 425 | if [ "$cln_status" != "enabled" ]; then # fallback from lightningd to cln for service name 426 | sn_cln="cln" 427 | cln_status=$(systemctl is-enabled $sn_cln 2>&1) 428 | fi 429 | # Mock specific 430 | if [ "${mockmode}" -eq 1 ]; then 431 | ln_alias="MyRaspiBolt-version3" 432 | ln_walletbalance="100000" 433 | ln_channelbalance="200000" 434 | ln_pendinglocal="50000" 435 | ln_sum_balance="350000" 436 | ln_channels_online="34" 437 | ln_channels_total="36" 438 | ln_channel_db_size="615M" 439 | ln_connect_guidance="lncli connect cdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcd@version3onionaddressgobbLedegookLookingL3ttersandnumbers.onion:9735" 440 | lserver_label="Lightning (MOCK)" 441 | lserver_running="up" 442 | lserver_color="${color_green}" 443 | lserver_version="v0.6.15" 444 | lserver_version_color="${color_green}" 445 | alias_color="${color_magenta}" 446 | ln_footer=$(printf "For others to connect to this lightning node: ${alias_color}${ln_alias}${color_grey}\n${ln_connect_guidance}") 447 | # data lines 448 | lserver_dataline_1=$(printf "${color_grey}Sync%10s" "ready") 449 | lserver_dataline_2=$(printf "${color_orange}"₿"${color_grey}%18s sat" "${ln_walletbalance}") 450 | lserver_dataline_3=$(printf "${color_grey}%3s %16s sat" "⚡" "${ln_channelbalance}") 451 | lserver_dataline_4=$(printf "${color_grey}%3s %16s sat" "∑" "${ln_sum_balance}") 452 | lserver_dataline_5=$(printf "${color_grey}%s/%s channels" "${ln_channels_online}" "${ln_channels_total}") 453 | lserver_dataline_6=$(printf "${color_grey}Channel.db size: ${color_green}%s" "${ln_channel_db_size}") 454 | # LND specific 455 | elif [ "$lnd_status" = "enabled" ]; then 456 | lnd_status=$(systemctl is-active $sn_lnd 2>&1) 457 | lserver_found=1 458 | lserver_label="Lightning (LND)" 459 | lserver_running="down" 460 | if [ "$lnd_status" = "active" ]; then 461 | lserver_running="up" 462 | lserver_color="${color_green}" 463 | # version specific stuff 464 | "$(dirname "$0")/get_LND_data.sh" $chain $color_green $color_red $lndgit 465 | load_lightning_data 466 | lserver_version="$(echo $ln_file_content | jq -r '.ln_version')" 467 | lserver_version_color="$(echo $ln_file_content | jq -r '.ln_version_color')" 468 | ln_footer=$(printf "For others to connect to this lightning node: ${alias_color}${ln_alias}${color_grey}\n${ln_connect_guidance}") 469 | # data lines 470 | lserver_dataline_1=$(printf "${color_grey}Sync${ln_sync_note1_color}%10s${ln_sync_note2_color}%9s" "${ln_sync_note1}" "${ln_sync_note2}") 471 | lserver_dataline_2=$(printf "${color_orange}"₿"${color_grey}%18s sat" "${ln_walletbalance}") 472 | lserver_dataline_3=$(printf "${color_grey}%3s %16s sat" "⚡" "${ln_channelbalance}") 473 | lserver_dataline_4=$(printf "${color_grey}%3s %16s sat" "⏳" "${ln_pendinglocal}") 474 | lserver_dataline_5=$(printf "${color_grey}%3s %17s sat" "∑" "${ln_sum_balance}") 475 | lserver_dataline_6=$(printf "${color_grey}%s/%s channels" "${ln_channels_online}" "${ln_channels_total}") 476 | lserver_dataline_7=$(printf "${color_grey}Channel.db size: ${color_green}%s" "${ln_channel_db_size}") 477 | fi 478 | # Core Lightning specific 479 | elif [ "$cln_status" = "enabled" ]; then 480 | cln_status=$(systemctl is-active $sn_cln 2>&1) 481 | lserver_found=1 482 | lserver_label="Lightning (CLN)" 483 | lserver_running="down" 484 | if [ "$cln_status" = "active" ]; then 485 | lserver_running="up" 486 | lserver_color="${color_green}" 487 | # version specific stuff 488 | "$(dirname "$0")/get_CLN_data.sh" $chain $color_green $color_red $clngit 489 | load_lightning_data 490 | lserver_version="$(echo $ln_file_content | jq -r '.ln_version')" 491 | lserver_version_color="$(echo $ln_file_content | jq -r '.ln_version_color')" 492 | ln_footer=$(printf "For others to connect to this lightning node: ${alias_color}${ln_alias}${color_grey}\n${ln_connect_guidance}") 493 | # data lines 494 | lserver_dataline_1=$(printf "${color_grey}Sync${ln_sync_note1_color}%10s${ln_sync_note2_color}%9s" "${ln_sync_note1}" "${ln_sync_note2}") 495 | lserver_dataline_2=$(printf "${color_orange}"₿"${color_grey}%18s sat" "${ln_walletbalance}") 496 | lserver_dataline_3=$(printf "${color_grey}%3s %16s sat" "⚡" "${ln_channelbalance}") 497 | lserver_dataline_4=$(printf "${color_grey}%3s %17s sat" "∑" "${ln_sum_balance}") 498 | lserver_dataline_5=$(printf "${color_grey}%s/%s channels" "${ln_channels_online}" "${ln_channels_total}") 499 | lserver_dataline_6=$(printf "${color_grey}Lightning DB size: ${color_green}%s" "${ln_channel_db_size}") 500 | fi 501 | # ... add any future supported lightning server implementation checks here 502 | fi 503 | if [ "$lserver_found" -eq 0 ]; then 504 | lserver_color="${color_grey}" 505 | fi 506 | 507 | 508 | 509 | # Gather Electrs or Fulcrum data 510 | # ------------------------------------------------------------------------------ 511 | printf "%0.s#" {1..65} 512 | echo -ne '\r### Loading Electrum Server data \r' 513 | eserver_found=0 514 | eserver_label="No Electrum Server" 515 | eserver_running="" 516 | eserver_color="${color_red}\e[7m" 517 | eserver_version="" 518 | eserver_version_color="${color_red}" 519 | electrs_status=$(systemctl is-enabled ${sn_electrs} 2>&1) 520 | fulcrum_status=$(systemctl is-enabled ${sn_fulcrum} 2>&1) 521 | # Electrs specific 522 | if [ "$electrs_status" = "enabled" ]; then 523 | electrs_status=$(systemctl is-active ${sn_electrs} 2>&1) 524 | eserver_found=1 525 | eserver_label="Electrs" 526 | eserver_running="down" 527 | if [ "$electrs_status" = "active" ]; then 528 | eserver_running="up" 529 | eserver_color="${color_green}" 530 | # Request params are client_name, protocol_version. Example result being parsed: ["Electrs 0.9.10", "1.4"] 531 | electrspi=$(echo '{"jsonrpc": "2.0", "method": "server.version", "params": [ "raspibolt", "1.4" ], "id": 0}' | netcat 127.0.0.1 50001 -q 1 | jq -r '.result[0]' | awk '{print "v"substr($1,9)}') 532 | if [ "$electrspi" = "$electrsgit" ]; then 533 | eserver_version="$electrspi" 534 | eserver_version_color="${color_green}" 535 | else 536 | eserver_version="$electrspi"" Update!" 537 | fi 538 | fi 539 | # Fulcrum specific 540 | elif [ "$fulcrum_status" = "enabled" ]; then 541 | fulcrum_status=$(systemctl is-active ${sn_fulcrum} 2>&1) 542 | eserver_found=1 543 | eserver_label="Fulcrum" 544 | eserver_running="down" 545 | if [ "$fulcrum_status" = "active" ]; then 546 | eserver_running="up" 547 | eserver_color="${color_green}" 548 | fulcrumpi=$(Fulcrum --version | grep Fulcrum | awk '{print "v"$2}') 549 | if [ "$fulcrumpi" = "$fulcrumgit" ]; then 550 | eserver_version="$fulcrumpi" 551 | eserver_version_color="${color_green}" 552 | else 553 | eserver_version="$fulcrumpi"" Update!" 554 | fi 555 | fi 556 | # ... add any future supported electrum server implementation checks here 557 | fi 558 | if [ "$eserver_found" -eq 0 ]; then 559 | eserver_color="${color_grey}" 560 | fi 561 | 562 | 563 | 564 | # Gather Bitcoin Explorer data 565 | # ------------------------------------------------------------------------------ 566 | printf "%0.s#" {1..70} 567 | echo -ne '\r### Loading Block Explorer data \r' 568 | bserver_found=0 569 | bserver_label="No Block Explorer" 570 | bserver_running="" 571 | bserver_color="${color_red}\e[7m" 572 | bserver_version="" 573 | bserver_version_color="${color_red}" 574 | btcrpcexplorer_status=$(systemctl is-enabled ${sn_btcrpcexplorer} 2>&1) 575 | # BTC RPC Explorer specific 576 | if [ "$btcrpcexplorer_status" = "enabled" ]; then 577 | un_btcrpcexplorer=$(systemctl show -pUser ${sn_btcrpcexplorer} | awk '{split($0,a,"="); print a[2]}') 578 | btcrpcexplorer_status=$(systemctl is-active ${sn_btcrpcexplorer} 2>&1) 579 | bserver_found=1 580 | bserver_label="Bitcoin Explorer" 581 | bserver_running="down" 582 | if [ "$btcrpcexplorer_status" = "active" ]; then 583 | bserver_running="up" 584 | bserver_color="${color_green}" 585 | btcrpcexplorerpi=v$(cd /home/${un_btcrpcexplorer}/btc-rpc-explorer; npm version | grep -oP "'btc-rpc-explorer': '\K(.*)(?=')") 586 | if [ "$btcrpcexplorerpi" = "$btcrpcexplorergit" ]; then 587 | bserver_version="$btcrpcexplorerpi" 588 | bserver_version_color="${color_green}" 589 | else 590 | bserver_version="$btcrpcexplorerpi"" Update!" 591 | fi 592 | fi 593 | # ... add any future supported blockchain explorer implementation checks here 594 | fi 595 | if [ "$bserver_found" -eq 0 ]; then 596 | bserver_color="${color_grey}" 597 | fi 598 | 599 | 600 | 601 | # Gather Lightning Web App data 602 | # ------------------------------------------------------------------------------ 603 | printf "%0.s#" {1..75} 604 | echo -ne '\r### Loading Lightning Web App \r' 605 | 606 | lwserver_found=0 607 | lwserver_label="No Lightning Web App" 608 | lwserver_running="" 609 | lwserver_color="${color_red}\e[7m" 610 | lwserver_version="" 611 | lwserver_version_color="${color_red}" 612 | rtl_status=$(systemctl is-enabled ${sn_rtl} 2>&1) 613 | if [ "$rtl_status" != "enabled" ]; then # fallback from rtl to ridethelightning for service name 614 | sn_rtl="ridethelightning" 615 | rtl_status=$(systemctl is-enabled ${sn_rtl} 2>&1) 616 | fi 617 | thunderhub_status=$(systemctl is-enabled ${sn_thunderhub} 2>&1) 618 | # Ride the Ligthning specific 619 | if [ "$rtl_status" = "enabled" ]; then 620 | un_rtl=$(systemctl show -pUser ${sn_rtl} | awk '{split($0,a,"="); print a[2]}') 621 | rtl_status=$(systemctl is-active ${sn_rtl} 2>&1) 622 | lwserver_found=1 623 | lwserver_label="Ride the Lightning" 624 | lwserver_running="down" 625 | if [ "$rtl_status" = "active" ]; then 626 | lwserver_running="up" 627 | lwserver_color="${color_green}" 628 | rtlpi=v$(cd /home/${un_rtl}/RTL; npm version | grep -oP "rtl: '\K(.*)(?=-beta')") 629 | if [ "$rtlpi" = "$rtlgit" ]; then 630 | lwserver_version="$rtlpi" 631 | lwserver_version_color="${color_green}" 632 | else 633 | lwserver_version="$rtlpi"" Update!" 634 | fi 635 | fi 636 | # Thunderhub specific 637 | elif [ "$thunderhub_status" = "enabled" ]; then 638 | un_thunderhub=$(systemctl show -pUser ${sn_thunderhub} | awk '{split($0,a,"="); print a[2]}') 639 | thunderhub_status=$(systemctl is-active ${sn_thunderhub} 2>&1) 640 | lwserver_found=1 641 | lwserver_label="Thunderhub" 642 | lwserver_running="down" 643 | if [ "$thunderhub_status" = "active" ]; then 644 | lwserver_running="up" 645 | lwserver_color="${color_green}" 646 | thunderhubpi=v$(cd /home/${un_thunderhub}/thunderhub; npm version | grep -oP "thunderhub: '\K(.*)(?=-beta')") 647 | if [ "$thunderhubpi" = "$thunderhubgit" ]; then 648 | lwserver_version="$thunderhubpi" 649 | lwserver_version_color="${color_green}" 650 | else 651 | lwserver_version="$thunderhubpi"" Update!" 652 | fi 653 | fi 654 | # ... add any future supported lightning web app implementation checks here 655 | fi 656 | if [ "$lwserver_found" -eq 0 ]; then 657 | lwserver_color="${color_grey}" 658 | fi 659 | 660 | 661 | # Render output 662 | # ------------------------------------------------------------------------------ 663 | 664 | echo -ne "\033[2K" 665 | printf "${color_grey}cpu temp: ${color_temp}%-4s${color_grey} tx: %-10s storage: ${color_storage}%-11s ${color_grey} load: %s${color_grey} 666 | ${color_grey}up: %-10s rx: %-10s 2nd drive: ${color_storage2nd}%-11s${color_grey} available mem: ${color_ram}%sM${color_grey} 667 | ${color_yellow}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${color_grey} 668 | ${color_green} .~~. .~~. ${color_orange}"₿"${color_yellow}%-19s${bitcoind_color}%-4s${color_grey} ${color_yellow}%-20s${lserver_color}%-4s${color_grey} 669 | ${color_green} '. \ ' ' / .' ${btcversion_color}%-26s ${lserver_version_color}%-24s${color_grey} 670 | ${color_red} .~ .~~~${color_yellow}.${color_red}.~. ${color_grey}Sync ${sync_color}%-18s ${lserver_dataline_1}${color_grey} 671 | ${color_red} : .~.'${color_yellow}//${color_red}~. : ${color_grey}Mempool %-18s ${lserver_dataline_2}${color_grey} 672 | ${color_red} ~ ( ${color_yellow}/ /_____${color_red}~ ${color_grey}Peers %-22s ${lserver_dataline_3}${color_grey} 673 | ${color_red} ( : ${color_yellow}/____ /${color_red} ) ${lserver_dataline_4}${color_grey} 674 | ${color_red} ~ .~ ( ${color_yellow}/ /${color_red}. ~ ${color_yellow}%-20s${eserver_color}%-4s${color_grey} ${lserver_dataline_5}${color_grey} 675 | ${color_red} ( : '${color_yellow}//${color_red}: ) ${eserver_version_color}%-26s ${lserver_dataline_6}${color_grey} 676 | ${color_red} '~ .~${color_yellow}°${color_red}~. ~' ${lserver_dataline_7}${color_grey} 677 | ${color_red} '~' ${color_yellow}%-20s${color_grey}${bserver_color}%-4s${color_grey} 678 | ${color_red} ${bserver_version_color}%-24s${color_grey} ${color_yellow}%-20s${lwserver_color}%-4s${color_grey} 679 | ${color_red} ${lwserver_version_color}%-24s${color_grey} 680 | 681 | ${color_grey}%s 682 | 683 | " \ 684 | "${temp}" "${network_tx}" "${storage} free" "${load}" \ 685 | "${uptime}" "${network_rx}" "${storage2nd}" "${ram_avail}" \ 686 | "${btc_title}" "${bitcoind_running}" "${lserver_label}" "${lserver_running}" \ 687 | "${btcversion}" "${lserver_version}" \ 688 | "${sync} ${sync_behind}" \ 689 | "${mempool} tx" \ 690 | "${connections} (📥${inbound} /📤${outbound})" \ 691 | "${eserver_label}" "${eserver_running}" \ 692 | "${eserver_version}" \ 693 | "${bserver_label}" "${bserver_running}" \ 694 | "${bserver_version}" "${lwserver_label}" "${lwserver_running}" \ 695 | "${lwserver_version}" \ 696 | "${ln_footer}" 697 | --------------------------------------------------------------------------------