Get upload/download kbps speed

Question:

I’m using the library called psutil to get system/network stats, but I can only get the total uploaded/downloaded bytes on my script.

What would be the way to natively get the network speed using Python?

Asked By: Kenny

||

Answers:

The (effective) network speed is simply bytes transferred in a given time interval, divided by the length of the interval. Obviously there are different ways to aggregate / average the times and they give you different “measures” … but it all basically boils down to division.

Answered By: Stephen C

If you need to know the transfer rate immediately, you should create a thread that does the calculations continuously. I’m not an expert on the subject, but I tried writing a simple program that does what you need:

import threading
import time
from collections import deque

import psutil


def calc_ul_dl(rate, dt=3, interface="WiFi"):
    t0 = time.time()
    counter = psutil.net_io_counters(pernic=True)[interface]
    tot = (counter.bytes_sent, counter.bytes_recv)

    while True:
        last_tot = tot
        time.sleep(dt)
        counter = psutil.net_io_counters(pernic=True)[interface]
        t1 = time.time()
        tot = (counter.bytes_sent, counter.bytes_recv)
        ul, dl = [
            (now - last) / (t1 - t0) / 1000.0
            for now, last in zip(tot, last_tot)
        ]
        rate.append((ul, dl))
        t0 = time.time()


def print_rate(rate):
    try:
        print("UL: {0:.0f} kB/s / DL: {1:.0f} kB/s".format(*rate[-1]))
    except IndexError:
        "UL: - kB/s/ DL: - kB/s"


# Create the ul/dl thread and a deque of length 1 to hold the ul/dl- values
transfer_rate = deque(maxlen=1)
t = threading.Thread(target=calc_ul_dl, args=(transfer_rate,))

# The program will exit if there are only daemonic threads left.
t.daemon = True
t.start()

# The rest of your program, emulated by me using a while True loop
while True:
    print_rate(transfer_rate)
    time.sleep(5)

Here you should set the dt argument to whatever seams reasonable for you. I tried using 3 seconds, and this is my output while runnning an online speedtest:

UL: 2 kB/s / DL: 8 kB/s
UL: 3 kB/s / DL: 45 kB/s
UL: 24 kB/s / DL: 1306 kB/s
UL: 79 kB/s / DL: 4 kB/s
UL: 121 kB/s / DL: 3 kB/s
UL: 116 kB/s / DL: 4 kB/s
UL: 0 kB/s / DL: 0 kB/s

The values seems reasonable since my result from the speedtest were DL: 1258 kB/s and UL: 111 kB/s.

Answered By: Steinar Lima

The answer provided by Steinar Lima is correct.
But it can be done without threading also:

import time
import psutil
import os

count = 0
qry = ""

ul = 0.00
dl = 0.00
t0 = time.time()
upload = psutil.net_io_counters(pernic=True)["Wireless Network Connection"][0]
download = psutil.net_io_counters(pernic=True)["Wireless Network Connection"][1]
up_down = (upload, download)


while True:
    last_up_down = up_down
    upload = psutil.net_io_counters(pernic=True)["Wireless Network Connection"][0]
    download = psutil.net_io_counters(pernic=True)["Wireless Network Connection"][1]
    t1 = time.time()
    up_down = (upload, download)
    try:
        ul, dl = [
            (now - last) / (t1 - t0) / 1024.0
            for now, last in zip(up_down, last_up_down)
        ]
        t0 = time.time()
    except:
        pass
    if dl > 0.1 or ul >= 0.1:
        time.sleep(0.75)
        os.system("cls")
        print("UL: {:0.2f} kB/s n".format(ul) + "DL: {:0.2f} kB/s".format(dl))

v = input()

Simple and easy 😉

Answered By: Abhay_

The first answer in interface should be change to desired network adapter. To see the name in ubuntu you can use ifconfig, then change interface='wifi' to the device name.

a little change to formatting in python3

def print_rate(rate):
    try:
        print(('UL: {0:.0f} kB/s / DL: {1:.0f} kB/s').format(*rate[-1]))
    except IndexError:
        'UL: - kB/s/ DL: - kB/s'
Answered By: martinbandung

I added an LCD mod for this code if you want to test it on a raspberry pi but you need to add the psutil and the lcddriver to your project code!!!!

import time
import psutil
import os
import lcddriver

count=0
qry=''

ul=0.00
dl=0.00
t0 = time.time()
upload=psutil.net_io_counters(pernic=True)['wlan0'][0]
download=psutil.net_io_counters(pernic=True)['wlan0'][1]
up_down=(upload,download)
display = lcddriver.lcd()

