Has anyone already created a netspeed display (download/upload speed Kbit/s, Mbit/s) for the waybar?
First for Sway would be enough for me.
Sorry if the terminology is wrong.
I move it from Garuda Community to FAQ and Tutorials .
Has anyone already created a netspeed display (download/upload speed Kbit/s, Mbit/s) for the waybar?
First for Sway would be enough for me.
I move it from Garuda Community to FAQ and Tutorials .
I use the tooltip,
but I think you want a custom module with the numbers in the bar, right?
Not promising anything but I'll look into it.
Quick and dirty (v2):
#!/bin/bash
# network_traffic.sh NETWORK_INTERFACE [POLLING_INTERVAL]
iface=${1:-lo}
isecs=${2:-1}
# `snore` adapted from https://blog.dhampir.no/content/sleeping-without-a-subprocess-in-bash-and-how-to-sleep-forever
# without MacOS workaround, TODO: with _snore_fd initialized separatedly, also i dont touch IFS so dont bother with it
snore() {
local IFS
[[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null
read ${1:+-t "$1"} -u $_snore_fd || :
}
# `human_readable` adapted from https://gist.github.com/cjsewell/96463db7fec6faeab291
human_readable() {
local value=$1
local units=( B K M G T P )
local index=0
while (( value > 1000 && index < 5 )); do
(( value /= 1000, index++ ))
done
echo "$value${units[$index]}"
}
# sanity checking, timing here is not an issue anymore -- TODO: check how waybar reacts to `exit 1`
test -n "${iface}" && grep -q "${iface}:" /proc/net/dev || { printf '{"text": "%s"}\n' "${iface} not found"; exit 1; }
test "$isecs" -gt 0 || { printf '{"text": "%s"}\n' "${isecs} not valid"; exit 1; }
# NOTE: `/proc/net/dev` format is:
# RX bytes packets errs drop fifo frame compressed multicast
# TX bytes packets errs drop fifo colls carrier compressed
declare -a traffic_prev traffic_curr traffic_delta
# NOTE: array items are:
# 0=rx_bytes 1=rx_packets 2=rx_errs 3=rx_drop
# 4=tx_bytes 5=tx_packets 6=tx_errs 7=tx_drop
# TODO: rearrange the loop, do not show bogus on first iteration
traffic_prev=( 0 0 0 0 0 0 0 0 )
while snore ${isecs} ;do
traffic_curr=( $(awk '/^ *'${iface}':/{print $2 " " $3 " " $4 " " $5 " " $10 " " $11 " " $12 " " $13}' /proc/net/dev) )
for i in {0..7}; do
(( traffic_delta[i] = ( traffic_curr[i] - traffic_prev[i] ) / isecs ))
done
traffic_prev=(${traffic_curr[@]})
printf '{"text": "%5s⇣ %5s⇡"}\n' $(human_readable ${traffic_delta[0]}) $(human_readable ${traffic_delta[4]})
#printf '{"text": "%5s⇣ %5s⇡", "alt": "%s", "tooltip": "%s", "class": "%s", "percentage": %d }\n' $(human_readable ${traffic_delta[0]}) $(human_readable ${traffic_delta[4]}) '_alt' '_tooltip' '_class' 0
done
# TODO: handle errors
# TODO: aggregate interfaces (default to all from `ls /sys/class/net | grep -E '^(eth|wlan|enp|wlp)'`)
# TODO: tooltip with details per each interface
# TODO: colors (?)
# TODO: styling (in waybar .css, using {percent})
# TODO: unicode meter (" ","▁","▁","▂","▃","▄","▅","▆","▇","█")
# TODO: split rx/tx (?)
# TODO: test and optimize
# NOTE: in waybar config (do NOT use "interval"):
# "custom/network_traffic": {
# "exec": "~/.config/waybar/scripts/network_traffic.sh enp14s0",
# },
Updates may or may not come but let me know of bugs.
Maybe it's better parsing ip -s -c link show
? Let me know.
Credits: adapted from traffic.sh · GitHub
edit: replaced script with better version, no more bogus results nor problems with more than one.
future updates when I post to gitlab the whole dots (a few weeks if nothing gets in the way)
@SGS
Thank you so much
Now it could, please, @OdiousImp implemented for the general public in Sway
Note that, just like the pacman one and any custom waybar script, if you have the bar on more than one monitor the two scripts stomp onto each other and give outdated (or, in this case) bogus results.
I worked around that in my pacman script but I'm not sure we want subshells talking to each other for something that refresh so often.
I hope to find time coming week to clean it up a bit before I share.
And the first bug is... sometimes it spits a negative number. crap.
Curiosity: does anyone use eww?
That would fit well with my ISP there it also jams more often.
I move this posts to Sway
This is nice, how did you set this up in ~/.config/waybar/config
? Is it a one-liner or does it source an external script from somewhere?
A few alternatives from my dots:
"format-wifi": "{icon} {essid}", // takes too much space and i dont want it in the screenshots
"format-wifi": "{icon} {ifname}",
//"format-alt": "{icon} {ifname}: {ipaddr}/{cidr}", // overridden by on-click below (click also toggles format/format-alt)
"tooltip-format": "{ifname}\t{ipaddr}/{cidr}\ngateway\t{gwaddr}",
"tooltip-format": "{ifname}\t{ipaddr}/{cidr}\ngateway\t{gwaddr}\n\t{essid}\n{icon} ⇣{bandwidthDownBytes} ⇡{bandwidthUpBytes}",
Work fine, interval I set to 1, correct?
"interval": 1,
"exec": "~/.config/waybar/scripts/network_traffic.sh wlp1s0 1",
Fine tuning
From i3 netspeed.sh, I add for my hardware wlp.
# Auto detect interfaces
ifaces=$(ls /sys/class/net | grep -E '^(eth|wlan|enp|wlp)')
@meanruse
Maybe you would like to become active here?
Shorter interval, more responsive but even less precise.
I'll try adding some averaging after I fix current issues, it's giving nonsense readings too often.
Next on the to-do list, combined traffic from all the interfaces and details in the tooltip (thanks for the hint about that).
Yep of course I'll share my stuff at some point, I want to clean it up first.
Reading Module: Custom · Alexays/Waybar Wiki · GitHub with more attention, I suspect I missed something and the "two scripts out of sync" may be entirely my fault... wouldn't be the first time I jump into some over-engineered solution to a non problem. Time to make coffee and have some fun!
OK, not entirely but for the most part. pacman next.
Turns out when I tried to use a "continuous script" last year I either done something wrong or hit a bug and gave up.
This has turned out well.
I do not like the { }"" in the waybar, so ...
printf 'Speed:%5s⇣ %5s⇡\n' $(human_readable ${traffic_delta[0]}) $(human_readable ${traffic_delta[4]})
Please, just post your fixes in a new post.
Darn, looks like I forgot to mention"return-type": "json"
in the waybar config.
New version, shows aggregate totals for multiple interfaces.
Default interval: 1 second, optional -tN
for N seconds.
Default interfaces: all except lo
, optional list as positional arguments.
Tooltip commented out because weird bug. Other features still under construction.
#!/bin/bash
# network_traffic.sh [-tPOLLING_INTERVAL] [NETWORK_INTERFACE...]
getopts t: __ && shift
isecs=${OPTARG:-1}
ifaces=($@)
: ${rate_max:=1000000} # maximum transfer rate for {percent}, can be overridden setting the env var
# `snore` adapted from https://blog.dhampir.no/content/sleeping-without-a-subprocess-in-bash-and-how-to-sleep-forever
# without MacOS workaround, TODO: with _snore_fd initialized separatedly, also i dont touch IFS so dont bother with it
snore() {
local IFS
[[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null
read ${1:+-t "$1"} -u $_snore_fd || :
}
# `human_readable` adapted from https://gist.github.com/cjsewell/96463db7fec6faeab291
human_readable() {
local value=$1
local units=( B K M G T P )
local index=0
while (( value > 1000 && index < 5 )); do
(( value /= 1000, index++ ))
done
echo "$value${units[$index]}"
}
exit_err() {
printf '{"text": "⚠ %s", "tooltip": "%s", "class": "error"}\n' "$@"
exit
}
if test ${#ifaces[@]} -gt 0; then
# sanity check the interface names
for iface in ${ifaces[@]}; do
test -h "/sys/class/net/${iface}" || exit_err "${iface}" "${iface} is not an existing network interface name"
done
else
# default to all interfaces except `lo`
ifaces=(/sys/class/net/*)
ifaces=(${ifaces[@]##*/})
ifaces=(${ifaces[@]//lo/})
# TODO: check that filtering out `lo` is enough, else `^(eth|wlan|enp|wlp)` as suggested
fi
# sanity check polling interval
if test ${isecs} -lt 1; then
exit_err "${isecs}" "${isecs} is not a valid polling interval"
fi
# NOTE: `snore` would take a decimal interval but bash arithmetic does not
#if test $(echo "${isecs} >= 0.2" |bc) -eq 0; then
# # TODO: set the class and tooltip
# exit_err "${isecs}" "${isecs} is not a valid polling interval"
#fi
# NOTE: `/proc/net/dev` format is:
# RX bytes packets errs drop fifo frame compressed multicast
# TX bytes packets errs drop fifo colls carrier compressed
# NOTE: array items are:
# 0=rx_bytes 1=rx_packets 2=rx_errs 3=rx_drop
# 4=tx_bytes 5=tx_packets 6=tx_errs 7=tx_drop
for iface in ${ifaces[@]} aggregate; do
declare -a traffic_prev_${iface} traffic_curr_${iface} traffic_delt_${iface}
declare -n traffic_prev=traffic_prev_${iface}
traffic_prev=( 0 0 0 0 0 0 0 0 )
done
# TODO: rearrange the loop, do not show bogus on first iteration
while snore ${isecs} ;do
tooltip=""
traffic_delt_aggregate=( 0 0 0 0 0 0 0 0 )
for iface in ${ifaces[@]}; do
declare -n traffic_prev=traffic_prev_${iface}
declare -n traffic_curr=traffic_curr_${iface}
declare -n traffic_delt=traffic_delt_${iface}
traffic_curr=( $(awk '/^ *'${iface}':/{print $2 " " $3 " " $4 " " $5 " " $10 " " $11 " " $12 " " $13}' /proc/net/dev) )
#FIXME: delayed one iteration wrt main display
#printf -v tooltip_hr_rx '%4s⇣' $(human_readable ${traffic_delt[0]})
#printf -v tooltip_hr_tx '%4s⇡' $(human_readable ${traffic_delt[4]})
#tooltip="${tooltip:+${tooltip}\r}${iface}\t${tooltip_hr_rx}\t${tooltip_hr_tx}"
for i in {0..7}; do
(( traffic_delt[i] = ( traffic_curr[i] - traffic_prev[i] ) / isecs ))
(( traffic_delt_aggregate[i] += traffic_delt[i] ))
done
traffic_prev=(${traffic_curr[@]})
done
printf '{"text": "%4s⇣ %4s⇡", "tooltip": "%s", "percent": %d}\n' \
$(human_readable ${traffic_delt_aggregate[0]}) \
$(human_readable ${traffic_delt_aggregate[4]}) \
"${tooltip}" \
$(( ( traffic_delt_aggregate[0] + traffic_delt_aggregate[4] ) / rate_max ))
#printf '{"text": "%5s⇣ %5s⇡", "alt": "%s", "tooltip": "%s", "class": "%s", "percentage": %d }\n' $(human_readable ${traffic_delt[0]}) $(human_readable ${traffic_delt[4]}) '_alt' '_tooltip' '_class' 0
done
# DONE: aggregate interfaces (default to all from `/sys/class/net` except `lo`)
# TODO: handle errors (partially done)
# TODO: tooltip with details per each interface (partially done, FIXME: tooltip is delayed compared to the main display, what the hell???)
# TODO: styling in waybar .css, using {percent} and "class" (partially done, "error" class but percent not working)
# TODO: unicode meter (" ","▁","▁","▂","▃","▄","▅","▆","▇","█")
# TODO: split rx/tx (?)
# TODO: colors (? unlikely)
# TODO: test and optimize
# NOTE: in waybar config (do NOT use "interval"):
# "custom/network_traffic": {
# "exec": "~/.config/waybar/scripts/network_traffic.sh",
# "return-type": "json",
# "format": "Speed: {}", // optional
# },
Yep. Sorry for the late response. I'll get it done tommrow. Thanks @meanruse!
Hold on, useless use of awk and one unnecessary loop got taken care of.
One small bug I'll fix in half an hour or so, then I post.
Apologies, I still could not find the time to upload a repo, my stuff is a bloody mess.
edit: it was just a variable not initialized, here it is. Unfinished but acceptable.
#!/bin/bash
# network_traffic.sh [-tPOLLING_INTERVAL] [NETWORK_INTERFACE...]
getopts t: __ && shift
isecs=${OPTARG:-1}
ifaces=($@)
: ${rate_max:=1000000} # maximum transfer rate for {percent}, can be overridden setting the env var
# `snore` adapted from https://blog.dhampir.no/content/sleeping-without-a-subprocess-in-bash-and-how-to-sleep-forever
# without MacOS workaround, TODO: with _snore_fd initialized separatedly, also i dont touch IFS so dont bother with it
snore() {
local IFS
[[ -n "${_snore_fd:-}" ]] || { exec {_snore_fd}<> <(:); } 2>/dev/null
read ${1:+-t "$1"} -u $_snore_fd || :
}
human_readable() {
local hrunits=( B K M G T P )
local ndigits=${#1}
local idxunit=$(( (2 + ndigits) / 3 - 1))
local lentrim=$(( ndigits - (idxunit * 3 ) ))
echo ${1::$lentrim}${hrunits[$idxunit]}
}
exit_err() {
printf '{"text": "⚠ %s", "tooltip": "%s", "class": "error"}\n' "$@"
exit
}
if test ${#ifaces[@]} -gt 0; then
# sanity check the interface names
for iface in ${ifaces[@]}; do
test -h "/sys/class/net/${iface}" || exit_err "${iface}" "${iface} is not an existing network interface name"
done
else
# default to all interfaces except `lo`
ifaces=(/sys/class/net/*)
ifaces=(${ifaces[@]##*/})
ifaces=(${ifaces[@]//lo/})
# TODO: check that filtering out `lo` is enough, else `^(eth|wlan|enp|wlp)` as suggested
fi
# sanity check polling interval
if test ${isecs} -lt 1; then
exit_err "${isecs}" "${isecs} is not a valid polling interval"
fi
# NOTE: `snore` would take a decimal interval but bash arithmetic does not
#if test $(echo "${isecs} >= 0.2" |bc) -eq 0; then
# exit_err "${isecs}" "${isecs} is not a valid polling interval"
#fi
# NOTE: `/proc/net/dev` format is:
# interface:
# RX bytes packets errs drop fifo frame compressed multicast
# TX bytes packets errs drop fifo colls carrier compressed
# NOTE: array items are:
# 0=rx_bytes 1=rx_packets 2=rx_errs 3=rx_drop
# 4=tx_bytes 5=tx_packets 6=tx_errs 7=tx_drop
for iface in ${ifaces[@]} aggregate; do
declare -a traffic_prev_${iface} traffic_curr_${iface} traffic_delt_${iface}
declare -n traffic_prev=traffic_prev_${iface}
declare -n traffic_curr=traffic_curr_${iface}
declare -n traffic_delt=traffic_delt_${iface}
traffic_prev=( 0 0 0 0 0 0 0 0 )
traffic_curr=( 0 0 0 0 0 0 0 0 )
traffic_delt=( 0 0 0 0 0 0 0 0 )
done
# TODO: rearrange the loop, do not show bogus on first iteration
while snore ${isecs} ;do
tooltip=""
traffic_delt_aggregate=( 0 0 0 0 0 0 0 0 )
readarray -s2 proc_net_dev </proc/net/dev
while read -a data; do
iface=${data[0]%:}
test "${ifaces[*]}" = "${ifaces[*]//${iface}/}" && continue
declare -n traffic_prev=traffic_prev_${iface}
declare -n traffic_curr=traffic_curr_${iface}
declare -n traffic_delt=traffic_delt_${iface}
traffic_curr=(${data[@]:1:4} ${data[@]:9:4})
#FIXME: tooltip is delayed one iteration wrt main display (but why?)
#printf -v tooltip_hr_rx '%4s⇣' $(human_readable ${traffic_delt[0]})
#printf -v tooltip_hr_tx '%4s⇡' $(human_readable ${traffic_delt[4]})
#tooltip="${tooltip:+${tooltip}\r}${iface}\t${tooltip_hr_rx}\t${tooltip_hr_tx}"
for i in {0..7}; do
(( traffic_delt[i] = ( traffic_curr[i] - traffic_prev[i] ) / isecs ))
(( traffic_delt_aggregate[i] += traffic_delt[i] ))
done
traffic_prev=(${traffic_curr[@]})
done <<<"${proc_net_dev[@]}"
printf '{"text": "%4s⇣ %4s⇡", "tooltip": "%s", "percentage": %d}\n' \
$(human_readable ${traffic_delt_aggregate[0]}) \
$(human_readable ${traffic_delt_aggregate[4]}) \
"${tooltip}" \
$(( ( traffic_delt_aggregate[0] + traffic_delt_aggregate[4] ) / rate_max ))
#printf '{"text": "%5s⇣ %5s⇡", "alt": "%s", "tooltip": "%s", "class": "%s", "percentage": %d }\n' $(human_readable ${traffic_delt[0]}) $(human_readable ${traffic_delt[4]}) '_alt' '_tooltip' '_class' 0
done
# DONE: aggregate interfaces (default to all from `/sys/class/net` except `lo`)
# DONE: get rid of "useless use of awk" (should be faster, but isn't -- still ~0.7 cpu on my box)
# DONE: avoid loop in human_readable (this makes it somewhat faster)
# TODO: handle errors (partially done)
# TODO: tooltip with details per each interface (partially done, FIXME: tooltip is delayed one iteration, ???)
# TODO: styling in waybar .css, using {percent} and "class" (partially done, "error" class but percent not working)
# TODO: unicode meter (" ","▁","▁","▂","▃","▄","▅","▆","▇","█")
# TODO: split rx/tx (?)
# TODO: colors (? unlikely)
# TODO: test and optimize
# NOTE: in waybar config (do NOT use "interval"):
# "custom/network_traffic": {
# "exec": "~/.config/waybar/scripts/network_traffic.sh",
# "return-type": "json",
# "format": "Speed: {}", // optional
# },
@meanruse is it ok for me to add this to the bar for EndeavourOS sway as well?
Of course it is, I just hope I actually works without problems.
I've been running it these last days, I noticed it is still a bit too CPU hungry for my taste.
At times, I see it (or waybar itself) spike over 1% . I think it's waybar redrawing though, I commented out the whole loop contents without noticeable difference.
I you have advice for that, let me know.
Facepalm time.
"format-ethernet": "{icon} {ifname} ⇣{bandwidthDownBytes} ⇡{bandwidthUpBytes}",
Some days, I really wish the internet could forget.
Something is wrong with me... and Depeche Mode made a song for me.
@OdiousImp @SGS
Done, correct?