i3blocks-bandwidth.plon commit improve webp-convert.sh (b8ae487)
   1#!/usr/bin/perl
   2#
   3#  i3blocks-bandwidth.pl
   4#
   5#  Get network throughput from /sys/class/net and convert it to readable format.
   6#  Keeps the text at a constant width regardless of the magnitude or units. This
   7#  is useful for i3bar with you don't want widgets changing width, but it could
   8#  also be used for other indicators or just as a quick shell script.
   9#
  10#  Usage: i3blocks-bandwidth.pl INTERFACE
  11#                               test 9198 (can be any float or integer)
  12#                               test {1..1000} (using shell expansion)
  13#
  14#  Note that Perl's printf doesn't round properly for numbers like 0.95 (i.e.
  15#  0.95 -> 0.9b not 1.0b). However, it is a lot faster than implementing a
  16#  custom rounding function. Accuracy doesn't matter much in this case. Also,
  17#  this script works best with a refresh rate of 1 second. It doesn't have to
  18#  be exact, but larger/smaller values give misleading averages.
  19#
  20
  21use strict;
  22use warnings;
  23
  24my $temppath = "/dev/shm/bandwidth-$ARGV[0]";
  25
  26offline() if ($#ARGV < 0);  # fail if no interface is specified
  27
  28if ($ARGV[0] eq "test") {   # see comment at top of file
  29  shift;
  30  foreach (@ARGV) {
  31    parse($_);
  32    print "\n";
  33  }
  34  exit;
  35}
  36
  37# Check if interface is up
  38open(STFILE, "/sys/class/net/$ARGV[0]/operstate") or offline();
  39my $state = <STFILE>;
  40close (STFILE);
  41$state =~  m/\A([^:\s]+)/;
  42offline() if ($1 ne "up");
  43
  44sub offline {
  45  print "<span color='#ff0000'>";
  46  print "down";
  47  print "</span>";
  48  exit;
  49}
  50
  51# Get rx bytes
  52open(BYTES, "/sys/class/net/$ARGV[0]/statistics/rx_bytes") or offline();
  53my $rx_bytes = <BYTES>;
  54close BYTES;
  55chomp $rx_bytes;
  56
  57# Get tx bytes
  58open(BYTES, "/sys/class/net/$ARGV[0]/statistics/tx_bytes") or offline();
  59my $tx_bytes = <BYTES>;
  60close (BYTES);
  61chomp $tx_bytes;
  62
  63# Get current time
  64my $time = time;
  65
  66if (-f $temppath) {   # Read then overwrite file
  67  open(BYTES, $temppath);
  68  my $oldcontent = <BYTES>;   # read old data
  69  close (BYTES);
  70  open(my $fh, '>', $temppath);
  71  print $fh "$time $rx_bytes $tx_bytes";  # write new data
  72  close $fh;
  73  my ($oldtime, $oldrx, $oldtx) = split / /, $oldcontent;
  74  my $dt = $time - $oldtime;
  75  my $drxdt = ($rx_bytes - $oldrx) / $dt * 8; # *8 converts bytes to bits
  76  my $dtxdt = ($tx_bytes - $oldtx) / $dt * 8;
  77  parse($drxdt);
  78  print " / ";
  79  parse($dtxdt);
  80} else {    # Write data and exit
  81  open(my $fh, '>', $temppath);
  82  print $fh "$time $rx_bytes $tx_bytes";
  83  close $fh;
  84  chmod 0666, $temppath;
  85  exit;
  86}
  87
  88sub parse {       # Determine best units and call round()
  89  my ($val) = @_;
  90  if ($val == 0) {
  91    print "000b";
  92  } elsif ($val < 999.5) {      # bits/second
  93    round($val, "b");
  94  } elsif ($val < 999500) {     # kilobits/second
  95    round($val / 1000, "k");
  96  } elsif ($val < 999500000) {  # megabits/second
  97    round($val / 1000000, "M");
  98  } else {
  99    round($val / 10000000000, "G");
 100  }
 101}
 102
 103sub round {     # Format to the correct number of characters
 104  my ($val, $suffix) = @_;
 105  if ($val < 9.95) {
 106    printf("%.1f%s", $val, $suffix);  # *.*
 107  } elsif ($val < 99.5) {
 108    printf("0%.0f%s", $val, $suffix); # 0**
 109  } else {
 110    printf("%.0f%s", $val, $suffix);  # ***
 111  }
 112}