while True:
    last_up_down = up_down
    upload=psutil.net_io_counters(pernic=True)['wlan0'][0]
    download=psutil.net_io_counters(pernic=True)['wlan0'][1]
    t1 = time.time()
    up_down = (upload,download)
    try:
        ul, dl = [(now - last) / (t1 - t0) / 1024.0
                 for now,last in zip(up_down, last_up_down)]             
        t0 = time.time()
        #display.lcd_display_string(str(datetime.datetime.now().time()), 1)
    except:
        pass
        
    if dl>0.1 or ul>=0.1:
       time.sleep(0.75) 
       os.system('cls')
       print('UL: {:0.2f} kB/s n'.format(ul)+'DL:{:0.2f} kB/s'.format(dl))
       display.lcd_display_string(str('DL:{:0.2f} KB/s      '.format(dl)), 1)
       display.lcd_display_string(str('UL:{:0.2f} KB/s      '.format(ul)), 2)
       
    # if KeyboardInterrupt: # If there is a KeyboardInterrupt (when you press ctrl+c), exit the program and cleanup
    #     print("Cleaning up!")
    #     display.lcd_clear()   
    
v=input()
Answered By: Christopher Samaan

Another and more simple solution (without threading and queues although still based on @Steinar Lima) and for more recent python:

import time
import psutil

def on_calculate_speed(self, interface):
    dt = 1 # I find that dt = 1 is good enough

    t0 = time.time()

    try:
        counter = psutil.net_io_counters(pernic=True)[interface]
    except KeyError:
        return []

    tot = (counter.bytes_sent, counter.bytes_recv)
    while True:
        last_tot = tot
        time.sleep(dt)
        try:
            counter = psutil.net_io_counters(pernic=True)[interface]
        except KeyError:
            break
        t1 = time.time()
        tot = (counter.bytes_sent, counter.bytes_recv)
        ul, dl = [
            (now - last) / (t1 - t0) / 1000.0
            for now, last
            in zip(tot, last_tot)
        ]
        return [int(ul), int(dl)]
        t0 = time.time()

while SomeCondition:
   # "wlp2s0" is usually the default wifi interface for linux, but you
   # could use any other interface that you want/have.
   interface = "wlp2s0"
   result_speed = on_calculate_speed(interface)
   if len(result_speed) < 1:
      print("Upload: - kB/s/ Download: - kB/s")
   else:
      ul, dl = result_speed[0], result_speed[1]
      print("Upload: {} kB/s / Download: {} kB/s".format(ul, dl))

Or you could also fetch the default interface with pyroute2:

while SomeCondition:
   ip = IPDB()
   interface = ip.interfaces[ip.routes['default']['oif']]["ifname"]
   result_speed = on_calculate_speed(interface)
   if len(result_speed) < 1:
      print("Upload: - kB/s/ Download: - kB/s")
   else:
      ul, dl = result_speed[0], result_speed[1]
      print("Upload: {} kB/s / Download: {} kB/s".format(ul, dl))
   ip.release()
Answered By: calexandru

i found this tread, and dont have any idea from python, i jst copy and paste codes, and now need a little help, this script, i have jst show the total of bytes send/recived, can modify to show the actual speed?

def network(iface):
stat = psutil.net_io_counters(pernic=True)[iface]
return "%s: Tx%s, Rx%s" % 
       (iface, bytes2human(stat.bytes_sent), bytes2human(stat.bytes_recv))



def stats(device):
# use custom font
font_path = str(Path(__file__).resolve().parent.joinpath('fonts', 'C&C Red Alert [INET].ttf'))
font_path2 = str(Path(__file__).resolve().parent.joinpath('fonts', 'Stockholm.ttf'))
font2 = ImageFont.truetype(font_path, 12)
font3 = ImageFont.truetype(font_path2, 11)

with canvas(device) as draw:
    draw.text((0, 0), cpu_usage(), font=font2, fill="white")
    if device.height >= 32:
        draw.text((0, 14), mem_usage(), font=font2, fill="white")

    if device.height >= 64:
        draw.text((0, 26), "IP: " + getIP("eth0"), font=font2, fill=255)
        try:
            draw.text((0, 38), network('eth0'), font=font2, fill="white")
        except KeyError:
            # no wifi enabled/available
            pass

The code

# pip install speedtest-cli

import speedtest

speed_test = speedtest.Speedtest()

def bytes_to_mb(bytes):
  KB = 1024 # One Kilobyte is 1024 bytes
  MB = KB * 1024 # One MB is 1024 KB
  return int(bytes/MB)

download_speed = bytes_to_mb(speed_test.download())
print("Your Download speed is", download_speed, "MB")
upload_speed = bytes_to_mb(speed_test.upload())
print("Your Upload speed is", upload_speed, "MB")
Answered By: Mounesh
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.